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