|
@@ -21,7 +21,8 @@ export default class XmppConnection extends Listenable {
|
21
|
21
|
*/
|
22
|
22
|
static get Events() {
|
23
|
23
|
return {
|
24
|
|
- CONN_STATUS_CHANGED: 'CONN_STATUS_CHANGED'
|
|
24
|
+ CONN_STATUS_CHANGED: 'CONN_STATUS_CHANGED',
|
|
25
|
+ CONN_SHARD_CHANGED: 'CONN_SHARD_CHANGED'
|
25
|
26
|
};
|
26
|
27
|
}
|
27
|
28
|
|
|
@@ -39,6 +40,8 @@ export default class XmppConnection extends Listenable {
|
39
|
40
|
*
|
40
|
41
|
* @param {Object} options
|
41
|
42
|
* @param {String} options.serviceUrl - The BOSH or WebSocket service URL.
|
|
43
|
+ * @param {String} options.shard - The BOSH or WebSocket is connecting to this shard.
|
|
44
|
+ * Useful for detecting when shard changes.
|
42
|
45
|
* @param {String} [options.enableWebsocketResume=true] - True/false to control the stream resumption functionality.
|
43
|
46
|
* It will enable automatically by default if supported by the XMPP server.
|
44
|
47
|
* @param {Number} [options.websocketKeepAlive=240000] - The websocket keep alive interval. It's 4 minutes by
|
|
@@ -47,11 +50,12 @@ export default class XmppConnection extends Listenable {
|
47
|
50
|
* The keep alive is HTTP GET request to the {@link options.serviceUrl}.
|
48
|
51
|
* @param {Object} [options.xmppPing] - The xmpp ping settings.
|
49
|
52
|
*/
|
50
|
|
- constructor({ enableWebsocketResume, websocketKeepAlive, serviceUrl, xmppPing }) {
|
|
53
|
+ constructor({ enableWebsocketResume, websocketKeepAlive, serviceUrl, shard, xmppPing }) {
|
51
|
54
|
super();
|
52
|
55
|
this._options = {
|
53
|
56
|
enableWebsocketResume: typeof enableWebsocketResume === 'undefined' ? true : enableWebsocketResume,
|
54
|
57
|
pingOptions: xmppPing,
|
|
58
|
+ shard,
|
55
|
59
|
websocketKeepAlive: typeof websocketKeepAlive === 'undefined' ? 4 * 60 * 1000 : Number(websocketKeepAlive)
|
56
|
60
|
};
|
57
|
61
|
|
|
@@ -89,6 +93,9 @@ export default class XmppConnection extends Listenable {
|
89
|
93
|
onPingThresholdExceeded: () => this._onPingErrorThresholdExceeded(),
|
90
|
94
|
pingOptions: xmppPing
|
91
|
95
|
}));
|
|
96
|
+
|
|
97
|
+ // tracks whether this is the initial connection or a reconnect
|
|
98
|
+ this._oneSuccessfulConnect = false;
|
92
|
99
|
}
|
93
|
100
|
|
94
|
101
|
/**
|
|
@@ -260,6 +267,14 @@ export default class XmppConnection extends Listenable {
|
260
|
267
|
|
261
|
268
|
if (status === Strophe.Status.CONNECTED || status === Strophe.Status.ATTACHED) {
|
262
|
269
|
this._maybeEnableStreamResume();
|
|
270
|
+
|
|
271
|
+ // after connecting - immediately check whether shard changed,
|
|
272
|
+ // we need this only when using websockets as bosh checks headers from every response
|
|
273
|
+ if (this._usesWebsocket && this._oneSuccessfulConnect) {
|
|
274
|
+ this._keepAliveAndCheckShard();
|
|
275
|
+ }
|
|
276
|
+ this._oneSuccessfulConnect = true;
|
|
277
|
+
|
263
|
278
|
this._maybeStartWSKeepAlive();
|
264
|
279
|
this._processDeferredIQs();
|
265
|
280
|
this._resumeTask.cancel();
|
|
@@ -377,18 +392,38 @@ export default class XmppConnection extends Listenable {
|
377
|
392
|
|
378
|
393
|
logger.debug(`Scheduling next WebSocket keep-alive in ${intervalWithJitter}ms`);
|
379
|
394
|
|
380
|
|
- this._wsKeepAlive = setTimeout(() => {
|
381
|
|
- const url = this.service.replace('wss://', 'https://').replace('ws://', 'http://');
|
382
|
|
-
|
383
|
|
- fetch(url).catch(
|
384
|
|
- error => {
|
385
|
|
- logger.error(`Websocket Keep alive failed for url: ${url}`, { error });
|
386
|
|
- })
|
387
|
|
- .then(() => this._maybeStartWSKeepAlive());
|
388
|
|
- }, intervalWithJitter);
|
|
395
|
+ this._wsKeepAlive = setTimeout(
|
|
396
|
+ () => this._keepAliveAndCheckShard()
|
|
397
|
+ .then(() => this._maybeStartWSKeepAlive()),
|
|
398
|
+ intervalWithJitter);
|
389
|
399
|
}
|
390
|
400
|
}
|
391
|
401
|
|
|
402
|
+ /**
|
|
403
|
+ * Do a http GET to the shard and if shard change will throw an event.
|
|
404
|
+ *
|
|
405
|
+ * @private
|
|
406
|
+ * @returns {Promise}
|
|
407
|
+ */
|
|
408
|
+ _keepAliveAndCheckShard() {
|
|
409
|
+ const { shard } = this._options;
|
|
410
|
+ const url = this.service.replace('wss://', 'https://').replace('ws://', 'http://');
|
|
411
|
+
|
|
412
|
+ return fetch(url)
|
|
413
|
+ .then(response => {
|
|
414
|
+ const responseShard = response.headers.get('x-jitsi-shard');
|
|
415
|
+
|
|
416
|
+ if (responseShard !== shard) {
|
|
417
|
+ logger.error(
|
|
418
|
+ `Detected that shard changed from ${shard} to ${responseShard}`);
|
|
419
|
+ this.eventEmitter.emit(XmppConnection.Events.CONN_SHARD_CHANGED);
|
|
420
|
+ }
|
|
421
|
+ })
|
|
422
|
+ .catch(error => {
|
|
423
|
+ logger.error(`Websocket Keep alive failed for url: ${url}`, { error });
|
|
424
|
+ });
|
|
425
|
+ }
|
|
426
|
+
|
392
|
427
|
/**
|
393
|
428
|
* Goes over the list of {@link DeferredSendIQ} tasks and sends them.
|
394
|
429
|
*
|