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

Refactor MAM and clear private chats upon reconnection

- Add `onReconnected` method for chatboxes to clear messages
- Move MAM models to headless build.
- New event `onChatReconnected`
JC Brand 6 éve
szülő
commit
7ab59ad63e

+ 1 - 0
.eslintrc.json

@@ -26,6 +26,7 @@
                 "split", "trim", "forEach", "toUpperCase", "includes", "values"
             ]
         }],
+        "lodash/import-scope": "off",
         "lodash/prefer-invoke-map": "off",
         "lodash/prefer-startswith": "off",
         "lodash/prefer-constant": "off",

+ 2 - 0
CHANGES.md

@@ -14,6 +14,8 @@
 - New API method [\_converse.api.disco.features.get](https://conversejs.org/docs/html/api/-_converse.api.disco.features.html#.get)
 - New config setting [muc_show_join_leave_status](https://conversejs.org/docs/html/configuration.html#muc-show-join-leave-status)
 - New event: `chatBoxBlurred`.
+- New event: [chatBoxBlurred](https://conversejs.org/docs/html/api/-_converse.html#event:chatBoxBlurred)
+- New event: [chatReconnected](https://conversejs.org/docs/html/api/-_converse.html#event:chatReconnected)
 - Properly handle message correction being received before the corrected message
 - #1296: `embedded` view mode shows `chatbox-navback` arrow in header
 - #1465: When highlighting a roster contact, they're incorrectly shown as online

+ 3 - 3
docs/source/_templates/jsdoc_layout.tmpl

@@ -10,15 +10,15 @@
     <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
     <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
     <link type="text/css" rel="stylesheet" href="/docs/source/_static/api.css">
-    <link type="text/css" rel="stylesheet" href="/css/converse.min.css">
-    <link rel="shortcut icon" href="/css/images/favicon.ico"/>
+    <link type="text/css" rel="stylesheet" href="/dist/converse.min.css">
+    <link rel="shortcut icon" href="/images/favicon.ico"/>
 </head>
 
 <body>
 
 <div id="main">
     <h1 class="brand-heading fade-in">
-        <svg 
+        <svg
             style="height: 8rem"
             xmlns:svg="http://www.w3.org/2000/svg"
             xmlns="http://www.w3.org/2000/svg"

+ 1 - 1
docs/source/_templates/layout.html

@@ -2,7 +2,7 @@
 {% extends "!layout.html" %}
 
 {# Custom CSS overrides #}
-{% set css_files = css_files + ['_static/style.css', "../../css/converse.min.css"] %}
+{% set css_files = css_files + ['_static/style.css', "../../dist/converse.min.css"] %}
 {% set script_files = script_files + ["../../dist/converse.min.js", "../../analytics.js"] %}
 
 {# Add some extra stuff before and use existing with 'super()' call. #}

+ 4 - 4
docs/source/quickstart.rst

@@ -18,7 +18,7 @@ which hosts its JavaScript and CSS files.
 The latest versions of these files are available at these URLs:
 
 * https://cdn.conversejs.org/dist/converse.min.js
-* https://cdn.conversejs.org/css/converse.min.css
+* https://cdn.conversejs.org/dist/converse.min.css
 
 If you are integrating Converse into an existing website or app, then we recommend
 that you load a specific version of Converse. Otherwise your website or app
@@ -26,15 +26,15 @@ might break when a new backwards-incompatible version of Converse is released.
 
 To load a specific version of Converse you can put the version in the URL:
 
-* https://cdn.conversejs.org/4.2.0/dist/converse.min.js
-* https://cdn.conversejs.org/4.2.0/css/converse.min.css
+* https://cdn.conversejs.org/5.0.0/dist/converse.min.js
+* https://cdn.conversejs.org/5.0.0/dist/converse.min.css
 
 You can include these two URLs inside the *<head>* element of your website
 via the *script* and *link* tags:
 
 .. code-block:: html
 
-    <link rel="stylesheet" type="text/css" media="screen" href="https://cdn.conversejs.org/4.2.0/css/converse.min.css">
+    <link rel="stylesheet" type="text/css" media="screen" href="https://cdn.conversejs.org/4.2.0/dist/converse.min.css">
     <script src="https://cdn.conversejs.org/4.2.0/dist/converse.min.js" charset="utf-8"></script>
 
 

+ 3 - 1
src/converse-controlbox.js

@@ -199,7 +199,9 @@ converse.plugins.add('converse-controlbox', {
                     'type': _converse.CONTROLBOX_TYPE,
                     'url': ''
                 }
-            }
+            },
+
+            onReconnection: _.noop
         });
 
 

+ 4 - 108
src/converse-mam-views.js

@@ -7,16 +7,12 @@
 // Views for XEP-0313 Message Archive Management
 
 import converse from "@converse/headless/converse-core";
-
-
-const CHATROOMS_TYPE = 'chatroom';
-const { Strophe, _ } = converse.env;
-const u = converse.env.utils;
+import { debounce } from 'lodash'
 
 
 converse.plugins.add('converse-mam-views', {
 
-    dependencies: ['converse-disco', 'converse-mam', 'converse-chatview', 'converse-muc-views'],
+    dependencies: ['converse-mam', 'converse-chatview', 'converse-muc-views'],
 
     overrides: {
         // Overrides mentioned here will be picked up by converse.js's
@@ -25,73 +21,11 @@ converse.plugins.add('converse-mam-views', {
         //
         // New functions which don't exist yet can also be added.
 
-
-        ChatBox: {
-            fetchNewestMessages () {
-                /* Fetches messages that might have been archived *after*
-                 * the last archived message in our local cache.
-                 */
-                if (this.disable_mam) {
-                    return;
-                }
-                const { _converse } = this.__super__;
-                const most_recent_msg = u.getMostRecentMessage(this);
-
-                if (_.isNil(most_recent_msg)) {
-                    this.fetchArchivedMessages();
-                } else {
-                    const stanza_id = most_recent_msg.get(`stanza_id ${this.get('jid')}`);
-                    if (stanza_id) {
-                        this.fetchArchivedMessages({'after': stanza_id});
-                    } else {
-                        this.fetchArchivedMessages({'start': most_recent_msg.get('time')});
-                    }
-                }
-            },
-
-            async fetchArchivedMessages (options) {
-                if (this.disable_mam) {
-                    return;
-                }
-                const { _converse } = this.__super__;
-                const is_groupchat = this.get('type') === CHATROOMS_TYPE;
-                const mam_jid = is_groupchat ? this.get('jid') : _converse.bare_jid;
-                if (!(await _converse.api.disco.supports(Strophe.NS.MAM, mam_jid))) {
-                    return;
-                }
-                let message_handler;
-                if (is_groupchat) {
-                    message_handler = this.onMessage.bind(this);
-                } else {
-                    message_handler = _converse.chatboxes.onMessage.bind(_converse.chatboxes)
-                }
-                let result = {};
-                try {
-                    result = await _converse.api.archive.query(
-                        Object.assign({
-                            'groupchat': is_groupchat,
-                            'before': '', // Page backwards from the most recent message
-                            'max': _converse.archived_messages_page_size,
-                            'with': this.get('jid'),
-                        }, options));
-                } catch (e) {
-                    _converse.log(
-                        "Error or timeout while trying to fetch "+
-                        "archived messages", Strophe.LogLevel.ERROR);
-                    _converse.log(e, Strophe.LogLevel.ERROR);
-                }
-                if (result.messages) {
-                    result.messages.forEach(message_handler);
-                }
-            }
-        },
-
         ChatBoxView: {
-
             render () {
                 const result = this.__super__.render.apply(this, arguments);
                 if (!this.disable_mam) {
-                    this.content.addEventListener('scroll', _.debounce(this.onScroll.bind(this), 100));
+                    this.content.addEventListener('scroll', debounce(this.onScroll.bind(this), 100));
                 }
                 return result;
             },
@@ -115,52 +49,14 @@ converse.plugins.add('converse-mam-views', {
             }
         },
 
-        ChatRoom: {
-
-            initialize () {
-                this.__super__.initialize.apply(this, arguments);
-                this.on('change:mam_enabled', this.fetchArchivedMessagesIfNecessary, this);
-                this.on('change:connection_status', this.fetchArchivedMessagesIfNecessary, this);
-            },
-
-            fetchArchivedMessagesIfNecessary () {
-                if (this.get('connection_status') !== converse.ROOMSTATUS.ENTERED ||
-                        !this.get('mam_enabled') ||
-                        this.get('mam_initialized')) {
-                    return;
-                }
-                this.fetchArchivedMessages();
-                this.save({'mam_initialized': true});
-            }
-        },
-
         ChatRoomView: {
-
             renderChatArea () {
                 const result = this.__super__.renderChatArea.apply(this, arguments);
                 if (!this.disable_mam) {
-                    this.content.addEventListener('scroll', _.debounce(this.onScroll.bind(this), 100));
+                    this.content.addEventListener('scroll', debounce(this.onScroll.bind(this), 100));
                 }
                 return result;
             }
         }
-    },
-
-    initialize () {
-        /* The initialize function gets called as soon as the plugin is
-         * loaded by Converse.js's plugin machinery.
-         */
-        const { _converse } = this;
-
-        /************************ BEGIN Event Handlers ************************/
-        _converse.api.listen.on('afterMessagesFetched', chatbox => chatbox.fetchNewestMessages());
-
-        _converse.api.listen.on('reconnected', () => {
-            const private_chats = _converse.chatboxviews.filter(
-                view => _.at(view, 'model.attributes.type')[0] === 'chatbox'
-            );
-            _.each(private_chats, view => view.model.fetchNewestMessages())
-        });
-        /************************ END Event Handlers ************************/
     }
 });

+ 13 - 0
src/headless/converse-chatboxes.js

@@ -352,6 +352,17 @@ converse.plugins.add('converse-chatboxes', {
                 }
             },
 
+            onReconnection () {
+                this.clearMessages();
+                /**
+                 * Triggered whenever a `_converse.ChatBox` instance has reconnected after an outage
+                 * @event _converse#onChatReconnected
+                 * @type {_converse.ChatBox | _converse.ChatRoom}
+                 * @example _converse.api.listen.on('onChatReconnected', chatbox => { ... });
+                 */
+                _converse.api.trigger('chatReconnected', this);
+            },
+
             validate (attrs, options) {
                 const { _converse } = this.__super__;
                 if (!attrs.jid) {
@@ -1150,6 +1161,8 @@ converse.plugins.add('converse-chatboxes', {
             _converse.api.trigger('chatBoxesInitialized');
         });
         _converse.api.listen.on('presencesInitialized', () => _converse.chatboxes.onConnected());
+
+        _converse.api.listen.on('reconnected', () => _converse.chatboxes.forEach(m => m.onReconnection()));
         /************************ END Event Handlers ************************/
 
 

+ 81 - 2
src/headless/converse-mam.js

@@ -23,7 +23,7 @@ const MAM_ATTRIBUTES = ['with', 'start', 'end'];
 
 converse.plugins.add('converse-mam', {
 
-    dependencies: ['converse-muc'],
+    dependencies: ['converse-disco', 'converse-muc'],
 
     overrides: {
         // Overrides mentioned here will be picked up by converse.js's
@@ -33,6 +33,64 @@ converse.plugins.add('converse-mam', {
         // New functions which don't exist yet can also be added.
         ChatBox: {
 
+            fetchNewestMessages () {
+                /* Fetches messages that might have been archived *after*
+                 * the last archived message in our local cache.
+                 */
+                if (this.disable_mam) {
+                    return;
+                }
+                const { _converse } = this.__super__;
+                const most_recent_msg = u.getMostRecentMessage(this);
+
+                if (_.isNil(most_recent_msg)) {
+                    this.fetchArchivedMessages();
+                } else {
+                    const stanza_id = most_recent_msg.get(`stanza_id ${this.get('jid')}`);
+                    if (stanza_id) {
+                        this.fetchArchivedMessages({'after': stanza_id});
+                    } else {
+                        this.fetchArchivedMessages({'start': most_recent_msg.get('time')});
+                    }
+                }
+            },
+
+            async fetchArchivedMessages (options) {
+                if (this.disable_mam) {
+                    return;
+                }
+                const { _converse } = this.__super__;
+                const is_groupchat = this.get('type') === CHATROOMS_TYPE;
+                const mam_jid = is_groupchat ? this.get('jid') : _converse.bare_jid;
+                if (!(await _converse.api.disco.supports(Strophe.NS.MAM, mam_jid))) {
+                    return;
+                }
+                let message_handler;
+                if (is_groupchat) {
+                    message_handler = this.onMessage.bind(this);
+                } else {
+                    message_handler = _converse.chatboxes.onMessage.bind(_converse.chatboxes)
+                }
+                let result = {};
+                try {
+                    result = await _converse.api.archive.query(
+                        Object.assign({
+                            'groupchat': is_groupchat,
+                            'before': '', // Page backwards from the most recent message
+                            'max': _converse.archived_messages_page_size,
+                            'with': this.get('jid'),
+                        }, options));
+                } catch (e) {
+                    _converse.log(
+                        "Error or timeout while trying to fetch "+
+                        "archived messages", Strophe.LogLevel.ERROR);
+                    _converse.log(e, Strophe.LogLevel.ERROR);
+                }
+                if (result.messages) {
+                    result.messages.forEach(message_handler);
+                }
+            },
+
             async findDuplicateFromArchiveID (stanza) {
                 const { _converse } = this.__super__;
                 const result = sizzle(`result[xmlns="${Strophe.NS.MAM}"]`, stanza).pop();
@@ -66,7 +124,26 @@ converse.plugins.add('converse-mam', {
                 }
                 return attrs;
             }
-        }
+        },
+
+        ChatRoom: {
+            initialize () {
+                this.__super__.initialize.apply(this, arguments);
+                this.on('change:mam_enabled', this.fetchArchivedMessagesIfNecessary, this);
+                this.on('change:connection_status', this.fetchArchivedMessagesIfNecessary, this);
+            },
+
+            fetchArchivedMessagesIfNecessary () {
+                if (this.get('connection_status') !== converse.ROOMSTATUS.ENTERED ||
+                        !this.get('mam_enabled') ||
+                        this.get('mam_initialized')) {
+                    return;
+                }
+                this.fetchArchivedMessages();
+                this.save({'mam_initialized': true});
+            }
+        },
+
     },
 
     initialize () {
@@ -139,6 +216,8 @@ converse.plugins.add('converse-mam', {
             }
         });
 
+        _converse.api.listen.on('afterMessagesFetched', chat => chat.fetchNewestMessages());
+        _converse.api.listen.on('chatReconnected', chat => chat.fetchNewestMessages());
         _converse.api.listen.on('addClientFeatures', () => _converse.api.disco.own.features.add(Strophe.NS.MAM));
         /************************ END Event Handlers ************************/
 

+ 8 - 17
src/headless/converse-muc.js

@@ -240,7 +240,6 @@ converse.plugins.add('converse-muc', {
                 }
             },
 
-
             async onConnectionStatusChanged () {
                 if (this.get('connection_status') === converse.ROOMSTATUS.ENTERED) {
                     this.occupants.fetchMembers();
@@ -254,6 +253,14 @@ converse.plugins.add('converse-muc', {
                 }
             },
 
+            onReconnection () {
+                this.save('connection_status', converse.ROOMSTATUS.DISCONNECTED);
+                this.clearMessages();
+                this.registerHandlers();
+                this.fetchMessages();
+                this.join();
+            },
+
             initFeatures () {
                 const storage = _converse.config.get('storage');
                 const id = `converse.muc-features-${_converse.bare_jid}-${this.get('jid')}`;
@@ -1559,22 +1566,6 @@ converse.plugins.add('converse-muc', {
                 }
             });
         });
-
-        function reconnectToChatRooms () {
-            /* Upon a reconnection event from converse, join again
-             * all the open groupchats.
-             */
-            _converse.chatboxes
-                .filter(m => (m.get('type') === _converse.CHATROOMS_TYPE))
-                .forEach(room => {
-                    room.save('connection_status', converse.ROOMSTATUS.DISCONNECTED);
-                    room.clearMessages();
-                    room.registerHandlers();
-                    room.fetchMessages();
-                    room.join();
-                });
-        }
-        _converse.api.listen.on('reconnected', reconnectToChatRooms);
         /************************ END Event Handlers ************************/