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

Sign up to get free protection for your applications and to get access to all the features.
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(