Mercurial > libervia-backend
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 |