slidge 0.1.3__py3-none-any.whl → 0.2.0a0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. slidge/__init__.py +3 -5
  2. slidge/__main__.py +2 -196
  3. slidge/__version__.py +5 -0
  4. slidge/command/adhoc.py +8 -1
  5. slidge/command/admin.py +5 -6
  6. slidge/command/base.py +1 -2
  7. slidge/command/register.py +32 -16
  8. slidge/command/user.py +85 -5
  9. slidge/contact/contact.py +93 -31
  10. slidge/contact/roster.py +54 -39
  11. slidge/core/config.py +13 -7
  12. slidge/core/gateway/base.py +139 -34
  13. slidge/core/gateway/disco.py +2 -4
  14. slidge/core/gateway/mam.py +1 -4
  15. slidge/core/gateway/ping.py +2 -3
  16. slidge/core/gateway/presence.py +1 -1
  17. slidge/core/gateway/registration.py +32 -21
  18. slidge/core/gateway/search.py +3 -5
  19. slidge/core/gateway/session_dispatcher.py +100 -51
  20. slidge/core/gateway/vcard_temp.py +6 -4
  21. slidge/core/mixins/__init__.py +11 -1
  22. slidge/core/mixins/attachment.py +15 -10
  23. slidge/core/mixins/avatar.py +66 -18
  24. slidge/core/mixins/base.py +8 -2
  25. slidge/core/mixins/message.py +11 -7
  26. slidge/core/mixins/message_maker.py +17 -9
  27. slidge/core/mixins/presence.py +14 -4
  28. slidge/core/pubsub.py +54 -212
  29. slidge/core/session.py +65 -33
  30. slidge/db/__init__.py +4 -0
  31. slidge/db/alembic/env.py +64 -0
  32. slidge/db/alembic/script.py.mako +26 -0
  33. slidge/db/alembic/versions/09f27f098baa_add_missing_attributes_in_room.py +36 -0
  34. slidge/db/alembic/versions/29f5280c61aa_store_subject_setter_in_room.py +37 -0
  35. slidge/db/alembic/versions/8d2ced764698_rely_on_db_to_store_contacts_rooms_and_.py +133 -0
  36. slidge/db/alembic/versions/aa9d82a7f6ef_db_creation.py +76 -0
  37. slidge/db/alembic/versions/b33993e87db3_move_everything_to_persistent_db.py +214 -0
  38. slidge/db/alembic/versions/e91195719c2c_store_users_avatars_persistently.py +26 -0
  39. slidge/db/avatar.py +224 -0
  40. slidge/db/meta.py +65 -0
  41. slidge/db/models.py +365 -0
  42. slidge/db/store.py +976 -0
  43. slidge/group/archive.py +13 -14
  44. slidge/group/bookmarks.py +59 -56
  45. slidge/group/participant.py +77 -25
  46. slidge/group/room.py +242 -142
  47. slidge/main.py +201 -0
  48. slidge/migration.py +30 -0
  49. slidge/slixfix/__init__.py +35 -2
  50. slidge/slixfix/roster.py +11 -4
  51. slidge/slixfix/xep_0292/vcard4.py +1 -0
  52. slidge/util/db.py +1 -47
  53. slidge/util/test.py +21 -4
  54. slidge/util/types.py +24 -4
  55. {slidge-0.1.3.dist-info → slidge-0.2.0a0.dist-info}/METADATA +3 -1
  56. slidge-0.2.0a0.dist-info/RECORD +108 -0
  57. slidge/core/cache.py +0 -183
  58. slidge/util/schema.sql +0 -126
  59. slidge/util/sql.py +0 -508
  60. slidge-0.1.3.dist-info/RECORD +0 -96
  61. {slidge-0.1.3.dist-info → slidge-0.2.0a0.dist-info}/LICENSE +0 -0
  62. {slidge-0.1.3.dist-info → slidge-0.2.0a0.dist-info}/WHEEL +0 -0
  63. {slidge-0.1.3.dist-info → slidge-0.2.0a0.dist-info}/entry_points.txt +0 -0
@@ -9,7 +9,6 @@ from slixmpp.plugins.xep_0084.stanza import Info
9
9
 
10
10
  from ... import LegacyContact
11
11
  from ...group.room import LegacyMUC
12
- from ...util.sql import db
13
12
  from ...util.types import LinkPreview, Recipient, RecipientType
14
13
  from ...util.util import (
15
14
  dict_to_named_tuple,
@@ -62,6 +61,13 @@ class SessionDispatcher:
62
61
  _exceptions_to_xmpp_errors(self.on_muc_owner_set), # type: ignore
63
62
  )
64
63
  )
64
+ xmpp.register_handler(
65
+ CoroutineCallback(
66
+ "ibr_remove",
67
+ StanzaPath("/iq/register"),
68
+ _exceptions_to_xmpp_errors(self.on_ibr_remove), # type: ignore
69
+ )
70
+ )
65
71
 
66
72
  for event in (
67
73
  "legacy_message",
@@ -157,7 +163,7 @@ class SessionDispatcher:
157
163
  reply_fallback = None
158
164
  if msg.get_plugin("reply", check=True):
159
165
  try:
160
- reply_to_msg_xmpp_id = _xmpp_msg_id_to_legacy(
166
+ reply_to_msg_xmpp_id = self._xmpp_msg_id_to_legacy(
161
167
  session, msg["reply"]["id"]
162
168
  )
163
169
  except XMPPError:
@@ -170,7 +176,7 @@ class SessionDispatcher:
170
176
  else:
171
177
  reply_to_jid = JID(msg["reply"]["to"])
172
178
  if msg["type"] == "chat":
173
- if reply_to_jid.bare != session.user.jid.bare:
179
+ if reply_to_jid.bare != session.user_jid.bare:
174
180
  try:
175
181
  reply_to = await session.contacts.by_jid(reply_to_jid)
176
182
  except XMPPError:
@@ -242,13 +248,17 @@ class SessionDispatcher:
242
248
  if isinstance(e, LegacyMUC):
243
249
  await e.echo(msg, legacy_msg_id)
244
250
  if legacy_msg_id is not None:
245
- session.muc_sent_msg_ids[legacy_msg_id] = msg.get_id()
251
+ self.xmpp.store.sent.set_group_message(
252
+ session.user_pk, legacy_msg_id, msg.get_id()
253
+ )
246
254
  else:
247
255
  self.__ack(msg)
248
256
  if legacy_msg_id is not None:
249
- session.sent[legacy_msg_id] = msg.get_id()
257
+ self.xmpp.store.sent.set_message(
258
+ session.user_pk, legacy_msg_id, msg.get_id()
259
+ )
250
260
  if session.MESSAGE_IDS_ARE_THREAD_IDS and (t := msg["thread"]):
251
- session.threads[t] = legacy_msg_id
261
+ self.xmpp.store.sent.set_thread(session.user_pk, t, legacy_msg_id)
252
262
 
253
263
  async def on_groupchat_message(self, msg: Message):
254
264
  await self.on_legacy_message(msg)
@@ -257,9 +267,11 @@ class SessionDispatcher:
257
267
  session, entity, thread = await self.__get_session_entity_thread(msg)
258
268
  xmpp_id = msg["replace"]["id"]
259
269
  if isinstance(entity, LegacyMUC):
260
- legacy_id = session.muc_sent_msg_ids.inverse.get(xmpp_id)
270
+ legacy_id = self.xmpp.store.sent.get_group_legacy_id(
271
+ session.user_pk, xmpp_id
272
+ )
261
273
  else:
262
- legacy_id = _xmpp_msg_id_to_legacy(session, xmpp_id)
274
+ legacy_id = self._xmpp_msg_id_to_legacy(session, xmpp_id)
263
275
 
264
276
  if isinstance(entity, LegacyMUC):
265
277
  mentions = await entity.parse_mentions(msg["body"])
@@ -323,12 +335,16 @@ class SessionDispatcher:
323
335
 
324
336
  if isinstance(entity, LegacyMUC):
325
337
  if new_legacy_msg_id is not None:
326
- session.muc_sent_msg_ids[new_legacy_msg_id] = msg.get_id()
338
+ self.xmpp.store.sent.set_group_message(
339
+ session.user_pk, new_legacy_msg_id, msg.get_id()
340
+ )
327
341
  await entity.echo(msg, new_legacy_msg_id)
328
342
  else:
329
343
  self.__ack(msg)
330
344
  if new_legacy_msg_id is not None:
331
- session.sent[new_legacy_msg_id] = msg.get_id()
345
+ self.xmpp.store.sent.set_message(
346
+ session.user_pk, new_legacy_msg_id, msg.get_id()
347
+ )
332
348
 
333
349
  async def on_message_retract(self, msg: Message):
334
350
  session, entity, thread = await self.__get_session_entity_thread(msg)
@@ -338,7 +354,7 @@ class SessionDispatcher:
338
354
  "This legacy service does not support message retraction.",
339
355
  )
340
356
  xmpp_id: str = msg["retract"]["id"]
341
- legacy_id = _xmpp_msg_id_to_legacy(session, xmpp_id)
357
+ legacy_id = self._xmpp_msg_id_to_legacy(session, xmpp_id)
342
358
  if legacy_id:
343
359
  await session.on_retract(entity, legacy_id, thread=thread)
344
360
  if isinstance(entity, LegacyMUC):
@@ -362,7 +378,7 @@ class SessionDispatcher:
362
378
  to_mark = [displayed_msg_id]
363
379
  for xmpp_id in to_mark:
364
380
  await session.on_displayed(
365
- e, _xmpp_msg_id_to_legacy(session, xmpp_id), legacy_thread
381
+ e, self._xmpp_msg_id_to_legacy(session, xmpp_id), legacy_thread
366
382
  )
367
383
  if isinstance(e, LegacyMUC):
368
384
  await e.echo(msg, None)
@@ -397,7 +413,7 @@ class SessionDispatcher:
397
413
  if special_msg:
398
414
  legacy_id = react_to
399
415
  else:
400
- legacy_id = _xmpp_msg_id_to_legacy(session, react_to)
416
+ legacy_id = self._xmpp_msg_id_to_legacy(session, react_to)
401
417
 
402
418
  if not legacy_id:
403
419
  log.debug("Ignored reaction from user")
@@ -434,9 +450,10 @@ class SessionDispatcher:
434
450
  else:
435
451
  self.__ack(msg)
436
452
 
437
- multi = db.attachment_get_associated_xmpp_ids(react_to)
453
+ multi = self.xmpp.store.multi.get_xmpp_ids(session.user_pk, react_to)
438
454
  if not multi:
439
455
  return
456
+ multi = [m for m in multi if react_to != m]
440
457
 
441
458
  if isinstance(entity, LegacyMUC):
442
459
  for xmpp_id in multi:
@@ -461,14 +478,17 @@ class SessionDispatcher:
461
478
 
462
479
  pto = p.get_to()
463
480
  if pto == self.xmpp.boundjid.bare:
464
- # NB: get_type() returns either a proper presence type or
465
- # a presence show if available. Weird, weird, weird slix.
481
+ session.log.debug("Received a presence from %s", p.get_from())
466
482
  if (ptype := p.get_type()) not in _USEFUL_PRESENCES:
467
483
  return
484
+ if not session.user.preferences.get("sync_presence", False):
485
+ session.log.debug("User does not want to sync their presence")
486
+ return
487
+ # NB: get_type() returns either a proper presence type or
488
+ # a presence show if available. Weird, weird, weird slix.
468
489
  resources = self.xmpp.roster[self.xmpp.boundjid.bare][
469
490
  p.get_from()
470
491
  ].resources
471
- session.log.debug("Received a presence from %s", p.get_from())
472
492
  await session.on_presence(
473
493
  p.get_from().resource,
474
494
  ptype, # type: ignore
@@ -478,8 +498,12 @@ class SessionDispatcher:
478
498
  )
479
499
  return
480
500
 
481
- muc = session.bookmarks._mucs_by_bare_jid.get(pto.bare)
482
- if muc is None or p.get_from().resource not in muc.user_resources:
501
+ muc = session.bookmarks.by_jid_only_if_exists(JID(pto.bare))
502
+
503
+ if muc is not None and p.get_type() == "unavailable":
504
+ return muc.on_presence_unavailable(p)
505
+
506
+ if muc is None or p.get_from().resource not in muc.get_user_resources():
483
507
  return
484
508
 
485
509
  if pto.resource == muc.user_nick:
@@ -530,29 +554,36 @@ class SessionDispatcher:
530
554
  return
531
555
 
532
556
  stanza_id = msg["pubsub_event"]["items"]["item"]["displayed"]["stanza_id"]["id"]
533
- await session.on_displayed(chat, _xmpp_msg_id_to_legacy(session, stanza_id))
557
+ await session.on_displayed(
558
+ chat, self._xmpp_msg_id_to_legacy(session, stanza_id)
559
+ )
534
560
 
535
561
  async def on_avatar_metadata_publish(self, m: Message):
536
- if not config.SYNC_AVATAR:
537
- return
538
-
539
562
  session = await self.__get_session(m, timeout=None)
563
+ if not session.user.preferences.get("sync_avatar", False):
564
+ session.log.debug("User does not want to sync their avatar")
565
+ return
540
566
  info = m["pubsub_event"]["items"]["item"]["avatar_metadata"]["info"]
541
567
 
542
568
  await self.on_avatar_metadata_info(session, info)
543
569
 
544
570
  async def on_avatar_metadata_info(self, session: BaseSession, info: Info):
545
- session.log.debug("Avatar metadata info: %s", info)
546
571
  hash_ = info["id"]
547
572
 
548
- if session.avatar_hash == hash_:
573
+ if session.user.avatar_hash == hash_:
574
+ session.log.debug("We already know this avatar hash")
549
575
  return
550
- session.avatar_hash = hash_
576
+ with self.xmpp.store.session() as orm_session:
577
+ user = self.xmpp.store.users.get(session.user_jid)
578
+ assert user is not None
579
+ user.avatar_hash = hash_
580
+ orm_session.add(user)
581
+ orm_session.commit()
551
582
 
552
583
  if hash_:
553
584
  try:
554
585
  iq = await self.xmpp.plugin["xep_0084"].retrieve_avatar(
555
- session.user.jid, hash_, ifrom=self.xmpp.boundjid.bare
586
+ session.user_jid, hash_, ifrom=self.xmpp.boundjid.bare
556
587
  )
557
588
  except IqError as e:
558
589
  session.log.warning("Could not fetch the user's avatar: %s", e)
@@ -593,7 +624,7 @@ class SessionDispatcher:
593
624
  "Slidge only implements moderation/retraction",
594
625
  )
595
626
 
596
- legacy_id = _xmpp_msg_id_to_legacy(session, xmpp_id)
627
+ legacy_id = self._xmpp_msg_id_to_legacy(session, xmpp_id)
597
628
  await session.on_moderate(muc, legacy_id, moderate["reason"] or None)
598
629
  iq.reply(clear=True).send()
599
630
 
@@ -718,25 +749,39 @@ class SessionDispatcher:
718
749
  )
719
750
  await muc.on_set_subject(msg["subject"])
720
751
 
752
+ async def on_ibr_remove(self, iq: Iq):
753
+ if iq.get_to() == self.xmpp.boundjid.bare:
754
+ return
755
+
756
+ session = await self.__get_session(iq)
757
+ session.raise_if_not_logged()
721
758
 
722
- def _xmpp_msg_id_to_legacy(session: "BaseSession", xmpp_id: str):
723
- sent = session.sent.inverse.get(xmpp_id)
724
- if sent:
725
- return sent
759
+ if iq["type"] == "set" and iq["register"]["remove"]:
760
+ muc = await session.bookmarks.by_jid(iq.get_to())
761
+ await session.on_leave_group(muc.legacy_id)
762
+ iq.reply().send()
763
+ return
726
764
 
727
- multi = db.attachment_get_legacy_id_for_xmpp_id(xmpp_id)
728
- if multi:
729
- return multi
765
+ raise XMPPError("feature-not-implemented")
730
766
 
731
- try:
732
- return session.xmpp_to_legacy_msg_id(xmpp_id)
733
- except XMPPError:
734
- raise
735
- except Exception as e:
736
- log.debug("Couldn't convert xmpp msg ID to legacy ID.", exc_info=e)
737
- raise XMPPError(
738
- "internal-server-error", "Couldn't convert xmpp msg ID to legacy ID."
739
- )
767
+ def _xmpp_msg_id_to_legacy(self, session: "BaseSession", xmpp_id: str):
768
+ sent = self.xmpp.store.sent.get_legacy_id(session.user_pk, xmpp_id)
769
+ if sent is not None:
770
+ return self.xmpp.LEGACY_MSG_ID_TYPE(sent)
771
+
772
+ multi = self.xmpp.store.multi.get_legacy_id(session.user_pk, xmpp_id)
773
+ if multi:
774
+ return self.xmpp.LEGACY_MSG_ID_TYPE(multi)
775
+
776
+ try:
777
+ return session.xmpp_to_legacy_msg_id(xmpp_id)
778
+ except XMPPError:
779
+ raise
780
+ except Exception as e:
781
+ log.debug("Couldn't convert xmpp msg ID to legacy ID.", exc_info=e)
782
+ raise XMPPError(
783
+ "internal-server-error", "Couldn't convert xmpp msg ID to legacy ID."
784
+ )
740
785
 
741
786
 
742
787
  def _ignore(session: "BaseSession", msg: Message):
@@ -755,14 +800,18 @@ async def _xmpp_to_legacy_thread(
755
800
  return
756
801
 
757
802
  if session.MESSAGE_IDS_ARE_THREAD_IDS:
758
- return session.threads.get(xmpp_thread)
803
+ return session.xmpp.store.sent.get_legacy_thread(session.user_pk, xmpp_thread)
759
804
 
760
805
  async with session.thread_creation_lock:
761
- legacy_thread = session.threads.get(xmpp_thread)
762
- if legacy_thread is None:
763
- legacy_thread = await recipient.create_thread(xmpp_thread)
764
- session.threads[xmpp_thread] = legacy_thread
765
- return legacy_thread
806
+ legacy_thread_str = session.xmpp.store.sent.get_legacy_thread(
807
+ session.user_pk, xmpp_thread
808
+ )
809
+ if legacy_thread_str is None:
810
+ legacy_thread = str(await recipient.create_thread(xmpp_thread))
811
+ session.xmpp.store.sent.set_thread(
812
+ session.user_pk, xmpp_thread, legacy_thread
813
+ )
814
+ return session.xmpp.LEGACY_MSG_ID_TYPE(legacy_thread)
766
815
 
767
816
 
768
817
  async def _get_entity(session: "BaseSession", m: Message) -> RecipientType:
@@ -770,7 +819,7 @@ async def _get_entity(session: "BaseSession", m: Message) -> RecipientType:
770
819
  if m.get_type() == "groupchat":
771
820
  muc = await session.bookmarks.by_jid(m.get_to())
772
821
  r = m.get_from().resource
773
- if r not in muc.user_resources:
822
+ if r not in muc.get_user_resources():
774
823
  session.create_task(muc.kick_resource(r))
775
824
  raise XMPPError("not-acceptable", "You are not connected to this chat")
776
825
  return muc
@@ -40,11 +40,13 @@ class VCardTemp:
40
40
  return await self.__handle_set_vcard_temp(iq)
41
41
 
42
42
  async def __fetch_user_avatar(self, session: BaseSession):
43
- hash_ = session.avatar_hash
43
+ hash_ = session.user.avatar_hash
44
44
  if not hash_:
45
- raise XMPPError("item-not-found", "This participant has no contact")
45
+ raise XMPPError(
46
+ "item-not-found", "The slidge user does not have any avatar set"
47
+ )
46
48
  meta_iq = await self.xmpp.plugin["xep_0060"].get_item(
47
- session.user.jid,
49
+ session.user_jid,
48
50
  MetaData.namespace,
49
51
  hash_,
50
52
  ifrom=self.xmpp.boundjid.bare,
@@ -52,7 +54,7 @@ class VCardTemp:
52
54
  info = meta_iq["pubsub"]["items"]["item"]["avatar_metadata"]["info"]
53
55
  type_ = info["type"]
54
56
  data_iq = await self.xmpp.plugin["xep_0084"].retrieve_avatar(
55
- session.user.jid, hash_, ifrom=self.xmpp.boundjid.bare
57
+ session.user_jid, hash_, ifrom=self.xmpp.boundjid.bare
56
58
  )
57
59
  bytes_ = data_iq["pubsub"]["items"]["item"]["avatar_data"]["value"]
58
60
  return bytes_, type_
@@ -2,6 +2,8 @@
2
2
  Mixins
3
3
  """
4
4
 
5
+ from typing import Optional
6
+
5
7
  from .avatar import AvatarMixin
6
8
  from .disco import ChatterDiscoMixin
7
9
  from .message import MessageCarbonMixin, MessageMixin
@@ -16,4 +18,12 @@ class FullCarbonMixin(ChatterDiscoMixin, MessageCarbonMixin, PresenceMixin):
16
18
  pass
17
19
 
18
20
 
19
- __all__ = ("AvatarMixin",)
21
+ class StoredAttributeMixin:
22
+ def serialize_extra_attributes(self) -> Optional[dict]:
23
+ return None
24
+
25
+ def deserialize_extra_attributes(self, data: dict) -> None:
26
+ pass
27
+
28
+
29
+ __all__ = ("AvatarMixin", "FullCarbonMixin", "StoredAttributeMixin")
@@ -22,7 +22,7 @@ from slixmpp.plugins.xep_0363 import FileUploadError
22
22
  from slixmpp.plugins.xep_0385.stanza import Sims
23
23
  from slixmpp.plugins.xep_0447.stanza import StatelessFileSharing
24
24
 
25
- from ...util.sql import db
25
+ from ...db.avatar import avatar_cache
26
26
  from ...util.types import (
27
27
  LegacyAttachment,
28
28
  LegacyMessageType,
@@ -31,11 +31,14 @@ from ...util.types import (
31
31
  )
32
32
  from ...util.util import fix_suffix
33
33
  from .. import config
34
- from ..cache import avatar_cache
35
34
  from .message_maker import MessageMaker
36
35
 
37
36
 
38
37
  class AttachmentMixin(MessageMaker):
38
+ def __init__(self, *a, **kw):
39
+ super().__init__(*a, **kw)
40
+ self.__store = self.xmpp.store.attachments
41
+
39
42
  def send_text(self, *_, **k) -> Optional[Message]:
40
43
  raise NotImplementedError
41
44
 
@@ -146,13 +149,13 @@ class AttachmentMixin(MessageMaker):
146
149
  legacy_file_id: Optional[Union[str, int]] = None,
147
150
  ) -> tuple[bool, Optional[Path], str]:
148
151
  if legacy_file_id:
149
- cache = db.attachment_get_url(legacy_file_id)
152
+ cache = self.__store.get_url(str(legacy_file_id))
150
153
  if cache is not None:
151
154
  async with self.session.http.head(cache) as r:
152
155
  if r.status < 400:
153
156
  return False, None, cache
154
157
  else:
155
- db.attachment_remove(legacy_file_id)
158
+ self.__store.remove(str(legacy_file_id))
156
159
 
157
160
  if file_url and config.USE_ATTACHMENT_ORIGINAL_URLS:
158
161
  return False, None, file_url
@@ -198,7 +201,7 @@ class AttachmentMixin(MessageMaker):
198
201
  local_path = file_path
199
202
  new_url = await self.__upload(file_path, file_name, content_type)
200
203
  if legacy_file_id:
201
- db.attachment_store_url(legacy_file_id, new_url)
204
+ self.__store.set_url(self.session.user_pk, str(legacy_file_id), new_url)
202
205
 
203
206
  return is_temp, local_path, new_url
204
207
 
@@ -211,7 +214,7 @@ class AttachmentMixin(MessageMaker):
211
214
  caption: Optional[str] = None,
212
215
  file_name: Optional[str] = None,
213
216
  ):
214
- cache = db.attachment_get_sims(uploaded_url)
217
+ cache = self.__store.get_sims(uploaded_url)
215
218
  if cache:
216
219
  msg.append(Sims(xml=ET.fromstring(cache)))
217
220
  return
@@ -238,7 +241,7 @@ class AttachmentMixin(MessageMaker):
238
241
  thumbnail["media-type"] = "image/blurhash"
239
242
  thumbnail["uri"] = "data:image/blurhash," + urlquote(h)
240
243
 
241
- db.attachment_store_sims(uploaded_url, str(sims))
244
+ self.__store.set_sims(uploaded_url, str(sims))
242
245
 
243
246
  msg.append(sims)
244
247
 
@@ -251,7 +254,7 @@ class AttachmentMixin(MessageMaker):
251
254
  caption: Optional[str] = None,
252
255
  file_name: Optional[str] = None,
253
256
  ):
254
- cache = db.attachment_get_sfs(uploaded_url)
257
+ cache = self.__store.get_sfs(uploaded_url)
255
258
  if cache:
256
259
  msg.append(StatelessFileSharing(xml=ET.fromstring(cache)))
257
260
  return
@@ -262,7 +265,7 @@ class AttachmentMixin(MessageMaker):
262
265
  sfs = self.xmpp["xep_0447"].get_sfs(path, [uploaded_url], content_type, caption)
263
266
  if file_name:
264
267
  sfs["file"]["name"] = file_name
265
- db.attachment_store_sfs(uploaded_url, str(sfs))
268
+ self.__store.set_sfs(uploaded_url, str(sfs))
266
269
 
267
270
  msg.append(sfs)
268
271
 
@@ -472,7 +475,9 @@ class AttachmentMixin(MessageMaker):
472
475
  ids.append(stanza_id["id"])
473
476
  else:
474
477
  ids.append(msg.get_id())
475
- db.attachment_store_legacy_to_multi_xmpp_msg_ids(legacy_msg_id, ids)
478
+ self.xmpp.store.multi.set_xmpp_ids(
479
+ self.session.user_pk, str(legacy_msg_id), ids
480
+ )
476
481
 
477
482
 
478
483
  def get_blurhash(path: Path, n=9) -> tuple[str, int, int]:
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, Optional
5
5
 
6
6
  from slixmpp import JID
7
7
 
8
+ from ...db.avatar import CachedAvatar, avatar_cache
8
9
  from ...util.types import (
9
10
  URL,
10
11
  AnyBaseSession,
@@ -12,7 +13,6 @@ from ...util.types import (
12
13
  AvatarType,
13
14
  LegacyFileIdType,
14
15
  )
15
- from ..cache import avatar_cache
16
16
 
17
17
  if TYPE_CHECKING:
18
18
  from ..pubsub import PepAvatar
@@ -34,7 +34,9 @@ class AvatarMixin:
34
34
  def __init__(self) -> None:
35
35
  super().__init__()
36
36
  self._set_avatar_task: Optional[Task] = None
37
+ self.__broadcast_task: Optional[Task] = None
37
38
  self.__avatar_unique_id: Optional[AvatarIdType] = None
39
+ self._avatar_pk: Optional[int] = None
38
40
 
39
41
  @property
40
42
  def __avatar_jid(self):
@@ -86,13 +88,28 @@ class AvatarMixin:
86
88
 
87
89
  async def __set_avatar(self, a: Optional[AvatarType], uid: Optional[AvatarIdType]):
88
90
  self.__avatar_unique_id = uid
89
- await self.session.xmpp.pubsub.set_avatar(
90
- jid=self.__avatar_jid,
91
- avatar=a,
92
- unique_id=None if isinstance(uid, URL) else uid,
93
- broadcast_to=self.session.user.jid.bare,
94
- broadcast=self._avatar_pubsub_broadcast,
95
- )
91
+
92
+ if a is None:
93
+ cached_avatar = None
94
+ self._avatar_pk = None
95
+ else:
96
+ try:
97
+ cached_avatar = await avatar_cache.convert_or_get(
98
+ URL(a) if isinstance(a, URL) else a,
99
+ None if isinstance(uid, URL) else uid,
100
+ )
101
+ except Exception as e:
102
+ self.session.log.error("Failed to set avatar %s", a, exc_info=e)
103
+ self._avatar_pk = None
104
+ self.__avatar_unique_id = uid
105
+ return
106
+ self._avatar_pk = cached_avatar.pk
107
+
108
+ if self._avatar_pubsub_broadcast:
109
+ await self.session.xmpp.pubsub.broadcast_avatar(
110
+ self.__avatar_jid, self.session.user_jid, cached_avatar
111
+ )
112
+
96
113
  self._post_avatar_update()
97
114
 
98
115
  async def _no_change(self, a: Optional[AvatarType], uid: Optional[AvatarIdType]):
@@ -103,7 +120,7 @@ class AvatarMixin:
103
120
  if isinstance(uid, URL):
104
121
  if self.__avatar_unique_id != uid:
105
122
  return False
106
- return not await avatar_cache.url_has_changed(uid)
123
+ return not await avatar_cache.url_modified(uid)
107
124
  return self.__avatar_unique_id == uid
108
125
 
109
126
  async def set_avatar(
@@ -136,32 +153,63 @@ class AvatarMixin:
136
153
  if blocking:
137
154
  await awaitable
138
155
 
139
- def get_avatar(self) -> Optional["PepAvatar"]:
156
+ def get_cached_avatar(self) -> Optional["CachedAvatar"]:
140
157
  if not self.__avatar_unique_id:
141
158
  return None
142
- return self.session.xmpp.pubsub.get_avatar(self.__avatar_jid)
159
+ return avatar_cache.get(self.__avatar_unique_id)
160
+
161
+ def get_avatar(self) -> Optional["PepAvatar"]:
162
+ cached_avatar = self.get_cached_avatar()
163
+ if cached_avatar is None:
164
+ return None
165
+ from ..pubsub import PepAvatar
166
+
167
+ item = PepAvatar()
168
+ item.set_avatar_from_cache(cached_avatar)
169
+ return item
143
170
 
144
171
  def _post_avatar_update(self) -> None:
145
172
  return
146
173
 
174
+ def __get_cached_avatar_id(self):
175
+ i = self._get_cached_avatar_id()
176
+ if i is None:
177
+ return None
178
+ return self.session.xmpp.AVATAR_ID_TYPE(i)
179
+
180
+ def _get_cached_avatar_id(self) -> Optional[str]:
181
+ raise NotImplementedError
182
+
147
183
  async def avatar_wrap_update_info(self):
148
- cached_id = avatar_cache.get_cached_id_for(self.__avatar_jid)
184
+ cached_id = self.__get_cached_avatar_id()
149
185
  self.__avatar_unique_id = cached_id
150
186
  try:
151
187
  await self.update_info() # type:ignore
152
188
  except NotImplementedError:
153
189
  return
154
190
  new_id = self.avatar
155
- if isinstance(new_id, URL) and not await avatar_cache.url_has_changed(new_id):
191
+ if isinstance(new_id, URL) and not await avatar_cache.url_modified(new_id):
156
192
  return
157
193
  elif new_id != cached_id:
158
194
  # at this point it means that update_info set the avatar, and we don't
159
195
  # need to do anything else
160
196
  return
161
197
 
162
- await self.session.xmpp.pubsub.set_avatar_from_cache(
163
- self.__avatar_jid,
164
- new_id is None and cached_id is not None,
165
- self.session.user.jid.bare,
166
- self._avatar_pubsub_broadcast,
198
+ if self._avatar_pubsub_broadcast:
199
+ if new_id is None and cached_id is None:
200
+ return
201
+ cached_avatar = avatar_cache.get(cached_id)
202
+ self.__broadcast_task = self.session.xmpp.loop.create_task(
203
+ self.session.xmpp.pubsub.broadcast_avatar(
204
+ self.__avatar_jid, self.session.user_jid, cached_avatar
205
+ )
206
+ )
207
+
208
+ def _set_avatar_from_store(self, stored):
209
+ if stored.avatar_id is None:
210
+ return
211
+ self.__avatar_unique_id = (
212
+ stored.avatar.legacy_id
213
+ if stored.avatar.legacy_id is not None
214
+ else URL(stored.avatar.url)
167
215
  )
@@ -8,7 +8,6 @@ from ...util.types import MessageOrPresenceTypeVar
8
8
  if TYPE_CHECKING:
9
9
  from slidge.core.gateway import BaseGateway
10
10
  from slidge.core.session import BaseSession
11
- from slidge.util.db import GatewayUser
12
11
 
13
12
 
14
13
  class MetaBase(ABCMeta):
@@ -18,11 +17,18 @@ class MetaBase(ABCMeta):
18
17
  class Base:
19
18
  session: "BaseSession" = NotImplemented
20
19
  xmpp: "BaseGateway" = NotImplemented
21
- user: "GatewayUser" = NotImplemented
22
20
 
23
21
  jid: JID = NotImplemented
24
22
  name: str = NotImplemented
25
23
 
24
+ @property
25
+ def user_jid(self):
26
+ return self.session.user_jid
27
+
28
+ @property
29
+ def user_pk(self):
30
+ return self.session.user_pk
31
+
26
32
 
27
33
  class BaseSender(Base):
28
34
  def _send(
@@ -111,7 +111,7 @@ class MarkerMixin(MessageMaker):
111
111
  self.xmpp.delivery_receipt.make_ack(
112
112
  self._legacy_to_xmpp(legacy_msg_id),
113
113
  mfrom=self.jid,
114
- mto=self.user.jid,
114
+ mto=self.user_jid,
115
115
  )
116
116
  )
117
117
  self._send(
@@ -144,7 +144,7 @@ class MarkerMixin(MessageMaker):
144
144
  # We'll see if we need to implement that later
145
145
  return
146
146
  xmpp_msg_id = self._legacy_to_xmpp(legacy_msg_id)
147
- iq = Iq(sto=self.user.bare_jid, sfrom=self.user.bare_jid, stype="set")
147
+ iq = Iq(sto=self.user_jid.bare, sfrom=self.user_jid.bare, stype="set")
148
148
  iq["pubsub"]["publish"]["node"] = self.xmpp["xep_0490"].stanza.NS
149
149
  iq["pubsub"]["publish"]["item"]["id"] = muc_jid
150
150
  displayed = self.xmpp["xep_0490"].stanza.Displayed()
@@ -169,8 +169,8 @@ class ContentMessageMixin(AttachmentMixin):
169
169
 
170
170
  def __replace_id(self, legacy_msg_id: LegacyMessageType):
171
171
  if self.mtype == "groupchat":
172
- return self.session.muc_sent_msg_ids.get(
173
- legacy_msg_id
172
+ return self.xmpp.store.sent.get_group_xmpp_id(
173
+ self.session.user_pk, str(legacy_msg_id)
174
174
  ) or self._legacy_to_xmpp(legacy_msg_id)
175
175
  else:
176
176
  return self._legacy_to_xmpp(legacy_msg_id)
@@ -215,14 +215,18 @@ class ContentMessageMixin(AttachmentMixin):
215
215
  but store it in the archive. Meant to be used during ``MUC.backfill()``
216
216
  """
217
217
  if carbon:
218
- if not correction and legacy_msg_id in self.session.sent:
218
+ if not correction and self.xmpp.store.sent.was_sent_by_user(
219
+ self.session.user_pk, str(legacy_msg_id)
220
+ ):
219
221
  log.warning(
220
222
  "Carbon message for a message an XMPP has sent? This is a bug! %s",
221
223
  legacy_msg_id,
222
224
  )
223
225
  return
224
- self.session.sent[legacy_msg_id] = self.session.legacy_to_xmpp_msg_id(
225
- legacy_msg_id
226
+ self.xmpp.store.sent.set_message(
227
+ self.session.user_pk,
228
+ str(legacy_msg_id),
229
+ self.session.legacy_to_xmpp_msg_id(legacy_msg_id),
226
230
  )
227
231
  hints = self.__default_hints(hints)
228
232
  msg = self._make_message(