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}, }; pub struct Bridgers { pub db: Db, pub discord: Mutex>>, pub matrix: Mutex>>, } impl Bridgers { pub fn new() -> Self { let db = sled::open("data/phoebe.sled").expect("Failed to open database"); Self { db, discord: Mutex::new(RefCell::new(None)), matrix: Mutex::new(RefCell::new(None)), } } 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, _) => { 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(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, } } fn get_related_messages(&self, source: &MessageReference) -> Option> { let message_relations = self .db .open_tree("message_relations") .expect("Failed to open relations tree"); let key = bincode::serialize(source).expect("Failed to serialize message reference"); message_relations .get(key) .expect("Failed to retrieve message references") .map(|r| { bincode::deserialize::>(&r) .expect("Failed to deserialize message references") }) } fn get_related_discord_message(&self, source: &MessageReference) -> Option<(u64, u64)> { if let MessageReference::Discord(channel_id, message_id) = source { return Some((*channel_id, *message_id)); } if let Some(relations) = self.get_related_messages(source) { for relation in relations { if let MessageReference::Discord(channel_id, message_id) = relation { return Some((channel_id, message_id)); } } } None } fn get_related_matrix_message(&self, source: &MessageReference) -> Option<(String, String)> { if let MessageReference::Matrix(room_id, event_id) = source { return Some((room_id.to_string(), event_id.to_string())); } if let Some(relations) = self.get_related_messages(source) { for relation in relations { if let MessageReference::Matrix(room_id, event_id) = relation { return Some((room_id, event_id)); } } } 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()]; if let Some(discord) = self.discord.lock().unwrap().borrow().as_ref() { if let Some(channel) = self.get_linked_discord_channel(&message.source) { let reply = message .replies_to .as_ref() .and_then(|r| self.get_related_discord_message(r)); if let Some(m) = forward_to_discord(discord, channel, &message, reply).await { related_messages.push(m); } } } if let Some(matrix) = self.matrix.lock().unwrap().borrow().as_ref() { if let Some(room_id) = self.get_linked_matrix_room(&message.source) { let reply = message .replies_to .as_ref() .and_then(|r| self.get_related_matrix_message(r)); if let Some(m) = forward_to_matrix(matrix, room_id, &message, reply).await { related_messages.push(m); } } } 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 key = bincode::serialize(source).expect("Failed to serialize message reference"); let value = bincode::serialize(&relations).expect("Failed to serialize message relations"); tree.insert(key, value) .expect("Failed to store message relations"); } related_messages } }