plugin XEP-0045, XEP-0402: Update bookmark on room join/leave:

As PEP bookmarks are nowadays used to sync joined state across devices, trigger points
have been added to XEP-0045 so XEP-0402 can automatically update the `autojoin` status on
MUC joining or leaving.

A check has been added to ignore already joined or left room when XEP-0402 plugin updates
the MUC status on bookmark update.
This commit is contained in:
Goffi 2026-09-01 17:32:09 +02:00
commit 1af645c0f0
2 changed files with 79 additions and 20 deletions

View file

@ -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:

View file

@ -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}))