From f8ab67245342ccf808cf43170c019a2a53292336 Mon Sep 17 00:00:00 2001 From: videogame hacker Date: Mon, 13 Sep 2021 04:20:49 +0100 Subject: [PATCH] Look up linked channels in the database We also have a Discord convenience command that lets you link to a Matrix room as long as you have a 'Phoebe' role --- src/bridgers.rs | 83 ++++++++++++++++++++++++++++++++++++++++++------- src/channels.rs | 7 +++++ src/discord.rs | 31 ++++++++++++++++-- src/main.rs | 6 +++- src/messages.rs | 3 +- 5 files changed, 114 insertions(+), 16 deletions(-) create mode 100644 src/channels.rs diff --git a/src/bridgers.rs b/src/bridgers.rs index 11b71ab..9843ed3 100644 --- a/src/bridgers.rs +++ b/src/bridgers.rs @@ -3,6 +3,7 @@ use std::{cell::RefCell, str::FromStr, sync::Mutex}; use sled::Db; use crate::{ + channels::ChannelReference, discord::{self, forward_to_discord}, matrix::{self, forward_to_matrix}, messages::{MessageReference, SentMessage}, @@ -26,25 +27,85 @@ impl Bridgers { } fn get_linked_discord_channel(&self, source: &MessageReference) -> Option { + let discord_channels = self + .db + .open_tree("discord_channels") + .expect("Failed to open discord channels tree"); + match source { - MessageReference::Matrix(_room_id, _event_id) => { - // TODO: Look up the linked channel - Some(discord::ChannelId(885690775193661463)) + MessageReference::Matrix(room_id, _) => { + let channel_ref = ChannelReference::Matrix(room_id.to_string()); + let channel_ref = bincode::serialize(&channel_ref).unwrap(); + + discord_channels + .get(channel_ref) + .unwrap() + .map(|bytes| bincode::deserialize::(&bytes).unwrap()) + .map(discord::ChannelId) } _ => None, } } fn get_linked_matrix_room(&self, source: &MessageReference) -> Option { + let matrix_channels = self + .db + .open_tree("matrix_channels") + .expect("Failed to open matrix channels tree"); + match source { - MessageReference::Discord(_, _) => { - // TODO: Look up the linked channel - Some(matrix::RoomId::from_str("!SjQatGOikRshcWNcln:matrix.org").unwrap()) + MessageReference::Discord(channel_id, _) => { + let channel_ref = ChannelReference::Discord(*channel_id); + let channel_ref = bincode::serialize(&channel_ref).unwrap(); + + matrix_channels + .get(channel_ref) + .unwrap() + .map(|bytes| bincode::deserialize::(&bytes).unwrap()) + .as_deref() + .map(matrix::RoomId::from_str) + .map(Result::unwrap) } _ => None, } } + pub fn link_channels(&self, channels: &[ChannelReference]) { + let discord_channels = self + .db + .open_tree("discord_channels") + .expect("Failed to open discord channels tree"); + + let matrix_channels = self + .db + .open_tree("matrix_channels") + .expect("Failed to open matrix channels tree"); + + for channel in channels.iter() { + let other_channels = channels + .iter() + .filter(|r| r != &channel) + .collect::>(); + + match channel { + ChannelReference::Discord(channel_id) => { + for other_channel in other_channels { + let key = bincode::serialize(other_channel).unwrap(); + let value = bincode::serialize(channel_id).unwrap(); + discord_channels.insert(key, value).unwrap(); + } + } + ChannelReference::Matrix(room_id) => { + for other_channel in other_channels { + let key = bincode::serialize(other_channel).unwrap(); + let value = bincode::serialize(room_id.as_str()).unwrap(); + matrix_channels.insert(key, value).unwrap(); + } + } + } + } + } + pub async fn send_message(&self, message: SentMessage) -> Vec { let mut related_messages = vec![message.source.clone()]; @@ -64,17 +125,17 @@ impl Bridgers { } } + let tree = self + .db + .open_tree("message_relations") + .expect("Failed to open relations tree"); + for source in related_messages.iter() { let relations = related_messages .iter() .filter(|r| r != &source) .collect::>(); - let tree = self - .db - .open_tree("message_relations") - .expect("Failed to open relations tree"); - tree.insert( bincode::serialize(source).expect("Failed to serialize message reference"), bincode::serialize(&relations).expect("Failed to serialize message relations"), diff --git a/src/channels.rs b/src/channels.rs new file mode 100644 index 0000000..93d2f0d --- /dev/null +++ b/src/channels.rs @@ -0,0 +1,7 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize, Clone, PartialEq)] +pub enum ChannelReference { + Discord(u64), + Matrix(String), +} diff --git a/src/discord.rs b/src/discord.rs index 71603b3..7f2c96d 100644 --- a/src/discord.rs +++ b/src/discord.rs @@ -3,6 +3,7 @@ use serenity::{async_trait, model::prelude::*, prelude::*}; use tokio::sync::mpsc; use crate::{ + channels::ChannelReference, message_ast::{self, format_discord}, messages::{MessageAuthor, MessageEvent, MessageReference, SentMessage}, }; @@ -18,7 +19,7 @@ impl From<&Message> for MessageReference { struct DiscordHandler { ctx_tx: mpsc::UnboundedSender, - message_tx: mpsc::UnboundedSender, + event_tx: mpsc::UnboundedSender, } #[async_trait] @@ -35,12 +36,33 @@ impl EventHandler for DiscordHandler { return; } + if let Some(target) = message.content.strip_prefix("phoebe!link ") { + if message + .member(&ctx) + .await + .unwrap() + .roles(&ctx) + .await + .unwrap() + .iter() + .any(|r| r.name == "Phoebe") + { + let _ = self.event_tx.send(MessageEvent::AdminLinkChannels(vec![ + ChannelReference::Discord(message.channel_id.0), + ChannelReference::Matrix(target.to_string()), + ])); + + message.reply(&ctx, "Linking with matrix.").await.unwrap(); + return; + } + } + let message_ref = MessageReference::from(&message); let content = discord_message_format::parse(&message.content); let content = message_ast::convert_discord(&content); - let _ = self.message_tx.send(MessageEvent::Send(SentMessage { + let _ = self.event_tx.send(MessageEvent::Send(SentMessage { source: message_ref, content, author: MessageAuthor { @@ -73,7 +95,10 @@ pub async fn create_discord_client( message_tx: mpsc::UnboundedSender, token: &str, ) -> Client { - let handler = DiscordHandler { ctx_tx, message_tx }; + let handler = DiscordHandler { + ctx_tx, + event_tx: message_tx, + }; info!("Discord logging in…"); let client = Client::builder(token) diff --git a/src/main.rs b/src/main.rs index 02b7267..cd70135 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ use discord::create_discord_client; use matrix::create_matrix_client; mod bridgers; +mod channels; mod message_ast; mod messages; @@ -89,9 +90,12 @@ async fn main() { MessageEvent::Send(sent_message) => { let _ = bridgers.send_message(sent_message).await; } - MessageEvent::Edit(edited_message) => { + MessageEvent::Edit(_edited_message) => { todo!(); } + MessageEvent::AdminLinkChannels(channels) => { + bridgers.link_channels(&channels); + } } } } diff --git a/src/messages.rs b/src/messages.rs index 0e7741c..cf02e43 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -use crate::message_ast::MessageContent; +use crate::{channels::ChannelReference, message_ast::MessageContent}; #[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] pub enum MessageReference { @@ -25,6 +25,7 @@ pub struct EditedMessage { } pub enum MessageEvent { + AdminLinkChannels(Vec), Send(SentMessage), Edit(EditedMessage), }