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

1import logging 

2from typing import TYPE_CHECKING 

3 

4from slixmpp import Message 

5from slixmpp.exceptions import IqError, IqTimeout 

6from slixmpp.plugins.xep_0084.stanza import Info 

7 

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 

18 

19if TYPE_CHECKING: 

20 from slidge.core.gateway import BaseGateway 

21 

22 

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"] 

34 

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 ) 

40 

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"] 

48 

49 await self.on_avatar_metadata_info(session, info) 

50 

51 async def on_avatar_metadata_info(self, session: BaseSession, info: Info) -> None: 

52 hash_ = info["id"] 

53 

54 if session.user.avatar_hash == hash_: 

55 session.log.debug("We already know this avatar hash") 

56 return 

57 

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) 

95 

96 

97log = logging.getLogger(__name__)