Thumbnail

steew/belltoll.git

Clone URL: https://git.buni.party/steew/belltoll.git

commit 9abb3d5a58006d1edb28dd93751c29eabe09469d Author: Daniel <daniel@steew.eu> Date: Wed Jan 07 14:12:52 2026 +0000 Refactor and split in submodules diff --git a/src/main.rs b/src/main.rs index 05aeb81..e559a45 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1201 +121 @@ -use std::collections::HashMap; -use std::collections::VecDeque;  use std::str::FromStr;  use std::sync::Arc;   -use futures_util::StreamExt;  use ini::Ini; -use irc::client::Sender;  use irc::client::data::Config; -use irc::proto::Command;  use serenity::all::ChannelId; -use serenity::all::ExecuteWebhook; -use serenity::all::Http; -use serenity::all::Message; -use serenity::all::Ready;  use serenity::all::Webhook; -use serenity::async_trait;  use serenity::prelude::*;  use tokio::spawn; -use tokio::sync::Notify;   -#[derive(Debug)] -enum RelayDirection { - INVALID, - IRC2DIS(String), - DIS2IRC(ChannelId), -} - -struct RelayMessage { - contents: String, - direction: RelayDirection, - author: String, -} - -struct MessageBuffer { - pending_relay_messages: VecDeque<RelayMessage>, -} - -struct RelayNotify { - notify: Notify, -} - -impl Default for RelayNotify { - fn default() -> Self { - RelayNotify { - notify: Notify::new(), - } - } -} - -struct RelayAssoc { - // stores the Discord - IRC channel bridge associations - bridge_assoc: HashMap<ChannelId, Vec<String>>, - // stores the webhook URL for the discord channels - chid_webhook_assoc: HashMap<ChannelId, String>, -} +mod relay; +mod relay_discord; +mod relay_irc;   -impl Default for RelayAssoc { - fn default() -> Self { - RelayAssoc { - bridge_assoc: HashMap::new(), - chid_webhook_assoc: HashMap::new() - } - } -} - -impl Default for RelayMessage { - fn default() -> Self { - RelayMessage { - contents: String::new(), - direction: RelayDirection::INVALID, - author: String::new() - } - } -} - -impl Default for MessageBuffer { - fn default() -> Self { - MessageBuffer { - pending_relay_messages: VecDeque::new(), - } - } -} - -impl TypeMapKey for MessageBuffer { - type Value = Arc<RwLock<MessageBuffer>>; -} +use relay::*; +use relay_discord::*; +use relay_irc::*;   -impl TypeMapKey for RelayNotify { - type Value = Arc<RelayNotify>; -} - -struct Handler; - -#[async_trait] -impl EventHandler for Handler { - async fn message(&self, ctx: Context, msg: Message) { - // open the shared lock as write - let data = ctx.data.read().await; - let buffer_lock = data.get::<MessageBuffer>().unwrap().clone(); - - if msg.author.bot { - return; - }; - - { - let mut relay_buffer = buffer_lock.write().await; - // create a new message with the received discord message contents - let mut new_message = RelayMessage::default(); - new_message.contents = msg.content; - new_message.direction = RelayDirection::DIS2IRC(msg.channel_id); - new_message.author = msg.author.name; - // push the pending message to the relay buffer - relay_buffer.pending_relay_messages.push_back(new_message); - } - println!("Added discord message to buffer."); - { - let notify = data.get::<RelayNotify>().unwrap().clone(); - notify.notify.notify_one(); - } - } - - async fn ready(&self, _: Context, ready: Ready) { - println!("{} is connected!", ready.user.name); - } -} - -async fn relay_consumer( - buffer: Arc<RwLock<MessageBuffer>>, - notify: Arc<RelayNotify>, - http: Arc<Http>, - webhook: Webhook, - sender: Sender, - assoc: RelayAssoc -) { - loop { - // await for new relay pending events - notify.notify.notified().await; - let pending: RelayMessage; - { - let mut buffer_lock = buffer.write().await; - pending = buffer_lock.pending_relay_messages.pop_front().unwrap(); - } - println!( - "Received message to relay: {}, {:?}", - pending.contents, pending.direction - ); - match pending.direction { - RelayDirection::IRC2DIS(chan) => { - // let chanid = ChannelId::new(591954698664149044); - // chanid.say(http.clone(), pending.contents).await.unwrap(); - let builder = ExecuteWebhook::new().content(pending.contents).username(pending.author); - webhook.execute(&http, false, builder).await.expect("Could not execute webhook."); - } - RelayDirection::DIS2IRC(chan) => { - let unpingable_name = pending.author.clone(); - let (first, rest) = unpingable_name.split_at(1); - let mut unpingable_name = String::new(); - unpingable_name.push_str(first); - unpingable_name.push_str("​"); - unpingable_name.push_str(rest); - - let response = format!("<{}>: {}", unpingable_name, pending.contents); - sender.send_privmsg("##steew", response).unwrap(); - } - _ => {} - } - } -} - -async fn irc_producer( - mut irc_client: irc::client::Client, - buffer_reference: Arc<RwLock<MessageBuffer>>, - notify: Arc<RelayNotify> -) { - let mut irc_stream: irc::client::ClientStream = irc_client.stream().unwrap(); - - while let Ok(Some(message)) = irc_stream.next().await.transpose() { - let msg_clone = message.clone(); - match message.command { - Command::PRIVMSG(_, contents) => { - { - let uname = msg_clone.source_nickname().unwrap(); - let mut buffer = buffer_reference.write().await; - let mut new_message = RelayMessage::default(); - new_message.contents = contents; - new_message.direction = RelayDirection::IRC2DIS(String::from_str(msg_clone.response_target().unwrap()).unwrap()); - new_message.author.push_str(uname); - buffer.pending_relay_messages.push_back(new_message); - notify.notify.notify_one(); - } - println!("Added IRC message to buffer"); - } - _ => {} - } - } - -}  #[tokio::main]  async fn main() { // Shared data initialization diff --git a/src/relay.rs b/src/relay.rs new file mode 100644 index 0000000..b6ebad5 --- /dev/null +++ b/src/relay.rs @@ -00 +1127 @@ +use std::collections::HashMap; +use std::collections::VecDeque; +use std::sync::Arc; + +use irc::client::Sender; +use serenity::all::ChannelId; +use serenity::all::ExecuteWebhook; +use serenity::all::Http; +use serenity::all::Webhook; +use serenity::prelude::*; +use tokio::sync::Notify; + +#[derive(Debug)] +pub enum RelayDirection { + INVALID, + IRC2DIS(String), + DIS2IRC(ChannelId), +} + +pub struct RelayMessage { + pub contents: String, + pub direction: RelayDirection, + pub author: String, +} + +pub struct MessageBuffer { + pub pending_relay_messages: VecDeque<RelayMessage>, +} + +pub struct RelayNotify { + pub notify: Notify, +} + +impl Default for RelayNotify { + fn default() -> Self { + RelayNotify { + notify: Notify::new(), + } + } +} + +pub struct RelayAssoc { + // stores the Discord - IRC channel bridge associations + pub bridge_assoc: HashMap<ChannelId, Vec<String>>, + // stores the webhook URL for the discord channels + pub chid_webhook_assoc: HashMap<ChannelId, String>, +} + +impl Default for RelayAssoc { + fn default() -> Self { + RelayAssoc { + bridge_assoc: HashMap::new(), + chid_webhook_assoc: HashMap::new() + } + } +} + +impl Default for RelayMessage { + fn default() -> Self { + RelayMessage { + contents: String::new(), + direction: RelayDirection::INVALID, + author: String::new() + } + } +} + +impl Default for MessageBuffer { + fn default() -> Self { + MessageBuffer { + pending_relay_messages: VecDeque::new(), + } + } +} + +impl TypeMapKey for MessageBuffer { + type Value = Arc<RwLock<MessageBuffer>>; +} + +impl TypeMapKey for RelayNotify { + type Value = Arc<RelayNotify>; +} + + +pub async fn relay_consumer( + buffer: Arc<RwLock<MessageBuffer>>, + notify: Arc<RelayNotify>, + http: Arc<Http>, + webhook: Webhook, + sender: Sender, + assoc: RelayAssoc +) { + loop { + // await for new relay pending events + notify.notify.notified().await; + let pending: RelayMessage; + { + let mut buffer_lock = buffer.write().await; + pending = buffer_lock.pending_relay_messages.pop_front().unwrap(); + } + println!( + "Received message to relay: {}, {:?}", + pending.contents, pending.direction + ); + match pending.direction { + RelayDirection::IRC2DIS(chan) => { + // let chanid = ChannelId::new(591954698664149044); + // chanid.say(http.clone(), pending.contents).await.unwrap(); + let builder = ExecuteWebhook::new().content(pending.contents).username(pending.author); + webhook.execute(&http, false, builder).await.expect("Could not execute webhook."); + } + RelayDirection::DIS2IRC(chan) => { + let unpingable_name = pending.author.clone(); + let (first, rest) = unpingable_name.split_at(1); + let mut unpingable_name = String::new(); + unpingable_name.push_str(first); + unpingable_name.push_str("​"); + unpingable_name.push_str(rest); + + let response = format!("<{}>: {}", unpingable_name, pending.contents); + sender.send_privmsg("##steew", response).unwrap(); + } + _ => {} + } + } +} + diff --git a/src/relay_discord.rs b/src/relay_discord.rs new file mode 100644 index 0000000..1afabb2 --- /dev/null +++ b/src/relay_discord.rs @@ -00 +142 @@ +use serenity::all::Message; +use serenity::all::Ready; +use serenity::async_trait; +use serenity::prelude::*; + +use crate::relay::*; + +pub struct Handler; + +#[async_trait] +impl EventHandler for Handler { + async fn message(&self, ctx: Context, msg: Message) { + // open the shared lock as write + let data = ctx.data.read().await; + let buffer_lock = data.get::<MessageBuffer>().unwrap().clone(); + + if msg.author.bot { + return; + }; + + { + let mut relay_buffer = buffer_lock.write().await; + // create a new message with the received discord message contents + let mut new_message = RelayMessage::default(); + new_message.contents = msg.content; + new_message.direction = RelayDirection::DIS2IRC(msg.channel_id); + new_message.author = msg.author.name; + // push the pending message to the relay buffer + relay_buffer.pending_relay_messages.push_back(new_message); + } + println!("Added discord message to buffer."); + { + let notify = data.get::<RelayNotify>().unwrap().clone(); + notify.notify.notify_one(); + } + } + + async fn ready(&self, _: Context, ready: Ready) { + println!("{} is connected!", ready.user.name); + } +} + diff --git a/src/relay_irc.rs b/src/relay_irc.rs new file mode 100644 index 0000000..2129a0f --- /dev/null +++ b/src/relay_irc.rs @@ -00 +137 @@ +use std::str::FromStr; +use std::sync::Arc; + +use futures_util::StreamExt; +use irc::proto::Command; +use serenity::prelude::*; + +use crate::relay::*; + +pub async fn irc_producer( + mut irc_client: irc::client::Client, + buffer_reference: Arc<RwLock<MessageBuffer>>, + notify: Arc<RelayNotify> +) { + let mut irc_stream: irc::client::ClientStream = irc_client.stream().unwrap(); + + while let Ok(Some(message)) = irc_stream.next().await.transpose() { + let msg_clone = message.clone(); + match message.command { + Command::PRIVMSG(_, contents) => { + { + let uname = msg_clone.source_nickname().unwrap(); + let mut buffer = buffer_reference.write().await; + let mut new_message = RelayMessage::default(); + new_message.contents = contents; + new_message.direction = RelayDirection::IRC2DIS(String::from_str(msg_clone.response_target().unwrap()).unwrap()); + new_message.author.push_str(uname); + buffer.pending_relay_messages.push_back(new_message); + notify.notify.notify_one(); + } + println!("Added IRC message to buffer"); + } + _ => {} + } + } + +}