Sfoglia il codice sorgente

disco: avoid `waitUntilItemsFetched` never resolving.

This breaks file sending.
JC Brand 3 mesi fa
parent
commit
9a5f519f33

+ 43 - 13
src/headless/plugins/disco/entity.js

@@ -43,9 +43,14 @@ class DiscoEntity extends Model {
         this.fields.browserStorage = createStore(id, 'session');
         this.listenTo(this.fields, 'add', this.onFieldAdded);
 
+        this.items = new Collection();
+        id = `converse.items-${this.get('jid')}`;
+        this.items.browserStorage = createStore(id, 'session');
+
         this.identities = new Collection();
         id = `converse.identities-${this.get('jid')}`;
         this.identities.browserStorage = createStore(id, 'session');
+
         this.fetchFeatures(options);
     }
 
@@ -102,21 +107,42 @@ class DiscoEntity extends Model {
 
     async fetchFeatures(options) {
         if (options.ignore_cache) {
-            this.queryInfo();
+            await this.queryInfo();
         } else {
             const store_id = this.features.browserStorage.name;
+
+            // Checking only whether features have been cached, even though
+            // there are other things that should be cached as well. We assume
+            // that if features have been cached, everything else has been also.
             const result = await this.features.browserStorage.store.getItem(store_id);
             if ((result && result.length === 0) || result === null) {
-                this.queryInfo();
+                await this.queryInfo();
             } else {
-                this.features.fetch({
-                    add: true,
-                    success: () => {
-                        this.waitUntilFeaturesDiscovered.resolve(this);
-                        this.trigger('featuresDiscovered');
-                    },
-                });
-                this.identities.fetch({ add: true });
+                await new Promise((resolve) => this.fetch({ success: resolve, error: resolve }));
+
+                await new Promise((resolve) =>
+                    this.features.fetch({
+                        add: true,
+                        success: () => {
+                            this.waitUntilFeaturesDiscovered.resolve(this);
+                            this.trigger('featuresDiscovered');
+                            resolve();
+                        },
+                        error: resolve,
+                    })
+                );
+
+                await new Promise((resolve) => this.identities.fetch({ add: true, success: resolve, error: resolve }));
+
+                const items = this.get('items');
+                if (Array.isArray(items)) {
+                    await Promise.all(
+                        items.map(/** @param {string} jid */ async (jid) => await api.disco.entities.get(jid, true))
+                    );
+                } else {
+                    await this.queryForItems();
+                }
+                this.waitUntilItemsFetched.resolve();
             }
         }
     }
@@ -137,25 +163,29 @@ class DiscoEntity extends Model {
      * @param {Element} stanza
      */
     onDiscoItems(stanza) {
-        sizzle(`query[xmlns="${Strophe.NS.DISCO_ITEMS}"] item`, stanza).forEach((item) => {
+        const item_els = sizzle(`query[xmlns="${Strophe.NS.DISCO_ITEMS}"] item`, stanza);
+        const item_jids = [];
+        item_els.forEach((item) => {
             if (item.getAttribute('node')) {
                 // XXX: Ignore nodes for now.
                 // See: https://xmpp.org/extensions/xep-0030.html#items-nodes
                 return;
             }
             const jid = item.getAttribute('jid');
-            const entity = _converse.state.disco_entities.get(jid);
+            let entity = _converse.state.disco_entities.get(jid);
             if (entity) {
                 const parent_jids = entity.get('parent_jids');
                 entity.set({ parent_jids: [...parent_jids, this.get('jid')] });
             } else {
-                api.disco.entities.create({
+                entity = api.disco.entities.create({
                     jid,
                     parent_jids: [this.get('jid')],
                     name: item.getAttribute('name'),
                 });
             }
+            item_jids.push(entity.get('jid'));
         });
+        this.save({ items: item_jids });
     }
 
     async queryForItems() {

+ 1 - 28
src/headless/plugins/disco/tests/disco.js

@@ -41,40 +41,13 @@ describe("Service Discovery", function () {
                 </iq>`;
             _converse.api.connection.get()._dataRecv(mock.createRequest(stanza));
 
-            await u.waitUntil(function () {
+            await u.waitUntil(() => {
                 // Converse.js sees that the entity has a disco#items feature,
                 // so it will make a query for it.
                 return IQ_stanzas.filter(iq => iq.querySelector('query[xmlns="http://jabber.org/protocol/disco#items"]')).length > 0;
             });
 
-            /* <iq type='result'
-             *     from='catalog.shakespeare.lit'
-             *     to='romeo@montague.net/orchard'
-             *     id='items2'>
-             * <query xmlns='http://jabber.org/protocol/disco#items'>
-             *     <item jid='people.shakespeare.lit'
-             *         name='Directory of Characters'/>
-             *     <item jid='plays.shakespeare.lit'
-             *         name='Play-Specific Chatrooms'/>
-             *     <item jid='mim.shakespeare.lit'
-             *         name='Gateway to Marlowe IM'/>
-             *     <item jid='words.shakespeare.lit'
-             *         name='Shakespearean Lexicon'/>
-             *
-             *     <item jid='catalog.shakespeare.lit'
-             *         node='books'
-             *         name='Books by and about Shakespeare'/>
-             *     <item jid='catalog.shakespeare.lit'
-             *         node='clothing'
-             *         name='Wear your literary taste with pride'/>
-             *     <item jid='catalog.shakespeare.lit'
-             *         node='music'
-             *         name='Music from the time of Shakespeare'/>
-             * </query>
-             * </iq>
-             */
             stanza = IQ_stanzas.find(iq => iq.querySelector('iq[to="montague.lit"] query[xmlns="http://jabber.org/protocol/disco#items"]'));
-
             const items_IQ_id = IQ_ids[IQ_stanzas.indexOf(stanza)];
 
             _converse.api.connection.get()._dataRecv(mock.createRequest(stx`

+ 1 - 0
src/headless/types/plugins/disco/entity.d.ts

@@ -27,6 +27,7 @@ declare class DiscoEntity extends Model {
     dataforms: Collection;
     features: Collection;
     fields: Collection;
+    items: Collection;
     identities: Collection;
     /**
      * Returns a Promise which resolves with a map indicating