Closed kl-pen closed 1 year ago
@kl-pen
In both cases you should restore chat connection. Usually mobile OS prevents chat connect after 2-5 mins in background
1) check your chat connection state - ConnectyCube.chat.isConnected
;
2) connect to chat if chat is not connected - if (ConnectyCube.chat.isConnected) { ConnectyCube.chat.connect() }
.
FYI. The ConnectyCube's session also expires after two hour of inactivity. I suggest you to manage this.
1) You can store the ConnectyCube's session and compare session.updated_at + 2 * 60 * 60
(timestamp in seconds) with current time and define to use the stored session (ConnectyCube.setSession(storedSession)
) or create new one (ConnectyCube.createSession()
).
2) To handle that a session was expired see the session expiration docs
Thank so much for your reply.
Regarding your explanation for handling chat connection and session expired ,
1. Since our app use External authentication via Custom Identity Provider (CIdP) for user authentication, after creating a new session using ConnectyCube.createSession()
, should we also do
ConnectyCube.login()
& ConnectyCube.chat.connect()
as well ?
Please see our code for handling createSession & connect to chat.
//Create ConnectyCube Session & login to Custom Identity Provider
let data = await this.createSession();
if (!data) {
this._inLogin = false;
return false;
}
let obj = {
userId: data.id,
password: data.token,
}
//Login to ConnectyCube Chat
let _connect = await this.connect(obj)
//CreateSession Function
createSession = async () => {
let session = await ConnectyCube.createSession().catch((error) => {
return { errors: error };
});
if (session?.errors) {
return false
}
let account = await Storage.getDataKeychain();
if (!account?.AccountVOIPID || !account?.VOIPToken) {
return false
}
const userCredentials = {
AccountVOIPID: account.AccountVOIPID,
VOIPToken: account.VOIPToken,
};
//LOGIN to Custom Identity Provider and use return data to connect to chat
let users = await ConnectyCube.login(userCredentials).catch((error) => {
return { errors: error };
});
if (users?.errors) {
return false
}
let obj = Object.assign(session, users);
await Storage.storeData('Session', obj);
return obj;
}
//Connect to Chat Function
connect = async (obj) => {
if (!ConnectyCube?.chat?.connect) {
return false
}
//Using authentication data return from createSession() to connect to chat
let _connect = await ConnectyCube.chat.connect(obj).catch((error) => {
return { errors: error };
});
if (_connect?.errors) {
return false
}
this._inLogin = false;
return true
}
2. Similar to first question, when session expired do we need to do ConnectyCube.login()
& ConnectyCube.chat.connect()
or just below?
sessionExpired: (handleResponse, retry) => {
console.log("-----------sessionExpired");
ConnectyCube.createSession()
.then(retry)
.catch((error) => {});
},
3. To handle incoming call when session has expired & device is in Lock Screen state, we also try using chat.ping() to recheck connection & recreate session again. Is this the correct way? or we should just check using only
if (ConnectyCube.chat.isConnected) { ConnectyCube.chat.connect() }
.
Due to sometimes we receive below error and we are not sure what is the meaning of below.
ERROR [Chat] xmppClient.start error [Error: Connection is not offline]
LOG -----connect error [Error: Connection is not offline]
4. Since we want to try handling session expired case correctly, is there any API we can use to simulate this without waiting for 2 hours? (ex. API to manually expired / destroy session)
Sorry for such a long question. We deeply appreciate for all you help and support and looking forward to hearing back from you soon.
ConnectyCube.createSession() creates empty session (w/o user). The ConnectyCube.login(params) is needed to upgrade session on server and pass user auth data to the session. It's all you need to have a normal session.
Yes. createSession + login > chat.connect
The error is from XMPP chat lib and it really looks strange. Usually it shows when you are trying to use chat connection before chat is connected
A sessions' expiration time is a server setting. You can use ConnectyCube.destroySession() to make behavior that similar to expired session.
I prefer to use custom chat statuses to manage the chat connection. E.g. this.chatStatus = 'disconnected'
before the ConnectyCube.chat.connect() wouldn't call, this.chatStatus = 'connecting'
with the same time with ConnectyCube.chat.connect(), this.chatStatus = 'connected'
after successful connected and this.chatStatus = 'failed'
otherwise. Setup ConnectyCube.chat.onDisconnectedListener = this.onDisconnect.bind(this);
where onDisconnect = () => { this.chatStatus = 'disconnected'; }
.
Also pay attention to '@react-native-community/netinfo' library to know offline/online state.
FYI. Here the sample code to use AppState with mark chat as active/inactive:
handleAppStateChange = (state) => {
if (state === 'inactive') {
// handle only 'active' and 'background'
// https://facebook.github.io/react-native/docs/appstate
return;
}
if (ConnectyCube.chat.isConnected) {
if (state === 'active') {
ConnectyCube.chat.markActive();
} else {
ConnectyCube.chat.markInactive();
}
} else if (isOnline) { // from NetInfo lib
ConnectyCube.chat.connect(params); // connect with user params
}
};
// AppState.addEventListener('change', handleAppStateChang);
Thank you so much for your detailed explanation!
As you suggested, we tried to handle session expired and chat re-connect by doing createSession + login > chat.connect
and used custom chat statuses to manage chat connection.
However, we sometimes found below error message when we tried to do createSession + login > chat.connect
in ConnectyCube.chat.onDisconnectedListener
event. And the connection process failed.
ERROR [Chat] xmppClient.start error [Error: Connection is not offline]
LOG -----connect error [Error: Connection is not offline]
Question:
1. Since we make sure to do createSession + login > chat.connect
after receive onDisconnect but still get this error, is there any other reasons for this [Error: Connection is not offline]
message?
ConnectyCube.chat.ping()
in some events to make sure the connection is still connected or trigger auto-reconnect event. If we do this during the createSession + login > chat.connect
would it might cause this error?2. Currently we use below config which enable both ping & chat auto-reconnect. Should we leave this setting enable as it is? or should we disable them (due to manually handling createSession + login > chat.connect
by ourselves)?
Connectycube Config
export const appConfig = {
debug: { mode: 0 },
chat: {
reconnectionTimeInterval: 2,
reconnect: {
enable: true,
timeInterval: 2
},
streamManagement: {
enable: true
},
ping: {
enable: true,
timeInterval: 30
}
},
videochat: {
alwaysRelayCalls: false,
answerTimeInterval: 45,
dialingTimeInterval: 3,
disconnectTimeInterval: 35,
statsReportTimeInterval: false,
},
Oh, sorry... I forgot about autoreconnect. I your case would be better to manually manage the connection to chat. Change your config:
export const appConfig = {
debug: { mode: 0 },
chat: {
streamManagement: {
enable: true,
},
reconnect: {
enable: false,
},
},
Try to do it w/o chat.ping() and remove it from your config. Please, show full log if the error [Error: Connection is not offline]
keeps repeating.
Thank you so much for your reply.
So you mean in our case we shouldn't use auto-reconnect & auto-ping at all ? (because of using External Authentication via Custom identity provider?)
If so, it means we need to manually handle reconnect by ourselves. So we need to manually checking connection & attempt reconnect in multiple events such as onDisconnect
, AppState: Active
, IncomingCall/OutgoingCall
??
With auto-reconnect config, it seems after a fews reconnect attempts it stopped retry eventually.
Is there any event/listener to detect if reconnect attempt is stopped or resulted in error ?
Because if there is such event, we think we can trigger our own reconnect flow using createSession + login > chat.connect
.
No, I recommend it, because of React Native. The reconnect: true works fine with web applications, but it brings some issues in React Native when OS close the WebSocket connection in background. It is normal to manage chat connections via statuses. Do not worry about ConnectyCube’s session, cause it works via HTTPS instead of chat (it keeps WS connection to be online)
Thank you so much for your support. We have tried as you suggested below.
Now after we answer the call, the connection will get established successfully. However after implementing the above, we seem to run into another problem....
Issue: After answer incoming call when leave the app in background for more than 2 hours, the call will get established but sometimes it will immediately got disconnect after 1-2 secs.
SessionConnectionState.CONNECTED
and the call got established SessionConnectionState.CLOSED
event after 1 -2 secs of CONNECTED state.Questions 1. What is the correct way to use onSessionConnectionStateChangedListener to monitor VOIP connection state and update call UI accordingly ?
Now we handle as below.
2. Why after answer call the receiver side sometimes receive SessionConnectionState.CLOSED
immediately after SessionConnectionState.CONNECTED
(1-2 secs)? Should we ignore CLOSED state ?
For more information on device & issue log please see below.
Device: Samsung A21, iPhone 11/14 P.S. This problem seems to happened more frequent if the receiver side is iPhone.
Version: react-native@0.67.4, react-native-connectycube@3.22.1
Log of Receiver (UserA) :
LOG [14:36:14 GMT+0700] _onDisconnectedListener: received disconnect event
LOG [14:36:18 GMT+0700] _reConnectWithSession: manual check session & handle reconnect
LOG [14:36:21 GMT+0700] _connectionState 1: CONNECTING
LOG [14:36:24 GMT+0700] _connectionState 2: CONNECTED
LOG [14:36:25 GMT+0700] _connectionState 5: CLOSED
Log of Caller (UserB):
LOG [14:34:45 GMT+0700] finish login flow: createSession + login + chatconnect()
LOG [14:36:26 GMT+0700] _connectionState 1: CONNECTING
LOG [14:36:26 GMT+0700] _connectionState 2: CONNECTED
LOG [14:36:28 GMT+0700] _connectionState 5: CLOSED
Hi, @kl-pen !
It is normal behavior for mobile's OS. Need to configure background service to solve the issue.
Pay attention to this guide.
The onSessionConnectionStateChangedListener
just informs about call peer state. I think that you use it correct when update some info on UI depending on current state.
Thank you so much for your response.
We have already followed your guide and finish config background mode correctly. However the issue still occurred, which we think it is not normal behavior (call end abruptly after pressed accept call without user doing anything)
We tested that our app works correctly in background mode in normal case, but seems to have issue only when we leaves the app in background for a long time. (our voip app uses voice call only and doesn't use video call)
Upon further analyzing our log, the issue seems to be on the Caller side as below.
ConnectyCube.videochat.onSessionConnectionStateChangedListener : DISCONNECTED
and
ConnectyCube.videochat.onStopCallListener
(even though the receivers side didn't do anything)Why do we received ConnectyCube event onStopCallListener even though users didn't do anything?
Please see our debug log taken from Caller side in the attached file below. ConnectyCubeLog.pdf
Hi, @kl-pen
Is caller receive event in the onStopCallListener immediately after callee answers or after some interval (reject or no answer)?
Do you have logs from callee side?
Thank you so much for your reply and sorry for taking such a long time to response back.
Upon analyzing logs of both caller & callee sides very carefully, it seems that the root cause is because our app mishandled case when user accepts call at the time session's already expired (which caused the callee side to force end call and triggered onStopCallListener event on the caller side).
After we fixed the above issue, now the call doesn't end abruptly anymore (even after leaving the app for long time in background). We are deeply sorry for the misunderstanding on our part.
Again, thank you so much for all the guidance and support. Now our app can do VOIP call in background and it works correctly!!
No problem! Good to know, that you have managed to solve the issue
We use Push notification (VOIP push for iOS) and Call Keep to handle incoming call in background state. However, we experience strange issues if the receiver side leaves app in background state for a long time (more than 1 hour)
Issue1: If leave the app in background state for a long time and try to answer incoming call within 5 secs, the call will never get established (due to receiver side will not get onCall() event)
Issue2: If leave the app in background state for a long time and try to reject incoming call within 5 secs, the calling side doesn’t receive onReject event.
Question What is the correct step to handle when receiving incoming call while app in background state for a long time? Should we re-login to connect cube every time when app change from background to active state?
Currently we do below connectycube login process when app is first open only.