Mercurial > libervia-backend
comparison sat/plugins/plugin_xep_0313.py @ 4037:524856bd7b19
massive refactoring to switch from camelCase to snake_case:
historically, Libervia (SàT before) was using camelCase as allowed by PEP8 when using a
pre-PEP8 code, to use the same coding style as in Twisted.
However, snake_case is more readable and it's better to follow PEP8 best practices, so it
has been decided to move on full snake_case. Because Libervia has a huge codebase, this
ended with a ugly mix of camelCase and snake_case.
To fix that, this patch does a big refactoring by renaming every function and method
(including bridge) that are not coming from Twisted or Wokkel, to use fully snake_case.
This is a massive change, and may result in some bugs.
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 08 Apr 2023 13:54:42 +0200 |
parents | 5245b675f7ad |
children |
comparison
equal
deleted
inserted
replaced
4036:c4464d7ae97b | 4037:524856bd7b19 |
---|---|
61 | 61 |
62 class XEP_0313(object): | 62 class XEP_0313(object): |
63 def __init__(self, host): | 63 def __init__(self, host): |
64 log.info(_("Message Archive Management plugin initialization")) | 64 log.info(_("Message Archive Management plugin initialization")) |
65 self.host = host | 65 self.host = host |
66 self.host.registerNamespace("mam", mam.NS_MAM) | 66 self.host.register_namespace("mam", mam.NS_MAM) |
67 host.registerNamespace("fulltextmam", NS_FTS) | 67 host.register_namespace("fulltextmam", NS_FTS) |
68 self._rsm = host.plugins["XEP-0059"] | 68 self._rsm = host.plugins["XEP-0059"] |
69 self._sid = host.plugins["XEP-0359"] | 69 self._sid = host.plugins["XEP-0359"] |
70 # Deferred used to store last stanza id in order of reception | 70 # Deferred used to store last stanza id in order of reception |
71 self._last_stanza_id_d = defer.Deferred() | 71 self._last_stanza_id_d = defer.Deferred() |
72 self._last_stanza_id_d.callback(None) | 72 self._last_stanza_id_d.callback(None) |
73 host.bridge.addMethod( | 73 host.bridge.add_method( |
74 "MAMGet", ".plugin", in_sign='sss', | 74 "mam_get", ".plugin", in_sign='sss', |
75 out_sign='(a(sdssa{ss}a{ss}ss)ss)', method=self._getArchives, | 75 out_sign='(a(sdssa{ss}a{ss}ss)ss)', method=self._get_archives, |
76 async_=True) | 76 async_=True) |
77 | 77 |
78 async def resume(self, client): | 78 async def resume(self, client): |
79 """Retrieve one2one messages received since the last we have in local storage""" | 79 """Retrieve one2one messages received since the last we have in local storage""" |
80 stanza_id_data = await self.host.memory.storage.getPrivates( | 80 stanza_id_data = await self.host.memory.storage.get_privates( |
81 mam.NS_MAM, [KEY_LAST_STANZA_ID], profile=client.profile) | 81 mam.NS_MAM, [KEY_LAST_STANZA_ID], profile=client.profile) |
82 stanza_id = stanza_id_data.get(KEY_LAST_STANZA_ID) | 82 stanza_id = stanza_id_data.get(KEY_LAST_STANZA_ID) |
83 rsm_req = None | 83 rsm_req = None |
84 if stanza_id is None: | 84 if stanza_id is None: |
85 log.info("can't retrieve last stanza ID, checking history") | 85 log.info("can't retrieve last stanza ID, checking history") |
86 last_mess = await self.host.memory.historyGet( | 86 last_mess = await self.host.memory.history_get( |
87 None, None, limit=1, filters={'not_types': C.MESS_TYPE_GROUPCHAT, | 87 None, None, limit=1, filters={'not_types': C.MESS_TYPE_GROUPCHAT, |
88 'last_stanza_id': True}, | 88 'last_stanza_id': True}, |
89 profile=client.profile) | 89 profile=client.profile) |
90 if not last_mess: | 90 if not last_mess: |
91 log.info(_("It seems that we have no MAM history yet")) | 91 log.info(_("It seems that we have no MAM history yet")) |
97 rsm_req = rsm.RSMRequest(max_=100, after=stanza_id) | 97 rsm_req = rsm.RSMRequest(max_=100, after=stanza_id) |
98 mam_req = mam.MAMRequest(rsm_=rsm_req) | 98 mam_req = mam.MAMRequest(rsm_=rsm_req) |
99 complete = False | 99 complete = False |
100 count = 0 | 100 count = 0 |
101 while not complete: | 101 while not complete: |
102 mam_data = await self.getArchives(client, mam_req, | 102 mam_data = await self.get_archives(client, mam_req, |
103 service=client.jid.userhostJID()) | 103 service=client.jid.userhostJID()) |
104 elt_list, rsm_response, mam_response = mam_data | 104 elt_list, rsm_response, mam_response = mam_data |
105 complete = mam_response["complete"] | 105 complete = mam_response["complete"] |
106 # we update MAM request for next iteration | 106 # we update MAM request for next iteration |
107 mam_req.rsm.after = rsm_response.last | 107 mam_req.rsm.after = rsm_response.last |
112 else: | 112 else: |
113 count += len(elt_list) | 113 count += len(elt_list) |
114 | 114 |
115 for mess_elt in elt_list: | 115 for mess_elt in elt_list: |
116 try: | 116 try: |
117 fwd_message_elt = self.getMessageFromResult( | 117 fwd_message_elt = self.get_message_from_result( |
118 client, mess_elt, mam_req) | 118 client, mess_elt, mam_req) |
119 except exceptions.DataError: | 119 except exceptions.DataError: |
120 continue | 120 continue |
121 | 121 |
122 try: | 122 try: |
140 'was expecting a message sent by our jid, but this one if ' | 140 'was expecting a message sent by our jid, but this one if ' |
141 'from {from_jid}, ignoring\n{xml}').format( | 141 'from {from_jid}, ignoring\n{xml}').format( |
142 from_jid=from_jid.full(), xml=mess_elt.toXml())) | 142 from_jid=from_jid.full(), xml=mess_elt.toXml())) |
143 continue | 143 continue |
144 # adding message to history | 144 # adding message to history |
145 mess_data = client.messageProt.parseMessage(fwd_message_elt) | 145 mess_data = client.messageProt.parse_message(fwd_message_elt) |
146 try: | 146 try: |
147 await client.messageProt.addToHistory(mess_data) | 147 await client.messageProt.add_to_history(mess_data) |
148 except exceptions.CancelError as e: | 148 except exceptions.CancelError as e: |
149 log.warning( | 149 log.warning( |
150 "message has not been added to history: {e}".format(e=e)) | 150 "message has not been added to history: {e}".format(e=e)) |
151 except Exception as e: | 151 except Exception as e: |
152 log.error( | 152 log.error( |
157 log.info(_("We have received no message while offline")) | 157 log.info(_("We have received no message while offline")) |
158 else: | 158 else: |
159 log.info(_("We have received {num_mess} message(s) while offline.") | 159 log.info(_("We have received {num_mess} message(s) while offline.") |
160 .format(num_mess=count)) | 160 .format(num_mess=count)) |
161 | 161 |
162 def profileConnected(self, client): | 162 def profile_connected(self, client): |
163 defer.ensureDeferred(self.resume(client)) | 163 defer.ensureDeferred(self.resume(client)) |
164 | 164 |
165 def getHandler(self, client): | 165 def get_handler(self, client): |
166 mam_client = client._mam = SatMAMClient(self) | 166 mam_client = client._mam = SatMAMClient(self) |
167 return mam_client | 167 return mam_client |
168 | 168 |
169 def parseExtra(self, extra, with_rsm=True): | 169 def parse_extra(self, extra, with_rsm=True): |
170 """Parse extra dictionnary to retrieve MAM arguments | 170 """Parse extra dictionnary to retrieve MAM arguments |
171 | 171 |
172 @param extra(dict): data for parse | 172 @param extra(dict): data for parse |
173 @param with_rsm(bool): if True, RSM data will be parsed too | 173 @param with_rsm(bool): if True, RSM data will be parsed too |
174 @return (data_form, None): request with parsed arguments | 174 @return (data_form, None): request with parsed arguments |
206 mam_args[arg] = value | 206 mam_args[arg] = value |
207 except KeyError: | 207 except KeyError: |
208 continue | 208 continue |
209 | 209 |
210 if with_rsm: | 210 if with_rsm: |
211 rsm_request = self._rsm.parseExtra(extra) | 211 rsm_request = self._rsm.parse_extra(extra) |
212 if rsm_request is not None: | 212 if rsm_request is not None: |
213 mam_args["rsm_"] = rsm_request | 213 mam_args["rsm_"] = rsm_request |
214 | 214 |
215 if form_args: | 215 if form_args: |
216 mam_args["form"] = mam.buildForm(**form_args) | 216 mam_args["form"] = mam.buildForm(**form_args) |
222 assert isinstance(order_by, list) | 222 assert isinstance(order_by, list) |
223 mam_args["orderBy"] = order_by | 223 mam_args["orderBy"] = order_by |
224 | 224 |
225 return mam.MAMRequest(**mam_args) if mam_args else None | 225 return mam.MAMRequest(**mam_args) if mam_args else None |
226 | 226 |
227 def getMessageFromResult(self, client, mess_elt, mam_req, service=None): | 227 def get_message_from_result(self, client, mess_elt, mam_req, service=None): |
228 """Extract usable <message/> from MAM query result | 228 """Extract usable <message/> from MAM query result |
229 | 229 |
230 The message will be validated, and stanza-id/delay will be added if necessary. | 230 The message will be validated, and stanza-id/delay will be added if necessary. |
231 @param mess_elt(domish.Element): result <message/> element wrapping the message | 231 @param mess_elt(domish.Element): result <message/> element wrapping the message |
232 to retrieve | 232 to retrieve |
265 else: | 265 else: |
266 if not result_elt["queryid"] == mam_req.query_id: | 266 if not result_elt["queryid"] == mam_req.query_id: |
267 log.error("Unexpected query id (was expecting {query_id}): {xml}" | 267 log.error("Unexpected query id (was expecting {query_id}): {xml}" |
268 .format(query_id=mam.query_id, xml=mess_elt.toXml())) | 268 .format(query_id=mam.query_id, xml=mess_elt.toXml())) |
269 raise exceptions.DataError("Invalid element") | 269 raise exceptions.DataError("Invalid element") |
270 stanza_id = self._sid.getStanzaId(fwd_message_elt, | 270 stanza_id = self._sid.get_stanza_id(fwd_message_elt, |
271 service_jid) | 271 service_jid) |
272 if stanza_id is None: | 272 if stanza_id is None: |
273 # not stanza-id element is present, we add one so message | 273 # not stanza-id element is present, we add one so message |
274 # will be archived with it, and we won't request several times | 274 # will be archived with it, and we won't request several times |
275 # the same MAM achive | 275 # the same MAM achive |
277 stanza_id = result_elt["id"] | 277 stanza_id = result_elt["id"] |
278 except AttributeError: | 278 except AttributeError: |
279 log.warning('Invalid MAM result: missing "id" attribute: {xml}' | 279 log.warning('Invalid MAM result: missing "id" attribute: {xml}' |
280 .format(xml=result_elt.toXml())) | 280 .format(xml=result_elt.toXml())) |
281 raise exceptions.DataError("Invalid element") | 281 raise exceptions.DataError("Invalid element") |
282 self._sid.addStanzaId(client, fwd_message_elt, stanza_id, by=service_jid) | 282 self._sid.add_stanza_id(client, fwd_message_elt, stanza_id, by=service_jid) |
283 | 283 |
284 if delay_elt is not None: | 284 if delay_elt is not None: |
285 fwd_message_elt.addChild(delay_elt) | 285 fwd_message_elt.addChild(delay_elt) |
286 | 286 |
287 return fwd_message_elt | 287 return fwd_message_elt |
302 None for user server | 302 None for user server |
303 @return (D(domish.Element)): <IQ/> result | 303 @return (D(domish.Element)): <IQ/> result |
304 """ | 304 """ |
305 return client._mam.queryArchive(mam_req, service) | 305 return client._mam.queryArchive(mam_req, service) |
306 | 306 |
307 def _appendMessage(self, elt_list, message_cb, message_elt): | 307 def _append_message(self, elt_list, message_cb, message_elt): |
308 if message_cb is not None: | 308 if message_cb is not None: |
309 elt_list.append(message_cb(message_elt)) | 309 elt_list.append(message_cb(message_elt)) |
310 else: | 310 else: |
311 elt_list.append(message_elt) | 311 elt_list.append(message_elt) |
312 | 312 |
313 def _queryFinished(self, iq_result, client, elt_list, event): | 313 def _query_finished(self, iq_result, client, elt_list, event): |
314 client.xmlstream.removeObserver(event, self._appendMessage) | 314 client.xmlstream.removeObserver(event, self._append_message) |
315 try: | 315 try: |
316 fin_elt = next(iq_result.elements(mam.NS_MAM, "fin")) | 316 fin_elt = next(iq_result.elements(mam.NS_MAM, "fin")) |
317 except StopIteration: | 317 except StopIteration: |
318 raise exceptions.DataError("Invalid MAM result") | 318 raise exceptions.DataError("Invalid MAM result") |
319 | 319 |
325 except rsm.RSMNotFoundError: | 325 except rsm.RSMNotFoundError: |
326 rsm_response = None | 326 rsm_response = None |
327 | 327 |
328 return (elt_list, rsm_response, mam_response) | 328 return (elt_list, rsm_response, mam_response) |
329 | 329 |
330 def serializeArchiveResult(self, data, client, mam_req, service): | 330 def serialize_archive_result(self, data, client, mam_req, service): |
331 elt_list, rsm_response, mam_response = data | 331 elt_list, rsm_response, mam_response = data |
332 mess_list = [] | 332 mess_list = [] |
333 for elt in elt_list: | 333 for elt in elt_list: |
334 fwd_message_elt = self.getMessageFromResult(client, elt, mam_req, | 334 fwd_message_elt = self.get_message_from_result(client, elt, mam_req, |
335 service=service) | 335 service=service) |
336 mess_data = client.messageProt.parseMessage(fwd_message_elt) | 336 mess_data = client.messageProt.parse_message(fwd_message_elt) |
337 mess_list.append(client.messageGetBridgeArgs(mess_data)) | 337 mess_list.append(client.message_get_bridge_args(mess_data)) |
338 metadata = { | 338 metadata = { |
339 'rsm': self._rsm.response2dict(rsm_response), | 339 'rsm': self._rsm.response2dict(rsm_response), |
340 'mam': mam_response | 340 'mam': mam_response |
341 } | 341 } |
342 return mess_list, data_format.serialise(metadata), client.profile | 342 return mess_list, data_format.serialise(metadata), client.profile |
343 | 343 |
344 def _getArchives(self, service, extra_ser, profile_key): | 344 def _get_archives(self, service, extra_ser, profile_key): |
345 """ | 345 """ |
346 @return: tuple with: | 346 @return: tuple with: |
347 - list of message with same data as in bridge.messageNew | 347 - list of message with same data as in bridge.message_new |
348 - response metadata with: | 348 - response metadata with: |
349 - rsm data (first, last, count, index) | 349 - rsm data (first, last, count, index) |
350 - mam data (complete, stable) | 350 - mam data (complete, stable) |
351 - profile | 351 - profile |
352 """ | 352 """ |
353 client = self.host.getClient(profile_key) | 353 client = self.host.get_client(profile_key) |
354 service = jid.JID(service) if service else None | 354 service = jid.JID(service) if service else None |
355 extra = data_format.deserialise(extra_ser, {}) | 355 extra = data_format.deserialise(extra_ser, {}) |
356 mam_req = self.parseExtra(extra) | 356 mam_req = self.parse_extra(extra) |
357 | 357 |
358 d = self.getArchives(client, mam_req, service=service) | 358 d = self.get_archives(client, mam_req, service=service) |
359 d.addCallback(self.serializeArchiveResult, client, mam_req, service) | 359 d.addCallback(self.serialize_archive_result, client, mam_req, service) |
360 return d | 360 return d |
361 | 361 |
362 def getArchives(self, client, query, service=None, message_cb=None): | 362 def get_archives(self, client, query, service=None, message_cb=None): |
363 """Query archive and gather page result | 363 """Query archive and gather page result |
364 | 364 |
365 @param query(mam.MAMRequest): MAM request | 365 @param query(mam.MAMRequest): MAM request |
366 @param service(jid.JID, None): MAM service to use | 366 @param service(jid.JID, None): MAM service to use |
367 None to use our own server | 367 None to use our own server |
376 """ | 376 """ |
377 if query.query_id is None: | 377 if query.query_id is None: |
378 query.query_id = str(uuid.uuid4()) | 378 query.query_id = str(uuid.uuid4()) |
379 elt_list = [] | 379 elt_list = [] |
380 event = MESSAGE_RESULT.format(mam_ns=mam.NS_MAM, query_id=query.query_id) | 380 event = MESSAGE_RESULT.format(mam_ns=mam.NS_MAM, query_id=query.query_id) |
381 client.xmlstream.addObserver(event, self._appendMessage, 0, elt_list, message_cb) | 381 client.xmlstream.addObserver(event, self._append_message, 0, elt_list, message_cb) |
382 d = self.queryArchive(client, query, service) | 382 d = self.queryArchive(client, query, service) |
383 d.addCallback(self._queryFinished, client, elt_list, event) | 383 d.addCallback(self._query_finished, client, elt_list, event) |
384 return d | 384 return d |
385 | 385 |
386 def getPrefs(self, client, service=None): | 386 def get_prefs(self, client, service=None): |
387 """Retrieve the current user preferences. | 387 """Retrieve the current user preferences. |
388 | 388 |
389 @param service: entity offering the MAM service (None for user archives) | 389 @param service: entity offering the MAM service (None for user archives) |
390 @return: the server response as a Deferred domish.Element | 390 @return: the server response as a Deferred domish.Element |
391 """ | 391 """ |
392 # http://xmpp.org/extensions/xep-0313.html#prefs | 392 # http://xmpp.org/extensions/xep-0313.html#prefs |
393 return client._mam.queryPrefs(service) | 393 return client._mam.queryPrefs(service) |
394 | 394 |
395 def _setPrefs(self, service_s=None, default="roster", always=None, never=None, | 395 def _set_prefs(self, service_s=None, default="roster", always=None, never=None, |
396 profile_key=C.PROF_KEY_NONE): | 396 profile_key=C.PROF_KEY_NONE): |
397 service = jid.JID(service_s) if service_s else None | 397 service = jid.JID(service_s) if service_s else None |
398 always_jid = [jid.JID(entity) for entity in always] | 398 always_jid = [jid.JID(entity) for entity in always] |
399 never_jid = [jid.JID(entity) for entity in never] | 399 never_jid = [jid.JID(entity) for entity in never] |
400 # TODO: why not build here a MAMPrefs object instead of passing the args separately? | 400 # TODO: why not build here a MAMPrefs object instead of passing the args separately? |
411 @return: the server response as a Deferred domish.Element | 411 @return: the server response as a Deferred domish.Element |
412 """ | 412 """ |
413 # http://xmpp.org/extensions/xep-0313.html#prefs | 413 # http://xmpp.org/extensions/xep-0313.html#prefs |
414 return client._mam.setPrefs(service, default, always, never) | 414 return client._mam.setPrefs(service, default, always, never) |
415 | 415 |
416 def onMessageStanzaId(self, message_elt, client): | 416 def on_message_stanza_id(self, message_elt, client): |
417 """Called when a message with a stanza-id is received | 417 """Called when a message with a stanza-id is received |
418 | 418 |
419 the messages' stanza ids are stored when received, so the last one can be used | 419 the messages' stanza ids are stored when received, so the last one can be used |
420 to retrieve missing history on next connection | 420 to retrieve missing history on next connection |
421 @param message_elt(domish.Element): <message> with a stanza-id | 421 @param message_elt(domish.Element): <message> with a stanza-id |
422 """ | 422 """ |
423 service_jid = client.jid.userhostJID() | 423 service_jid = client.jid.userhostJID() |
424 stanza_id = self._sid.getStanzaId(message_elt, service_jid) | 424 stanza_id = self._sid.get_stanza_id(message_elt, service_jid) |
425 if stanza_id is None: | 425 if stanza_id is None: |
426 log.debug("Ignoring <message>, stanza id is not from our server") | 426 log.debug("Ignoring <message>, stanza id is not from our server") |
427 else: | 427 else: |
428 # we use self._last_stanza_id_d do be sure that last_stanza_id is stored in | 428 # we use self._last_stanza_id_d do be sure that last_stanza_id is stored in |
429 # the order of reception | 429 # the order of reception |
430 self._last_stanza_id_d.addCallback( | 430 self._last_stanza_id_d.addCallback( |
431 lambda __: self.host.memory.storage.setPrivateValue( | 431 lambda __: self.host.memory.storage.set_private_value( |
432 namespace=mam.NS_MAM, | 432 namespace=mam.NS_MAM, |
433 key=KEY_LAST_STANZA_ID, | 433 key=KEY_LAST_STANZA_ID, |
434 value=stanza_id, | 434 value=stanza_id, |
435 profile=client.profile)) | 435 profile=client.profile)) |
436 | 436 |
447 | 447 |
448 def connectionInitialized(self): | 448 def connectionInitialized(self): |
449 observer_xpath = MESSAGE_STANZA_ID.format( | 449 observer_xpath = MESSAGE_STANZA_ID.format( |
450 ns_stanza_id=self.host.ns_map['stanza_id']) | 450 ns_stanza_id=self.host.ns_map['stanza_id']) |
451 self.xmlstream.addObserver( | 451 self.xmlstream.addObserver( |
452 observer_xpath, self.plugin_parent.onMessageStanzaId, client=self.parent | 452 observer_xpath, self.plugin_parent.on_message_stanza_id, client=self.parent |
453 ) | 453 ) |
454 | 454 |
455 def getDiscoInfo(self, requestor, target, nodeIdentifier=""): | 455 def getDiscoInfo(self, requestor, target, nodeIdentifier=""): |
456 return [disco.DiscoFeature(mam.NS_MAM)] | 456 return [disco.DiscoFeature(mam.NS_MAM)] |
457 | 457 |