Mercurial > libervia-backend
comparison libervia/backend/plugins/plugin_xep_0313.py @ 4154:85f5e6225aa1
plugin XEP-0313: better error logging + store last stanza ID when retrieving archives + small improvments
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 22 Nov 2023 14:56:14 +0100 |
parents | 4b842c1fb686 |
children | 1c30d574df2b |
comparison
equal
deleted
inserted
replaced
4153:9162d3480b9e | 4154:85f5e6225aa1 |
---|---|
16 # GNU Affero General Public License for more details. | 16 # GNU Affero General Public License for more details. |
17 | 17 |
18 # You should have received a copy of the GNU Affero General Public License | 18 # You should have received a copy of the GNU Affero General Public License |
19 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 19 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
20 | 20 |
21 from datetime import datetime | |
22 import uuid | |
23 | |
24 from dateutil import tz | |
25 from twisted.internet import defer | |
26 from twisted.words.protocols.jabber import jid | |
27 from twisted.words.protocols.jabber.error import StanzaError | |
28 from wokkel import disco | |
29 from wokkel import data_form | |
30 from wokkel import rsm | |
31 from wokkel import mam | |
32 from zope.interface import implementer | |
33 | |
34 from libervia.backend.core import exceptions | |
21 from libervia.backend.core.constants import Const as C | 35 from libervia.backend.core.constants import Const as C |
22 from libervia.backend.core.i18n import _ | 36 from libervia.backend.core.i18n import _ |
23 from libervia.backend.core.log import getLogger | 37 from libervia.backend.core.log import getLogger |
24 from libervia.backend.core import exceptions | 38 from libervia.backend.tools import xml_tools |
25 from libervia.backend.tools.common import data_format | 39 from libervia.backend.tools.common import data_format |
26 from twisted.words.protocols.jabber import jid | |
27 from twisted.internet import defer | |
28 from zope.interface import implementer | |
29 from datetime import datetime | |
30 from dateutil import tz | |
31 from wokkel import disco | |
32 from wokkel import data_form | |
33 import uuid | |
34 | |
35 # XXX: mam and rsm come from sat_tmp.wokkel | |
36 from wokkel import rsm | |
37 from wokkel import mam | |
38 | 40 |
39 | 41 |
40 log = getLogger(__name__) | 42 log = getLogger(__name__) |
41 | 43 |
42 PLUGIN_INFO = { | 44 PLUGIN_INFO = { |
97 rsm_req = rsm.RSMRequest(max_=100, after=stanza_id) | 99 rsm_req = rsm.RSMRequest(max_=100, after=stanza_id) |
98 mam_req = mam.MAMRequest(rsm_=rsm_req) | 100 mam_req = mam.MAMRequest(rsm_=rsm_req) |
99 complete = False | 101 complete = False |
100 count = 0 | 102 count = 0 |
101 while not complete: | 103 while not complete: |
102 mam_data = await self.get_archives(client, mam_req, | 104 try: |
103 service=client.jid.userhostJID()) | 105 mam_data = await self.get_archives(client, mam_req, |
106 service=client.jid.userhostJID()) | |
107 except StanzaError as e: | |
108 log.warning( | |
109 f"Can't retrieve MAM archives: {e}\n" | |
110 f"{xml_tools.pp_elt(mam_req.toElement())}\n" | |
111 f"{xml_tools.pp_elt(e.stanza)}" | |
112 ) | |
113 return | |
114 except Exception as e: | |
115 log.exception( | |
116 f"Can't retrieve retrieve MAM archive" | |
117 ) | |
118 return | |
104 elt_list, rsm_response, mam_response = mam_data | 119 elt_list, rsm_response, mam_response = mam_data |
105 complete = mam_response["complete"] | 120 complete = mam_response["complete"] |
106 # we update MAM request for next iteration | 121 # we update MAM request for next iteration |
107 mam_req.rsm.after = rsm_response.last | 122 mam_req.rsm.after = rsm_response.last |
108 # before may be set if we had no previous history | 123 # before may be set if we had no previous history |
110 if not elt_list: | 125 if not elt_list: |
111 break | 126 break |
112 else: | 127 else: |
113 count += len(elt_list) | 128 count += len(elt_list) |
114 | 129 |
115 for mess_elt in elt_list: | 130 for idx, mess_elt in enumerate(elt_list): |
116 try: | 131 try: |
117 fwd_message_elt = self.get_message_from_result( | 132 fwd_message_elt = self.get_message_from_result( |
118 client, mess_elt, mam_req) | 133 client, mess_elt, mam_req) |
119 except exceptions.DataError: | 134 except exceptions.DataError: |
120 continue | 135 continue |
150 "message has not been added to history: {e}".format(e=e)) | 165 "message has not been added to history: {e}".format(e=e)) |
151 except Exception as e: | 166 except Exception as e: |
152 log.error( | 167 log.error( |
153 "can't add message to history: {e}\n{xml}" | 168 "can't add message to history: {e}\n{xml}" |
154 .format(e=e, xml=mess_elt.toXml())) | 169 .format(e=e, xml=mess_elt.toXml())) |
170 if complete and idx == len(elt_list) - 1: | |
171 # We are at the last message from archive, we store the ID to not | |
172 # ask again the same messages next time. | |
173 try: | |
174 stanza_id = mess_elt.result["id"] | |
175 await self.host.memory.storage.set_private_value( | |
176 namespace=mam.NS_MAM, | |
177 key=KEY_LAST_STANZA_ID, | |
178 value=stanza_id, | |
179 profile=client.profile | |
180 ) | |
181 except Exception: | |
182 log.exception("Can't store last stanza ID") | |
155 | 183 |
156 if not count: | 184 if not count: |
157 log.info(_("We have received no message while offline")) | 185 log.info(_("We have received no message while offline")) |
158 else: | 186 else: |
159 log.info(_("We have received {num_mess} message(s) while offline.") | 187 log.info(_("We have received {num_mess} message(s) while offline.") |
161 | 189 |
162 def profile_connected(self, client): | 190 def profile_connected(self, client): |
163 defer.ensureDeferred(self.resume(client)) | 191 defer.ensureDeferred(self.resume(client)) |
164 | 192 |
165 def get_handler(self, client): | 193 def get_handler(self, client): |
166 mam_client = client._mam = SatMAMClient(self) | 194 mam_client = client._mam = LiberviaMAMClient(self) |
167 return mam_client | 195 return mam_client |
168 | 196 |
169 def parse_extra(self, extra, with_rsm=True): | 197 def parse_extra(self, extra, with_rsm=True): |
170 """Parse extra dictionnary to retrieve MAM arguments | 198 """Parse extra dictionnary to retrieve MAM arguments |
171 | 199 |
238 if mess_elt.name != "message": | 266 if mess_elt.name != "message": |
239 log.warning("unexpected stanza in archive: {xml}".format( | 267 log.warning("unexpected stanza in archive: {xml}".format( |
240 xml=mess_elt.toXml())) | 268 xml=mess_elt.toXml())) |
241 raise exceptions.DataError("Invalid element") | 269 raise exceptions.DataError("Invalid element") |
242 service_jid = client.jid.userhostJID() if service is None else service | 270 service_jid = client.jid.userhostJID() if service is None else service |
243 mess_from = mess_elt["from"] | 271 mess_from = mess_elt.getAttribute("from") or client.jid.userhostJID() |
244 # we check that the message has been sent by the right service | 272 # we check that the message has been sent by the right service |
245 # if service is None (i.e. message expected from our own server) | 273 # if service is None (i.e. message expected from our own server) |
246 # from can be server jid or user's bare jid | 274 # from can be server jid or user's bare jid |
247 if (mess_from != service_jid.full() | 275 if (mess_from != service_jid.full() |
248 and not (service is None and mess_from == client.jid.host)): | 276 and not (service is None and mess_from == client.jid.host)): |
418 | 446 |
419 the messages' stanza ids are stored when received, so the last one can be used | 447 the messages' stanza ids are stored when received, so the last one can be used |
420 to retrieve missing history on next connection | 448 to retrieve missing history on next connection |
421 @param message_elt(domish.Element): <message> with a stanza-id | 449 @param message_elt(domish.Element): <message> with a stanza-id |
422 """ | 450 """ |
451 if message_elt.getAttribute("type") == C.MESS_TYPE_GROUPCHAT: | |
452 # groupchat message MAM is handled by XEP-0045 | |
453 return | |
423 service_jid = client.jid.userhostJID() | 454 service_jid = client.jid.userhostJID() |
424 stanza_id = self._sid.get_stanza_id(message_elt, service_jid) | 455 stanza_id = self._sid.get_stanza_id(message_elt, service_jid) |
425 if stanza_id is None: | 456 if stanza_id is None: |
426 log.debug("Ignoring <message>, stanza id is not from our server") | 457 log.debug("Ignoring <message>, stanza id is not from our server") |
427 else: | 458 else: |
434 value=stanza_id, | 465 value=stanza_id, |
435 profile=client.profile)) | 466 profile=client.profile)) |
436 | 467 |
437 | 468 |
438 @implementer(disco.IDisco) | 469 @implementer(disco.IDisco) |
439 class SatMAMClient(mam.MAMClient): | 470 class LiberviaMAMClient(mam.MAMClient): |
440 | 471 |
441 def __init__(self, plugin_parent): | 472 def __init__(self, plugin_parent): |
442 self.plugin_parent = plugin_parent | 473 self.plugin_parent = plugin_parent |
443 | 474 |
444 @property | 475 @property |