Forráskód Böngészése

MAM: Fix a MUC timing issue.

If a message comes in after joining the MUC but before the MAM messages
have been fetched, then converse-mam will query for MAM messages newer
than that message, causing an empty history (except for that one message).
JC Brand 5 éve
szülő
commit
0da8067129
4 módosított fájl, 116 hozzáadás és 2 törlés
  1. 2 0
      spec/mock.js
  2. 109 1
      spec/muc.js
  3. 1 0
      src/headless/converse-chat.js
  4. 4 1
      src/headless/converse-mam.js

+ 2 - 0
spec/mock.js

@@ -1,3 +1,5 @@
+/*global converse */
+
 const mock = {};
 window.mock = mock;
 let _converse, initConverse;

+ 109 - 1
spec/muc.js

@@ -1,4 +1,4 @@
-/*global mock */
+/*global mock, converse */
 
 const _ = converse.env._;
 const $pres = converse.env.$pres;
@@ -12,6 +12,7 @@ const u = converse.env.utils;
 
 describe("Groupchats", function () {
 
+
     describe("The \"rooms\" API", function () {
 
         it("has a method 'close' which closes rooms by JID or all rooms when called with no arguments",
@@ -356,6 +357,113 @@ describe("Groupchats", function () {
 
     describe("A Groupchat", function () {
 
+        it("maintains its state across reloads",
+            mock.initConverse(
+                ['rosterGroupsFetched'], {
+                    'clear_messages_on_reconnection': true,
+                    'loglevel': 'debug',
+                    'enable_smacks': false
+                }, async function (done, _converse) {
+
+            const nick = 'romeo';
+            const sent_IQs = _converse.connection.IQ_stanzas;
+            const muc_jid = 'lounge@montague.lit'
+            await mock.openAndEnterChatRoom(_converse, muc_jid, nick, [], []);
+            const view = _converse.chatboxviews.get(muc_jid);
+            let iq_get = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector(`iq query[xmlns="${Strophe.NS.MAM}"]`)).pop());
+            const first_msg_id = _converse.connection.getUniqueId();
+            const last_msg_id = _converse.connection.getUniqueId();
+            let message = u.toStanza(
+                `<message xmlns="jabber:client"
+                        to="romeo@montague.lit/orchard"
+                        from="${muc_jid}">
+                    <result xmlns="urn:xmpp:mam:2" queryid="${iq_get.querySelector('query').getAttribute('queryid')}" id="${first_msg_id}">
+                        <forwarded xmlns="urn:xmpp:forward:0">
+                            <delay xmlns="urn:xmpp:delay" stamp="2018-01-09T06:15:23Z"/>
+                            <message from="${muc_jid}/some1" type="groupchat">
+                                <body>1st Message</body>
+                            </message>
+                        </forwarded>
+                    </result>
+                </message>`);
+            _converse.connection._dataRecv(mock.createRequest(message));
+
+            message = u.toStanza(
+                `<message xmlns="jabber:client"
+                        to="romeo@montague.lit/orchard"
+                        from="${muc_jid}">
+                    <result xmlns="urn:xmpp:mam:2" queryid="${iq_get.querySelector('query').getAttribute('queryid')}" id="${last_msg_id}">
+                        <forwarded xmlns="urn:xmpp:forward:0">
+                            <delay xmlns="urn:xmpp:delay" stamp="2018-01-09T06:16:23Z"/>
+                            <message from="${muc_jid}/some1" type="groupchat">
+                                <body>2nd Message</body>
+                            </message>
+                        </forwarded>
+                    </result>
+                </message>`);
+            _converse.connection._dataRecv(mock.createRequest(message));
+
+            const result = u.toStanza(
+                `<iq type='result' id='${iq_get.getAttribute('id')}'>
+                    <fin xmlns='urn:xmpp:mam:2'>
+                        <set xmlns='http://jabber.org/protocol/rsm'>
+                            <first index='0'>${first_msg_id}</first>
+                            <last>${last_msg_id}</last>
+                            <count>2</count>
+                        </set>
+                    </fin>
+                </iq>`);
+            _converse.connection._dataRecv(mock.createRequest(result));
+            await u.waitUntil(()  => view.el.querySelectorAll('.chat-msg__text').length === 2);
+
+            while (sent_IQs.length) { sent_IQs.pop(); } // Clear so that we don't match the older query
+            await _converse.api.connection.reconnect();
+            await mock.getRoomFeatures(_converse, muc_jid, []);
+            await u.waitUntil(() => (view.model.session.get('connection_status') === converse.ROOMSTATUS.CONNECTING));
+
+            // The user has just entered the room (because join was called)
+            // and receives their own presence from the server.
+            // See example 24: https://xmpp.org/extensions/xep-0045.html#enter-pres
+            await mock.receiveOwnMUCPresence(_converse, muc_jid, nick);
+
+            message = u.toStanza(`
+                <message xmlns="jabber:client" type="groupchat" id="918172de-d5c5-4da4-b388-446ef4a05bec" to="${_converse.jid}" xml:lang="en" from="${muc_jid}/juliet">
+                    <body>Wherefore art though?</body>
+                    <active xmlns="http://jabber.org/protocol/chatstates"/>
+                    <origin-id xmlns="urn:xmpp:sid:0" id="918172de-d5c5-4da4-b388-446ef4a05bec"/>
+                    <stanza-id xmlns="urn:xmpp:sid:0" id="88cc9c93-a8f4-4dd5-b02a-d19855eb6303" by="${muc_jid}"/>
+                    <delay xmlns="urn:xmpp:delay" stamp="2020-07-14T17:46:47Z" from="juliet@shakespeare.lit"/>
+                </message>`);
+            _converse.connection._dataRecv(mock.createRequest(message));
+
+            message = u.toStanza(`
+                <message xmlns="jabber:client" type="groupchat" id="awQo6a-mi-Wa6NYh" to="${_converse.jid}" from="${muc_jid}/ews000" xml:lang="en">
+                    <composing xmlns="http://jabber.org/protocol/chatstates"/>
+                    <no-store xmlns="urn:xmpp:hints"/>
+                    <no-permanent-store xmlns="urn:xmpp:hints"/>
+                    <delay xmlns="urn:xmpp:delay" stamp="2020-07-14T17:46:54Z" from="juliet@shakespeare.lit"/>
+                </message>`);
+            _converse.connection._dataRecv(mock.createRequest(message));
+
+            const affs = _converse.muc_fetch_members;
+            const all_affiliations = Array.isArray(affs) ? affs :  (affs ? ['member', 'admin', 'owner'] : []);
+            await mock.returnMemberLists(_converse, muc_jid, [], all_affiliations);
+
+            iq_get = await u.waitUntil(() => sent_IQs.filter(iq => iq.querySelector(`iq query[xmlns="${Strophe.NS.MAM}"]`)).pop());
+            expect(Strophe.serialize(iq_get)).toBe(
+                `<iq id="${iq_get.getAttribute('id')}" to="${muc_jid}" type="set" xmlns="jabber:client">`+
+                    `<query queryid="${iq_get.querySelector('query').getAttribute('queryid')}" xmlns="${Strophe.NS.MAM}">`+
+                        `<x type="submit" xmlns="jabber:x:data">`+
+                            `<field type="hidden" var="FORM_TYPE"><value>urn:xmpp:mam:2</value></field>`+
+                        `</x>`+
+                        `<set xmlns="http://jabber.org/protocol/rsm"><max>50</max><before></before></set>`+
+                    `</query>`+
+                `</iq>`);
+
+            done();
+        }));
+
+
         describe("upon being entered", function () {
 
             it("will fetch the member list if muc_fetch_members is true",

+ 1 - 0
src/headless/converse-chat.js

@@ -487,6 +487,7 @@ converse.plugins.add('converse-chat', {
                     this.messages.trigger('reset');
                     log.error(e);
                 } finally {
+                    delete this.msg_chain;
                     delete this.messages.fetched;
                 }
             },

+ 4 - 1
src/headless/converse-mam.js

@@ -35,7 +35,10 @@ const MAMEnabledChat = {
             return;
         }
         const most_recent_msg = this.getMostRecentMessage();
-        if (most_recent_msg) {
+        // if clear_messages_on_reconnection is true, than any recent messages
+        // must have been received *after* connection and we instead must query
+        // for earlier messages
+        if (most_recent_msg && !api.settings.get('clear_messages_on_reconnection')) {
             const stanza_id = most_recent_msg.get(`stanza_id ${this.get('jid')}`);
             if (stanza_id) {
                 this.fetchArchivedMessages({'after': stanza_id}, 'forwards');