Bladeren bron

muc: avoid sending duplicate `unavailable` presences

Only unregister muc nickname and trigger the `leaveRoom` event if the user explicitly left the MUC.
JC Brand 2 maanden geleden
bovenliggende
commit
8cb3d058c4

+ 4 - 3
src/headless/plugins/bookmarks/api.js

@@ -15,12 +15,13 @@ const bookmarks = {
      *
      * @method api.bookmarks.set
      * @param {import('./types').BookmarkAttrs} attrs - The room attributes
-     * @param {boolean} create=true - Whether the bookmark should be created if it doesn't exist
+     * @param {boolean} [create=true] - Whether the bookmark should be created if it doesn't exist
+     * @param {object} [options] - Skeletor set/add options
      * @returns {Promise<import('./model').default>}
      */
-    async set(attrs, create = true) {
+    async set(attrs, create = true, options = {}) {
         const bookmarks = await waitUntil('bookmarksInitialized');
-        return bookmarks.setBookmark(attrs, create);
+        return bookmarks.setBookmark(attrs, create, options);
     },
 
     /**

+ 5 - 3
src/headless/plugins/bookmarks/collection.js

@@ -99,8 +99,10 @@ class Bookmarks extends Collection {
 
     /**
      * @param {import('./types').BookmarkAttrs} attrs
+     * @param {boolean} [create=true]
+     * @param {object} [options]
      */
-    setBookmark(attrs, create = true) {
+    setBookmark(attrs, create = true, options = {}) {
         if (!attrs.jid) return log.warn('No JID provided for setBookmark');
 
         let send_stanza = false;
@@ -112,11 +114,11 @@ class Bookmarks extends Collection {
                 return result || (attrs[k] ?? '') !== (bookmark.attributes[k] ?? '');
             }, false);
             if (has_changed) {
-                bookmark.save(attrs);
+                bookmark.save(attrs, options);
                 send_stanza = true;
             }
         } else if (create) {
-            bookmark = this.create(attrs);
+            bookmark = this.create(attrs, options);
             send_stanza = true;
         }
         if (send_stanza) {

+ 10 - 2
src/headless/plugins/bookmarks/plugin.js

@@ -9,7 +9,7 @@ import api from '../../shared/api/index.js';
 import converse from '../../shared/api/public.js';
 import { initBookmarks, getNicknameFromBookmark, handleBookmarksPush } from './utils.js';
 import '../../plugins/muc/index.js';
-import log from "@converse/log";
+import log from '@converse/log';
 import bookmarks_api from './api.js';
 
 const { Strophe } = converse.env;
@@ -104,7 +104,15 @@ converse.plugins.add('converse-bookmarks', {
                         jid,
                         autojoin: false,
                     },
-                    false
+                    false,
+                    // Don't trigger a Skeletor `change` event.
+                    // This MUC is being left explicitly by the user,
+                    // so we don't want to trigger the `onAutoJoinChanged`
+                    // listener in ./collection.js to again call `close()`
+                    // on the MUC.
+                    {
+                        silent: true,
+                    }
                 );
             }
         );

+ 20 - 14
src/headless/plugins/muc/muc.js

@@ -945,19 +945,15 @@ class MUC extends ModelWithVCard(ModelWithMessages(ColorAwareModel(ChatBoxBase))
     }
 
     /**
-     * Leave the groupchat.
+     * Leave the groupchat by sending an unavailable presence stanza, and then
+     * tear down the features and disco collections so that they'll be
+     * recreated if/when we rejoin.
      * @param {string} [exit_msg] - Message to indicate your reason for leaving
      */
     async leave(exit_msg) {
-        /**
-         * Triggered when the user leaves a MUC
-         * @event _converse#leaveRoom
-         * @type {MUC}
-         * @example _converse.api.listen.on('leaveRoom', model => { ... });
-         */
-        api.trigger("leaveRoom", this);
+        api.user.presence.send("unavailable", this.getRoomJIDAndNick(), exit_msg);
 
-        api.connection.connected() && api.user.presence.send("unavailable", this.getRoomJIDAndNick(), exit_msg);
+        safeSave(this.session, { connection_status: ROOMSTATUS.DISCONNECTED });
 
         // Delete the features model
         if (this.features) {
@@ -984,7 +980,6 @@ class MUC extends ModelWithVCard(ModelWithMessages(ColorAwareModel(ChatBoxBase))
                 })
             );
         }
-        safeSave(this.session, { "connection_status": ROOMSTATUS.DISCONNECTED });
     }
 
     /**
@@ -996,14 +991,25 @@ class MUC extends ModelWithVCard(ModelWithMessages(ColorAwareModel(ChatBoxBase))
         const { ENTERED, CLOSING } = ROOMSTATUS;
         const was_entered = this.session.get("connection_status") === ENTERED;
 
-        safeSave(this.session, { "connection_status": CLOSING });
+        safeSave(this.session, { connection_status: CLOSING });
         was_entered && this.sendMarkerForLastMessage("received", true);
-        await this.unregisterNickname();
         await this.leave();
 
         this.occupants.clearStore();
-        if (ev?.name !== "closeAllChatBoxes" && api.settings.get("muc_clear_messages_on_leave")) {
-            this.clearMessages();
+
+        const is_closed_by_user = ev?.name !== "closeAllChatBoxes";
+        if (is_closed_by_user) {
+            await this.unregisterNickname();
+            if (api.settings.get("muc_clear_messages_on_leave")) {
+                this.clearMessages();
+            }
+            /**
+             * Triggered when the user leaves a MUC
+             * @event _converse#leaveRoom
+             * @type {MUC}
+             * @example _converse.api.listen.on('leaveRoom', model => { ... });
+             */
+            api.trigger("leaveRoom", this);
         }
 
         // Delete the session model

+ 3 - 2
src/headless/types/plugins/bookmarks/api.d.ts

@@ -9,10 +9,11 @@ declare namespace bookmarks {
      *
      * @method api.bookmarks.set
      * @param {import('./types').BookmarkAttrs} attrs - The room attributes
-     * @param {boolean} create=true - Whether the bookmark should be created if it doesn't exist
+     * @param {boolean} [create=true] - Whether the bookmark should be created if it doesn't exist
+     * @param {object} [options] - Skeletor set/add options
      * @returns {Promise<import('./model').default>}
      */
-    function set(attrs: import("./types").BookmarkAttrs, create?: boolean): Promise<import("./model").default>;
+    function set(attrs: import("./types").BookmarkAttrs, create?: boolean, options?: object): Promise<import("./model").default>;
     /**
      * @method api.bookmarks.get
      * @param {string} jid - The JID of the bookmark to return.

+ 7 - 3
src/headless/types/plugins/bookmarks/collection.d.ts

@@ -20,17 +20,21 @@ declare class Bookmarks extends Collection {
     };
     /**
      * @param {import('./types').BookmarkAttrs} attrs
+     * @param {boolean} [create=true]
+     * @param {object} [options]
      */
-    setBookmark(attrs: import("./types").BookmarkAttrs, create?: boolean): void;
+    setBookmark(attrs: import("./types").BookmarkAttrs, create?: boolean, options?: object): void;
     /**
      * @param {'urn:xmpp:bookmarks:1'|'storage:bookmarks'} node
+     * @param {Bookmark} bookmark
      * @returns {Stanza|Stanza[]}
      */
-    getPublishedItems(node: "urn:xmpp:bookmarks:1" | "storage:bookmarks"): Stanza | Stanza[];
+    getPublishedItems(node: "urn:xmpp:bookmarks:1" | "storage:bookmarks", bookmark: Bookmark): Stanza | Stanza[];
     /**
+     * @param {Bookmark} bookmark
      * @returns {Promise<void|Element>}
      */
-    sendBookmarkStanza(): Promise<void | Element>;
+    sendBookmarkStanza(bookmark: Bookmark): Promise<void | Element>;
     /**
      * @param {Element} iq
      * @param {import('./types').BookmarkAttrs} attrs

+ 3 - 1
src/headless/types/plugins/muc/muc.d.ts

@@ -468,7 +468,9 @@ declare class MUC extends MUC_base {
      */
     sendDestroyIQ(reason?: string, new_jid?: string): any;
     /**
-     * Leave the groupchat.
+     * Leave the groupchat by sending an unavailable presence stanza, and then
+     * tear down the features and disco collections so that they'll be
+     * recreated if/when we rejoin.
      * @param {string} [exit_msg] - Message to indicate your reason for leaving
      */
     leave(exit_msg?: string): Promise<void>;

+ 1 - 1
src/plugins/roomslist/templates/roomslist.js

@@ -61,7 +61,7 @@ function tplRoomItem (el, room) {
                 data-room-jid="${room.get('jid')}"
                 data-room-name="${room.getDisplayName()}"
                 title="${i18n_leave_room}"
-                @click=${ev => el.closeRoom(ev)}>
+                @click=${(ev) => el.closeRoom(ev)}>
                 <converse-icon
                     class="fa fa-sign-out-alt"
                     size="1.2em"