|
@@ -13,7 +13,7 @@ import GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';
|
13
|
13
|
import Listenable from '../util/Listenable';
|
14
|
14
|
import RandomUtil from '../util/RandomUtil';
|
15
|
15
|
|
16
|
|
-import Caps from './Caps';
|
|
16
|
+import Caps, { parseDiscoInfo } from './Caps';
|
17
|
17
|
import XmppConnection from './XmppConnection';
|
18
|
18
|
import MucConnectionPlugin from './strophe.emuc';
|
19
|
19
|
import JingleConnectionPlugin from './strophe.jingle';
|
|
@@ -278,52 +278,22 @@ export default class XMPP extends Listenable {
|
278
|
278
|
|
279
|
279
|
this.eventEmitter.emit(XMPPEvents.CONNECTION_STATUS_CHANGED, credentials, status, msg);
|
280
|
280
|
if (status === Strophe.Status.CONNECTED || status === Strophe.Status.ATTACHED) {
|
281
|
|
- this.connection.jingle.getStunAndTurnCredentials();
|
|
281
|
+ this.sendDiscoInfo && this.connection.jingle.getStunAndTurnCredentials();
|
282
|
282
|
|
283
|
283
|
logger.info(`My Jabber ID: ${this.connection.jid}`);
|
284
|
284
|
|
285
|
285
|
// XmppConnection emits CONNECTED again on reconnect - a good opportunity to clear any "last error" flags
|
286
|
286
|
this._resetState();
|
287
|
287
|
|
288
|
|
- // FIXME no need to do it again on stream resume
|
289
|
|
- this.caps.getFeaturesAndIdentities(this.options.hosts.domain)
|
|
288
|
+ this.sendDiscoInfo && this.caps.getFeaturesAndIdentities(this.options.hosts.domain)
|
290
|
289
|
.then(({ features, identities }) => {
|
291
|
290
|
if (!features.has(Strophe.NS.PING)) {
|
292
|
291
|
logger.error(`Ping NOT supported by ${
|
293
|
292
|
this.options.hosts.domain} - please enable ping in your XMPP server config`);
|
294
|
293
|
}
|
295
|
294
|
|
296
|
|
- // check for speakerstats
|
297
|
|
- identities.forEach(identity => {
|
298
|
|
- if (identity.type === 'speakerstats') {
|
299
|
|
- this.speakerStatsComponentAddress = identity.name;
|
300
|
|
- }
|
301
|
|
-
|
302
|
|
- if (identity.type === 'conference_duration') {
|
303
|
|
- this.conferenceDurationComponentAddress = identity.name;
|
304
|
|
- }
|
305
|
|
-
|
306
|
|
- if (identity.type === 'lobbyrooms') {
|
307
|
|
- this.lobbySupported = true;
|
308
|
|
- identity.name && this.caps.getFeaturesAndIdentities(identity.name, identity.type)
|
309
|
|
- .then(({ features: f }) => {
|
310
|
|
- f.forEach(fr => {
|
311
|
|
- if (fr.endsWith('#displayname_required')) {
|
312
|
|
- this.eventEmitter.emit(
|
313
|
|
- JitsiConnectionEvents.DISPLAY_NAME_REQUIRED);
|
314
|
|
- }
|
315
|
|
- });
|
316
|
|
- })
|
317
|
|
- .catch(e => logger.warn('Error getting features from lobby.', e && e.message));
|
318
|
|
- }
|
319
|
|
- });
|
320
|
|
-
|
321
|
|
- if (this.speakerStatsComponentAddress
|
322
|
|
- || this.conferenceDurationComponentAddress) {
|
323
|
|
- this.connection.addHandler(
|
324
|
|
- this._onPrivateMessage.bind(this), null,
|
325
|
|
- 'message', null, null);
|
326
|
|
- }
|
|
295
|
+ this._processDiscoInfoIdentities(
|
|
296
|
+ identities, undefined /* when querying we will query for features */);
|
327
|
297
|
})
|
328
|
298
|
.catch(error => {
|
329
|
299
|
const errmsg = 'Feature discovery error';
|
|
@@ -333,6 +303,9 @@ export default class XMPP extends Listenable {
|
333
|
303
|
logger.error(errmsg, error);
|
334
|
304
|
});
|
335
|
305
|
|
|
306
|
+ // make sure we don't query again
|
|
307
|
+ this.sendDiscoInfo = false;
|
|
308
|
+
|
336
|
309
|
if (credentials.password) {
|
337
|
310
|
this.authenticatedUser = true;
|
338
|
311
|
}
|
|
@@ -419,6 +392,50 @@ export default class XMPP extends Listenable {
|
419
|
392
|
}
|
420
|
393
|
}
|
421
|
394
|
|
|
395
|
+ /**
|
|
396
|
+ * Process received identities.
|
|
397
|
+ * @param {Set<String>} identities The identities to process.
|
|
398
|
+ * @param {Set<String>} features The features to process, optional. If missing lobby component will be queried
|
|
399
|
+ * for more features.
|
|
400
|
+ * @private
|
|
401
|
+ */
|
|
402
|
+ _processDiscoInfoIdentities(identities, features) {
|
|
403
|
+ // check for speakerstats
|
|
404
|
+ identities.forEach(identity => {
|
|
405
|
+ if (identity.type === 'speakerstats') {
|
|
406
|
+ this.speakerStatsComponentAddress = identity.name;
|
|
407
|
+ }
|
|
408
|
+
|
|
409
|
+ if (identity.type === 'conference_duration') {
|
|
410
|
+ this.conferenceDurationComponentAddress = identity.name;
|
|
411
|
+ }
|
|
412
|
+
|
|
413
|
+ if (identity.type === 'lobbyrooms') {
|
|
414
|
+ this.lobbySupported = true;
|
|
415
|
+ const processLobbyFeatures = f => {
|
|
416
|
+ f.forEach(fr => {
|
|
417
|
+ if (fr.endsWith('#displayname_required')) {
|
|
418
|
+ this.eventEmitter.emit(JitsiConnectionEvents.DISPLAY_NAME_REQUIRED);
|
|
419
|
+ }
|
|
420
|
+ });
|
|
421
|
+ };
|
|
422
|
+
|
|
423
|
+ if (features) {
|
|
424
|
+ processLobbyFeatures(features);
|
|
425
|
+ } else {
|
|
426
|
+ identity.name && this.caps.getFeaturesAndIdentities(identity.name, identity.type)
|
|
427
|
+ .then(({ features: f }) => processLobbyFeatures(f))
|
|
428
|
+ .catch(e => logger.warn('Error getting features from lobby.', e && e.message));
|
|
429
|
+ }
|
|
430
|
+ }
|
|
431
|
+ });
|
|
432
|
+
|
|
433
|
+ if (this.speakerStatsComponentAddress
|
|
434
|
+ || this.conferenceDurationComponentAddress) {
|
|
435
|
+ this.connection.addHandler(this._onPrivateMessage.bind(this), null, 'message', null, null);
|
|
436
|
+ }
|
|
437
|
+ }
|
|
438
|
+
|
422
|
439
|
/**
|
423
|
440
|
* Parses a raw failure xmpp xml message received on auth failed.
|
424
|
441
|
*
|
|
@@ -469,6 +486,30 @@ export default class XMPP extends Listenable {
|
469
|
486
|
// Status.ATTACHED - The connection has been attached
|
470
|
487
|
|
471
|
488
|
this._resetState();
|
|
489
|
+
|
|
490
|
+ this.sendDiscoInfo = true;
|
|
491
|
+
|
|
492
|
+ if (this.connection._stropheConn && this.connection._stropheConn._addSysHandler) {
|
|
493
|
+ this.connection._stropheConn._addSysHandler(msg => {
|
|
494
|
+ this.sendDiscoInfo = false;
|
|
495
|
+
|
|
496
|
+ this.connection.jingle.onReceiveStunAndTurnCredentials(msg);
|
|
497
|
+
|
|
498
|
+ const { features, identities } = parseDiscoInfo(msg);
|
|
499
|
+
|
|
500
|
+ this._processDiscoInfoIdentities(identities, features);
|
|
501
|
+
|
|
502
|
+ // check for shard name in identities
|
|
503
|
+ identities.forEach(i => {
|
|
504
|
+ if (i.type === 'shard') {
|
|
505
|
+ this.options.deploymentInfo.shard = i.name;
|
|
506
|
+ }
|
|
507
|
+ });
|
|
508
|
+ }, null, 'message', 'service-info', null);
|
|
509
|
+ } else {
|
|
510
|
+ logger.warn('Cannot attach strophe system handler, jiconop cannot operate');
|
|
511
|
+ }
|
|
512
|
+
|
472
|
513
|
this.connection.connect(
|
473
|
514
|
jid,
|
474
|
515
|
password,
|