plugin XEP-0045: join / MAM history improvements:
- fixed use of history_d deferred so MAM history is stored in database as soon as possible and in right order - get MAM history with pages of 20 messages instead of 100 - if a message can't be parsed, an error message is logged (with a dump of the stanza), and the message is ignored, avoiding a crash and the impossibility the join the room at all - a new `mucRoomPrepareJoin` signal, containing room jid and profile, is sent when a room joining is started, this allow better UX as the frontend can show the room immediately, and lock it with a waiting message until it is fully available. The `mucRoomJoined` is still sent when the room is fully joined/avaiable, meaning that the frontend can unlock it and let the user interact with it
This commit is contained in:
parent
34ca8a6cb3
commit
f065ba4ff6
1 changed files with 73 additions and 25 deletions
|
|
@ -86,24 +86,61 @@ class XEP_0045(object):
|
|||
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='(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("mucNickGet", ".plugin", in_sign='ss', out_sign='s', method=self._getRoomNick)
|
||||
host.bridge.addMethod("mucLeave", ".plugin", in_sign='ss', out_sign='', method=self._leave, async_=True)
|
||||
host.bridge.addMethod("mucOccupantsGet", ".plugin", in_sign='ss', out_sign='a{sa{ss}}', method=self._getRoomOccupants)
|
||||
host.bridge.addMethod("mucSubject", ".plugin", in_sign='sss', out_sign='', method=self._subject)
|
||||
host.bridge.addMethod("mucGetRoomsJoined", ".plugin", in_sign='s', out_sign='a(sa{sa{ss}}ss)', method=self._getRoomsJoined)
|
||||
host.bridge.addMethod("mucGetUniqueRoomName", ".plugin", in_sign='ss', out_sign='s', method=self._getUniqueName)
|
||||
host.bridge.addMethod("mucConfigureRoom", ".plugin", in_sign='ss', out_sign='s', method=self._configureRoom, async_=True)
|
||||
host.bridge.addMethod("mucGetDefaultService", ".plugin", in_sign='', out_sign='s', method=self.getDefaultMUC)
|
||||
host.bridge.addMethod("mucGetService", ".plugin", in_sign='ss', out_sign='s', method=self._getMUCService, async_=True)
|
||||
host.bridge.addSignal("mucRoomJoined", ".plugin", signature='sa{sa{ss}}sss') # args: room_jid, occupants, user_nick, subject, profile
|
||||
host.bridge.addSignal("mucRoomLeft", ".plugin", signature='ss') # args: room_jid, profile
|
||||
host.bridge.addSignal("mucRoomUserChangedNick", ".plugin", signature='ssss') # args: room_jid, old_nick, new_nick, profile
|
||||
host.bridge.addSignal("mucRoomNewSubject", ".plugin", signature='sss') # args: room_jid, subject, profile
|
||||
self.__submit_conf_id = host.registerCallback(self._submitConfiguration, with_data=True)
|
||||
# return same arguments as mucRoomJoined + a boolean set to True is the room was
|
||||
# already joined (first argument)
|
||||
host.bridge.addMethod(
|
||||
"mucJoin", ".plugin", in_sign='ssa{ss}s', out_sign='(bsa{sa{ss}}sss)',
|
||||
method=self._join, async_=True)
|
||||
host.bridge.addMethod(
|
||||
"mucNick", ".plugin", in_sign='sss', out_sign='', method=self._nick)
|
||||
host.bridge.addMethod(
|
||||
"mucNickGet", ".plugin", in_sign='ss', out_sign='s', method=self._getRoomNick)
|
||||
host.bridge.addMethod(
|
||||
"mucLeave", ".plugin", in_sign='ss', out_sign='', method=self._leave,
|
||||
async_=True)
|
||||
host.bridge.addMethod(
|
||||
"mucOccupantsGet", ".plugin", in_sign='ss', out_sign='a{sa{ss}}',
|
||||
method=self._getRoomOccupants)
|
||||
host.bridge.addMethod(
|
||||
"mucSubject", ".plugin", in_sign='sss', out_sign='', method=self._subject)
|
||||
host.bridge.addMethod(
|
||||
"mucGetRoomsJoined", ".plugin", in_sign='s', out_sign='a(sa{sa{ss}}ss)',
|
||||
method=self._getRoomsJoined)
|
||||
host.bridge.addMethod(
|
||||
"mucGetUniqueRoomName", ".plugin", in_sign='ss', out_sign='s',
|
||||
method=self._getUniqueName)
|
||||
host.bridge.addMethod(
|
||||
"mucConfigureRoom", ".plugin", in_sign='ss', out_sign='s',
|
||||
method=self._configureRoom, async_=True)
|
||||
host.bridge.addMethod(
|
||||
"mucGetDefaultService", ".plugin", in_sign='', out_sign='s',
|
||||
method=self.getDefaultMUC)
|
||||
host.bridge.addMethod(
|
||||
"mucGetService", ".plugin", in_sign='ss', out_sign='s',
|
||||
method=self._getMUCService, async_=True)
|
||||
# called when a room will be joined but must be locked until join is received
|
||||
# (room is prepared, history is getting retrieved)
|
||||
# args: room_jid, profile
|
||||
host.bridge.addSignal(
|
||||
"mucRoomPrepareJoin", ".plugin", signature='ss')
|
||||
# args: room_jid, occupants, user_nick, subject, profile
|
||||
host.bridge.addSignal(
|
||||
"mucRoomJoined", ".plugin", signature='sa{sa{ss}}sss')
|
||||
# args: room_jid, profile
|
||||
host.bridge.addSignal(
|
||||
"mucRoomLeft", ".plugin", signature='ss')
|
||||
# args: room_jid, old_nick, new_nick, profile
|
||||
host.bridge.addSignal(
|
||||
"mucRoomUserChangedNick", ".plugin", signature='ssss')
|
||||
# args: room_jid, subject, profile
|
||||
host.bridge.addSignal(
|
||||
"mucRoomNewSubject", ".plugin", signature='sss')
|
||||
self.__submit_conf_id = host.registerCallback(
|
||||
self._submitConfiguration, with_data=True)
|
||||
self._room_join_id = host.registerCallback(self._UIRoomJoinCb, with_data=True)
|
||||
host.importMenu((D_("MUC"), D_("configure")), self._configureRoomMenu, security_limit=0, help_string=D_("Configure Multi-User Chat room"), type_=C.MENU_ROOM)
|
||||
host.importMenu(
|
||||
(D_("MUC"), D_("configure")), self._configureRoomMenu, security_limit=0,
|
||||
help_string=D_("Configure Multi-User Chat room"), type_=C.MENU_ROOM)
|
||||
try:
|
||||
self.text_cmds = self.host.plugins[C.TEXT_CMDS]
|
||||
except KeyError:
|
||||
|
|
@ -487,6 +524,7 @@ class XEP_0045(object):
|
|||
return defer.fail(AlreadyJoined(room))
|
||||
log.info(_("[{profile}] is joining room {room} with nick {nick}").format(
|
||||
profile=client.profile, room=room_jid.userhost(), nick=nick))
|
||||
self.host.bridge.mucRoomPrepareJoin(room_jid.userhost(), client.profile)
|
||||
|
||||
password = options.get("password")
|
||||
|
||||
|
|
@ -911,7 +949,10 @@ class SatMUCClient(muc.MUCClient):
|
|||
# we don't want any history from room as we'll get it with MAM
|
||||
room_jid, nick, muc.HistoryOptions(maxStanzas=0), password=password)
|
||||
room._history_type = HISTORY_MAM
|
||||
room._history_d = defer.Deferred()
|
||||
history_d = room._history_d = defer.Deferred()
|
||||
# we trigger now the deferred so all callback are processed as soon as possible
|
||||
# and in order
|
||||
history_d.callback(None)
|
||||
|
||||
last_mess = yield self.host.memory.historyGet(
|
||||
room_jid,
|
||||
|
|
@ -924,7 +965,7 @@ class SatMUCClient(muc.MUCClient):
|
|||
profile=client.profile)
|
||||
if last_mess:
|
||||
stanza_id = last_mess[0][-1]['stanza_id']
|
||||
rsm_req = rsm.RSMRequest(max_=100, after=stanza_id)
|
||||
rsm_req = rsm.RSMRequest(max_=20, after=stanza_id)
|
||||
no_loop=False
|
||||
else:
|
||||
log.info("We have no MAM archive for room {room_jid}.".format(
|
||||
|
|
@ -961,7 +1002,14 @@ class SatMUCClient(muc.MUCClient):
|
|||
'Forwarded message element has a "to" attribute while it is '
|
||||
'forbidden by specifications')
|
||||
fwd_message_elt["to"] = client.jid.full()
|
||||
mess_data = client.messageProt.parseMessage(fwd_message_elt)
|
||||
try:
|
||||
mess_data = client.messageProt.parseMessage(fwd_message_elt)
|
||||
except Exception as e:
|
||||
log.error(
|
||||
f"Can't parse message, ignoring it: {e}\n"
|
||||
f"{fwd_message_elt.toXml()}"
|
||||
)
|
||||
continue
|
||||
# we attache parsed message data to element, to avoid parsing
|
||||
# again in _addToHistory
|
||||
fwd_message_elt._mess_data = mess_data
|
||||
|
|
@ -981,11 +1029,11 @@ class SatMUCClient(muc.MUCClient):
|
|||
# the order is different (we have to join then get MAM archive, so subject
|
||||
# is received before archive), so we change state and add the callbacks here.
|
||||
self.changeRoomState(room, ROOM_STATE_LIVE)
|
||||
room._history_d.addCallbacks(self._historyCb, self._historyEb, [room],
|
||||
history_d.addCallbacks(self._historyCb, self._historyEb, [room],
|
||||
errbackArgs=[room])
|
||||
|
||||
# callback is done now that all needed Deferred have been added to _history_d
|
||||
room._history_d.callback(None)
|
||||
# we wait for all callbacks to be processed
|
||||
yield history_d
|
||||
|
||||
defer.returnValue(room)
|
||||
|
||||
|
|
@ -1243,8 +1291,8 @@ class SatMUCClient(muc.MUCClient):
|
|||
There are a few event methods that may get called here.
|
||||
L{receivedGroupChat}, L{receivedSubject} or L{receivedHistory}.
|
||||
"""
|
||||
# We override this method to fix subject handling
|
||||
# FIXME: remove this merge fixed upstream
|
||||
# We override this method to fix subject handling (empty strings were discarded)
|
||||
# FIXME: remove this once fixed upstream
|
||||
room, user = self._getRoomUser(message)
|
||||
|
||||
if room is None:
|
||||
|
|
|
|||
Loading…
Reference in a new issue