110 lines
2.8 KiB
Rust
110 lines
2.8 KiB
Rust
use std::sync::Arc;
|
|
|
|
use async_trait::async_trait;
|
|
use log::{info, debug};
|
|
use serde::Deserialize;
|
|
use serenity::{prelude::*, model::prelude::*, http::Http};
|
|
|
|
use crate::{linkmap::Linkmap, supervisor::{Task, TaskResult, Id, Sender, Receiver}};
|
|
use crate::supervisor::Message as BMessage;
|
|
|
|
use super::DiscordConfig;
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct DiscordTask {
|
|
config: DiscordConfig,
|
|
links: Arc<Linkmap<ChannelId>>,
|
|
}
|
|
|
|
#[async_trait]
|
|
impl Task for DiscordTask {
|
|
async fn start(&self, id: Id, tx: Sender, mut rx: Receiver) -> TaskResult {
|
|
let handler = Handler {
|
|
links: self.links.clone(),
|
|
tx,
|
|
id,
|
|
};
|
|
|
|
let intents = GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT;
|
|
|
|
debug!("{id}: building Discord client");
|
|
let mut client = Client::builder(&self.config.token, intents)
|
|
.event_handler(handler)
|
|
.await?;
|
|
|
|
let http = client.cache_and_http.http.clone();
|
|
|
|
let bridge_handler = async move {
|
|
loop {
|
|
let msg = rx.recv().await?;
|
|
self.handle_bridge_msg(msg, id, http.as_ref()).await?;
|
|
}
|
|
};
|
|
|
|
debug!("{id}: entering event loop");
|
|
tokio::select! {
|
|
result = bridge_handler => result,
|
|
result = client.start() => result.map_err(|e| e.into()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DiscordTask {
|
|
async fn handle_bridge_msg(&self, msg: BMessage, id: Id, http: &Http) -> TaskResult {
|
|
let content = format!("<{}> {}", msg.author, msg.content);
|
|
|
|
for channel in self.links.get_channels(&msg.link) {
|
|
if msg.origin.0 == id && msg.origin.1 == channel.to_string() {
|
|
continue
|
|
}
|
|
|
|
debug!("{id}: bridging message from {:?}/{:?} to {channel:?}", msg.origin, msg.link);
|
|
if let Some(hook) = self.config.webhooks.get(channel) {
|
|
let hook = http.get_webhook(*hook.as_u64()).await?;
|
|
hook.execute(http, false, |hook| {
|
|
hook.username(&msg.author)
|
|
.content(&msg.content)
|
|
.avatar_url(msg.avatar.as_ref().map(|s| s.as_str()).unwrap_or(""))
|
|
}).await?;
|
|
} else {
|
|
channel.say(http, &content).await?;
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
struct Handler {
|
|
id: Id,
|
|
links: Arc<Linkmap<ChannelId>>,
|
|
tx: Sender,
|
|
}
|
|
|
|
#[async_trait]
|
|
impl EventHandler for Handler {
|
|
async fn message(&self, ctx: Context, msg: Message) {
|
|
if msg.author.bot {
|
|
return
|
|
}
|
|
|
|
let avatar = msg.author.avatar_url();
|
|
let Some(link) = self.links.get_link(&msg.channel_id) else { return };
|
|
let author = msg.author.nick_in(ctx.http, msg.guild_id.expect("failed to get guild ID"))
|
|
.await.unwrap_or(msg.author.name);
|
|
|
|
debug!("{}: broadcasting message from {:?} to {:?}", self.id, msg.channel_id, link);
|
|
|
|
self.tx.send(BMessage {
|
|
origin: (self.id, msg.channel_id.to_string()),
|
|
link: link.clone(),
|
|
author,
|
|
content: msg.content,
|
|
avatar,
|
|
}).expect("failed to broadcast message");
|
|
}
|
|
|
|
async fn ready(&self, _: Context, _: Ready) {
|
|
info!("{}: ready", self.id);
|
|
}
|
|
}
|