abridged/src/bridge_irc/mod.rs

68 lines
1.8 KiB
Rust

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<String>,
}
impl IrcTask {
pub fn new(config: IrcConfig, channels: Linkmap<String>) -> 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()),
}
};
}
}
}