comparison sat/plugins/plugin_xep_0313.py @ 2713:19000c506d0c

plugin XEP-0313: improvments to prepare MUC MAM: - discard groupchat message when retrieving last stanza_id on connection - service can be specified in getMessageFromResult - service is also used when using getArchives from bridge
author Goffi <goffi@goffi.org>
date Fri, 07 Dec 2018 17:43:43 +0100
parents 2ea2369ae7de
children bb6adaa580ee
comparison
equal deleted inserted replaced
2712:c3f59c1dcb0a 2713:19000c506d0c
69 async=True) 69 async=True)
70 70
71 @defer.inlineCallbacks 71 @defer.inlineCallbacks
72 def profileConnected(self, client): 72 def profileConnected(self, client):
73 last_mess = yield self.host.memory.historyGet( 73 last_mess = yield self.host.memory.historyGet(
74 None, None, limit=1, filters={u'last_stanza_id': True}, 74 None, None, limit=1, filters={u'not_types': C.MESS_TYPE_GROUPCHAT,
75 u'last_stanza_id': True},
75 profile=client.profile) 76 profile=client.profile)
76 if not last_mess: 77 if not last_mess:
77 log.info(_(u"It seems that we have no MAM history yet")) 78 log.info(_(u"It seems that we have no MAM history yet"))
78 return 79 return
79 stanza_id = last_mess[0][-1][u'stanza_id'] 80 stanza_id = last_mess[0][-1][u'stanza_id']
80 # XXX: test
81 # stanza_id = "IIheJOfiIhkPYkw6"
82 rsm_req = rsm.RSMRequest(after=stanza_id) 81 rsm_req = rsm.RSMRequest(after=stanza_id)
83 mam_req = mam.MAMRequest(rsm_=rsm_req) 82 mam_req = mam.MAMRequest(rsm_=rsm_req)
84 mam_data = yield self.getArchives(client, mam_req, 83 mam_data = yield self.getArchives(client, mam_req,
85 service=client.jid.userhostJID()) 84 service=client.jid.userhostJID())
86 elt_list, rsm_response = mam_data 85 elt_list, rsm_response = mam_data
87 if not elt_list: 86 if not elt_list:
88 log.info(_(u"We have received no message while offline")) 87 log.info(_(u"We have received no message while offline"))
89 return 88 return
90 else: 89 else:
152 if form_args: 151 if form_args:
153 mam_args["form"] = mam.buildForm(**form_args) 152 mam_args["form"] = mam.buildForm(**form_args)
154 153
155 return mam.MAMRequest(**mam_args) if mam_args else None 154 return mam.MAMRequest(**mam_args) if mam_args else None
156 155
157 def getMessageFromResult(self, client, mess_elt, mam_req): 156 def getMessageFromResult(self, client, mess_elt, mam_req, service=None):
158 """Extract usable <message/> from MAM query result 157 """Extract usable <message/> from MAM query result
159 158
160 The message will be validated, and stanza-id/delay will be added if necessary. 159 The message will be validated, and stanza-id/delay will be added if necessary.
161 @param mess_elt(domish.Element): result <message/> element wrapping the message 160 @param mess_elt(domish.Element): result <message/> element wrapping the message
162 to retrieve 161 to retrieve
163 @param mam_req(mam.MAMRequest): request used 162 @param mam_req(mam.MAMRequest): request used
163 @param service(jid.JID, None): MAM service where the request has been sent
164 None if it's user server
164 @return (domish.Element): <message/> that can be used directly with onMessage 165 @return (domish.Element): <message/> that can be used directly with onMessage
165 """ 166 """
166 if mess_elt.name != u"message": 167 if mess_elt.name != u"message":
167 log.warning(u"unexpected stanza in archive: {xml}".format( 168 log.warning(u"unexpected stanza in archive: {xml}".format(
168 xml=mess_elt.toXml())) 169 xml=mess_elt.toXml()))
169 raise exceptions.DataError(u"Invalid element") 170 raise exceptions.DataError(u"Invalid element")
171 service_jid = client.jid.userhostJID() if service is None else service
170 mess_from = mess_elt[u"from"] 172 mess_from = mess_elt[u"from"]
171 if mess_from != client.jid.host and mess_from != client.jid.userhost(): 173 # we check that the message has been sent by the right service
174 # if service is None (i.e. message expected from our own server)
175 # from can be server jid or user's bare jid
176 if (mess_from != service_jid.full()
177 and not (service is None and mess_from == client.jid.host)):
172 log.error(u"Message is not from our server, something went wrong: " 178 log.error(u"Message is not from our server, something went wrong: "
173 u"{xml}".format(xml=mess_elt.toXml())) 179 u"{xml}".format(xml=mess_elt.toXml()))
174 raise exceptions.DataError(u"Invalid element") 180 raise exceptions.DataError(u"Invalid element")
175 try: 181 try:
176 result_elt = next(mess_elt.elements(mam.NS_MAM, u"result")) 182 result_elt = next(mess_elt.elements(mam.NS_MAM, u"result"))
189 if not result_elt[u"queryid"] == mam_req.query_id: 195 if not result_elt[u"queryid"] == mam_req.query_id:
190 log.error(u"Unexpected query id (was expecting {query_id}): {xml}" 196 log.error(u"Unexpected query id (was expecting {query_id}): {xml}"
191 .format(query_id=mam.query_id, xml=mess_elt.toXml())) 197 .format(query_id=mam.query_id, xml=mess_elt.toXml()))
192 raise exceptions.DataError(u"Invalid element") 198 raise exceptions.DataError(u"Invalid element")
193 stanza_id = self._sid.getStanzaId(fwd_message_elt, 199 stanza_id = self._sid.getStanzaId(fwd_message_elt,
194 client.jid.userhostJID()) 200 service_jid)
195 if stanza_id is None: 201 if stanza_id is None:
196 # not stanza-id element is present, we add one so message 202 # not stanza-id element is present, we add one so message
197 # will be archived with it, and we won't request several times 203 # will be archived with it, and we won't request several times
198 # the same MAM achive 204 # the same MAM achive
199 try: 205 try:
200 stanza_id = result_elt[u"id"] 206 stanza_id = result_elt[u"id"]
201 except AttributeError: 207 except AttributeError:
202 log.warning(u'Invalid MAM result: missing "id" attribute: {xml}' 208 log.warning(u'Invalid MAM result: missing "id" attribute: {xml}'
203 .format(xml=result_elt.toXml())) 209 .format(xml=result_elt.toXml()))
204 raise exceptions.DataError(u"Invalid element") 210 raise exceptions.DataError(u"Invalid element")
205 self._sid.addStanzaId(client, fwd_message_elt, stanza_id) 211 self._sid.addStanzaId(client, fwd_message_elt, stanza_id, by=service_jid)
206 212
207 if delay_elt is not None: 213 if delay_elt is not None:
208 fwd_message_elt.addChild(delay_elt) 214 fwd_message_elt.addChild(delay_elt)
209 215
210 return fwd_message_elt 216 return fwd_message_elt
245 except rsm.RSMNotFoundError: 251 except rsm.RSMNotFoundError:
246 rsm_response = None 252 rsm_response = None
247 253
248 return (elt_list, rsm_response) 254 return (elt_list, rsm_response)
249 255
250 def serializeArchiveResult(self, data, client, mam_req): 256 def serializeArchiveResult(self, data, client, mam_req, service):
251 elt_list, rsm_response = data 257 elt_list, rsm_response = data
252 mess_list = [] 258 mess_list = []
253 for elt in elt_list: 259 for elt in elt_list:
254 fwd_message_elt = self.getMessageFromResult(client, elt, mam_req) 260 fwd_message_elt = self.getMessageFromResult(client, elt, mam_req,
261 service=service)
255 mess_data = client.messageProt.parseMessage(fwd_message_elt) 262 mess_data = client.messageProt.parseMessage(fwd_message_elt)
256 mess_list.append(client.messageGetBridgeArgs(mess_data)) 263 mess_list.append(client.messageGetBridgeArgs(mess_data))
257 return mess_list, client.profile 264 return mess_list, client.profile
258 265
259 def _getArchives(self, service, extra_ser, profile_key): 266 def _getArchives(self, service, extra_ser, profile_key):
261 service = jid.JID(service) if service else None 268 service = jid.JID(service) if service else None
262 extra = data_format.deserialise(extra_ser, {}) 269 extra = data_format.deserialise(extra_ser, {})
263 mam_req = self.parseExtra(extra) 270 mam_req = self.parseExtra(extra)
264 271
265 d = self.getArchives(client, mam_req, service=service) 272 d = self.getArchives(client, mam_req, service=service)
266 d.addCallback(self.serializeArchiveResult, client, mam_req) 273 d.addCallback(self.serializeArchiveResult, client, mam_req, service)
267 return d 274 return d
268 275
269 def getArchives(self, client, query, service=None, message_cb=None): 276 def getArchives(self, client, query, service=None, message_cb=None):
270 """Query archive then grab and return them all in the result 277 """Query archive then grab and return them all in the result
271 278