diff --git a/src/headless/converse-disco.js b/src/headless/converse-disco.js index 2a4cb0198e..952b7783cf 100644 --- a/src/headless/converse-disco.js +++ b/src/headless/converse-disco.js @@ -206,7 +206,7 @@ converse.plugins.add('converse-disco', { if (stanza.querySelector(`feature[var="${Strophe.NS.DISCO_ITEMS}"]`)) { this.queryForItems(); } - _.forEach(stanza.querySelectorAll('feature'), feature => { + Array.from(stanza.querySelectorAll('feature')).forEach(feature => { this.features.create({ 'var': feature.getAttribute('var'), 'from': stanza.getAttribute('from') @@ -243,6 +243,7 @@ converse.plugins.add('converse-disco', { } }); + function addClientFeatures () { // See https://xmpp.org/registrar/disco-categories.html _converse.api.disco.own.identities.add('client', 'web', 'Converse'); @@ -263,39 +264,52 @@ converse.plugins.add('converse-disco', { return this; } + function initStreamFeatures () { - const bare_jid = Strophe.getBareJidFromJid(_converse.jid); - const id = `converse.stream-features-${bare_jid}`; - if (!_converse.stream_features || _converse.stream_features.browserStorage.name !== id) { + // Initialize the stream_features collection, and if we're + // re-attaching to a pre-existing BOSH session, we restore the + // features from cache. + // Otherwise the features will be created once we've received them + // from the server (see populateStreamFeatures). + if (!_converse.stream_features) { + const bare_jid = Strophe.getBareJidFromJid(_converse.jid); + const id = `converse.stream-features-${bare_jid}`; + _converse.api.promises.add('streamFeaturesAdded'); _converse.stream_features = new _converse.Collection(); _converse.stream_features.browserStorage = _converse.createStore(id, "session"); - _converse.stream_features.fetch({ - success (collection) { - if (collection.length === 0 && _converse.connection.features) { - Array.from(_converse.connection.features.childNodes) - .forEach(feature => { - _converse.stream_features.create({ - 'name': feature.nodeName, - 'xmlns': feature.getAttribute('xmlns') - }); - }); - } - /** - * Triggered as soon as Converse has processed the stream features as advertised by - * the server. If you want to check whether a stream feature is supported before - * proceeding, then you'll first want to wait for this event. - * @event _converse#streamFeaturesAdded - * @example _converse.api.listen.on('streamFeaturesAdded', () => { ... }); - */ - _converse.api.trigger('streamFeaturesAdded'); - }, - error (m, e) { - log.error(e); - } - }); } } + + function populateStreamFeatures () { + // Strophe.js sets the element on the + // Strophe.Connection instance (_converse.connection). + // + // Once this is done, we populate the _converse.stream_features collection + // and trigger streamFeaturesAdded. + initStreamFeatures(); + Array.from(_converse.connection.features.childNodes).forEach(feature => { + _converse.stream_features.create({ + 'name': feature.nodeName, + 'xmlns': feature.getAttribute('xmlns') + }); + }); + notifyStreamFeaturesAdded(); + } + + + function notifyStreamFeaturesAdded () { + /** + * Triggered as soon as the stream features are known. + * If you want to check whether a stream feature is supported before proceeding, + * then you'll first want to wait for this event. + * @event _converse#streamFeaturesAdded + * @example _converse.api.listen.on('streamFeaturesAdded', () => { ... }); + */ + _converse.api.trigger('streamFeaturesAdded'); + } + + const plugin = this; plugin._identities = []; plugin._features = []; @@ -355,9 +369,15 @@ converse.plugins.add('converse-disco', { /******************** Event Handlers ********************/ - // Re-create promise upon reconnection - _converse.api.listen.on('userSessionInitialized', initStreamFeatures); - _converse.api.listen.on('beforeResourceBinding', initStreamFeatures); + _converse.api.listen.on('userSessionInitialized', async () => { + initStreamFeatures(); + if (_converse.connfeedback.get('connection_status') === Strophe.Status.ATTACHED) { + // When re-attaching to a BOSH session, we fetch the stream features from the cache. + await new Promise((success, error) => _converse.stream_features.fetch({ success, error })); + notifyStreamFeaturesAdded(); + } + }); + _converse.api.listen.on('beforeResourceBinding', populateStreamFeatures); _converse.api.listen.on('reconnected', initializeDisco); _converse.api.listen.on('connected', initializeDisco);