diff --git a/libervia/backend/plugins/plugin_xep_0045.py b/libervia/backend/plugins/plugin_xep_0045.py index 652682c0..d18b1f77 100644 --- a/libervia/backend/plugins/plugin_xep_0045.py +++ b/libervia/backend/plugins/plugin_xep_0045.py @@ -951,6 +951,8 @@ class XEP_0045: # We use `ensureDeferred` to run the archive sync in background defer.ensureDeferred(self._sync_mam_history(client, room)) + await self.host.trigger.async_point("muc_room_joined", client, room_jid) + return room async def _sync_mam_history(self, client: SatXMPPEntity, room: muc.Room) -> None: @@ -1098,27 +1100,22 @@ class XEP_0045: self.check_room_joined(client, room_jid) client.get_plugin_data(IMPORT_NAME, MUCClientData).muc_client.nick(room_jid, nick) - def _leave(self, room_jid: str, profile_key: str) -> defer.Deferred: - """Leave room. - - @param room_jid: Room JID string. - @param profile_key: Profile key. - @return: Deferred. - """ + @utils.ensure_deferred + async def _leave(self, room_jid: str, profile_key: str) -> None: client = self.host.get_client(profile_key) - return self.leave(client, jid.JID(room_jid)) + await self.leave(client, jid.JID(room_jid)) - def leave(self, client: SatXMPPEntity, room_jid: jid.JID) -> defer.Deferred: + async def leave(self, client: SatXMPPEntity, room_jid: jid.JID) -> None: """Leave a room. @param client: The client instance. @param room_jid: Room JID. - @return: Deferred firing when leave is complete. """ self.check_room_joined(client, room_jid) - return client.get_plugin_data(IMPORT_NAME, MUCClientData).muc_client.leave( + await client.get_plugin_data(IMPORT_NAME, MUCClientData).muc_client.leave( room_jid ) + await self.host.trigger.async_point("muc_room_left", client, room_jid) def _subject(self, room_jid_s: str, new_subject: str, profile_key: str) -> None: """Set room subject.""" @@ -1269,7 +1266,7 @@ class XEP_0045: room = self.text_cmds.get_room_jid(room_raw, mess_data["to"].host) else: room = mess_data["to"] - self.leave(client, room) + defer.ensureDeferred(self.leave(client, room)) return False def cmd_part(self, client: SatXMPPEntity, mess_data: dict) -> bool: diff --git a/libervia/backend/plugins/plugin_xep_0402.py b/libervia/backend/plugins/plugin_xep_0402.py index 428a4c7c..40a05685 100644 --- a/libervia/backend/plugins/plugin_xep_0402.py +++ b/libervia/backend/plugins/plugin_xep_0402.py @@ -31,7 +31,7 @@ from libervia.backend.core.core_types import SatXMPPEntity from libervia.backend.core.i18n import _ from libervia.backend.core.log import getLogger from libervia.backend.models.types import DomishElementType, JIDType -from libervia.backend.plugins.plugin_xep_0045 import XEP_0045 +from libervia.backend.plugins.plugin_xep_0045 import AlreadyJoined, XEP_0045 from libervia.backend.plugins.plugin_xep_0048 import XEP_0048 from libervia.backend.plugins.plugin_xep_0060 import XEP_0060 from libervia.backend.plugins.plugin_xep_0163 import XEP_0163 @@ -227,6 +227,10 @@ class XEP_0402: ) pep.add_pep_event(None, NS_BOOKMARKS2, self._on_bookmark_event) host.register_namespace("bookmarks2", NS_BOOKMARKS2) + host.trigger.add_with_check("muc_room_left", self, self._muc_room_left_trigger) + host.trigger.add_with_check( + "muc_room_joined", self, self._muc_room_joined_trigger + ) async def profile_connected(self, client: SatXMPPEntity) -> None: """Fetch bookmarks and autojoin in background.""" @@ -288,14 +292,21 @@ class XEP_0402: log.exception("Can't parse bookmark item: {item_elt.toXml()}") else: if conference.autojoin: - await self._muc.join( - client, - room_jid, - conference.nick, - {"password": conference.password}, - ) + try: + await self._muc.join( + client, + room_jid, + conference.nick, + {"password": conference.password}, + ) + except AlreadyJoined: + pass else: - await self._muc.leave(client, room_jid) + try: + await self._muc.leave(client, room_jid) + except exceptions.NotFound: + # Room not joined, nothing to do + pass @utils.ensure_deferred async def _bookmark_get(self, bookmark_jid: str, profile: str) -> str: @@ -426,6 +437,14 @@ class XEP_0402: """ client = self.host.get_client(profile) bookmarks = Bookmarks.model_validate_json(bookmarks_raw) + await self.set(client, bookmarks) + + async def set(self, client: SatXMPPEntity, bookmarks: Bookmarks) -> None: + """Add or update one or more bookmarks. + + @param client: Client session. + @param bookmarks: Bookmarks to add or update, keyed by their JID. + """ pep_jid = client.jid.userhostJID() if await self.host.memory.disco.has_feature( @@ -475,3 +494,46 @@ class XEP_0402: storage_type="private", profile_key=client.profile, ) + + async def _muc_room_joined_trigger( + self, client: SatXMPPEntity, room_jid: jid.JID + ) -> None: + """Update the autojoin flag of a room's bookmark on room join. + + @param client: Client session. + @param room_jid: JID of the room that was joined. + """ + await self._set_autojoin(client, room_jid, True) + + async def _muc_room_left_trigger( + self, client: SatXMPPEntity, room_jid: jid.JID + ) -> None: + """Update the autojoin flag of a room's bookmark on room leave. + + @param client: Client session. + @param room_jid: JID of the room that was left. + """ + await self._set_autojoin(client, room_jid, False) + + async def _set_autojoin( + self, client: SatXMPPEntity, room_jid: jid.JID, autojoin: bool + ) -> None: + """Set the autojoin flag of a room's bookmark, if it exists. + + @param client: Client session. + @param room_jid: JID of the room. + @param autojoin: True if the room is joined, False otherwise. + """ + try: + conference = await self.get(client, room_jid) + except (IndexError, KeyError): + # No bookmark for this room, nothing to do + return + except Exception: + # Updating the autojoin flag must not break the join/leave + log.exception(f"Can't get bookmark for {room_jid}") + return + if conference.autojoin == autojoin: + return + conference.autojoin = autojoin + await self.set(client, Bookmarks({room_jid: conference}))