Closed tjmeal closed 1 year ago
You can add a function for the onWebSocketDone
callback. This will trigger on both expected disconnects and unexpected connection loss/disconnect.
Checking if the client is still active in this function tells you wether this was a intentional disconnect or not. Like this:
onWebSocketDone: () {
if (client.isActive) {
_scheduleReconnect();
}
},
Hello,
Thanks for your reply, this is what i have but it seems not to get triggered.
How am i testing > I am running on my pc a simulator and i run the server to a different pc throw ngrok on which you need internet access to connect to.
Then i close the wifi on the pc with my flutter simulator > And the onWebSocketDone is not triggered. The only think that indicate there is no connection is the onDebugMessage is stop triggering (while i have wifi off).
Thanks i will be waiting your reply.
Hey,
i am using this library in a big app where it is very crucial that it detects disconnects reliably. We don't have any issues and i just tested it in my Android Emulator by turning Wifi off (Airplane Mode on). Seems to be working fine. If you close the Wifi it might take a few seconds to register that the connection is down. Can you maybe provide some code?
Hello,
Thanks a lot for your reply, because i am not working on android simulator, i tried it and indeed works as expected.
But i am afraid works only on android:
Android Simulator: Works Android Real Device As Web App: Works
Ios simulator : Don't work Ios Device with IOS build: Don't work Ios Device As Web App: Don't Work Wep App On Computer: Don't Work
Thanks again for your time and i will be waiting for your reply.
Hey,
i would be very surprised if it did not work on iOS since the main devices our app is running on are IPads. I currently don't have access to a iOS device so it might take a bit until i can confirm/check if i find any issues. Can you share a minimal example which isn't working please?
Thanks
Hello again,
Thanks for you reply, i think i have noticed something which maybe the root of the problem.
In android device you must detecting the internet connection > based on device's wifi api if its on/off > and not if the device has actually connection to the internet.
Try the following on Android Emulator (for server use an api that needs internet connection and not localhost)
When you turn off wifi / airplane mode it detects the lost of connection successfully try to leave wifi open but turn off your pc's wifi/internet connection you will see that it won't detect the loss of connection (and if you try to access any webpage through emulator's browser app you can't (meaning that you dont have internet access to the emulator)).
Please let me know with your thoughts about that.
Regarding your request to share a example > Send me your email or a way in which i can send you a dm > so i can share with you a staging version of our app to test it.
Hello again,
Do we have any news ?
Hey,
i've tested this with the emulator and can confirm that it does not detect the disconnect. I've also tested it on a real device and this works fine. So i guess this is a quirk of the emulator, and there is probably very little i can do about it.
Hello again,
And thanks for your reply,
I did record a video showing the issue > i dont know how you are testing it.
But if you see on the video i am following 100% same process and on Android Works perfectly while on IOS don't. (Both are WebApps and using the same version/link everything in Real devices).
https://drive.google.com/file/d/1wuUHvEyYc_VC_LtI_Zwna7359IYKv3wg/view?usp=sharing
Please let me know how you are testing it and works on your end.
Thanks again i will be waiting your reply.
Hey,
thanks for the video. So you are building it as a WebApp and hosting it and then using this website for both the Android and iOS showcase in the video? So your app was not natively installed on any of those two devices? Just wanted to make sure.
Do you by any chance have a hosted example where this can be tested at? Or at least code i can use to host my own app?
Edit: Are you currently using heartbeats, specifically heartbeatIncoming
? Or did you set both of them to 0?
Thanks
Hello and good morning,
Correct, is a pwa webApp and hosting it and then using this website for both Android and IOS. (NOT natively installed).
I can send you by direct message a demo url with demo credentials for you to test if you give me an email or a way to contact you privately, i can also share my screen and use via USB a real ios device and run the app there ( which i have also tested and not working, which installs the application natively) so its not webApp issue, is Ios platform issue i think.
Please find bellow my StompClientConfig. Regarding heartbeatIncoming > i have the commend out, maybe is the issue there ? If you could share your configuration to try it out ?
`final stompClient = StompClient( config: StompConfig.SockJS( url: '$BASE_ROUTE_ENDPOINT/websocket', beforeConnect: _beforeConnect, onConnect: onConnect, //webSocketConnectHeaders: {'Authorization': 'Bearer $_jwtToken'}, stompConnectHeaders: {'Authorization': 'Bearer $_jwtToken'}, onWebSocketDone: loaderDialogWidget,
//heartbeatIncoming: Duration(seconds: 1),
//heartbeatOutgoing: Duration(seconds: 1),
//connectionTimeout: Duration(seconds: 15),
reconnectDelay: const Duration(seconds: 2),
onUnhandledFrame: (StompFrame frame) => print('onUnhandledFrame :: ${frame.body}'),
onUnhandledMessage: (StompFrame frame) => print('onUnhandledMessage :: ${frame.body}'),
onUnhandledReceipt: (StompFrame frame) => print('onUnhandledReceipt :: ${frame.body}'),
onStompError: (StompFrame frame) => print('onStompError :: ${frame.body}'),
onWebSocketError: (dynamic error) => print('onWebSocketError ::$error'),
onDisconnect: (StompFrame frame) => print('onDisconnect :: ${frame.toString()}'),
onDebugMessage: (dynamic frame) => print('onDebugMessage :: ${frame.toString()}'),
), );`
Thanks for the config. What is your outgoing heartbeat value on the server? Can you share your config on the server-side? I am asking because there seem to be some native issues on iOS and WebSocket disconnect detection. One can circumvent those by using a heartbeat and our library indeed should automatically close the connection if a heartbeat is configured and not received.
Hello,
ON server i have very basic implementation without explicitly config the heartbeat and Spring has as default to 25 seconds. Please find it attached.
I am only using inboundChanel to authenticate Users, nothing else, could you send me your config on server to try it out ?
Hey,
are you sure that the default is 25 seconds? If i read the documentation correctly, it is set to 0 seconds, unless you define a taskScheduler https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/messaging/simp/config/SimpleBrokerRegistration.html#setHeartbeatValue(long%5B%5D)
Edit: Ah. You might be right about 25 seconds for SockJS. Can you try to specifically set a task-scheduler and lower the heartbeat values? Like this:
ThreadPoolTaskScheduler te = new ThreadPoolTaskScheduler();
te.setPoolSize(1);
te.setThreadNamePrefix("wss-heartbeat-thread-");
te.initialize();
messageBrokerRegistry.enableSimpleBroker("/topic", "/queue")
.setHeartbeatValue(new long[] {5000, 5000})
.setTaskScheduler(te);
Can you also match this config on your client and check if it now disconnects correctly after 10 seconds?
Hello thanks again it works now.
With the bellow implementation it too : 10 seconds to disconnect and 5 sec to reconnect.
If its possible and easy for you without want to disturb always.
a) Can you give me a tested clientConfig which i should use ? b) Now we have set the server to send heartbeat every 5 seconds and client hearBeatIncoming to 5 sec why it takes 10? What is heartbeat incoming/Outgoing and what its use? can you give me an article or explain me roughly how it works to have a better understanding ?
Thanks again i will be waiting your reply.
all the best
Hey,
in our app we also use 5 seconds for both directions, so you should be fine. Here is the description in the Stomp specification: https://stomp.github.io/stomp-specification-1.2.html#Heart-beating
It basically makes sure that the connection/end point is still up and functioning/sending.
Regarding: Why it takes 10 seconds to disconnect? The client expects the server to send a message at least every 5 seconds, if it fails to do so it will disconnect and try to reconnect. The specification states: "because of timing inaccuracies, the receiver SHOULD be tolerant and take into account an error margin" and because of this we multiply this value by 2 and thus we wait 10 seconds until we ultimately disconnect.
See also here for potential issues with iOS and onDone: https://github.com/dart-lang/sdk/issues/47807 https://github.com/dart-lang/web_socket_channel/issues/207
Okay great,
As always really helpful !!
Thanks you very very much.
Glad i could help. I will close this issue. If you have any other issue feel free to open another issue/reopen this one.
Hello again,
May i ask you about an issue i am facing now to give me your thoughts,
Everything works perfect > what i don't like (maybe its not possible to do otherwise) >
When the put the app on the background (not terminate) the connection is lost, and even if i minimize the app for 5 seconds and bring it back again > i have to go throw the reconnection process to web sockets .
Is that normal behavior ? Can somehow keep web sockets open when app is in the background? Or another trick because i am sure you would have face that behavior aswell.
Thanks again and i will be waiting your reply.
Hey,
That is normal behaviour and expected. Keeping your connection open in the background is probably going to be very difficult (if not impossible on iOS). There are a lot of restrictions when it comes to running something in the background on the devices. But i am not an expert and my knowledge here might be outdated. I suggest you read up on the various ways this might be achievable.
https://developer.apple.com/library/archive/technotes/tn2277/_index.html#//apple_ref/doc/uid/DTS40010841-CH1-SUBSECTION11 https://developer.android.com/guide/background
Thanks you very much !! Have great holidays.
Best Themis.
Hello again,
How are you ?
Everything works, i am just trying to make it work even better.
The "issues" i am facing is the following:
a) I am using bellow code to send message to the server > it have happened when the app is minimized has loss connection > and open the app back again > not to reconnect to webosckets (while i have a set a dialog to block the screen when there is NO connection) > and try send an update to the server > which of course didnt happened because there is no connection.
Is there any way when i use stompCLinet.send() .... to identify if there is no connection and show an error to the user that this actions is not possible to perform and trigger reconnection ?
Future
b) Every time i minimize the app and open something else and then open it again even for 1-2 seconds > it losses connection and i am waiting to reconnect again, which is really annoying... i have tried other apps and they do loss connection but not after 1-2 second > maybe after 30 or so. Which parameter or what kills the connection when the app is minimized ? And how are the other apps able to keep connection for longer ?
c) IOS does not recognise immediately the connection lost of the server, no matter how i config the heartBeats (while i have tested with another well know app which does it immediately). Which part affects that behavior so i can find how they have done it to work immediately ?
I have tested those issues with a well know IOS app and its not there.
Thanks again i will be waiting your reply.
Hi,
a) You can check stompClient.connected
to validate your connection before sending any message
b) & c) Internally we use WebSocketChannel
(https://pub.dev/packages/web_socket_channel), so we are not actively disconnecting but only listen to the events given to us. If you are only interested in the IO part of this library you could try to alter the code here: https://github.com/blackhorse-one/stomp_dart_client/blob/master/lib/src/_connect_io.dart to also set the pingInterval
of the underlying WebSocket connection, like this: webSocket.pingInterval = Duration(seconds: 1)
(https://api.dart.dev/stable/3.0.0/dart-io/WebSocket/pingInterval.html). And see if that helps.
As i said our library only handles voluntary disconnects actively. All other types of (premature) disconnects etc. are probably caused by either the WebSocket implementation of dart or the WebSocketChannel
library.
Hello and hope you are doing well,
I am facing an issue,
Imagine you are on the road > and for some reason you lose connection to the internet due to weak signal.
How can i detect such occasion ?
Thanks in advance and i will be waiting for your reply.