diff --git a/xmpp/ChangeLog b/xmpp/ChangeLog index 1450555fb5ba00f174682c9ead8bbcdbf0d160dd..60f90b19907ffbea072398379bf1f236802dfdb5 100644 --- a/xmpp/ChangeLog +++ b/xmpp/ChangeLog @@ -43,6 +43,7 @@ XXXX-YY-ZZ [ RELEASER ] stanzas. - Added documentation on `Event` enum. - Update to edition 2024 + - Add Config::Config struct as a user-facing Agent configuration method. * Fixes: - Use tokio::sync::RwLock not std::sync::RwLock (!432) - The default caps node has been shortened to https://xmpp.rs since we diff --git a/xmpp/src/agent.rs b/xmpp/src/agent.rs index 1d613d414c171529aecb3ab563e474ea80d47d8e..4a6f0973dd658a845d689866efd0fac2fdeb740b 100644 --- a/xmpp/src/agent.rs +++ b/xmpp/src/agent.rs @@ -12,7 +12,7 @@ use tokio::io; use tokio::sync::RwLock; use crate::{ - Error, Event, RoomNick, event_loop, + Config, Error, Event, RoomNick, event_loop, jid::{BareJid, Jid}, message, muc, parsers::disco::DiscoInfoResult, @@ -24,6 +24,7 @@ use tokio_xmpp::{Stanza, stanzastream::StanzaToken}; pub struct Agent { pub(crate) client: TokioXmppClient, + pub(crate) config: Arc>, pub(crate) default_nick: Arc>, pub(crate) lang: Arc>, pub(crate) disco: DiscoInfoResult, @@ -39,6 +40,7 @@ pub struct Agent { impl Agent { pub fn new( client: TokioXmppClient, + config: Config, default_nick: RoomNick, lang: Vec, disco: DiscoInfoResult, @@ -46,6 +48,7 @@ impl Agent { ) -> Agent { Agent { client, + config: Arc::new(RwLock::new(config)), default_nick: Arc::new(RwLock::new(default_nick)), lang: Arc::new(lang), disco, @@ -58,6 +61,13 @@ impl Agent { } } + /// Reset the agent configuration to the provided Config struct + // TODO: refresh everything that is affected by this reset? + pub async fn set_config(&mut self, config: Config) { + let mut c = self.config.write().await; + *c = config; + } + pub async fn disconnect(self) -> Result<(), Error> { self.client.send_end().await } diff --git a/xmpp/src/builder.rs b/xmpp/src/builder.rs index a05483d42b2bf01d9223f945d29f387a0234713d..5de8a862dc402ef22f6c95676b16ec2ab68501a9 100644 --- a/xmpp/src/builder.rs +++ b/xmpp/src/builder.rs @@ -9,7 +9,7 @@ use crate::tokio_xmpp::connect::{DnsConfig, StartTlsServerConnector}; use core::str::FromStr; use crate::{ - Agent, ClientFeature, RoomNick, + Agent, ClientFeature, Config, RoomNick, jid::{BareJid, Jid, ResourceRef}, parsers::{ disco::{DiscoInfoResult, Feature, Identity}, @@ -43,6 +43,7 @@ pub struct ClientBuilder<'a, C: ServerConnector> { jid: BareJid, password: &'a str, server_connector: C, + config: Config, website: String, default_nick: RoomNick, lang: Vec, @@ -73,6 +74,7 @@ impl ClientBuilder<'_, C> { jid, password, server_connector, + config: Config::default(), website: String::from("https://gitlab.com/xmpp-rs/tokio-xmpp"), default_nick: RoomNick::from_str("xmpp-rs").unwrap(), lang: vec![String::from("en")], @@ -89,6 +91,11 @@ impl ClientBuilder<'_, C> { self } + pub fn set_config(mut self, config: Config) -> Self { + self.config = config; + self + } + pub fn set_client(mut self, type_: ClientType, name: &str) -> Self { self.disco = (type_, String::from(name)); self @@ -169,6 +176,13 @@ impl ClientBuilder<'_, C> { let disco = self.make_disco(); let node = self.website; - Agent::new(client, self.default_nick, self.lang, disco, node) + Agent::new( + client, + self.config, + self.default_nick, + self.lang, + disco, + node, + ) } } diff --git a/xmpp/src/config.rs b/xmpp/src/config.rs new file mode 100644 index 0000000000000000000000000000000000000000..69a4eaf69019db038591cabf8f88cc438f34ae22 --- /dev/null +++ b/xmpp/src/config.rs @@ -0,0 +1,31 @@ +// Copyright (c) 2025 Crate authors +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +/// Store Agent configuration. Differs from state which is generated at runtime +pub struct Config { + /// Synchronize bookmarks based on autojoin flag. + /// The client will join and leave based on the value of the `autojoin` flag on the (pubsub) + /// bookmark item. + /// If this `bookmarks_autojoin` attribute is set to false, `autojoin` set to false won't make + /// the client leave a room, neither will the removal of a bookmark item. This will only happen + /// after the client is restarted, as these items won't be automatically joined anymore. + /// + pub bookmarks_autojoin: bool, +} + +impl Default for Config { + fn default() -> Self { + Self::new() + } +} + +impl Config { + fn new() -> Self { + Config { + bookmarks_autojoin: true, + } + } +} diff --git a/xmpp/src/lib.rs b/xmpp/src/lib.rs index e9de88c599f4bfd6d43ca5a521c66eb86ed0634a..6f2f70a9e2b1a259c6cdf3631095aa478e1114c9 100644 --- a/xmpp/src/lib.rs +++ b/xmpp/src/lib.rs @@ -65,6 +65,7 @@ use parsers::message::Id as MessageId; pub mod agent; pub mod builder; +pub mod config; pub mod delay; pub mod disco; pub mod event; @@ -79,6 +80,7 @@ pub mod upload; pub use agent::Agent; pub use builder::{ClientBuilder, ClientType}; +pub use config::Config; pub use event::Event; pub use feature::ClientFeature; diff --git a/xmpp/src/pubsub/mod.rs b/xmpp/src/pubsub/mod.rs index 7718b7befee016e38963b5d8ad68c19463871c88..e18523c068b49987995a86306290b4f9a01786fe 100644 --- a/xmpp/src/pubsub/mod.rs +++ b/xmpp/src/pubsub/mod.rs @@ -66,18 +66,22 @@ pub(crate) async fn handle_event( status: None, }) .await; + } else { + if agent.config.read().await.bookmarks_autojoin { + // So maybe another client of ours left the room... let's leave it too + agent.leave_room(LeaveRoomSettings::new(jid)).await; + } } - } else { - // So maybe another client of ours left the room... let's leave it too - agent.leave_room(LeaveRoomSettings::new(jid)).await; } } Err(err) => println!("not bookmark: {}", err), } } else if let [item] = &retracted[..] { - let jid = BareJid::from_str(&item.0).unwrap(); + if agent.config.read().await.bookmarks_autojoin { + let jid = BareJid::from_str(&item.0).unwrap(); - agent.leave_room(LeaveRoomSettings::new(jid)).await; + agent.leave_room(LeaveRoomSettings::new(jid)).await; + } } else { error!("No published or retracted item in pubsub event!"); } @@ -146,8 +150,10 @@ pub(crate) async fn handle_iq_result( .await; } } else { - // Leave the room that is no longer autojoin - agent.leave_room(LeaveRoomSettings::new(jid)).await; + if agent.config.read().await.bookmarks_autojoin { + // Leave the room that is no longer autojoin + agent.leave_room(LeaveRoomSettings::new(jid)).await; + } } } Err(err) => { @@ -156,16 +162,18 @@ pub(crate) async fn handle_iq_result( } } - // Now we leave the rooms that are no longer in the bookmarks - let mut rooms_to_leave: Vec = Vec::new(); - for (room, _nick) in &agent.rooms_joined { - if !new_room_list.contains(&room) { - rooms_to_leave.push(room.clone()); + if agent.config.read().await.bookmarks_autojoin { + // Now we leave the rooms that are no longer in the bookmarks + let mut rooms_to_leave: Vec = Vec::new(); + for (room, _nick) in &agent.rooms_joined { + if !new_room_list.contains(&room) { + rooms_to_leave.push(room.clone()); + } } - } - for room in rooms_to_leave { - agent.leave_room(LeaveRoomSettings::new(room)).await; + for room in rooms_to_leave { + agent.leave_room(LeaveRoomSettings::new(room)).await; + } } } _ => unimplemented!(),