ConnectyCube / connectycube-flutter-samples

Code samples for Flutter, based on ConnectyCube platform
https://developers.connectycube.com/flutter/
Apache License 2.0
86 stars 90 forks source link

onReceiveMessage not fired after reconnected #261

Closed lethanhclub closed 6 months ago

lethanhclub commented 1 year ago

Specify the sample to which the issue belongs (use [x]): [] Chat sample [] P2P Calls sample [] Conference Calls sample

Platform (use [x]) [] Android [] iOS [] macOS [] Windows [] Web [] Linux

Device info Manufacture: Model: OS version:

Describe the bug:

Steps to Reproduce:

  1. Turn on airplane mode
  2. Send messages to offline device
  3. Turn off airplane mode

Logs:

[log] ---Xmpp Sending:---
[log] <r xmlns="urn:xmpp:sm:3"/>
[log] ---Xmpp Receiving:---
[log] <a xmlns='urn:xmpp:sm:3' h='6'/>
[log] D/[Connection]: Handle connection done
[log] D/[Connection]: State: XmppConnectionState.ForcefullyClosed
[log] D/[ReconnectionManager]: Connection forcefully closed!
E/flutter (20776): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: SocketException: Software caused connection abort (OS Error: Software caused connection abort, errno = 103), address = chat.connectycube.com, port = 48034
E/flutter (20776):
I/flutter (20776): CB-SDK: CubeChatConnection: Chat connection ForcefullyClosed
E/flutter (20776): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: SocketException: Software caused connection abort (OS Error: Software caused connection abort, errno = 103), address = chat.connectycube.com, port = 48034
E/flutter (20776):
I/ViewRootImpl@933dee[MainActivity](20776): MSG_WINDOW_FOCUS_CHANGED 1 1
D/InputMethodManager(20776): startInputInner - Id : 0
I/InputMethodManager(20776): startInputInner - mService.startInputOrWindowGainedFocus
I/ViewRootImpl@933dee[MainActivity](20776): MSG_WINDOW_FOCUS_CHANGED 0 1
I/ViewRootImpl@933dee[MainActivity](20776): MSG_WINDOW_FOCUS_CHANGED 1 1
D/InputMethodManager(20776): startInputInner - Id : 0
I/InputMethodManager(20776): startInputInner - mService.startInputOrWindowGainedFocus
[log] D/[Connection]: State: XmppConnectionState.Reconnecting
[log] D/[Connection]: State: XmppConnectionState.SocketOpening
I/flutter (20776): CB-SDK: : chatConnectionState = CubeChatConnectionState.ForceClosed
I/flutter (20776): CB-SDK: CubeChatConnection: Chat connection Reconnecting
I/flutter (20776): CB-SDK: CubeChatConnection: Chat connection SocketOpening
[log] D/[Connection]: State: XmppConnectionState.SocketOpened
[log] ---Xmpp Sending:---
I/flutter (20776): CB-SDK: CubeChatConnection: Chat connection SocketOpened
[log] <?xml version='1.0'?><stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='chat.connectycube.com' xml:lang='en'>
[log] ---Xmpp Receiving:---
[log] D/[Connection]: processInitialStream
[log] <?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='chat.connectycube.com' id='9305f866-5f24-4673-bef4-1182fa3afdea' version='1.0' xml:lang='en'>
[log] ---Xmpp Receiving:---
[log] D/[ConnectionNegotiatorManager]: Negotiating features
[log] D/[ConnectionNegotiatorManager]: Found matching negotiator true
[log] ---Xmpp Sending:---
[log] <auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">ADc5Njk4OTQtNzAzNABPQ0RZOVB0SWdtYWVHS0dpVmhOM2NaUWNvU0ky</auth>
[log] <stream:features><sm xmlns="urn:xmpp:sm:3"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism><mechanism>PLAIN_FAST</mechanism></mechanisms><ver xmlns="urn:xmpp:features:rosterver"/><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression></stream:features>
[log] D/[ConnectionNegotiatorManager]: ACTIVE FEATURE: {name: SaslAuthenticationFeature, name_space: null, priority: 1000, state: NegotiatorState.NEGOTIATING}, isReady: true
[log] ---Xmpp Receiving:---
[log] <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>
[log] ---Xmpp Sending:---
[log] D/[Connection]: State: XmppConnectionState.Authenticated
I/flutter (20776): CB-SDK: CubeChatConnection: Chat connection Authenticated
[log] D/[ConnectionNegotiatorManager]: Found matching negotiator true
[log] ---Xmpp Sending:---
[log] <enable xmlns="urn:xmpp:sm:3"/>
[log] D/[ConnectionNegotiatorManager]: Feature Started Parsing
[log] <?xml version='1.0'?><stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='chat.connectycube.com' xml:lang='en'>
[log] D/[ConnectionNegotiatorManager]: ACTIVE FEATURE: {name: StreamManagementModule, name_space: null, priority: 1000, state: NegotiatorState.NEGOTIATING}, isReady: true
[log] ---Xmpp Receiving:---
[log] D/[Connection]: processInitialStream
[log] <?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='chat.connectycube.com' id='9305f866-5f24-4673-bef4-1182fa3afdea' version='1.0' xml:lang='en'>
[log] ---Xmpp Receiving:---
[log] D/[ConnectionNegotiatorManager]: Negotiating features
[log] D/[ConnectionNegotiatorManager]: Found matching negotiator true
[log] ---Xmpp Sending:---
[log] <stream:features><sm xmlns="urn:xmpp:sm:3"/><mobile xmlns="http://tigase.org/protocol/mobile#v2"/><ver xmlns="urn:xmpp:features:rosterver"/><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></stream:features>
[log] <iq id="TLCGFEPTW" type="set">
        <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
          <resource>flutter_U1AxQS4yMTA4MTIuMDE2</resource>
        </bind>
      </iq>
[log] D/[ConnectionNegotiatorManager]: ACTIVE FEATURE: {name: BindingResourceConnectionNegotiator, name_space: null, priority: 100, state: NegotiatorState.NEGOTIATING}, isReady: true
[log] ---Xmpp Receiving:---
[log] <enabled xmlns='urn:xmpp:sm:3' />
[log] ---Xmpp Receiving:---
[log] ---Xmpp Sending:---
[log] <a xmlns="urn:xmpp:sm:3" h="8"/>
[log] ---Xmpp Sending:---
[log] <a xmlns="urn:xmpp:sm:3" h="8"/>
[log] D/[ConnectionNegotiatorManager]: Found matching negotiator false
[log] D/[ConnectionNegotiatorManager]: Found matching negotiator true
[log] ---Xmpp Sending:---
[log] <iq id="JNHHJHSOC" type="set" to="chat.connectycube.com">
        <session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>
      </iq>
[log] <iq xmlns="jabber:client" id="TLCGFEPTW" to="7969894-7034@chat.connectycube.com/flutter_U1AxQS4yMTA4MTIuMDE2" type="result"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>7969894-7034@chat.connectycube.com/flutter_U1AxQS4yMTA4MTIuMDE2</jid></bind></iq><r xmlns='urn:xmpp:sm:3' />
[log] D/[ConnectionNegotiatorManager]: ACTIVE FEATURE: {name: SessionInitiationNegotiator, name_space: null, priority: 1000, state: NegotiatorState.NEGOTIATING}, isReady: true
[log] ---Xmpp Receiving:---
I/flutter (20776): CB-SDK: CubeChatConnection: Chat connection SessionInitialized
[log] D/[Connection]: State: XmppConnectionState.SessionInitialized
[log] D/[ConnectionNegotiatorManager]: Found matching negotiator false
[log] D/[ConnectionNegotiatorManager]: Found matching negotiator false
[log] D/[ConnectionNegotiatorManager]: No matching negotiator
[log] D/[Connection]: State: XmppConnectionState.Ready
I/flutter (20776): CB-SDK: CubeChatConnection: Chat connection Ready
[log] ---Xmpp Sending:---
[log] <iq id="FIBYRRSGF" type="get">
        <query xmlns="jabber:iq:roster"/>
      </iq>
[log] ---Xmpp Sending:---
[log] <presence/>
[log] <iq from="chat.connectycube.com" xmlns="jabber:client" id="JNHHJHSOC" to="7969894-7034@chat.connectycube.com/flutter_U1AxQS4yMTA4MTIuMDE2" type="result"/>
[log] ---Xmpp Receiving:---
[log] <r xmlns='urn:xmpp:sm:3' />
[log] ---Xmpp Sending:---
[log] <a xmlns="urn:xmpp:sm:3" h="10"/>
[log] ---Xmpp Sending:---
[log] <a xmlns="urn:xmpp:sm:3" h="10"/>
[log] ---Xmpp Receiving:---
[log] ---Xmpp Sending:---
[log] <a xmlns="urn:xmpp:sm:3" h="12"/>
[log] ---Xmpp Sending:---
[log] <a xmlns="urn:xmpp:sm:3" h="12"/>
[log] <iq xmlns="jabber:client" id="FIBYRRSGF" to="7969894-7034@chat.connectycube.com/flutter_U1AxQS4yMTA4MTIuMDE2" type="result"><query xmlns="jabber:iq:roster"/></iq><r xmlns='urn:xmpp:sm:3' />
[log] ---Xmpp Receiving:---
[log] D/[StanzaParser]: No id found for stanza
[log] ---Xmpp Sending:---
[log] <a xmlns="urn:xmpp:sm:3" h="14"/>
[log] ---Xmpp Sending:---
[log] <a xmlns="urn:xmpp:sm:3" h="14"/>
[log] <presence from="7969894-7034@chat.connectycube.com/flutter_U1AxQS4yMTA4MTIuMDE2" xmlns="jabber:client" to="7969894-7034@chat.connectycube.com"/><r xmlns='urn:xmpp:sm:3' />
[log] ---Xmpp Sending:---
[log] <r xmlns="urn:xmpp:sm:3"/>
[log] ---Xmpp Receiving:---
[log] <a xmlns='urn:xmpp:sm:3' h='4'/>
[log] ---Xmpp Sending:---
[log] <r xmlns="urn:xmpp:sm:3"/>
[log] ---Xmpp Receiving:---
[log] <a xmlns='urn:xmpp:sm:3' h='4'/>
[log] ---Xmpp Sending:---
[log] <r xmlns="urn:xmpp:sm:3"/>
[log] ---Xmpp Receiving:---
[log] <a xmlns='urn:xmpp:sm:3' h='4'/>
[log] ---Xmpp Sending:---
[log] <r xmlns="urn:xmpp:sm:3"/>
[log] ---Xmpp Receiving:---
[log] <a xmlns='urn:xmpp:sm:3' h='4'/>
D/InputMethodManager(20776): startInputInner - Id : 0
I/InputMethodManager(20776): startInputInner - mService.startInputOrWindowGainedFocus
I/flutter (20776): CB-SDK: : Current app state: AppLifecycleState.inactive
I/ViewRootImpl@933dee[MainActivity](20776): MSG_WINDOW_FOCUS_CHANGED 0 1
I/ViewRootImpl@933dee[MainActivity](20776): handleAppVisibility mAppVisible=true visible=false
I/ViewRootImpl@933dee[MainActivity](20776): stopped(true) old=false
I/SurfaceView@b5e38b5(20776): 114807449 wPL, frameNr = 0
I/SurfaceView@b5e38b5(20776): aOrMT: uB = true t = android.view.SurfaceControl$Transaction@765795e fN = 0 android.view.SurfaceView.access$500:124 android.view.SurfaceView$SurfaceViewPositionUpdateListener.positionLost:1785 android.graphics.RenderNode$CompositePositionUpdateListener.positionLost:326
I/SurfaceView@b5e38b5(20776): aOrMT: vR.mWNT, vR = ViewRootImpl@933dee[MainActivity]
I/ViewRootImpl@933dee[MainActivity](20776): mWNT: t = android.view.SurfaceControl$Transaction@765795e fN = 0 android.view.SurfaceView.applyOrMergeTransaction:1628 android.view.SurfaceView.access$500:124 android.view.SurfaceView$SurfaceViewPositionUpdateListener.positionLost:1785
I/ViewRootImpl@933dee[MainActivity](20776): mWNT: merge t to BBQ
I/SurfaceView@b5e38b5(20776): windowStopped(true) false io.flutter.embedding.android.FlutterSurfaceView{b5e38b5 V.E...... ........ 0,0-1080,2136} of ViewRootImpl@933dee[MainActivity]
I/SurfaceView@b5e38b5(20776): pST: mTmpTransaction.apply, mTmpTransaction = android.view.SurfaceControl$Transaction@8fef180
I/SurfaceView@b5e38b5(20776): surfaceDestroyed callback.size 1 #1 io.flutter.embedding.android.FlutterSurfaceView{b5e38b5 V.E...... ........ 0,0-1080,2136}
I/SurfaceView@b5e38b5(20776): updateSurface: mVisible = false mSurface.isValid() = true
I/SurfaceView@b5e38b5(20776): remove() io.flutter.embedding.android.FlutterSurfaceView{b5e38b5 V.E...... ........ 0,0-1080,2136} Surface(name=SurfaceView - com.connectycube.flutter.chat_sample/com.connectycube.flutter.chat_sample.MainActivity@b5e38b5@0)/@0xde3813f
D/SurfaceView@b5e38b5(20776): updateSurface: surface is not valid
I/MSHandlerLifeCycle(20776): isMultiSplitHandlerRequested: windowingMode=1 isFullscreen=true isPopOver=false isHidden=false skipActivityType=false isHandlerType=true this: DecorView@43829a2[MainActivity]
I/MSHandlerLifeCycle(20776): removeMultiSplitHandler: no exist. decor=DecorView@43829a2[MainActivity]
I/SurfaceView@b5e38b5(20776): onWindowVisibilityChanged(8) false io.flutter.embedding.android.FlutterSurfaceView{b5e38b5 G.E...... ......I. 0,0-1080,2136} of ViewRootImpl@933dee[MainActivity]
D/SurfaceView@b5e38b5(20776): updateSurface: surface is not valid
D/OpenGLRenderer(20776): setSurface called with nullptr
D/OpenGLRenderer(20776): setSurface() destroyed EGLSurface
D/OpenGLRenderer(20776): destroyEglSurface
I/ViewRootImpl@933dee[MainActivity](20776): Relayout returned: old=(0,0,1080,2280) new=(0,0,1080,2280) req=(1080,2280)8 dur=43 res=0x5 s={false 0} ch=false fn=-1
D/SurfaceView@b5e38b5(20776): updateSurface: surface is not valid
I/flutter (20776): CB-SDK: : Current app state: AppLifecycleState.paused
I/flutter (20776): CB-SDK: AsyncStanzaSender: getInstance
I/flutter (20776): CB-SDK: AsyncStanzaSender: add new task OGCROSOKF
I/flutter (20776): CB-SDK: AsyncStanzaSender: start timer OGCROSOKF
D/SurfaceView@b5e38b5(20776): updateSurface: surface is not valid
D/InputTransport(20776): Input channel destroyed: 'ClientS', fd=126
D/InputTransport(20776): Input channel destroyed: 'ClientS', fd=132
D/InputTransport(20776): Input channel destroyed: 'ClientS', fd=145
Lost connection to device.

Exited.

or Gist log

Actual result: Sometimes offline messages are not sent to the device after reconnected

Expected behavior: offline messages are always sent to the device after reconnected

Additional info Add any other context about the problem here.

TatankaConCube commented 1 year ago

Could you please specify all required fields we are requesting in the template to issue? Which platform do you use while reproducing this issue? Can you reproduce it in the latest version of our sample? Please provide the full log from the device during the reproduction of this issue. We just checked it a few times on Android and iOS and can't reproduce it in the Chat sample from the master branch.

lethanhclub commented 1 year ago

this bug happened on both iOS and android. You have to turn off wifi and LTE while the app is still in foreground, then you send a few messages to the offline device. Finally, you turn on wifi/LTE and wait for reconnecting. You can see offline messages lost sometimes.

TatankaConCube commented 1 year ago

can you please share the log from the device where you reproduce this issue? or please specify in more detail how can we reproduce it on our side. turning on/off the internet connection on our side doesn't lead to this issue

lethanhclub commented 1 year ago

can you please share the log from the device where you reproduce this issue? or please specify in more detail how can we reproduce it on our side. turning on/off the internet connection on our side doesn't lead to this issue

I just updated my post with log.

TatankaConCube commented 1 year ago

Can you receive messages after successful reconnection? I mean messages sent after reconnection, not messages sent when a user was offline. To avoid the inconsistency of data you can request new messages via an API request. You can request the messages with the date_sent more than received last message's dateSent. You can use the next request for it:

  Future<List<CubeMessage>> getMessagesByDate(int date, bool isLoadNew) async {
    var params = GetMessagesParameters();
    params.sorter = RequestSorter(SORT_DESC, '', 'date_sent');
    params.limit = messagesPerPage;
    params.filters = [
      RequestFilter('', 'date_sent', isLoadNew || date == 0 ? 'gt' : 'lt', date)
    ];

    return getMessages(_cubeDialog.dialogId!, params.getRequestParameters())
        .then((result) {
          lastPartSize = result!.items.length;

          return result.items;
        })
        .whenComplete(() {})
        .catchError((onError) {});
  }

In our sample, we use it for loading messages by pages and you can use it for loading new messages.

lethanhclub commented 1 year ago

Can you receive messages after successful reconnection? I mean messages sent after reconnection, not messages sent when a user was offline. To avoid the inconsistency of data you can request new messages via an API request. You can request the messages with the date_sent more than received last message's dateSent. You can use the next request for it:

  Future<List<CubeMessage>> getMessagesByDate(int date, bool isLoadNew) async {
    var params = GetMessagesParameters();
    params.sorter = RequestSorter(SORT_DESC, '', 'date_sent');
    params.limit = messagesPerPage;
    params.filters = [
      RequestFilter('', 'date_sent', isLoadNew || date == 0 ? 'gt' : 'lt', date)
    ];

    return getMessages(_cubeDialog.dialogId!, params.getRequestParameters())
        .then((result) {
          lastPartSize = result!.items.length;

          return result.items;
        })
        .whenComplete(() {})
        .catchError((onError) {});
  }

In our sample, we use it for loading messages by pages and you can use it for loading new messages.

I can receive messages after reconnected.

btw, I can use this function for a dialog, but I also want to update the recent dialogs screen where the latest messages for dialogs will be displayed correctly. This function cannot do that.

TatankaConCube commented 1 year ago

you can refresh the list of the dialogs in a similar way by requesting dialogs by filtering them by updated_at field (this field updates after sending the message to this dialog). The request can look similar to the next:

      var lastUpdateTime; // some time point in seconds when the last message was received or dialogs requested
      Map<String, dynamic> additionalParams = {
        "updated_at[gt]": lastUpdateTime
      };

      getDialogs(additionalParams).then((dialogs) async {
        logTime("Success GET_DIALOGS: $dialogs");

      });
TatankaConCube commented 6 months ago

no activity for a long time. closing...