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
legacy
Charlotte Som 2021-09-13 04:20:49 +01:00
parent fee137f947
commit f8ab672453
5 changed files with 114 additions and 16 deletions

View File

@ -3,6 +3,7 @@ use std::{cell::RefCell, str::FromStr, sync::Mutex};
use sled::Db; use sled::Db;
use crate::{ use crate::{
channels::ChannelReference,
discord::{self, forward_to_discord}, discord::{self, forward_to_discord},
matrix::{self, forward_to_matrix}, matrix::{self, forward_to_matrix},
messages::{MessageReference, SentMessage}, messages::{MessageReference, SentMessage},
@ -26,25 +27,85 @@ impl Bridgers {
} }
fn get_linked_discord_channel(&self, source: &MessageReference) -> Option<discord::ChannelId> { fn get_linked_discord_channel(&self, source: &MessageReference) -> Option<discord::ChannelId> {
let discord_channels = self
.db
.open_tree("discord_channels")
.expect("Failed to open discord channels tree");
match source { match source {
MessageReference::Matrix(_room_id, _event_id) => { MessageReference::Matrix(room_id, _) => {
// TODO: Look up the linked channel let channel_ref = ChannelReference::Matrix(room_id.to_string());
Some(discord::ChannelId(885690775193661463)) let channel_ref = bincode::serialize(&channel_ref).unwrap();
discord_channels
.get(channel_ref)
.unwrap()
.map(|bytes| bincode::deserialize::<u64>(&bytes).unwrap())
.map(discord::ChannelId)
} }
_ => None, _ => None,
} }
} }
fn get_linked_matrix_room(&self, source: &MessageReference) -> Option<matrix::RoomId> { fn get_linked_matrix_room(&self, source: &MessageReference) -> Option<matrix::RoomId> {
let matrix_channels = self
.db
.open_tree("matrix_channels")
.expect("Failed to open matrix channels tree");
match source { match source {
MessageReference::Discord(_, _) => { MessageReference::Discord(channel_id, _) => {
// TODO: Look up the linked channel let channel_ref = ChannelReference::Discord(*channel_id);
Some(matrix::RoomId::from_str("!SjQatGOikRshcWNcln:matrix.org").unwrap()) let channel_ref = bincode::serialize(&channel_ref).unwrap();
matrix_channels
.get(channel_ref)
.unwrap()
.map(|bytes| bincode::deserialize::<String>(&bytes).unwrap())
.as_deref()
.map(matrix::RoomId::from_str)
.map(Result::unwrap)
} }
_ => None, _ => 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::<Vec<_>>();
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<MessageReference> { pub async fn send_message(&self, message: SentMessage) -> Vec<MessageReference> {
let mut related_messages = vec![message.source.clone()]; 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() { for source in related_messages.iter() {
let relations = related_messages let relations = related_messages
.iter() .iter()
.filter(|r| r != &source) .filter(|r| r != &source)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let tree = self
.db
.open_tree("message_relations")
.expect("Failed to open relations tree");
tree.insert( tree.insert(
bincode::serialize(source).expect("Failed to serialize message reference"), bincode::serialize(source).expect("Failed to serialize message reference"),
bincode::serialize(&relations).expect("Failed to serialize message relations"), bincode::serialize(&relations).expect("Failed to serialize message relations"),

7
src/channels.rs Normal file
View File

@ -0,0 +1,7 @@
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, Clone, PartialEq)]
pub enum ChannelReference {
Discord(u64),
Matrix(String),
}

View File

@ -3,6 +3,7 @@ use serenity::{async_trait, model::prelude::*, prelude::*};
use tokio::sync::mpsc; use tokio::sync::mpsc;
use crate::{ use crate::{
channels::ChannelReference,
message_ast::{self, format_discord}, message_ast::{self, format_discord},
messages::{MessageAuthor, MessageEvent, MessageReference, SentMessage}, messages::{MessageAuthor, MessageEvent, MessageReference, SentMessage},
}; };
@ -18,7 +19,7 @@ impl From<&Message> for MessageReference {
struct DiscordHandler { struct DiscordHandler {
ctx_tx: mpsc::UnboundedSender<Context>, ctx_tx: mpsc::UnboundedSender<Context>,
message_tx: mpsc::UnboundedSender<MessageEvent>, event_tx: mpsc::UnboundedSender<MessageEvent>,
} }
#[async_trait] #[async_trait]
@ -35,12 +36,33 @@ impl EventHandler for DiscordHandler {
return; 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 message_ref = MessageReference::from(&message);
let content = discord_message_format::parse(&message.content); let content = discord_message_format::parse(&message.content);
let content = message_ast::convert_discord(&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, source: message_ref,
content, content,
author: MessageAuthor { author: MessageAuthor {
@ -73,7 +95,10 @@ pub async fn create_discord_client(
message_tx: mpsc::UnboundedSender<MessageEvent>, message_tx: mpsc::UnboundedSender<MessageEvent>,
token: &str, token: &str,
) -> Client { ) -> Client {
let handler = DiscordHandler { ctx_tx, message_tx }; let handler = DiscordHandler {
ctx_tx,
event_tx: message_tx,
};
info!("Discord logging in…"); info!("Discord logging in…");
let client = Client::builder(token) let client = Client::builder(token)

View File

@ -4,6 +4,7 @@ use discord::create_discord_client;
use matrix::create_matrix_client; use matrix::create_matrix_client;
mod bridgers; mod bridgers;
mod channels;
mod message_ast; mod message_ast;
mod messages; mod messages;
@ -89,9 +90,12 @@ async fn main() {
MessageEvent::Send(sent_message) => { MessageEvent::Send(sent_message) => {
let _ = bridgers.send_message(sent_message).await; let _ = bridgers.send_message(sent_message).await;
} }
MessageEvent::Edit(edited_message) => { MessageEvent::Edit(_edited_message) => {
todo!(); todo!();
} }
MessageEvent::AdminLinkChannels(channels) => {
bridgers.link_channels(&channels);
}
} }
} }
} }

View File

@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::message_ast::MessageContent; use crate::{channels::ChannelReference, message_ast::MessageContent};
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] #[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
pub enum MessageReference { pub enum MessageReference {
@ -25,6 +25,7 @@ pub struct EditedMessage {
} }
pub enum MessageEvent { pub enum MessageEvent {
AdminLinkChannels(Vec<ChannelReference>),
Send(SentMessage), Send(SentMessage),
Edit(EditedMessage), Edit(EditedMessage),
} }