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