cusku/src/bot.rs
pep eb0b7ff020
Don't follow bookmarks autojoin config
If this flag is enabled, the library expects bookmarks to be added to
the account itself, and when there's no bookmark for a room, the
corresponding room is automatically left. This doesn't work in the case
where many instances of the bot are on the same account.

It may work in the future if support for various sets of rooms/hooks are
added, but for the moment it seemed easier (and maybe also more useful
for other users of the xmpp-rs lib) to implement this.

Signed-off-by: pep <pep@bouah.net>
2025-11-15 22:00:26 +01:00

131 lines
3.3 KiB
Rust

// Copyright (C) 2023-2099 The crate authors.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU Affero General Public License as published by the
// Free Software Foundation, either version 3 of the License, or (at your
// option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
// for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::hooks::{format_hook, Hook};
use crate::Error;
use log::debug;
use tokio::{signal::ctrl_c, sync::mpsc};
use xmpp::jid::{BareJid, Jid, ResourcePart};
use xmpp::parsers::message::MessageType;
use xmpp::{
message::send::RawMessageSettings, muc::room::JoinRoomSettings, Agent, ClientBuilder,
ClientFeature, ClientType, Event, RoomNick, Config as AgentConfig,
};
pub struct XmppClient {
is_online: bool,
agent: Agent,
rooms: Vec<BareJid>,
nickname: ResourcePart,
}
impl XmppClient {
pub fn new(
jid: BareJid,
password: &str,
rooms: Vec<BareJid>,
nickname: ResourcePart,
) -> XmppClient {
let config = AgentConfig {
bookmarks_autojoin: false,
..AgentConfig::default()
};
let agent = ClientBuilder::new(jid, password)
.set_config(config)
.set_client(ClientType::Bot, "xmpp-rs")
.set_website("https://gitlab.com/xmpp-rs/xmpp-rs")
.set_default_nick(&nickname)
.enable_feature(ClientFeature::JoinRooms)
.build();
XmppClient {
is_online: false,
agent,
rooms,
nickname,
}
}
pub async fn next(&mut self) {
for event in self.agent.wait_for_events().await {
match event {
Event::Online => {
self.is_online = true;
debug!("XMPP Online");
for room in &self.rooms {
self.agent
.join_room(JoinRoomSettings {
room: room.clone(),
nick: Some(RoomNick::from_resource_ref(self.nickname.as_ref())),
password: None,
status: Some(("en", "Hi there!")),
})
.await
}
}
Event::Disconnected(e) => {
self.is_online = false;
debug!("XMPP Disconnected: {e}");
}
_ => {
debug!("XMPP Event not supported")
}
}
}
}
pub async fn receive(&mut self, mut rx: mpsc::UnboundedReceiver<Hook>) {
loop {
tokio::select! {
_ = ctrl_c() => {
return; // Disconnecting
},
_ = self.next() => (),
wh = rx.recv() => {
if let Some(hook) = wh {
debug!("XMPP Bot Received Hook");
self.hook(hook).await
}
}
}
}
}
pub async fn hook(&mut self, wh: Hook) {
debug!("XMPP Bot Processing Hook");
if let Some(display) = format_hook(&wh) {
debug!("Hook: {}", display);
for room in &self.rooms {
self.agent
.send_raw_message(RawMessageSettings {
recipient: Jid::from(room.clone()),
message_type: MessageType::Groupchat,
message: &display,
lang: Some("en"),
payloads: Vec::new(),
})
.await
}
debug!("XMPP Bot Processed Hook");
}
}
pub async fn disconnect(self) -> Result<(), Error> {
log::info!("Disconnecting...");
Ok(self.agent.disconnect().await?)
}
}