From 535afb479614c1b309bd60a3487fad815ad5b686 Mon Sep 17 00:00:00 2001 From: videogame hacker Date: Mon, 13 Sep 2021 20:41:55 +0100 Subject: [PATCH] Implement bridged message replies --- src/bridgers.rs | 73 ++++++++++++++++++++++++++++++++++++++++++++----- src/discord.rs | 15 +++++++++- src/matrix.rs | 64 +++++++++++++++++++++++++++++++++++++------ src/messages.rs | 1 + 4 files changed, 136 insertions(+), 17 deletions(-) diff --git a/src/bridgers.rs b/src/bridgers.rs index 9843ed3..dd562ea 100644 --- a/src/bridgers.rs +++ b/src/bridgers.rs @@ -70,6 +70,54 @@ impl Bridgers { } } + 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 @@ -111,7 +159,12 @@ impl Bridgers { if let Some(discord) = self.discord.lock().unwrap().borrow().as_ref() { if let Some(channel) = self.get_linked_discord_channel(&message.source) { - if let Some(m) = forward_to_discord(discord, channel, &message).await { + 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); } } @@ -119,7 +172,12 @@ impl Bridgers { if let Some(matrix) = self.matrix.lock().unwrap().borrow().as_ref() { if let Some(room_id) = self.get_linked_matrix_room(&message.source) { - if let Some(m) = forward_to_matrix(matrix, room_id, &message).await { + 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); } } @@ -136,11 +194,12 @@ impl Bridgers { .filter(|r| r != &source) .collect::>(); - tree.insert( - bincode::serialize(source).expect("Failed to serialize message reference"), - bincode::serialize(&relations).expect("Failed to serialize message relations"), - ) - .expect("Failed to store message relations"); + 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 diff --git a/src/discord.rs b/src/discord.rs index 7f2c96d..47ca345 100644 --- a/src/discord.rs +++ b/src/discord.rs @@ -62,6 +62,11 @@ impl EventHandler for DiscordHandler { let content = discord_message_format::parse(&message.content); let content = message_ast::convert_discord(&content); + let replies_to = message + .referenced_message + .as_ref() + .map(|m| MessageReference::from(m.as_ref())); + let _ = self.event_tx.send(MessageEvent::Send(SentMessage { source: message_ref, content, @@ -71,6 +76,7 @@ impl EventHandler for DiscordHandler { .await .unwrap_or(message.author.name), }, + replies_to, })); } } @@ -79,10 +85,17 @@ pub async fn forward_to_discord( discord_ctx: &Context, channel: ChannelId, message: &SentMessage, + reply: Option<(u64, u64)>, ) -> Option { channel .send_message(&discord_ctx.http, |m| { - m.content(format_discord(&message.content)) + let b = m.content(format_discord(&message.content)); + + if let Some((channel_id, message_id)) = reply { + b.reference_message((ChannelId(channel_id), MessageId(message_id))) + } else { + b + } }) .await .as_ref() diff --git a/src/matrix.rs b/src/matrix.rs index 7256a4b..55b80bf 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{str::FromStr, sync::Arc}; use matrix_sdk::{ room::{Joined, Room}, @@ -10,7 +10,8 @@ use matrix_sdk::{ }, redaction::RedactionEventContent, }, - AnyMessageEventContent, AnySyncRoomEvent, SyncMessageEvent, + AnyMessageEvent, AnyMessageEventContent, AnyRoomEvent, AnySyncRoomEvent, + SyncMessageEvent, }, EventId, UserId, }, @@ -125,10 +126,21 @@ async fn on_room_message_event( let content = ctx.get_content(&text.body, &text.formatted); if let Some(author) = ctx.get_message_author(&room, &event.sender).await { + let replies_to = + if let Some(Relation::Reply { in_reply_to }) = &event.content.relates_to { + Some(MessageReference::from(( + room.room_id(), + &in_reply_to.event_id, + ))) + } else { + None + }; + let _ = ctx.message_tx.send(MessageEvent::Send(SentMessage { source: message_ref, content, author, + replies_to, })); } } @@ -142,6 +154,7 @@ async fn on_room_message_event( source: message_ref, content, author, + replies_to: None, })); } } @@ -158,16 +171,49 @@ pub async fn forward_to_matrix( client: &Client, room_id: RoomId, message: &SentMessage, + reply: Option<(String, String)>, ) -> Option { if let Some(room) = client.get_joined_room(&room_id) { - let event = room - .send( - AnyMessageEventContent::RoomMessage(MessageEventContent::text_html( - format_discord(&message.content), - format_matrix(&message.content), - )), - None, + let replied_message_event = if let Some((room_id, event_id)) = reply { + let event = room + .event( + matrix_sdk::ruma::api::client::r0::room::get_room_event::Request::new( + &RoomId::from_str(&room_id).unwrap(), + &EventId::from_str(&event_id).unwrap(), + ), + ) + .await + .unwrap() + .event + .deserialize() + .unwrap(); + + if let AnyRoomEvent::Message(AnyMessageEvent::RoomMessage(original_message_event)) = + event + { + Some(original_message_event) + } else { + None + } + } else { + None + }; + + let content = if let Some(replied_message_event) = &replied_message_event { + MessageEventContent::text_reply_html( + format_discord(&message.content), + format_matrix(&message.content), + replied_message_event, ) + } else { + MessageEventContent::text_html( + format_discord(&message.content), + format_matrix(&message.content), + ) + }; + + let event = room + .send(AnyMessageEventContent::RoomMessage(content), None) .await .ok()?; diff --git a/src/messages.rs b/src/messages.rs index cf02e43..bae1b8e 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -16,6 +16,7 @@ pub struct SentMessage { pub source: MessageReference, pub content: MessageContent, pub author: MessageAuthor, + pub replies_to: Option, } pub struct EditedMessage {