xmpp: Allow resyncs in Agent::join_room

pep created

Signed-off-by: pep <pep@bouah.net>

Change summary

xmpp/ChangeLog             |  2 ++
xmpp/examples/hello_bot.rs |  4 +---
xmpp/src/iq/result.rs      |  3 +--
xmpp/src/muc/room.rs       | 14 +++++++++++++-
xmpp/src/pubsub/mod.rs     |  6 ++----
5 files changed, 19 insertions(+), 10 deletions(-)

Detailed changes

xmpp/ChangeLog πŸ”—

@@ -26,6 +26,8 @@ XXXX-YY-ZZ [ RELEASER <admin@localhost> ]
         to be enabled for compilation to succeed).
 
         Please refer to the crate docs for details. (!581)
+      - Allow joining an already joined room with `Agent::join_room` to enable
+        resyncs. Adds a parameter to `muc::room::JoinRoomSettings`.
     * Added:
       - Agent::send_room_message takes RoomMessageSettings argument (!483)
       - Agent::send_raw_message takes RawMessageSettings for any message type (!487)

xmpp/examples/hello_bot.rs πŸ”—

@@ -103,10 +103,8 @@ async fn handle_events(client: &mut Agent, event: Event, rooms: &Vec<BareJid>) {
                 log::info!("Joining room {} from CLI argument…", room);
                 client
                     .join_room(JoinRoomSettings {
-                        room: room.clone(),
-                        nick: None,
-                        password: None,
                         status: Some(("en", "Yet another bot!")),
+                        ..JoinRoomSettings::new(room.clone())
                     })
                     .await;
             }

xmpp/src/iq/result.rs πŸ”—

@@ -41,10 +41,9 @@ pub async fn handle_iq_result(
                     let (jid, room) = conf.into_bookmarks2();
                     agent
                         .join_room(JoinRoomSettings {
-                            room: jid,
                             nick: room.nick.map(RoomNick::new),
                             password: room.password,
-                            status: None,
+                            ..JoinRoomSettings::new(jid)
                         })
                         .await;
                 }

xmpp/src/muc/room.rs πŸ”—

@@ -21,6 +21,11 @@ pub struct JoinRoomSettings<'a> {
     pub nick: Option<RoomNick>,
     pub password: Option<String>,
     pub status: Option<(&'a str, &'a str)>,
+    /// Send the join payload again even though we're already supposedly joined.
+    /// This was made explicit in version 1.27 of XEP-0045 (cee524dbde4, 2016), that is just rejoin
+    /// with the standard MUC payload to force a resync of the client state (receive all occupants
+    /// and subject again).
+    pub force_resync: bool,
 }
 
 impl<'a> JoinRoomSettings<'a> {
@@ -30,6 +35,7 @@ impl<'a> JoinRoomSettings<'a> {
             nick: None,
             password: None,
             status: None,
+            force_resync: false,
         }
     }
 
@@ -47,6 +53,11 @@ impl<'a> JoinRoomSettings<'a> {
         self.status = Some((lang, content));
         self
     }
+
+    pub fn with_resync(mut self) -> Self {
+        self.force_resync = true;
+        self
+    }
 }
 
 /// TODO: this method should add bookmark and ensure autojoin is true
@@ -56,6 +67,7 @@ pub async fn join_room<'a>(agent: &mut Agent, settings: JoinRoomSettings<'a>) {
         nick,
         password,
         status,
+        force_resync,
     } = settings;
 
     if agent.rooms_joining.contains_key(&room) {
@@ -64,7 +76,7 @@ pub async fn join_room<'a>(agent: &mut Agent, settings: JoinRoomSettings<'a>) {
         return;
     }
 
-    if agent.rooms_joined.contains_key(&room) {
+    if !force_resync && agent.rooms_joined.contains_key(&room) {
         // We are already joined, cannot join
         warn!("Requesting to join room {room} which is already joined...");
         return;

xmpp/src/pubsub/mod.rs πŸ”—

@@ -61,10 +61,9 @@ pub(crate) async fn handle_event(
                                     if !agent.rooms_joined.contains_key(&jid) {
                                         agent
                                             .join_room(JoinRoomSettings {
-                                                room: jid,
                                                 nick: conference.nick.map(RoomNick::new),
                                                 password: conference.password,
-                                                status: None,
+                                                ..JoinRoomSettings::new(jid)
                                             })
                                             .await;
                                     } else {
@@ -144,10 +143,9 @@ pub(crate) async fn handle_iq_result(
                                 if !agent.rooms_joined.contains_key(&jid) {
                                     agent
                                         .join_room(JoinRoomSettings {
-                                            room: jid,
                                             nick: conference.nick.map(RoomNick::new),
                                             password: conference.password,
-                                            status: None,
+                                            ..JoinRoomSettings::new(jid)
                                         })
                                         .await;
                                 }