for a grpc client `listen` function to the stream not working same as `await for (...)` - flutter

I have a golang server which streams data and a dart client. I put the following code which seems to be working fine
var response = stub.streamMusic(RequestMusicId(musicId: musicId));
await for(var v in response) {
print(v);
}
but when i tried to listen to the stream using this
var response = stub.streamMusic(RequestMusicId(musicId: musicId));
response.listen((value) {
print(value);
});
i get the following error, even though the server is running.
Connecting to VM Service at http://127.0.0.1:55936/l3_uHzU_qIw=/
Unhandled exception:
gRPC Error (code: 14, codeName: UNAVAILABLE, message: Error connecting: Connection shutting down., details: null, rawResponse: null, trailers: {})
Exited (255)

Related

Flutter websocket connects to wrong port

In my app, I created a Route for communicating with a socket.
class _SocketRouteState extends State<SocketRoute> {
#override
void initState() {
super.initState();
try {
WebSocketChannel _channel = IOWebSocketChannel.connect(
Uri.parse('ws://192.168.1.90:9998'),
);
///
/// Start listening to new notifications / messages
///
_channel.stream.listen(
(data) {
debugPrint(data);
},
onDone: () {
debugPrint('ws channel closed');
},
onError: (error) {
debugPrint('ws error $error');
},
);
_channel.sink.add('testing');
} catch (e) {
///
/// General error handling
/// TODO handle connection failure
///
debugPrint('Connection exception $e');
}
}
}
When I run this code, it fails to connect to the socket, though. After waiting for ~2 minutes, Xcode shows me the following error:
flutter: ws error WebSocketChannelException: WebSocketChannelException: SocketException: OS Error: Operation timed out, errno = 60, address = 192.168.1.90, port = 52168
This clearly shows a different port. Could that be the issue? Anyone know why it's connecting on port 52168 instead of 9998?
The problem with the confusing port number is, that the error message is not that great, since it shows the local port being used on your own machine and not the remote port you are trying to connect to. TCP requires a port to be open on both the server and the client so they can communicate both ways. But normally, you are mostly interested in the remote port.
There are an old github issue here about this issue:
https://github.com/dart-lang/sdk/issues/12693

build Flutter client for IPFS

please trying to build a FLUTTER client to access IPFS server using dart_ipfs_client
my function
sendMessage() async {
print('-------------1');
var ipfs = Ipfs(url: 'http://10.0.2.2:5001');
print('-------------2');
var addRes = await ipfs.add(utf8.encode('Hello World!'));
print('-------------3');
}
I have this error
[ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception:
SocketException: OS Error: Connection timed out, errno = 110, address
= 10.0.2.2, port = 41004
Please is the any solution to fix this?

Cannot connect to to FastAPI with WebSocket in Flutter. 403 forbidden / code 1006

So I've been trying for while to establish a websocket connection between my flutter app and FastAPI.
I believe the problem lies in Flutter.
So far i've tried the flutter packages socket_io_client, web_socket_channel and websocket_manager to no awail.
I suspect it might have to do with the app architecture maybe... bit at a loss atm.
Here is the flutter errors:
I/onListen(26110): arguments: null
I/EventStreamHandler(26110): đź”´ event sink
I/onListen(26110): arguments: null
I/EventStreamHandler(26110): đź”´ event sink
W/System.err(26110): java.net.ProtocolException: Expected HTTP 101 response but was '403 Forbidden'
W/System.err(26110): at okhttp3.internal.ws.RealWebSocket.checkUpgradeSuccess$okhttp(RealWebSocket.kt:185)
W/System.err(26110): at okhttp3.internal.ws.RealWebSocket$connect$1.onResponse(RealWebSocket.kt:156)
W/System.err(26110): at okhttp3.RealCall$AsyncCall.run(RealCall.kt:140)
W/System.err(26110): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
W/System.err(26110): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
W/System.err(26110): at java.lang.Thread.run(Thread.java:923)
I/EventStreamHandler(26110): âś… sink is not null
I/flutter (26110): websocket closed
Im aware it says the 403 forbidden came from my API, though i know websocket connection is possible, as i've tested it with javascript.
here is the log from the API:
DEBUG | websockets.protocol:__init__:244 - server - state = CONNECTING
DEBUG | websockets.protocol:connection_made:1340 - server - event = connection_made(<_SelectorSocketTransport fd=484 read=polling write=<idle, bufsize=0>>)
DEBUG | websockets.protocol:data_received:1412 - server - event = data_received(<422 bytes>)
DEBUG | websockets.server:read_http_request:237 - server < GET /11 HTTP/1.1
DEBUG | websockets.server:read_http_request:238 - server < Headers([('authorization', 'Bearer *JWTTOKEN*'), ('upgrade', 'websocket'), ('connection', 'Upgrade'), ('sec-websocket-key', 'zytoCsWVlcmsKghL5XFEdA=='), ('sec-websocket-version', '13'), ('host', '10.0.2.2:8000'), ('accept-encoding', 'gzip'), ('user-agent', 'okhttp/4.3.1')])
INFO | uvicorn.protocols.websockets.websockets_impl:asgi_send:198 - ('127.0.0.1', 50772) - "WebSocket /11" 403
DEBUG | websockets.server:write_http_response:256 - server > HTTP/1.1 403 Forbidden
DEBUG | websockets.server:write_http_response:257 - server > Headers([('Date', 'Fri, 09 Apr 2021 11:10:11 GMT'), ('Server', 'Python/3.7 websockets/8.1'), ('Content-Length', '0'), ('Content-Type', 'text/plain'), ('Connection', 'close')])
DEBUG | websockets.server:write_http_response:267 - server > body (0 bytes)
DEBUG | websockets.protocol:fail_connection:1261 - server ! failing CONNECTING WebSocket connection with code 1006
DEBUG | websockets.protocol:connection_lost:1354 - server - event = connection_lost(None)
DEBUG | websockets.protocol:connection_lost:1356 - server - state = CLOSED
DEBUG | websockets.protocol:connection_lost:1365 - server x code = 1006, reason = [no reason]
I have all the WebSocket code in a Class that is beeing 'provided', I.E WebSocketState:
return runApp(
MultiProvider(
providers: [
Provider<AuthenticationState>(
create: (_) => new AuthenticationState(),
),
Provider<WebSocketState>(
create: (_) => new WebSocketState(),
),
],
child: MyApp(),
),
);
WebSocketState:
class WebSocketState {
final _socketMessage = StreamController<Message>();
Sink<Message> get getMessageSink => _socketMessage.sink;
Stream<Message> get getMessageStream => _socketMessage.stream;
WebsocketManager socket;
bool isConnected() => true;
void connectAndListen(int userId) async {
var token = await secureStorage.read(key: 'token');
socket = WebsocketManager(
'ws://10.0.2.2:8000/$userId', {'Authorization': 'Bearer $token'});
socket.onClose((dynamic message) {
print('websocket closed');
});
// Listen to server messages
socket.onMessage((dynamic message) {
print("Message = " + message.toString());
});
// Connect to server
socket.connect();
}
void dispose() {
_socketMessage.close();
socket.close();
}
}
the connectAndListen method is called in the first/main page after user has authenticated, then in other Pages the websocket is beeing used.
#override
void didChangeDependencies() {
super.didChangeDependencies();
Provider.of<WebSocketState>(context, listen: false).connectAndListen(
Provider.of<AuthenticationState>(context, listen: false).id);
}
API websocket 'class':
websocket_notifier.py
from enum import Enum
import json
from typing import List
class SocketClient:
def __init__(self, user_id: int, websocket: WebSocket):
self.user_id = user_id
self.websocket = websocket
class WSObjects(Enum):
Message = 0
class Notifier:
def __init__(self):
self.connections: List[SocketClient] = []
self.generator = self.get_notification_generator()
async def get_notification_generator(self):
while True:
message = yield
await self._notify(message)
async def push(self, msg: str):
await self.generator.asend(msg)
async def connect(self, user_id: int, websocket: WebSocket):
await websocket.accept()
self.connections.append(SocketClient(user_id, websocket))
def remove(self, websocket: WebSocket):
client: SocketClient
for x in self.connections:
if x.websocket == websocket:
client = x
self.connections.remove(client)
async def _notify(self, message: str):
living_connections = []
while len(self.connections) > 0:
# Looping like this is necessary in case a disconnection is handled
# during await websocket.send_text(message)
client = self.connections.pop()
await client.websocket.send_text(message)
living_connections.append(client)
self.connections = living_connections
async def send(self, user_id: int, info: WSObjects, json_object: dict):
print("WS send running")
msg = {
"info": info,
"data": json_object
}
print("connections count: " + str(len(self.connections)))
for client in self.connections:
if client.user_id == user_id:
print("WS sending msg to ${client.user_id}")
await client.websocket.send_text(json.dumps(msg))
break
notifier = Notifier()
API main:
from fastapi import FastAPI
from websocket_notifier import notifier
from starlette.websockets import WebSocket, WebSocketDisconnect
app = FastAPI()
#app.get("/")
async def root():
return {"message": "Root"}
#app.websocket("/ws/{user_id}")
async def websocket_endpoint(user_id: int, websocket: WebSocket):
await notifier.connect(user_id, websocket)
try:
while True:
data = await websocket.receive_text()
await websocket.send_text(f"Message text was: {data}")
except WebSocketDisconnect:
notifier.remove(websocket)
#app.on_event("startup")
async def startup():
# Prime the push notification generator
await notifier.generator.asend(None)
Any ideas what Im doing wrong? (the other flutter websocket packages I've used virutally In the same way as the one I showed)
through lots of testing i finally found a way to get websockets to work with my flutter app and fastapi.
https://github.com/tiangolo/fastapi/issues/129
Had to try a bit of different things from that issue thread. But endend up with using python-socketio. I had to use a lower version of python-socketio to be compatible with the newest flutter socket_io_client package.
For those who have the same problem, please also check #2639. Prefix of the APIRouter does not work in websocket decorator.

Flutter: Connecting to localhost:5001 with http package from local device doesn't work

I have the following problem: I have a .NET API running on my local machine at https://localhost:5001. When I execute a request in Postman, it works totally fine, but when executing the same API call in Dart, it won't work.
In Postman https://localhost:5001 will respond with a 401 or a 200 Statuscode.
When I execute the exact same URL in Flutter, it will give me a timeout:
Flutter Devtools
When using https://localhost:5001 in Flutter -> SocketException: OS Error: Connection refused, errno = 111, address = localhost, port = 41838
When using https://192.168.0.154:5001 in Flutter -> SocketException: OS Error: Connection timed out, errno = 110, address = 192.168.0.154, port = 44624
Im executing the following code:
var response = await http.get(url);
if(response.statusCode == 200) {
print(response.body);
}else{
throw Exception('Failed to fetch');
}```

How to handle idle_in_transaction_session_timeout?

When we set idle_in_transaction_session_timeout, the database will terminate connections that are idle for some time.
This works as expected, but I wonder how we should deal with this situation in the aplication code.
We are using pg-promise 10.3.1.
Details of the test:
we set the connection pool size to 1, so that we only have a single session
we set the for the idle-transaction-session-timeout to 2.5 sec:
SET idle_in_transaction_session_timeout TO 2500
now the active transaction will be in state idle in transaction:
see What can cause “idle in transaction” for “BEGIN” statements
now we start a transaction and sleep for 5 seconds
after 2.5sec the database will terminate the session and send an error to the client:
pgp-error error: terminating connection due to idle-in-transaction timeout
after another 2.5sec the transactional code tries to send a query (via the already terminated session), and this fails as expected:
dbIdle failed Error: Client has encountered a connection error and is not queryable
then pg-promise will try to rollback the transaction which will also fail (also expected, I guess)
But now we start a new query and also this query fails with
dbCall failed Client has encountered a connection error and is not queryable
is this expected? I was hoping that pg-promise can somehow remove the "broken" connection from the pool and that we could get a new one
obvously this is not the case, so how should we deal with this situation: i.e. how to recover, so that we can send new queries to the database?
Code example:
import pgPromise, { IMain } from "pg-promise";
import * as dbConfig from "./db-config.json";
import { IConnectionParameters } from "pg-promise/typescript/pg-subset";
const cll = "pg";
console.time(cll);
const pgp: IMain = pgPromise({
query(e) {
console.timeLog(cll,`> ${e.query}`);
},
error(e, ctx) {
console.timeLog(cll,"pgp-error", e);
}
});
const connectParams: IConnectionParameters = {
...dbConfig,
application_name: "pg-test",
max: 1
};
const db = pgp(connectParams);
/**
* #param timeoutMs 0 is no timeout
*/
async function setDbIdleInTxTimeout(timeoutMs: number = 0) {
await db.any("SET idle_in_transaction_session_timeout TO $1;", timeoutMs);
}
async function dbIdle(sleepTimeSec: number) {
console.timeLog(cll, `starting db idle ${sleepTimeSec}`);
const result = await db.tx(async t => {
await new Promise(resolve => setTimeout(resolve, sleepTimeSec * 1000));
return t.one("Select $1 as sleep_sec", sleepTimeSec);
});
console.timeLog(cll, result);
}
async function main() {
await setDbIdleInTxTimeout(2500);
try {
await dbIdle(5);
} catch (e) {
console.timeLog(cll, "dbIdle failed", e);
}
try {
await db.one("Select 1+1 as res");
} catch (e) {
console.timeLog(cll, "dbCall failed", e);
}
}
main().finally(() => {
pgp.end();
});
Console output (removed some useless lines):
"C:\Program Files\nodejs\node.exe" D:\dev_no_backup\pg-promise-tx\dist\index.js
pg: 23.959ms > SET idle_in_transaction_session_timeout TO 2500;
pg: 28.696ms starting db idle 5
pg: 29.705ms > begin
pg: 2531.247ms pgp-error error: terminating connection due to idle-in-transaction timeout
at TCP.onStreamRead (internal/stream_base_commons.js:182:23) {
name: 'error',
severity: 'FATAL',
code: '25P03',
}
pg: 2533.569ms pgp-error Error: Connection terminated unexpectedly
pg: 5031.091ms > Select 5 as sleep_sec
pg: 5031.323ms pgp-error Error: Client has encountered a connection error and is not queryable
pg: 5031.489ms > rollback
pg: 5031.570ms pgp-error Error: Client has encountered a connection error and is not queryable
pg: 5031.953ms dbIdle failed Error: Client has encountered a connection error and is not queryable
pg: 5032.094ms > Select 1+1 as res
pg: 5032.164ms pgp-error Error: Client has encountered a connection error and is not queryable
pg: 5032.303ms dbCall failed Error: Client has encountered a connection error and is not queryable
Process finished with exit code 0
This issue #680 has been fixed in pg-promise 10.3.5