use async_trait::async_trait; use futures::StreamExt; use tokio::select; use irc::{client::Client, proto::Command}; use crate::linkmap::Linkmap; use crate::message::Id; use crate::{message::{Message, Sender, Receiver}, supervisor::{Task, TaskResult}}; use irc::proto::Message as IrcMessage; pub use irc::client::prelude::Config as IrcConfig; pub struct IrcTask { config: IrcConfig, channels: Linkmap, } impl IrcTask { pub fn new(config: IrcConfig, channels: Linkmap) -> Self { Self { config, channels } } async fn handle_bridge_msg(&self, id: Id, client: &mut Client, msg: Message) -> TaskResult { for channel in self.channels.get_channels(&msg.link) { if msg.origin.0 == id && &msg.origin.1 == channel { continue } client.send_privmsg(channel, format!("<{}> {}", msg.author, msg.content))?; } Ok(()) } async fn handle_irc_msg(&self, id: Id, tx: &mut Sender, msg: IrcMessage) -> TaskResult { if let Command::PRIVMSG(channel, message) = &msg.command { let Some(link) = self.channels.get_link(channel) else { return Ok(()) }; let Some(author) = msg.source_nickname() else { return Ok(()) }; tx.send(Message { origin: (id, channel.to_owned()), link: link.clone(), author: author.to_owned(), content: message.clone(), })?; } Ok(()) } } #[async_trait] impl Task for IrcTask { async fn start(&self, id: Id, mut tx: Sender, mut rx: Receiver) -> TaskResult { let mut client = Client::from_config(self.config.clone()).await?; client.identify()?; let mut stream = client.stream()?; loop { select! { bridge_msg = rx.recv() => self.handle_bridge_msg(id, &mut client, bridge_msg?).await?, irc_msg = stream.next() => match irc_msg { Some(msg) => self.handle_irc_msg(id, &mut tx, msg?).await?, None => return Err("Lost connection to IRC server".into()), } }; } } }