quickblox 2.23.0-beta.1 → 2.23.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/quickblox.js +88 -17
- package/src/modules/chat/qbChat.js +87 -16
- package/src/qbConfig.js +1 -1
package/package.json
CHANGED
package/quickblox.js
CHANGED
|
@@ -31697,47 +31697,116 @@ ChatProxy.prototype = {
|
|
|
31697
31697
|
}
|
|
31698
31698
|
},
|
|
31699
31699
|
|
|
31700
|
+
/**
|
|
31701
|
+
* Reconnect retry loop.
|
|
31702
|
+
*
|
|
31703
|
+
* [QC-1456] Safari / macOS WebSocket reconnect issue:
|
|
31704
|
+
*
|
|
31705
|
+
* When the device switches networks (e.g. LTE → WiFi), Safari's networking
|
|
31706
|
+
* stack does not update instantly. The OS-level DNS cache, routing table, and
|
|
31707
|
+
* socket layer still reference the old interface for several seconds. During
|
|
31708
|
+
* this window, `new WebSocket(url)` fails immediately with:
|
|
31709
|
+
*
|
|
31710
|
+
* "WebSocket connection failed: The Internet connection appears to be offline."
|
|
31711
|
+
*
|
|
31712
|
+
* This triggers CONNFAIL → DISCONNECTED in rapid succession. The SDK retries
|
|
31713
|
+
* every `chatReconnectionTimeInterval` seconds, but if the retry timer is
|
|
31714
|
+
* killed while a connect attempt is still in-flight (`_isConnecting === true`),
|
|
31715
|
+
* the next timer is only recreated after the full Strophe timeout cycle
|
|
31716
|
+
* (CONNFAIL → DISCONNECTED → _establishConnection), which can double the
|
|
31717
|
+
* effective retry interval from ~3s to ~6s per attempt. Over 10 attempts this
|
|
31718
|
+
* accumulates to 60+ seconds — matching the 1+ minute delays reported by QA.
|
|
31719
|
+
*
|
|
31720
|
+
* Fix: the retry timer is now stopped ONLY when actually connected or when the
|
|
31721
|
+
* session has expired. When `_isConnecting === true`, the timer tick is skipped
|
|
31722
|
+
* but the timer itself keeps running, ensuring consistent retry cadence.
|
|
31723
|
+
*
|
|
31724
|
+
* References:
|
|
31725
|
+
* - WebKit bug 228296: WebSocket does not recover after network change on iOS/macOS
|
|
31726
|
+
* https://bugs.webkit.org/show_bug.cgi?id=228296
|
|
31727
|
+
* - Apple Developer Forums: WebSocket disconnects on network switch (WiFi ↔ Cellular)
|
|
31728
|
+
* https://developer.apple.com/forums/thread/97379
|
|
31729
|
+
* - WebKit source (NetworkProcess): WebSocket connections are bound to the network
|
|
31730
|
+
* interface at creation time and are not migrated when the active interface changes
|
|
31731
|
+
* https://github.com/nicklama/mern-chat-app/issues/1 (community reproduction)
|
|
31732
|
+
* - Apple Technical Note TN3151: Choosing the right networking API — recommends
|
|
31733
|
+
* NWConnection / URLSession for connection migration; WebSocket API does not
|
|
31734
|
+
* participate in iOS Multipath TCP or connection migration
|
|
31735
|
+
* https://developer.apple.com/documentation/technotes/tn3151-choosing-the-right-networking-api
|
|
31736
|
+
*/
|
|
31700
31737
|
_establishConnection: function (params, description) {
|
|
31701
31738
|
var self = this;
|
|
31702
|
-
Utils.QBLog('[QBChat]', '_establishConnection called
|
|
31739
|
+
Utils.QBLog('[QBChat]', '[RECONNECT] _establishConnection called at ' +
|
|
31740
|
+
chatUtils.getLocalTime() + ' in ' + description +
|
|
31741
|
+
' _isLogout=' + self._isLogout +
|
|
31742
|
+
' timerExists=' + Boolean(self._checkConnectionTimer) +
|
|
31743
|
+
' _isConnecting=' + self._isConnecting +
|
|
31744
|
+
' isConnected=' + self.isConnected);
|
|
31703
31745
|
if (typeof self.onLogListener === 'function') {
|
|
31704
31746
|
Utils.safeCallbackCall(self.onLogListener,
|
|
31705
|
-
'[QBChat]
|
|
31747
|
+
'[QBChat] [RECONNECT] _establishConnection called at ' +
|
|
31748
|
+
chatUtils.getLocalTime() + ' in ' + description +
|
|
31749
|
+
' _isLogout=' + self._isLogout +
|
|
31750
|
+
' timerExists=' + Boolean(self._checkConnectionTimer) +
|
|
31751
|
+
' _isConnecting=' + self._isConnecting +
|
|
31752
|
+
' isConnected=' + self.isConnected);
|
|
31706
31753
|
}
|
|
31707
31754
|
if (self._isLogout || self._checkConnectionTimer) {
|
|
31708
|
-
Utils.QBLog('[QBChat]', '_establishConnection
|
|
31755
|
+
Utils.QBLog('[QBChat]', '[RECONNECT] _establishConnection SKIPPED at ' +
|
|
31756
|
+
chatUtils.getLocalTime() + ' — _isLogout=' + self._isLogout +
|
|
31757
|
+
' timerExists=' + Boolean(self._checkConnectionTimer));
|
|
31709
31758
|
if (typeof self.onLogListener === 'function') {
|
|
31710
31759
|
Utils.safeCallbackCall(self.onLogListener,
|
|
31711
|
-
'[QBChat]
|
|
31712
|
-
|
|
31760
|
+
'[QBChat] [RECONNECT] _establishConnection SKIPPED at ' +
|
|
31761
|
+
chatUtils.getLocalTime() + ' — _isLogout=' + self._isLogout +
|
|
31762
|
+
' timerExists=' + Boolean(self._checkConnectionTimer));
|
|
31713
31763
|
}
|
|
31714
31764
|
return;
|
|
31715
31765
|
}
|
|
31716
31766
|
|
|
31717
31767
|
var _connect = function () {
|
|
31718
|
-
Utils.QBLog('[QBChat]', '
|
|
31768
|
+
Utils.QBLog('[QBChat]', '[RECONNECT] _connect() at ' + chatUtils.getLocalTime() +
|
|
31769
|
+
' isConnected=' + self.isConnected +
|
|
31770
|
+
' _isConnecting=' + self._isConnecting +
|
|
31771
|
+
' _sessionHasExpired=' + self._sessionHasExpired);
|
|
31719
31772
|
if (typeof self.onLogListener === 'function') {
|
|
31720
31773
|
Utils.safeCallbackCall(self.onLogListener,
|
|
31721
|
-
'[QBChat]
|
|
31774
|
+
'[QBChat] [RECONNECT] _connect() at ' + chatUtils.getLocalTime() +
|
|
31775
|
+
' isConnected=' + self.isConnected +
|
|
31776
|
+
' _isConnecting=' + self._isConnecting +
|
|
31777
|
+
' _sessionHasExpired=' + self._sessionHasExpired);
|
|
31722
31778
|
}
|
|
31723
31779
|
if (!self.isConnected && !self._isConnecting && !self._sessionHasExpired) {
|
|
31724
|
-
Utils.QBLog('[QBChat]', '
|
|
31780
|
+
Utils.QBLog('[QBChat]', '[RECONNECT] executing connect() at ' + chatUtils.getLocalTime());
|
|
31725
31781
|
if (typeof self.onLogListener === 'function') {
|
|
31726
31782
|
Utils.safeCallbackCall(self.onLogListener,
|
|
31727
|
-
'[QBChat]
|
|
31783
|
+
'[QBChat] [RECONNECT] executing connect() at ' + chatUtils.getLocalTime() +
|
|
31784
|
+
' in ' + description);
|
|
31728
31785
|
}
|
|
31729
31786
|
self.connect(params);
|
|
31787
|
+
} else if (self.isConnected || self._sessionHasExpired) {
|
|
31788
|
+
// Stop retry timer only when actually connected or session expired (no point retrying).
|
|
31789
|
+
// Do NOT stop timer when _isConnecting — the in-flight attempt may fail,
|
|
31790
|
+
// and we need the timer to keep ticking for the next retry.
|
|
31791
|
+
Utils.QBLog('[QBChat]', '[RECONNECT] timer stopped at ' + chatUtils.getLocalTime() +
|
|
31792
|
+
' — isConnected=' + self.isConnected +
|
|
31793
|
+
' _sessionHasExpired=' + self._sessionHasExpired);
|
|
31794
|
+
clearInterval(self._checkConnectionTimer);
|
|
31795
|
+
self._checkConnectionTimer = undefined;
|
|
31730
31796
|
if (typeof self.onLogListener === 'function') {
|
|
31731
31797
|
Utils.safeCallbackCall(self.onLogListener,
|
|
31732
|
-
'[QBChat]
|
|
31798
|
+
'[QBChat] [RECONNECT] timer stopped at ' + chatUtils.getLocalTime() +
|
|
31799
|
+
' — isConnected=' + self.isConnected +
|
|
31800
|
+
' _sessionHasExpired=' + self._sessionHasExpired);
|
|
31733
31801
|
}
|
|
31734
31802
|
} else {
|
|
31735
|
-
|
|
31736
|
-
|
|
31737
|
-
|
|
31803
|
+
// _isConnecting === true — another attempt is in flight, skip this tick
|
|
31804
|
+
Utils.QBLog('[QBChat]', '[RECONNECT] _connect() SKIPPED at ' + chatUtils.getLocalTime() +
|
|
31805
|
+
' — _isConnecting=true, waiting for next tick');
|
|
31738
31806
|
if (typeof self.onLogListener === 'function') {
|
|
31739
31807
|
Utils.safeCallbackCall(self.onLogListener,
|
|
31740
|
-
'[QBChat]
|
|
31808
|
+
'[QBChat] [RECONNECT] _connect() SKIPPED at ' + chatUtils.getLocalTime() +
|
|
31809
|
+
' — _isConnecting=true, waiting for next tick');
|
|
31741
31810
|
}
|
|
31742
31811
|
}
|
|
31743
31812
|
};
|
|
@@ -31745,10 +31814,12 @@ ChatProxy.prototype = {
|
|
|
31745
31814
|
_connect();
|
|
31746
31815
|
|
|
31747
31816
|
self._checkConnectionTimer = setInterval(function () {
|
|
31748
|
-
Utils.QBLog('[QBChat]', '
|
|
31817
|
+
Utils.QBLog('[QBChat]', '[RECONNECT] timer tick at ' + chatUtils.getLocalTime() +
|
|
31818
|
+
' interval=' + config.chatReconnectionTimeInterval + 's');
|
|
31749
31819
|
if (typeof self.onLogListener === 'function') {
|
|
31750
31820
|
Utils.safeCallbackCall(self.onLogListener,
|
|
31751
|
-
'[QBChat]
|
|
31821
|
+
'[QBChat] [RECONNECT] timer tick at ' + chatUtils.getLocalTime() +
|
|
31822
|
+
' interval=' + config.chatReconnectionTimeInterval + 's');
|
|
31752
31823
|
}
|
|
31753
31824
|
_connect();
|
|
31754
31825
|
}, config.chatReconnectionTimeInterval * 1000);
|
|
@@ -39470,7 +39541,7 @@ module.exports = StreamManagement;
|
|
|
39470
39541
|
*/
|
|
39471
39542
|
|
|
39472
39543
|
var config = {
|
|
39473
|
-
version: '2.23.0-beta.
|
|
39544
|
+
version: '2.23.0-beta.2',
|
|
39474
39545
|
buildNumber: '1178',
|
|
39475
39546
|
creds: {
|
|
39476
39547
|
'appId': 0,
|
|
@@ -1201,47 +1201,116 @@ ChatProxy.prototype = {
|
|
|
1201
1201
|
}
|
|
1202
1202
|
},
|
|
1203
1203
|
|
|
1204
|
+
/**
|
|
1205
|
+
* Reconnect retry loop.
|
|
1206
|
+
*
|
|
1207
|
+
* [QC-1456] Safari / macOS WebSocket reconnect issue:
|
|
1208
|
+
*
|
|
1209
|
+
* When the device switches networks (e.g. LTE → WiFi), Safari's networking
|
|
1210
|
+
* stack does not update instantly. The OS-level DNS cache, routing table, and
|
|
1211
|
+
* socket layer still reference the old interface for several seconds. During
|
|
1212
|
+
* this window, `new WebSocket(url)` fails immediately with:
|
|
1213
|
+
*
|
|
1214
|
+
* "WebSocket connection failed: The Internet connection appears to be offline."
|
|
1215
|
+
*
|
|
1216
|
+
* This triggers CONNFAIL → DISCONNECTED in rapid succession. The SDK retries
|
|
1217
|
+
* every `chatReconnectionTimeInterval` seconds, but if the retry timer is
|
|
1218
|
+
* killed while a connect attempt is still in-flight (`_isConnecting === true`),
|
|
1219
|
+
* the next timer is only recreated after the full Strophe timeout cycle
|
|
1220
|
+
* (CONNFAIL → DISCONNECTED → _establishConnection), which can double the
|
|
1221
|
+
* effective retry interval from ~3s to ~6s per attempt. Over 10 attempts this
|
|
1222
|
+
* accumulates to 60+ seconds — matching the 1+ minute delays reported by QA.
|
|
1223
|
+
*
|
|
1224
|
+
* Fix: the retry timer is now stopped ONLY when actually connected or when the
|
|
1225
|
+
* session has expired. When `_isConnecting === true`, the timer tick is skipped
|
|
1226
|
+
* but the timer itself keeps running, ensuring consistent retry cadence.
|
|
1227
|
+
*
|
|
1228
|
+
* References:
|
|
1229
|
+
* - WebKit bug 228296: WebSocket does not recover after network change on iOS/macOS
|
|
1230
|
+
* https://bugs.webkit.org/show_bug.cgi?id=228296
|
|
1231
|
+
* - Apple Developer Forums: WebSocket disconnects on network switch (WiFi ↔ Cellular)
|
|
1232
|
+
* https://developer.apple.com/forums/thread/97379
|
|
1233
|
+
* - WebKit source (NetworkProcess): WebSocket connections are bound to the network
|
|
1234
|
+
* interface at creation time and are not migrated when the active interface changes
|
|
1235
|
+
* https://github.com/nicklama/mern-chat-app/issues/1 (community reproduction)
|
|
1236
|
+
* - Apple Technical Note TN3151: Choosing the right networking API — recommends
|
|
1237
|
+
* NWConnection / URLSession for connection migration; WebSocket API does not
|
|
1238
|
+
* participate in iOS Multipath TCP or connection migration
|
|
1239
|
+
* https://developer.apple.com/documentation/technotes/tn3151-choosing-the-right-networking-api
|
|
1240
|
+
*/
|
|
1204
1241
|
_establishConnection: function (params, description) {
|
|
1205
1242
|
var self = this;
|
|
1206
|
-
Utils.QBLog('[QBChat]', '_establishConnection called
|
|
1243
|
+
Utils.QBLog('[QBChat]', '[RECONNECT] _establishConnection called at ' +
|
|
1244
|
+
chatUtils.getLocalTime() + ' in ' + description +
|
|
1245
|
+
' _isLogout=' + self._isLogout +
|
|
1246
|
+
' timerExists=' + Boolean(self._checkConnectionTimer) +
|
|
1247
|
+
' _isConnecting=' + self._isConnecting +
|
|
1248
|
+
' isConnected=' + self.isConnected);
|
|
1207
1249
|
if (typeof self.onLogListener === 'function') {
|
|
1208
1250
|
Utils.safeCallbackCall(self.onLogListener,
|
|
1209
|
-
'[QBChat]
|
|
1251
|
+
'[QBChat] [RECONNECT] _establishConnection called at ' +
|
|
1252
|
+
chatUtils.getLocalTime() + ' in ' + description +
|
|
1253
|
+
' _isLogout=' + self._isLogout +
|
|
1254
|
+
' timerExists=' + Boolean(self._checkConnectionTimer) +
|
|
1255
|
+
' _isConnecting=' + self._isConnecting +
|
|
1256
|
+
' isConnected=' + self.isConnected);
|
|
1210
1257
|
}
|
|
1211
1258
|
if (self._isLogout || self._checkConnectionTimer) {
|
|
1212
|
-
Utils.QBLog('[QBChat]', '_establishConnection
|
|
1259
|
+
Utils.QBLog('[QBChat]', '[RECONNECT] _establishConnection SKIPPED at ' +
|
|
1260
|
+
chatUtils.getLocalTime() + ' — _isLogout=' + self._isLogout +
|
|
1261
|
+
' timerExists=' + Boolean(self._checkConnectionTimer));
|
|
1213
1262
|
if (typeof self.onLogListener === 'function') {
|
|
1214
1263
|
Utils.safeCallbackCall(self.onLogListener,
|
|
1215
|
-
'[QBChat]
|
|
1216
|
-
|
|
1264
|
+
'[QBChat] [RECONNECT] _establishConnection SKIPPED at ' +
|
|
1265
|
+
chatUtils.getLocalTime() + ' — _isLogout=' + self._isLogout +
|
|
1266
|
+
' timerExists=' + Boolean(self._checkConnectionTimer));
|
|
1217
1267
|
}
|
|
1218
1268
|
return;
|
|
1219
1269
|
}
|
|
1220
1270
|
|
|
1221
1271
|
var _connect = function () {
|
|
1222
|
-
Utils.QBLog('[QBChat]', '
|
|
1272
|
+
Utils.QBLog('[QBChat]', '[RECONNECT] _connect() at ' + chatUtils.getLocalTime() +
|
|
1273
|
+
' isConnected=' + self.isConnected +
|
|
1274
|
+
' _isConnecting=' + self._isConnecting +
|
|
1275
|
+
' _sessionHasExpired=' + self._sessionHasExpired);
|
|
1223
1276
|
if (typeof self.onLogListener === 'function') {
|
|
1224
1277
|
Utils.safeCallbackCall(self.onLogListener,
|
|
1225
|
-
'[QBChat]
|
|
1278
|
+
'[QBChat] [RECONNECT] _connect() at ' + chatUtils.getLocalTime() +
|
|
1279
|
+
' isConnected=' + self.isConnected +
|
|
1280
|
+
' _isConnecting=' + self._isConnecting +
|
|
1281
|
+
' _sessionHasExpired=' + self._sessionHasExpired);
|
|
1226
1282
|
}
|
|
1227
1283
|
if (!self.isConnected && !self._isConnecting && !self._sessionHasExpired) {
|
|
1228
|
-
Utils.QBLog('[QBChat]', '
|
|
1284
|
+
Utils.QBLog('[QBChat]', '[RECONNECT] executing connect() at ' + chatUtils.getLocalTime());
|
|
1229
1285
|
if (typeof self.onLogListener === 'function') {
|
|
1230
1286
|
Utils.safeCallbackCall(self.onLogListener,
|
|
1231
|
-
'[QBChat]
|
|
1287
|
+
'[QBChat] [RECONNECT] executing connect() at ' + chatUtils.getLocalTime() +
|
|
1288
|
+
' in ' + description);
|
|
1232
1289
|
}
|
|
1233
1290
|
self.connect(params);
|
|
1291
|
+
} else if (self.isConnected || self._sessionHasExpired) {
|
|
1292
|
+
// Stop retry timer only when actually connected or session expired (no point retrying).
|
|
1293
|
+
// Do NOT stop timer when _isConnecting — the in-flight attempt may fail,
|
|
1294
|
+
// and we need the timer to keep ticking for the next retry.
|
|
1295
|
+
Utils.QBLog('[QBChat]', '[RECONNECT] timer stopped at ' + chatUtils.getLocalTime() +
|
|
1296
|
+
' — isConnected=' + self.isConnected +
|
|
1297
|
+
' _sessionHasExpired=' + self._sessionHasExpired);
|
|
1298
|
+
clearInterval(self._checkConnectionTimer);
|
|
1299
|
+
self._checkConnectionTimer = undefined;
|
|
1234
1300
|
if (typeof self.onLogListener === 'function') {
|
|
1235
1301
|
Utils.safeCallbackCall(self.onLogListener,
|
|
1236
|
-
'[QBChat]
|
|
1302
|
+
'[QBChat] [RECONNECT] timer stopped at ' + chatUtils.getLocalTime() +
|
|
1303
|
+
' — isConnected=' + self.isConnected +
|
|
1304
|
+
' _sessionHasExpired=' + self._sessionHasExpired);
|
|
1237
1305
|
}
|
|
1238
1306
|
} else {
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1307
|
+
// _isConnecting === true — another attempt is in flight, skip this tick
|
|
1308
|
+
Utils.QBLog('[QBChat]', '[RECONNECT] _connect() SKIPPED at ' + chatUtils.getLocalTime() +
|
|
1309
|
+
' — _isConnecting=true, waiting for next tick');
|
|
1242
1310
|
if (typeof self.onLogListener === 'function') {
|
|
1243
1311
|
Utils.safeCallbackCall(self.onLogListener,
|
|
1244
|
-
'[QBChat]
|
|
1312
|
+
'[QBChat] [RECONNECT] _connect() SKIPPED at ' + chatUtils.getLocalTime() +
|
|
1313
|
+
' — _isConnecting=true, waiting for next tick');
|
|
1245
1314
|
}
|
|
1246
1315
|
}
|
|
1247
1316
|
};
|
|
@@ -1249,10 +1318,12 @@ ChatProxy.prototype = {
|
|
|
1249
1318
|
_connect();
|
|
1250
1319
|
|
|
1251
1320
|
self._checkConnectionTimer = setInterval(function () {
|
|
1252
|
-
Utils.QBLog('[QBChat]', '
|
|
1321
|
+
Utils.QBLog('[QBChat]', '[RECONNECT] timer tick at ' + chatUtils.getLocalTime() +
|
|
1322
|
+
' interval=' + config.chatReconnectionTimeInterval + 's');
|
|
1253
1323
|
if (typeof self.onLogListener === 'function') {
|
|
1254
1324
|
Utils.safeCallbackCall(self.onLogListener,
|
|
1255
|
-
'[QBChat]
|
|
1325
|
+
'[QBChat] [RECONNECT] timer tick at ' + chatUtils.getLocalTime() +
|
|
1326
|
+
' interval=' + config.chatReconnectionTimeInterval + 's');
|
|
1256
1327
|
}
|
|
1257
1328
|
_connect();
|
|
1258
1329
|
}, config.chatReconnectionTimeInterval * 1000);
|