299 lines
12 KiB
Rust
299 lines
12 KiB
Rust
use std::{cell::RefCell, collections::HashSet, str::FromStr, sync::Mutex};
|
|
|
|
use sled::Db;
|
|
|
|
use crate::{
|
|
channels::ChannelReference,
|
|
discord::{self, delete_on_discord, edit_on_discord, forward_to_discord},
|
|
matrix::{self, delete_on_matrix, edit_on_matrix, forward_to_matrix},
|
|
messages::{DeletedMessage, EditedMessage, MessageReference, SentMediaMessage, 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<matrix::EventId> {
|
|
if let MessageReference::Matrix(_, event_id) = source {
|
|
return Some(matrix::EventId::from_str(event_id).unwrap());
|
|
}
|
|
|
|
if let Some(relations) = self.get_related_messages(source) {
|
|
for relation in relations {
|
|
if let MessageReference::Matrix(_, event_id) = relation {
|
|
return Some(matrix::EventId::from_str(&event_id).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::<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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn store_related_messages(&self, related_messages: &[MessageReference]) {
|
|
let tree = self
|
|
.db
|
|
.open_tree("message_relations")
|
|
.expect("Failed to open relations tree");
|
|
|
|
for source in related_messages {
|
|
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");
|
|
}
|
|
}
|
|
|
|
pub async fn send_message(&self, message: SentMessage) {
|
|
if self.get_related_messages(&message.source).is_some() {
|
|
return;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
self.store_related_messages(&related_messages);
|
|
}
|
|
|
|
pub async fn edit_message(&self, message: EditedMessage) {
|
|
if let Some(related_messages) = self.get_related_messages(&message.replacing) {
|
|
let mut new_related_messages = HashSet::new();
|
|
related_messages.iter().for_each(|r| {
|
|
new_related_messages.insert(r.clone());
|
|
});
|
|
|
|
for related_message in related_messages.iter() {
|
|
match related_message {
|
|
MessageReference::Discord(channel_id, message_id) => {
|
|
if let Some(discord) = self.discord.lock().unwrap().borrow().as_ref() {
|
|
let channel_id = discord::ChannelId(*channel_id);
|
|
let message_id = discord::MessageId(*message_id);
|
|
|
|
if let Some(m) =
|
|
edit_on_discord(discord, channel_id, message_id, &message).await
|
|
{
|
|
new_related_messages.insert(m);
|
|
}
|
|
}
|
|
}
|
|
MessageReference::Matrix(room_id, event_id) => {
|
|
if let Some(matrix) = self.matrix.lock().unwrap().borrow().as_ref() {
|
|
let room_id = matrix::RoomId::from_str(room_id).unwrap();
|
|
let event_id = matrix::EventId::from_str(event_id).unwrap();
|
|
|
|
if let Some(m) =
|
|
edit_on_matrix(matrix, room_id, event_id, &message).await
|
|
{
|
|
new_related_messages.insert(m);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
self.store_related_messages(&new_related_messages.into_iter().collect::<Vec<_>>())
|
|
}
|
|
}
|
|
|
|
pub async fn delete_message(&self, message: DeletedMessage) {
|
|
if let Some(related_messages) = self.get_related_messages(&message.reference) {
|
|
for related_message in related_messages.iter() {
|
|
match related_message {
|
|
MessageReference::Discord(channel_id, message_id) => {
|
|
if let Some(discord) = self.discord.lock().unwrap().borrow().as_ref() {
|
|
let channel_id = discord::ChannelId(*channel_id);
|
|
let message_id = discord::MessageId(*message_id);
|
|
|
|
let _success =
|
|
delete_on_discord(discord, channel_id, message_id, &message).await;
|
|
}
|
|
}
|
|
MessageReference::Matrix(room_id, event_id) => {
|
|
if let Some(matrix) = self.matrix.lock().unwrap().borrow().as_ref() {
|
|
let room_id = matrix::RoomId::from_str(room_id).unwrap();
|
|
let event_id = matrix::EventId::from_str(event_id).unwrap();
|
|
|
|
let _success =
|
|
delete_on_matrix(matrix, room_id, event_id, &message).await;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn send_media(&self, message: SentMediaMessage) {
|
|
if self.get_related_messages(&message.source).is_some() {
|
|
return;
|
|
}
|
|
|
|
if let Some(_discord) = self.discord.lock().unwrap().borrow().as_ref() {
|
|
if let Some(_discord_channel) = self.get_linked_discord_channel(&message.source) {
|
|
// TODO: Send the media
|
|
}
|
|
}
|
|
|
|
if let Some(_matrix) = self.matrix.lock().unwrap().borrow().as_ref() {
|
|
if let Some(_room_id) = self.get_linked_matrix_room(&message.source) {
|
|
// TODO: Send the media
|
|
}
|
|
}
|
|
}
|
|
}
|