瀏覽代碼

mam: Upgrade MAM support to version 2

JC Brand 8 年之前
父節點
當前提交
095e7add86
共有 4 個文件被更改,包括 97 次插入79 次删除
  1. 2 0
      CHANGES.md
  2. 49 54
      spec/mam.js
  3. 1 1
      src/converse-core.js
  4. 45 24
      src/converse-mam.js

+ 2 - 0
CHANGES.md

@@ -2,6 +2,8 @@
 
 ## 3.1.0 (Unreleased)
 
+- Support for [XMPP-0313 Message Archive Management](https://xmpp.org/extensions/xep-0313.html)
+  has been upgraded to version 2. [jcbrand]
 - New non-core plugin `converse-singleton` which ensures that no more than
   one chat is visible at any given time. Used in the mobile build:
   `converse-mobile.js` and makes the unread messages counter possible there.

+ 49 - 54
spec/mam.js

@@ -28,7 +28,7 @@
                 _converse.api.archive.query();
                 var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
                 expect(sent_stanza.toString()).toBe(
-                    "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'><query xmlns='urn:xmpp:mam:0' queryid='"+queryid+"'/></iq>");
+                    "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'><query xmlns='urn:xmpp:mam:2' queryid='"+queryid+"'/></iq>");
             }));
 
            it("can be used to query for all messages to/from a particular JID", mock.initConverse(function (_converse) {
@@ -45,10 +45,10 @@
                 var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
                 expect(sent_stanza.toString()).toBe(
                     "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
-                        "<query xmlns='urn:xmpp:mam:0' queryid='"+queryid+"'>"+
+                        "<query xmlns='urn:xmpp:mam:2' queryid='"+queryid+"'>"+
                             "<x xmlns='jabber:x:data' type='submit'>"+
                             "<field var='FORM_TYPE' type='hidden'>"+
-                                "<value>urn:xmpp:mam:0</value>"+
+                                "<value>urn:xmpp:mam:2</value>"+
                             "</field>"+
                             "<field var='with'>"+
                                 "<value>juliet@capulet.lit</value>"+
@@ -79,10 +79,10 @@
                 var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
                 expect(sent_stanza.toString()).toBe(
                     "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
-                        "<query xmlns='urn:xmpp:mam:0' queryid='"+queryid+"'>"+
+                        "<query xmlns='urn:xmpp:mam:2' queryid='"+queryid+"'>"+
                             "<x xmlns='jabber:x:data' type='submit'>"+
                             "<field var='FORM_TYPE' type='hidden'>"+
-                                "<value>urn:xmpp:mam:0</value>"+
+                                "<value>urn:xmpp:mam:2</value>"+
                             "</field>"+
                             "<field var='start'>"+
                                 "<value>"+moment(start).format()+"</value>"+
@@ -120,10 +120,10 @@
                 var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
                 expect(sent_stanza.toString()).toBe(
                     "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
-                        "<query xmlns='urn:xmpp:mam:0' queryid='"+queryid+"'>"+
+                        "<query xmlns='urn:xmpp:mam:2' queryid='"+queryid+"'>"+
                             "<x xmlns='jabber:x:data' type='submit'>"+
                             "<field var='FORM_TYPE' type='hidden'>"+
-                                "<value>urn:xmpp:mam:0</value>"+
+                                "<value>urn:xmpp:mam:2</value>"+
                             "</field>"+
                             "<field var='start'>"+
                                 "<value>"+moment(start).format()+"</value>"+
@@ -149,10 +149,10 @@
                 var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
                 expect(sent_stanza.toString()).toBe(
                     "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
-                        "<query xmlns='urn:xmpp:mam:0' queryid='"+queryid+"'>"+
+                        "<query xmlns='urn:xmpp:mam:2' queryid='"+queryid+"'>"+
                             "<x xmlns='jabber:x:data' type='submit'>"+
                                 "<field var='FORM_TYPE' type='hidden'>"+
-                                    "<value>urn:xmpp:mam:0</value>"+
+                                    "<value>urn:xmpp:mam:2</value>"+
                                 "</field>"+
                                 "<field var='start'>"+
                                     "<value>"+moment(start).format()+"</value>"+
@@ -185,10 +185,10 @@
                 var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
                 expect(sent_stanza.toString()).toBe(
                     "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
-                        "<query xmlns='urn:xmpp:mam:0' queryid='"+queryid+"'>"+
+                        "<query xmlns='urn:xmpp:mam:2' queryid='"+queryid+"'>"+
                             "<x xmlns='jabber:x:data' type='submit'>"+
                                 "<field var='FORM_TYPE' type='hidden'>"+
-                                    "<value>urn:xmpp:mam:0</value>"+
+                                    "<value>urn:xmpp:mam:2</value>"+
                                 "</field>"+
                                 "<field var='start'>"+
                                     "<value>"+moment(start).format()+"</value>"+
@@ -217,10 +217,10 @@
                 var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
                 expect(sent_stanza.toString()).toBe(
                     "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
-                        "<query xmlns='urn:xmpp:mam:0' queryid='"+queryid+"'>"+
+                        "<query xmlns='urn:xmpp:mam:2' queryid='"+queryid+"'>"+
                             "<x xmlns='jabber:x:data' type='submit'>"+
                                 "<field var='FORM_TYPE' type='hidden'>"+
-                                    "<value>urn:xmpp:mam:0</value>"+
+                                    "<value>urn:xmpp:mam:2</value>"+
                                 "</field>"+
                             "</x>"+
                             "<set xmlns='http://jabber.org/protocol/rsm'>"+
@@ -254,10 +254,10 @@
                 var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
                 expect(sent_stanza.toString()).toBe(
                     "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
-                        "<query xmlns='urn:xmpp:mam:0' queryid='"+queryid+"'>"+
+                        "<query xmlns='urn:xmpp:mam:2' queryid='"+queryid+"'>"+
                             "<x xmlns='jabber:x:data' type='submit'>"+
                                 "<field var='FORM_TYPE' type='hidden'>"+
-                                    "<value>urn:xmpp:mam:0</value>"+
+                                    "<value>urn:xmpp:mam:2</value>"+
                                 "</field>"+
                                 "<field var='with'>"+
                                     "<value>romeo@montague.lit</value>"+
@@ -289,27 +289,22 @@
                 _converse.api.archive.query({'with': 'romeo@capulet.lit', 'max':'10'}, callback);
                 var queryid = $(sent_stanza.toString()).find('query').attr('queryid');
 
-                // Send the result stanza, so that the callback is called.
-                var stanza = $iq({'type': 'result', 'id': IQ_id});
-                _converse.connection._dataRecv(test_utils.createRequest(stanza));
-
-                /* <message id='aeb213' to='juliet@capulet.lit/chamber'>
-                 *   <result xmlns='urn:xmpp:mam:0' queryid='f27' id='28482-98726-73623'>
-                 *     <forwarded xmlns='urn:xmpp:forward:0'>
-                 *       <delay xmlns='urn:xmpp:delay' stamp='2010-07-10T23:08:25Z'/>
-                 *       <message
-                 *         to='juliet@capulet.lit/balcony'
-                 *         from='romeo@montague.lit/orchard'
-                 *         type='chat'
-                 *         xmlns='jabber:client'>
-                 *         <body>Call me but love, and I'll be new baptized; Henceforth I never will be Romeo.</body>
-                 *       </message>
-                 *     </forwarded>
-                 *   </result>
-                 * </message>
+                /*  <message id='aeb213' to='juliet@capulet.lit/chamber'>
+                 *  <result xmlns='urn:xmpp:mam:2' queryid='f27' id='28482-98726-73623'>
+                 *      <forwarded xmlns='urn:xmpp:forward:0'>
+                 *      <delay xmlns='urn:xmpp:delay' stamp='2010-07-10T23:08:25Z'/>
+                 *      <message xmlns='jabber:client'
+                 *          to='juliet@capulet.lit/balcony'
+                 *          from='romeo@montague.lit/orchard'
+                 *          type='chat'>
+                 *          <body>Call me but love, and I'll be new baptized; Henceforth I never will be Romeo.</body>
+                 *      </message>
+                 *      </forwarded>
+                 *  </result>
+                 *  </message>
                  */
                 var msg1 = $msg({'id':'aeb213', 'to':'juliet@capulet.lit/chamber'})
-                            .c('result',  {'xmlns': 'urn:xmpp:mam:0', 'queryid':queryid, 'id':'28482-98726-73623'})
+                            .c('result',  {'xmlns': 'urn:xmpp:mam:2', 'queryid':queryid, 'id':'28482-98726-73623'})
                                 .c('forwarded', {'xmlns':'urn:xmpp:forward:0'})
                                     .c('delay', {'xmlns':'urn:xmpp:delay', 'stamp':'2010-07-10T23:08:25Z'}).up()
                                     .c('message', {
@@ -321,7 +316,7 @@
                 _converse.connection._dataRecv(test_utils.createRequest(msg1));
 
                 var msg2 = $msg({'id':'aeb213', 'to':'juliet@capulet.lit/chamber'})
-                            .c('result',  {'xmlns': 'urn:xmpp:mam:0', 'queryid':queryid, 'id':'28482-98726-73624'})
+                            .c('result',  {'xmlns': 'urn:xmpp:mam:2', 'queryid':queryid, 'id':'28482-98726-73624'})
                                 .c('forwarded', {'xmlns':'urn:xmpp:forward:0'})
                                     .c('delay', {'xmlns':'urn:xmpp:delay', 'stamp':'2010-07-10T23:08:25Z'}).up()
                                     .c('message', {
@@ -332,23 +327,23 @@
                                     .c('body').t("Henceforth I never will be Romeo.");
                 _converse.connection._dataRecv(test_utils.createRequest(msg2));
 
-                /* Send a <fin> message to indicate the end of the result set.
+                /* Send an <iq> stanza to indicate the end of the result set.
                  *
-                 * <message>
-                 *     <fin xmlns='urn:xmpp:mam:0' complete='true'>
-                 *         <set xmlns='http://jabber.org/protocol/rsm'>
-                 *             <first index='0'>23452-4534-1</first>
-                 *             <last>390-2342-22</last>
-                 *             <count>16</count>
-                 *         </set>
-                 *     </fin>
-                 * </message>
+                 * <iq type='result' id='juliet1'>
+                 *     <fin xmlns='urn:xmpp:mam:2'>
+                 *     <set xmlns='http://jabber.org/protocol/rsm'>
+                 *         <first index='0'>28482-98726-73623</first>
+                 *         <last>09af3-cc343-b409f</last>
+                 *         <count>20</count>
+                 *     </set>
+                 * </iq>
                  */
-                stanza = $msg().c('fin', {'xmlns': 'urn:xmpp:mam:0', 'queryid':queryid, 'complete': 'true'})
-                            .c('set',  {'xmlns': 'http://jabber.org/protocol/rsm'})
-                                .c('first', {'index': '0'}).t('23452-4534-1').up()
-                                .c('last').t('390-2342-22').up()
-                                .c('count').t('16');
+                var stanza = $iq({'type': 'result', 'id': IQ_id})
+                    .c('fin', {'xmlns': 'urn:xmpp:mam:2'})
+                        .c('set',  {'xmlns': 'http://jabber.org/protocol/rsm'})
+                            .c('first', {'index': '0'}).t('23452-4534-1').up()
+                            .c('last').t('09af3-cc343-b409f').up()
+                            .c('count').t('16');
                 _converse.connection._dataRecv(test_utils.createRequest(stanza));
 
                 expect(callback).toHaveBeenCalled();
@@ -360,7 +355,7 @@
                 expect(args[1].max).toBe('10');
                 expect(args[1].count).toBe('16');
                 expect(args[1].first).toBe('23452-4534-1');
-                expect(args[1].last).toBe('390-2342-22');
+                expect(args[1].last).toBe('09af3-cc343-b409f');
            }));
 
         });
@@ -386,11 +381,11 @@
                 expect(_converse.connection.sendIQ).toHaveBeenCalled();
                 expect(sent_stanza.toLocaleString()).toBe(
                     "<iq type='get' xmlns='jabber:client' id='"+IQ_id+"'>"+
-                        "<prefs xmlns='urn:xmpp:mam:0'/>"+
+                        "<prefs xmlns='urn:xmpp:mam:2'/>"+
                     "</iq>"
                 );
 
-                /* Example 15. Server responds with current preferences
+                /* Example 20. Server responds with current preferences
                  *
                  * <iq type='result' id='juliet2'>
                  *   <prefs xmlns='urn:xmpp:mam:0' default='roster'>
@@ -410,7 +405,7 @@
                 expect(_converse.connection.sendIQ.calls.count()).toBe(2);
                 expect(sent_stanza.toString()).toBe(
                     "<iq type='set' xmlns='jabber:client' id='"+IQ_id+"'>"+
-                        "<prefs xmlns='urn:xmpp:mam:0' default='never'>"+
+                        "<prefs xmlns='urn:xmpp:mam:2' default='never'>"+
                             "<always><jid>romeo@montague.lit</jid></always>"+
                             "<never><jid>montague@montague.lit</jid></never>"+
                         "</prefs>"+

+ 1 - 1
src/converse-core.js

@@ -192,7 +192,7 @@
         Strophe.addNamespace('CSI', 'urn:xmpp:csi:0');
         Strophe.addNamespace('DELAY', 'urn:xmpp:delay');
         Strophe.addNamespace('HINTS', 'urn:xmpp:hints');
-        Strophe.addNamespace('MAM', 'urn:xmpp:mam:0');
+        Strophe.addNamespace('MAM', 'urn:xmpp:mam:2');
         Strophe.addNamespace('NICK', 'http://jabber.org/protocol/nick');
         Strophe.addNamespace('PUBSUB', 'http://jabber.org/protocol/pubsub');
         Strophe.addNamespace('ROSTERX', 'http://jabber.org/protocol/rosterx');

+ 45 - 24
src/converse-mam.js

@@ -125,6 +125,23 @@
             },
 
             ChatRoomView: {
+
+                initialize: function () {
+                    var _converse = this.__super__._converse;
+                    this.__super__.initialize.apply(this, arguments);
+                    this.model.on('change:mam_enabled', function () {
+                        // Fetch messages again if we find out that mam has
+                        // been enabled (because the first attempt would then
+                        // have failed.
+                        this.fetchArchivedMessages({
+                            'before': '', // Page backwards from the most recent message
+                            'with': this.model.get('jid'),
+                            'max': _converse.archived_messages_page_size
+                        });
+                        this.model.save({'mam_initialized': true});
+                    }, this);
+                },
+
                 render: function () {
                     var result = this.__super__.render.apply(this, arguments);
                     if (!this.disable_mam) {
@@ -150,7 +167,6 @@
                      * Then, upon receiving them, call onChatRoomMessage
                      * so that they are displayed inside it.
                      */
-                    var that = this;
                     var _converse = this.__super__._converse;
                     if (!_converse.features.findWhere({'var': Strophe.NS.MAM})) {
                         _converse.log(
@@ -162,6 +178,8 @@
                         return;
                     }
                     this.addSpinner();
+
+                    var that = this;
                     _converse.api.archive.query(_.extend(options, {'groupchat': true}),
                         function (messages) {
                             that.clearSpinner();
@@ -216,18 +234,13 @@
                     callback = options;
                     errback = callback;
                 }
-                /*
-                if (!_converse.features.findWhere({'var': Strophe.NS.MAM})) {
-                    _converse.log('This server does not support XEP-0313, Message Archive Management');
-                    errback(null);
-                    return;
-                }
-                */
                 var queryid = _converse.connection.getUniqueId();
                 var attrs = {'type':'set'};
                 if (!_.isUndefined(options) && options.groupchat) {
                     if (!options['with']) {
-                        throw new Error('You need to specify a "with" value containing the chat room JID, when querying groupchat messages.');
+                        throw new Error(
+                            'You need to specify a "with" value containing '+
+                            'the chat room JID, when querying groupchat messages.');
                     }
                     attrs.to = options['with'];
                 }
@@ -258,23 +271,31 @@
                     }
                 }
 
-                if (_.isFunction(callback)) {
-                    _converse.connection.addHandler(function (message) {
-                        var $msg = $(message), rsm,
-                            $fin = $msg.find('fin[xmlns="'+Strophe.NS.MAM+'"]');
-                        if ($fin.length && $fin.attr('queryid') === queryid) {
-                            rsm = new Strophe.RSM({xml: $fin.find('set')[0]});
-                            _.extend(rsm, _.pick(options, ['max']));
-                            _.extend(rsm, _.pick(options, MAM_ATTRIBUTES));
+                var message_handler = _converse.connection.addHandler(function (message) {
+                    var result = message.querySelector('result');
+                    if (!_.isNull(result) && result.getAttribute('queryid') === queryid) {
+                        messages.push(message);
+                    }
+                    return true;
+                }, Strophe.NS.MAM);
+
+                _converse.connection.sendIQ(
+                    stanza,
+                    function (iq) {
+                        _converse.connection.deleteHandler(message_handler);
+                        if (_.isFunction(callback)) {
+                            var set = iq.querySelector('set');
+                            var rsm = new Strophe.RSM({xml: set});
+                            _.extend(rsm, _.pick(options, _.concat(MAM_ATTRIBUTES, ['max'])));
                             callback(messages, rsm);
-                            return false; // We've received all messages, decommission this handler
-                        } else if (queryid === $msg.find('result').attr('queryid')) {
-                            messages.push(message);
                         }
-                        return true;
-                    }, Strophe.NS.MAM);
-                }
-                _converse.connection.sendIQ(stanza, null, errback, _converse.message_archiving_timeout);
+                    },
+                    function () {
+                        _converse.connection.deleteHandler(message_handler);
+                        if (_.isFunction(errback)) { errback.apply(this, arguments); }
+                    },
+                    _converse.message_archiving_timeout
+                );
             };
 
             _.extend(_converse.api, {