changeset 3008:c8c68a3b0a79

plugins XEP-0045, XEP-0198: rejoin MUC rooms while a hot reconnection is done: when resuming is not possible with stream management, a hot reconnection is done (reconnecting without restarting every plugin). This was causing trouble for joined MUC rooms, which were not accessible anymore (because they were not re-joined). This patch fixes it by clearing rooms first (to avoid considering the room joined and broadcasting the initial presence to them), then re-joining them. fix 322
author Goffi <goffi@goffi.org>
date Tue, 16 Jul 2019 21:59:30 +0200
parents 420897488080
children bba1c51bf2c6
files sat/plugins/plugin_xep_0045.py sat/plugins/plugin_xep_0198.py
diffstat 2 files changed, 31 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/sat/plugins/plugin_xep_0045.py	Mon Jul 15 22:36:28 2019 +0200
+++ b/sat/plugins/plugin_xep_0045.py	Tue Jul 16 21:59:30 2019 +0200
@@ -496,6 +496,19 @@
                        errbackArgs=(client, room_jid, nick, password))
         return d
 
+    def popRooms(self, client):
+        """Remove rooms and return data needed to re-join them
+
+        This methods is to be called before a hot reconnection
+        @return (list[(jid.JID, unicode)]): arguments needed to re-join the rooms
+            This list can be used directly (unpacked) with self.join
+        """
+        args_list = []
+        for room in client._muc_client.joined_rooms.values():
+            client._muc_client._removeRoom(room.roomJID)
+            args_list.append((client, room.roomJID, room.nick))
+        return args_list
+
     def _nick(self, room_jid_s, nick, profile_key=C.PROF_KEY_NONE):
         client = self.host.getClient(profile_key)
         return self.nick(client, jid.JID(room_jid_s), nick)
@@ -785,7 +798,8 @@
             whois_msg.append(_("Show: %s") % user.show)
 
     def presenceTrigger(self, presence_elt, client):
-        # XXX: shouldn't it be done by the server ?!!
+        # FIXME: should we add a privacy parameters in settings to activate before
+        #        broadcasting the presence to all MUC rooms ?
         muc_client = client._muc_client
         for room_jid, room in muc_client.joined_rooms.iteritems():
             elt = xml_tools.elementCopy(presence_elt)
--- a/sat/plugins/plugin_xep_0198.py	Mon Jul 15 22:36:28 2019 +0200
+++ b/sat/plugins/plugin_xep_0198.py	Tue Jul 16 21:59:30 2019 +0200
@@ -35,14 +35,15 @@
 log = getLogger(__name__)
 
 PLUGIN_INFO = {
-    C.PI_NAME: "Stream Management",
-    C.PI_IMPORT_NAME: "XEP-0198",
-    C.PI_TYPE: "XEP",
+    C.PI_NAME: u"Stream Management",
+    C.PI_IMPORT_NAME: u"XEP-0198",
+    C.PI_TYPE: u"XEP",
     C.PI_MODES: C.PLUG_MODE_BOTH,
-    C.PI_PROTOCOLS: ["XEP-0198"],
+    C.PI_PROTOCOLS: [u"XEP-0198"],
     C.PI_DEPENDENCIES: [],
-    C.PI_MAIN: "XEP_0198",
-    C.PI_HANDLER: "yes",
+    C.PI_RECOMMENDATIONS: [u"XEP-0045"],
+    C.PI_MAIN: u"XEP_0198",
+    C.PI_HANDLER: u"yes",
     C.PI_DESCRIPTION: _(u"""Implementation of Stream Management"""),
 }
 
@@ -394,6 +395,10 @@
                 client.conn_deferred = defer.Deferred()
             else:
                 log.error(u"conn_deferred should be called at this point")
+            plg_0045 = self.host.plugins.get(u'XEP-0045')
+            if plg_0045 is not None:
+                # we have to remove joined rooms
+                muc_join_args = plg_0045.popRooms(client)
             # we need to recreate roster
             client.handlers.remove(client.roster)
             client.roster = client.roster.__class__(self.host)
@@ -412,6 +417,10 @@
             d.addCallback(lambda __: client.roster.got_roster)
             # initial presence must be sent manually
             d.addCallback(lambda __: client.presence.available())
+            if plg_0045 is not None:
+                muc_d_list = defer.DeferredList(
+                    [plg_0045.join(*args) for args in muc_join_args])
+                d.addCallback(lambda __: muc_d_list)
 
     def onReceive(self, element, client):
         if not client.is_component:
@@ -437,7 +446,7 @@
         session.ack_requested = False
         if self._ack_timeout:
             if session.req_timer is None:
-                log.error("reg_timer should be set")
+                log.error("req_timer should be set")
             else:
                 session.req_timer.cancel()
                 session.req_timer = None