Explorar el Código

Bugfix. `streamFeaturesAdded` triggered too soon.

`streamFeaturesAdded` should only be triggered once we've received them
from the server.

This appears to be a timing bug, likely introduced by the IndexedDB
refactoring.
JC Brand hace 5 años
padre
commit
762717dd38
Se han modificado 1 ficheros con 51 adiciones y 31 borrados
  1. 51 31
      src/headless/converse-disco.js

+ 51 - 31
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 <stream:features> 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);