Coverage for slidge/core/dispatcher/session_dispatcher.py: 86%
63 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-09-29 05:05 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-09-29 05:05 +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] = [
37 "_CapsMixin__contact_vers",
38 "_CapsMixin__gateway_ver",
39 "_MamMixin__mam_cleanup_task",
40 "xmpp",
41 ]
42 xmpp: "BaseGateway"
44 def __init__(self, xmpp: "BaseGateway") -> None:
45 super().__init__(xmpp)
46 xmpp.add_event_handler(
47 "avatar_metadata_publish", self.on_avatar_metadata_publish
48 )
50 @exceptions_to_xmpp_errors
51 async def on_avatar_metadata_publish(self, m: Message) -> None:
52 session = await self._get_session(m, timeout=None)
53 if not session.user.preferences.get("sync_avatar", False):
54 session.log.debug("User does not want to sync their avatar")
55 return
56 info = m["pubsub_event"]["items"]["item"]["avatar_metadata"]["info"]
58 await self.on_avatar_metadata_info(session, info)
60 async def on_avatar_metadata_info(self, session: AnySession, info: Info) -> None:
61 hash_ = info["id"]
63 if session.user.avatar_hash == hash_:
64 session.log.debug("We already know this avatar hash")
65 return
67 if hash_:
68 try:
69 iq = await self.xmpp.plugin["xep_0084"].retrieve_avatar(
70 session.user_jid, hash_, ifrom=self.xmpp.boundjid.bare
71 )
72 except (IqError, IqTimeout) as e:
73 session.log.warning("Could not fetch the user's avatar: %s", e)
74 return
75 bytes_ = iq["pubsub"]["items"]["item"]["avatar_data"]["value"]
76 type_ = info["type"]
77 height = info["height"]
78 width = info["width"]
79 else:
80 with self.xmpp.store.session(expire_on_commit=False) as orm:
81 session.user.avatar_hash = None
82 orm.add(session.user)
83 orm.commit()
84 bytes_ = type_ = height = width = hash_ = None
85 try:
86 await session.on_avatar(bytes_, hash_, type_, width, height)
87 except NotImplementedError:
88 pass
89 except Exception as e: # noqa: BLE001
90 # If something goes wrong here, replying an error stanza will to the
91 # avatar update will likely not show in most clients, so let's send
92 # a normal message from the component to the user.
93 session.send_gateway_message(
94 f"Something went wrong trying to set your avatar: {e!r}"
95 )
96 else:
97 session.user.avatar_hash = hash_
98 with self.xmpp.store.session(expire_on_commit=False) as orm:
99 orm.add(session.user)
100 orm.commit()
101 for room in session.bookmarks:
102 participant = await room.get_user_participant()
103 participant.send_last_presence(force=True, no_cache_online=True)
106log = logging.getLogger(__name__)