Browse Source

Remove dependency on the strophe disco plugin

And instead implement it ourselves.

This solves a bug with that plugin whereby the connection handlers are
added to early and are therefore never fired.

Also fixed a problem whereby entity items are queried for features
before the features have been fetched.
JC Brand 7 years ago
parent
commit
b3619077f9

+ 0 - 1
package.json

@@ -68,7 +68,6 @@
     "snabbdom": "0.7.1",
     "snyk": "^1.21.2",
     "strophe.js": "1.2.14",
-    "strophejs-plugin-disco": "0.0.1",
     "strophejs-plugin-ping": "0.0.1",
     "strophejs-plugin-register": "0.0.1",
     "strophejs-plugin-rsm": "0.0.1",

+ 0 - 1
src/config.js

@@ -54,7 +54,6 @@ require.config({
         "snabbdom-props":           "node_modules/snabbdom/dist/snabbdom-props",
         "snabbdom-style":           "node_modules/snabbdom/dist/snabbdom-style",
         "strophe":                  "node_modules/strophe.js/strophe",
-        "strophe.disco":            "node_modules/strophejs-plugin-disco/strophe.disco",
         "strophe.ping":             "node_modules/strophejs-plugin-ping/strophe.ping",
         "strophe.rsm":              "node_modules/strophejs-plugin-rsm/strophe.rsm",
         "strophe.vcard":            "node_modules/strophejs-plugin-vcard/strophe.vcard",

+ 2 - 2
src/converse-chatboxes.js

@@ -765,8 +765,8 @@
             _converse.on('chatBoxesFetched', autoJoinChats);
 
             _converse.on('addClientFeatures', () => {
-                _converse.connection.disco.addFeature(Strophe.NS.HTTPUPLOAD);
-                _converse.connection.disco.addFeature(Strophe.NS.OUTOFBAND);
+                _converse.api.disco.addFeature(Strophe.NS.HTTPUPLOAD);
+                _converse.api.disco.addFeature(Strophe.NS.OUTOFBAND);
             });
 
             _converse.api.listen.on('pluginsInitialized', () => {

+ 1 - 1
src/converse-chatview.js

@@ -1064,7 +1064,7 @@
 
             _converse.on('connected', () => {
                 // Advertise that we support XEP-0382 Message Spoilers
-                _converse.connection.disco.addFeature(Strophe.NS.SPOILER);
+                _converse.api.disco.addFeature(Strophe.NS.SPOILER);
             });
 
             /************************ BEGIN API ************************/

+ 98 - 15
src/converse-disco.js

@@ -9,10 +9,10 @@
 
 /*global Backbone, define, window */
 (function (root, factory) {
-    define(["converse-core", "sizzle", "strophe.disco"], factory);
+    define(["converse-core", "sizzle"], factory);
 }(this, function (converse, sizzle) {
 
-    const { Backbone, Promise, Strophe, b64_sha1, utils, _, f } = converse.env;
+    const { Backbone, Promise, Strophe, $iq, b64_sha1, utils, _, f } = converse.env;
 
     converse.plugins.add('converse-disco', {
 
@@ -127,7 +127,7 @@
                 },
 
                 queryInfo () {
-                    _converse.connection.disco.info(this.get('jid'), null, this.onInfo.bind(this));
+                    _converse.api.disco.info(this.get('jid'), null, this.onInfo.bind(this));
                 },
 
                 onDiscoItems (stanza) {
@@ -150,7 +150,7 @@
                         // server or a conference component.
                         return;
                     }
-                    _converse.connection.disco.items(this.get('jid'), null, this.onDiscoItems.bind(this));
+                    _converse.api.disco.items(this.get('jid'), null, this.onDiscoItems.bind(this));
                 },
 
                 onInfo (stanza) {
@@ -211,14 +211,14 @@
                  */
 
                 // See http://xmpp.org/registrar/disco-categories.html
-                _converse.connection.disco.addIdentity('client', 'web', 'Converse.js');
+                _converse.api.disco.addIdentity('client', 'web', 'Converse.js');
 
-                _converse.connection.disco.addFeature(Strophe.NS.BOSH);
-                _converse.connection.disco.addFeature(Strophe.NS.CHATSTATES);
-                _converse.connection.disco.addFeature(Strophe.NS.DISCO_INFO);
-                _converse.connection.disco.addFeature(Strophe.NS.ROSTERX); // Limited support
+                _converse.api.disco.addFeature(Strophe.NS.BOSH);
+                _converse.api.disco.addFeature(Strophe.NS.CHATSTATES);
+                _converse.api.disco.addFeature(Strophe.NS.DISCO_INFO);
+                _converse.api.disco.addFeature(Strophe.NS.ROSTERX); // Limited support
                 if (_converse.message_carbons) {
-                    _converse.connection.disco.addFeature(Strophe.NS.CARBONS);
+                    _converse.api.disco.addFeature(Strophe.NS.CARBONS);
                 }
                 _converse.emit('addClientFeatures');
                 return this;
@@ -226,6 +226,8 @@
 
             function initializeDisco () {
                 addClientFeatures();
+                _converse.connection.addHandler(onDiscoInfoRequest, Strophe.NS.DISCO_INFO, 'iq', 'get', null, null);
+
                 _converse.disco_entities = new _converse.DiscoEntities();
                 _converse.disco_entities.browserStorage = new Backbone.BrowserStorage[_converse.storage](
                     b64_sha1(`converse.disco-entities-${_converse.bare_jid}`)
@@ -240,6 +242,7 @@
                     _converse.emit('discoInitialized');
                 }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
             }
+
             _converse.api.listen.on('reconnected', initializeDisco);
             _converse.api.listen.on('connected', initializeDisco);
 
@@ -254,9 +257,69 @@
                 }
             });
 
+            const plugin = this;
+            plugin._identities = [];
+            plugin._features = [];
+
+            function onDiscoInfoRequest (stanza) {
+                const node = stanza.getElementsByTagName('query')[0].getAttribute('node');
+                const attrs = {xmlns: Strophe.NS.DISCO_INFO};
+                if (node) { attrs.node = node; }
+
+                const iqresult = $iq({'type': 'result', 'id': stanza.getAttribute('id')});
+                const from = stanza.getAttribute('from');
+                if (from !== null) {
+                    iqresult.attrs({'to': from});
+                }
+                _.each(plugin._identities, (identity) => {
+                    const attrs = {
+                        'category': identity.category,
+                        'type': identity.type
+                    };
+                    if (identity.name) {
+                        attrs.name = identity.name;
+                    }
+                    if (identity.lang) {
+                        attrs['xml:lang'] = identity.lang;
+                    }
+                    iqresult.c('identity', attrs).up();
+                });
+                _.each(plugin._features, (feature) => {
+                    iqresult.c('feature', {'var': feature}).up();
+                });
+                _converse.connection.send(iqresult.tree());
+                return true;
+            }
+
             /* We extend the default converse.js API to add methods specific to service discovery */
             _.extend(_converse.api, {
                 'disco': {
+                    'info' (jid, node, callback, errback, timeout) {
+                        const attrs = {xmlns: Strophe.NS.DISCO_INFO};
+                        if (node) {
+                            attrs.node = node;
+                        }
+                        const info = $iq({
+                            'from': _converse.connection.jid,
+                            'to':jid,
+                            'type':'get'
+                        }).c('query', attrs);
+                        _converse.connection.sendIQ(info, callback, errback, timeout);
+                    },
+
+                    'items' (jid, node, callback, errback, timeout) {
+                        const attrs = {'xmlns': Strophe.NS.DISCO_ITEMS};
+                        if (node) {
+                            attrs.node = node;
+                        }
+                        const items = $iq({
+                            'from': _converse.connection.jid,
+                            'to':jid,
+                            'type':'get'
+                        }).c('query', attrs);
+                        _converse.connection.sendIQ(items, callback, errback, timeout);
+                    },
+
                     'entities': {
                         'get' (entity_jid, create=false) {
                             return _converse.api.waitUntil('discoInitialized').then(() => {
@@ -292,19 +355,39 @@
                         return _converse.api.waitUntil('discoInitialized').then(() => {
                             return new Promise((resolve, reject) => {
                                 _converse.api.disco.entities.get(entity_jid, true).then((entity) => {
-                                    Promise.all(
-                                        _.concat(
+                                    entity.waitUntilFeaturesDiscovered.then(() => {
+                                        const promises = _.concat(
                                             entity.items.map((item) => item.hasFeature(feature)),
                                             entity.hasFeature(feature)
-                                        )
-                                    ).then((result) => {
-                                        resolve(f.filter(f.isObject, result));
+                                        );
+                                        Promise.all(promises).then((result) => {
+                                            resolve(f.filter(f.isObject, result));
+                                        }).catch(reject);
                                     }).catch(reject);
                                 })
                             });
                         }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
                     },
 
+                    'addIdentity' (category, type, name, lang) {
+                        for (var i=0; i<plugin._identities.length; i++) {
+                            if (plugin._identities[i].category == category &&
+                                plugin._identities[i].type == type &&
+                                plugin._identities[i].name == name &&
+                                plugin._identities[i].lang == lang) {
+                                return false;
+                            }
+                        }
+                        plugin._identities.push({category: category, type: type, name: name, lang: lang});
+                    },
+
+                    'addFeature' (name) {
+                        for (var i=0; i<plugin._features.length; i++) {
+                            if (plugin._features[i] == name) { return false; }
+                        }
+                        plugin._features.push(name);
+                    },
+
                     'getIdentity' (category, type, entity_jid) {
                         /* Returns a Promise which resolves with a map indicating
                          * whether an identity with a given type is provided by

+ 1 - 1
src/converse-mam.js

@@ -384,7 +384,7 @@
             });
 
             _converse.on('addClientFeatures', () => {
-                _converse.connection.disco.addFeature(Strophe.NS.MAM);
+                _converse.api.disco.addFeature(Strophe.NS.MAM);
             });
 
             _converse.on('afterMessagesFetched', (chatboxview) => {

+ 1 - 1
src/converse-muc-views.js

@@ -295,7 +295,7 @@
                     parent_el.querySelector('a.room-info').classList.remove('selected');
                 } else {
                     parent_el.insertAdjacentHTML('beforeend', tpl_spinner());
-                    _converse.connection.disco.info(
+                    _converse.api.disco.info(
                         ev.target.getAttribute('data-room-jid'),
                         null,
                         _.partial(insertRoomInfo, parent_el)

+ 4 - 4
src/converse-muc.js

@@ -67,7 +67,7 @@
          *
          * NB: These plugins need to have already been loaded via require.js.
          */
-        dependencies: ["converse-chatboxes", "converse-controlbox"],
+        dependencies: ["converse-chatboxes", "converse-disco", "converse-controlbox"],
 
         overrides: {
             // Overrides mentioned here will be picked up by converse.js's
@@ -319,7 +319,7 @@
                     /* Fetch the room disco info, parse it and then save it.
                      */
                     return new Promise((resolve, reject) => {
-                        _converse.connection.disco.info(
+                        _converse.api.disco.info(
                             this.get('jid'),
                             null,
                             _.flow(this.parseRoomFeatures.bind(this), resolve),
@@ -1134,10 +1134,10 @@
             /************************ BEGIN Event Handlers ************************/
             _converse.on('addClientFeatures', () => {
                 if (_converse.allow_muc) {
-                    _converse.connection.disco.addFeature(Strophe.NS.MUC);
+                    _converse.api.disco.addFeature(Strophe.NS.MUC);
                 }
                 if (_converse.allow_muc_invitations) {
-                    _converse.connection.disco.addFeature('jabber:x:conference'); // Invites
+                    _converse.api.disco.addFeature('jabber:x:conference'); // Invites
                 }
             });
             _converse.on('chatBoxesFetched', autoJoinRooms);

+ 1 - 1
src/converse-ping.js

@@ -57,7 +57,7 @@
 
             _converse.registerPongHandler = function () {
                 if (!_.isUndefined(_converse.connection.disco)) {
-                    _converse.connection.disco.addFeature(Strophe.NS.PING);
+                    _converse.api.disco.addFeature(Strophe.NS.PING);
                 }
                 _converse.connection.ping.addPingHandler(_converse.pong);
             };

+ 1 - 1
src/converse-vcard.js

@@ -84,7 +84,7 @@
 
 
             _converse.on('addClientFeatures', () => {
-                _converse.connection.disco.addFeature(Strophe.NS.VCARD);
+                _converse.api.disco.addFeature(Strophe.NS.VCARD);
             });
 
             _converse.on('statusInitialized', function fetchOwnVCard () {