From 0137eb88ae7a8fd9e92a66ff899bf6103158de25 Mon Sep 17 00:00:00 2001 From: JC Brand Date: Tue, 18 Feb 2020 23:04:30 +0100 Subject: [PATCH] Smacks: Handle MUC messages received before the MUC exists --- package-lock.json | 14 +++--- spec/smacks.js | 88 ++++++++++++++++++++++++++++++++++++ src/headless/converse-mam.js | 4 -- src/headless/converse-muc.js | 15 ++++++ tests/mock.js | 8 +++- webpack.html | 2 +- 6 files changed, 117 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index c0ac45ede..7d7004dd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14188,7 +14188,7 @@ }, "camelcase-keys": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "dev": true, "requires": { @@ -14198,7 +14198,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -14240,7 +14240,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -14259,7 +14259,7 @@ }, "meow": { "version": "3.7.0", - "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "dev": true, "requires": { @@ -19126,7 +19126,7 @@ }, "pinkie-promise": { "version": "2.0.1", - "resolved": "http://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { @@ -20617,7 +20617,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -20630,7 +20630,7 @@ }, "os-locale": { "version": "1.4.0", - "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "dev": true, "requires": { diff --git a/spec/smacks.js b/spec/smacks.js index 233a4ae6e..1aef5d43f 100644 --- a/spec/smacks.js +++ b/spec/smacks.js @@ -3,6 +3,7 @@ } (this, function (jasmine, mock, test_utils) { "use strict"; const $iq = converse.env.$iq; + const $msg = converse.env.$msg; const Strophe = converse.env.Strophe; const sizzle = converse.env.sizzle; const u = converse.env.utils; @@ -178,5 +179,92 @@ await test_utils.waitForRoster(_converse, 'current', 1); done(); })); + + + it("can cause MUC messages to be received before chatboxes are initialized", + mock.initConverse( + ['chatBoxesInitialized'], + { 'auto_login': false, + 'enable_smacks': true, + 'show_controlbox_by_default': true, + 'blacklisted_plugins': 'converse-mam', + 'smacks_max_unacked_stanzas': 2 + }, + async function (done, _converse) { + + const key = "converse-test-session/converse.session-romeo@montague.lit-converse.session-romeo@montague.lit"; + sessionStorage.setItem( + key, + JSON.stringify({ + "id": "converse.session-romeo@montague.lit", + "jid": "romeo@montague.lit/converse.js-100020907", + "bare_jid": "romeo@montague.lit", + "resource": "converse.js-100020907", + "domain": "montague.lit", + "active": false, + "smacks_enabled": true, + "num_stanzas_handled": 580, + "num_stanzas_handled_by_server": 525, + "num_stanzas_since_last_ack": 0, + "unacked_stanzas": [], + "smacks_stream_id": "some-long-sm-id", + "push_enabled": ["romeo@montague.lit"], + "carbons_enabled": true, + "roster_cached": true + }) + ); + + const muc_jid = 'lounge@montague.lit'; + const chatkey = `converse.chatboxes-romeo@montague.lit-${muc_jid}`; + sessionStorage.setItem('converse.chatboxes-romeo@montague.lit', JSON.stringify([chatkey])); + sessionStorage.setItem(chatkey, + JSON.stringify({ + hidden: false, + message_type: "groupchat", + name: "lounge", + num_unread: 0, + type: "chatroom", + jid: muc_jid, + id: muc_jid, + box_id: "box-YXJnQGNvbmZlcmVuY2UuY2hhdC5leGFtcGxlLm9yZw==", + nick: "romeo" + }) + ); + + _converse.no_connection_on_bind = true; // XXX Don't trigger CONNECTED in tests/mock.js + _converse.api.user.login('romeo@montague.lit', 'secret'); + delete _converse.no_connection_on_bind; + + const sent_stanzas = _converse.connection.sent_stanzas; + const stanza = await u.waitUntil(() => sent_stanzas.filter(s => (s.tagName === 'resume')).pop()); + expect(Strophe.serialize(stanza)).toEqual(''); + + const result = u.toStanza(``); + _converse.connection._dataRecv(test_utils.createRequest(result)); + expect(_converse.session.get('smacks_enabled')).toBe(true); + + const func = _converse.chatboxes.onChatBoxesFetched; + spyOn(_converse.chatboxes, 'onChatBoxesFetched').and.callFake(collection => { + const muc = new _converse.ChatRoom({'jid': muc_jid, 'id': muc_jid}, {'collection': _converse.chatboxes}); + _converse.chatboxes.add(muc); + func.call(_converse.chatboxes, collection); + }); + + // A MUC message gets received + const msg = $msg({ + from: `${muc_jid}/juliet`, + id: u.getUniqueId(), + to: 'romeo@montague.lit', + type: 'groupchat' + }).c('body').t('First message').tree(); + + _converse.connection._dataRecv(test_utils.createRequest(msg)); + + await _converse.api.waitUntil('chatBoxesFetched'); + const muc = _converse.chatboxes.get(muc_jid); + await u.waitUntil(() => muc.messages.length === 1); + expect(muc.messages.at(0).get('message')).toBe('First message') + done(); + })); }); })); diff --git a/src/headless/converse-mam.js b/src/headless/converse-mam.js index c93f547ee..0de37e895 100644 --- a/src/headless/converse-mam.js +++ b/src/headless/converse-mam.js @@ -130,10 +130,6 @@ converse.plugins.add('converse-mam', { Object.assign(_converse.ChatBox.prototype, MAMEnabledChat); - Object.assign(_converse.ChatRoom.prototype, { - }); - - _converse.onMAMError = function (iq) { if (iq && iq.querySelectorAll('feature-not-implemented').length) { log.warn("Message Archive Management (XEP-0313) not supported by this server"); diff --git a/src/headless/converse-muc.js b/src/headless/converse-muc.js index c69cca437..f7746ae68 100644 --- a/src/headless/converse-muc.js +++ b/src/headless/converse-muc.js @@ -2398,6 +2398,21 @@ converse.plugins.add('converse-muc', { _converse.api.listen.on('chatBoxesFetched', autoJoinRooms); + _converse.api.listen.on('beforeResourceBinding', () => { + _converse.connection.addHandler(stanza => { + const muc_jid = Strophe.getBareJidFromJid(stanza.getAttribute('from')); + if (!_converse.chatboxes.get(muc_jid)) { + _converse.api.waitUntil('chatBoxesFetched') + .then(() => { + const muc = _converse.chatboxes.get(muc_jid); + muc && muc.message_handler.run(stanza); + }); + } + return true; + }, null, 'message', 'groupchat') + }); + + function disconnectChatRooms () { /* When disconnecting, mark all groupchats as * disconnected, so that they will be properly entered again diff --git a/tests/mock.js b/tests/mock.js index 32577c5f0..3fd01e68e 100644 --- a/tests/mock.js +++ b/tests/mock.js @@ -155,6 +155,8 @@ }; + let _converse; + const OriginalConnection = Strophe.Connection; function MockConnection (service, options) { @@ -210,7 +212,9 @@ this.bind = () => { this.authenticated = true; this.authenticated = true; - this._changeConnectStatus(Strophe.Status.CONNECTED); + if (!_converse.no_connection_on_bind) { + this._changeConnectStatus(Strophe.Status.CONNECTED); + } }; this._proto._disconnect = () => this._onDisconnectTimeout(); @@ -254,7 +258,7 @@ clearStores(); await clearIndexedDB(); - const _converse = await converse.initialize(Object.assign({ + _converse = await converse.initialize(Object.assign({ 'animate': false, 'auto_subscribe': false, 'bosh_service_url': 'montague.lit/http-bind', diff --git a/webpack.html b/webpack.html index 83cabd319..9d6fcd3c5 100644 --- a/webpack.html +++ b/webpack.html @@ -29,7 +29,7 @@ persistent_store: 'IndexedDB', muc_domain: 'conference.chat.example.org', muc_respect_autojoin: true, - view_mode: 'overlayed', + view_mode: 'fullscreen', websocket_url: 'ws://chat.example.org:5380/xmpp-websocket', // bosh_service_url: 'http://chat.example.org:5280/http-bind', muc_show_logs_before_join: true,