xmpp: new Config struct for Agent, with bookmarks_autojoin for now

Signed-off-by: pep <pep@bouah.net>
This commit is contained in:
pep 2025-11-13 20:23:45 +01:00
commit 147b79ca52
6 changed files with 84 additions and 18 deletions

View file

@ -43,6 +43,7 @@ XXXX-YY-ZZ [ RELEASER <admin@localhost> ]
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

View file

@ -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<RwLock<Config>>,
pub(crate) default_nick: Arc<RwLock<RoomNick>>,
pub(crate) lang: Arc<Vec<String>>,
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<String>,
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
}

View file

@ -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<String>,
@ -73,6 +74,7 @@ impl<C: ServerConnector> 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<C: ServerConnector> 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<C: ServerConnector> 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,
)
}
}

31
xmpp/src/config.rs Normal file
View file

@ -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.
/// <https://xmpp.org/extensions/xep-0402.html#notification>
pub bookmarks_autojoin: bool,
}
impl Default for Config {
fn default() -> Self {
Self::new()
}
}
impl Config {
fn new() -> Self {
Config {
bookmarks_autojoin: true,
}
}
}

View file

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

View file

@ -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<BareJid> = 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<BareJid> = 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!(),