Coverage for slidge/core/dispatcher/session_dispatcher.py: 85%
62 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-04 08:17 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-04 08:17 +0000
1import logging
2from typing import TYPE_CHECKING
4from slixmpp import Message
5from slixmpp.exceptions import IqError, IqTimeout
6from slixmpp.plugins.xep_0084.stanza import Info
8from ..session import BaseSession
9from .caps import CapsMixin
10from .disco import DiscoMixin
11from .message import MessageMixin
12from .muc import MucMixin
13from .presence import PresenceHandlerMixin
14from .registration import RegistrationMixin
15from .search import SearchMixin
16from .util import exceptions_to_xmpp_errors
17from .vcard import VCardMixin
19if TYPE_CHECKING:
20 from slidge.core.gateway import BaseGateway
23class SessionDispatcher(
24 CapsMixin,
25 DiscoMixin,
26 RegistrationMixin,
27 MessageMixin,
28 MucMixin,
29 PresenceHandlerMixin,
30 SearchMixin,
31 VCardMixin,
32):
33 __slots__: list[str] = ["xmpp", "_MamMixin__mam_cleanup_task"]
35 def __init__(self, xmpp: "BaseGateway") -> None:
36 super().__init__(xmpp)
37 xmpp.add_event_handler(
38 "avatar_metadata_publish", self.on_avatar_metadata_publish
39 )
41 @exceptions_to_xmpp_errors
42 async def on_avatar_metadata_publish(self, m: Message) -> None:
43 session = await self._get_session(m, timeout=None)
44 if not session.user.preferences.get("sync_avatar", False):
45 session.log.debug("User does not want to sync their avatar")
46 return
47 info = m["pubsub_event"]["items"]["item"]["avatar_metadata"]["info"]
49 await self.on_avatar_metadata_info(session, info)
51 async def on_avatar_metadata_info(self, session: BaseSession, info: Info) -> None:
52 hash_ = info["id"]
54 if session.user.avatar_hash == hash_:
55 session.log.debug("We already know this avatar hash")
56 return
58 if hash_:
59 try:
60 iq = await self.xmpp.plugin["xep_0084"].retrieve_avatar(
61 session.user_jid, hash_, ifrom=self.xmpp.boundjid.bare
62 )
63 except (IqError, IqTimeout) as e:
64 session.log.warning("Could not fetch the user's avatar: %s", e)
65 return
66 bytes_ = iq["pubsub"]["items"]["item"]["avatar_data"]["value"]
67 type_ = info["type"]
68 height = info["height"]
69 width = info["width"]
70 else:
71 with self.xmpp.store.session(expire_on_commit=False) as orm:
72 session.user.avatar_hash = None
73 orm.add(session.user)
74 orm.commit()
75 bytes_ = type_ = height = width = hash_ = None
76 try:
77 await session.on_avatar(bytes_, hash_, type_, width, height)
78 except NotImplementedError:
79 pass
80 except Exception as e:
81 # If something goes wrong here, replying an error stanza will to the
82 # avatar update will likely not show in most clients, so let's send
83 # a normal message from the component to the user.
84 session.send_gateway_message(
85 f"Something went wrong trying to set your avatar: {e!r}"
86 )
87 else:
88 session.user.avatar_hash = hash_
89 with self.xmpp.store.session(expire_on_commit=False) as orm:
90 orm.add(session.user)
91 orm.commit()
92 for room in session.bookmarks:
93 participant = await room.get_user_participant()
94 participant.send_last_presence(force=True, no_cache_online=True)
97log = logging.getLogger(__name__)