changeset 2066:09c18fcd8225

plugin XEP-0045, quick frontend (app,chat): various chat improvments: - (XEP-0045): join defered is now fired when room is full joined and history is available - (XEP-0045): mucJOIN signature has changed, it now returns the same arguments as mucRoomJoined and a boolean which is True if the room was alread joined - quick frontend (app, chat): adapted code to new changes
author Goffi <goffi@goffi.org>
date Fri, 09 Sep 2016 23:54:33 +0200 (2016-09-09)
parents f3167c873e7b
children 7834743705f0
files frontends/src/quick_frontend/quick_app.py frontends/src/quick_frontend/quick_chat.py src/plugins/plugin_xep_0045.py
diffstat 3 files changed, 47 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/frontends/src/quick_frontend/quick_app.py	Fri Sep 09 23:54:33 2016 +0200
+++ b/frontends/src/quick_frontend/quick_app.py	Fri Sep 09 23:54:33 2016 +0200
@@ -526,8 +526,7 @@
         """Called when a MUC room is joined"""
         log.debug(u"Room [{room_jid}] joined by {profile}, users presents:{users}".format(room_jid=room_jid_s, profile=profile, users=occupants.keys()))
         room_jid = jid.JID(room_jid_s)
-        chat_widget = self.widgets.getOrCreateWidget(quick_chat.QuickChat, room_jid, type_=C.CHAT_GROUP, occupants=occupants, subject=subject, profile=profile)
-        chat_widget.setUserNick(unicode(user_nick))
+        self.widgets.getOrCreateWidget(quick_chat.QuickChat, room_jid, type_=C.CHAT_GROUP, nick=user_nick, occupants=occupants, subject=subject, profile=profile)
         self.contact_lists[profile].setSpecial(room_jid, C.CONTACT_SPECIAL_GROUP)
         # chat_widget.update()
 
--- a/frontends/src/quick_frontend/quick_chat.py	Fri Sep 09 23:54:33 2016 +0200
+++ b/frontends/src/quick_frontend/quick_chat.py	Fri Sep 09 23:54:33 2016 +0200
@@ -218,10 +218,9 @@
 
 
 class QuickChat(quick_widgets.QuickWidget):
-
     visible_states = ['chat_state']  # FIXME: to be removed, used only in quick_games
 
-    def __init__(self, host, target, type_=C.CHAT_ONE2ONE, occupants=None, subject=None, profiles=None):
+    def __init__(self, host, target, type_=C.CHAT_ONE2ONE, nick=None, occupants=None, subject=None, profiles=None):
         """
         @param type_: can be C.CHAT_ONE2ONE for single conversation or C.CHAT_GROUP for chat à la IRC
         """
@@ -236,12 +235,15 @@
         if type_ == C.CHAT_GROUP:
             if target.resource:
                 raise exceptions.InternalError(u"a group chat entity can't have a resource")
-            self.nick = None
+            if nick is None:
+                raise exceptions.InternalError(u"nick must not be None for group chat")
+
+            self.nick = nick
             self.occupants = {}
             self.setOccupants(occupants)
         else:
-            if occupants is not None:
-                raise exceptions.InternalError(u"only group chat can have occupants")
+            if occupants is not None or nick is not None:
+                raise exceptions.InternalError(u"only group chat can have occupants or nick")
         self.messages = OrderedDict()  # key: uid, value: Message instance
         self.games = {}  # key=game name (unicode), value=instance of quick_games.RoomGame
         self.subject = subject
@@ -290,6 +292,10 @@
         if self.type == C.CHAT_GROUP:
             kwargs['occupants'] = {o.nick: o.data for o in self.occupants.itervalues()}
         kwargs['subject'] = self.subject
+        try:
+            kwargs['nick'] = self.nick
+        except AttributeError:
+            pass
 
     def onPrivateCreated(self, widget):
         """Method called when a new widget for private conversation (MUC) is created"""
--- a/src/plugins/plugin_xep_0045.py	Fri Sep 09 23:54:33 2016 +0200
+++ b/src/plugins/plugin_xep_0045.py	Fri Sep 09 23:54:33 2016 +0200
@@ -64,6 +64,13 @@
 default_conf = {"default_muc": u'sat@chat.jabberfr.org'}
 
 
+class AlreadyJoined(exceptions.ConflictError):
+
+    def __init__(self, room):
+        super(AlreadyJoined, self).__init__()
+        self.room = room
+
+
 class XEP_0045(object):
     # TODO: handle invitations
 
@@ -71,7 +78,7 @@
         log.info(_("Plugin XEP_0045 initialization"))
         self.host = host
         self._sessions = memory.Sessions()
-        host.bridge.addMethod("mucJoin", ".plugin", in_sign='ssa{ss}s', out_sign='s', method=self._join, async=True)
+        host.bridge.addMethod("mucJoin", ".plugin", in_sign='ssa{ss}s', out_sign='(bsa{sa{ss}}sss)', method=self._join, async=True)  # return same arguments as mucRoomJoined + a boolean set to True is the room was already joined (first argument)
         host.bridge.addMethod("mucNick", ".plugin", in_sign='sss', out_sign='', method=self._nick)
         host.bridge.addMethod("mucLeave", ".plugin", in_sign='ss', out_sign='', method=self._leave, async=True)
         host.bridge.addMethod("mucSubject", ".plugin", in_sign='sss', out_sign='', method=self._subject)
@@ -140,6 +147,15 @@
         else:
             return True
 
+    def _getRoomJoinedArgs(self, room, profile):
+        return [
+            room.roomJID.userhost(),
+            XEP_0045._getOccupants(room),
+            room.nick,
+            room.subject,
+            profile
+            ]
+
     def _UIRoomJoinCb(self, data, profile):
         room_jid = jid.JID(data['index'])
         client = self.host.getClient(profile)
@@ -173,7 +189,7 @@
             log.debug(_(u"room locked !"))
             d = client._muc_client.configure(room.roomJID, {})
             d.addErrback(lambda dummy: log.error(_(u'Error while configuring the room')))
-        return room
+        return room.fully_joined
 
     def _joinEb(self, failure, client, room_jid, nick, password):
         """Called when something is going wrong when joining the room"""
@@ -389,6 +405,11 @@
         """
         return self.host.memory.getConfig(CONFIG_SECTION, 'default_muc', default_conf['default_muc'])
 
+    def _join_eb(self, failure_, client):
+        failure_.trap(AlreadyJoined)
+        room = failure_.value.room
+        return [True] + self._getRoomJoinedArgs(room, client.profile)
+
     def _join(self, room_jid_s, nick, options, profile_key=C.PROF_KEY_NONE):
         """join method used by bridge
 
@@ -407,7 +428,9 @@
             room_jid = self.getUniqueName(profile_key=client.profile)
         # TODO: error management + signal in bridge
         d = self.join(client, room_jid, nick, options or None)
-        return d.addCallback(lambda room: room.roomJID.userhost())
+        d.addCallback(lambda room: [False] + self._getRoomJoinedArgs(room, client.profile))
+        d.addErrback(self._join_eb, client)
+        return d
 
     def join(self, client, room_jid, nick=None, options=None):
         if not nick:
@@ -420,8 +443,9 @@
             return d
 
         if room_jid in client._muc_client.joined_rooms:
+            room = client._muc_client.joined_rooms[room_jid]
             log.warning(_(u'{profile} is already in room {room_jid}').format(profile=client.profile, room_jid = room_jid.userhost()))
-            raise failure.Failure(exceptions.ConflictError(_(u"The room has already been joined")))
+            return defer.fail(AlreadyJoined(room))
         log.info(_(u"[{profile}] is joining room {room} with nick {nick}").format(profile=client.profile, room=room_jid.userhost(), nick=nick))
 
         password = options["password"] if "password" in options else None
@@ -745,11 +769,13 @@
 
     def _addRoom(self, room):
         super(SatMUCClient, self)._addRoom(room)
-        room._roster_ok = False
+        room._roster_ok = False  # True when occupants list has been fully received
         room._room_ok = None  # False when roster, history and subject are available
                               # True when new messages are saved to database
-        room._history_d = defer.Deferred()  # use to send bridge signal once backlog are written in history
+        room._history_d = defer.Deferred()  # used to send bridge signal once backlog are written in history
         room._history_d.callback(None)
+        # FIXME: check if history_d is not redundant with fully_joined
+        room.fully_joined = defer.Deferred()  # called when everything is OK
         room._cache = []
 
     def _gotLastDbHistory(self, mess_data_list, room_jid, nick, password):
@@ -978,12 +1004,8 @@
         return muc.MUCClientProtocol.subject(self, room, subject)
 
     def _historyCb(self, dummy, room):
-        self.host.bridge.mucRoomJoined(
-            room.roomJID.userhost(),
-            XEP_0045._getOccupants(room),
-            room.nick,
-            room.subject,
-            self.parent.profile)
+        args = self.plugin_parent._getRoomJoinedArgs(room, self.parent.profile)
+        self.host.bridge.mucRoomJoined(*args)
         del room._history_d
         cache = room._cache
         del room._cache
@@ -991,7 +1013,6 @@
         for elem in cache:
             self.parent.xmlstream.dispatch(elem)
 
-
     def _historyEb(self, failure_, room):
         log.error(u"Error while managing history: {}".format(failure_))
         self._historyCb(None, room)
@@ -1006,6 +1027,7 @@
             # that mean that we have received everything we need
             room._room_ok = False
             room._history_d.addCallbacks(self._historyCb, self._historyEb, [room], errbackArgs=[room])
+            room.fully_joined.callback(room)
         else:
             # the subject has been changed
             log.debug(_(u"New subject for room ({room_id}): {subject}").format(room_id = room.roomJID.full(), subject = subject))