phoebe/src/bridgers.rs

208 lines
7.3 KiB
Rust

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<RefCell<Option<discord::Context>>>,
pub matrix: Mutex<RefCell<Option<matrix::Client>>>,
}
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<discord::ChannelId> {
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::<u64>(&bytes).unwrap())
.map(discord::ChannelId)
}
_ => None,
}
}
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 {
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::<String>(&bytes).unwrap())
.as_deref()
.map(matrix::RoomId::from_str)
.map(Result::unwrap)
}
_ => None,
}
}
fn get_related_messages(&self, source: &MessageReference) -> Option<Vec<MessageReference>> {
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::<Vec<MessageReference>>(&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::<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> {
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::<Vec<_>>();
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
}
}