cusku/src/bot.rs
pep e064263f96 Cleanly shutdown on ctrl_c
Signed-off-by: pep <pep@bouah.net>
2025-05-03 17:46:29 +02:00

126 lines
3.1 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,
};
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 agent = ClientBuilder::new(jid, password)
.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?)
}
}