diff --git a/mid-chat/src/event.rs b/mid-chat/src/event.rs index ac87d4b..75900c1 100644 --- a/mid-chat/src/event.rs +++ b/mid-chat/src/event.rs @@ -1,7 +1,8 @@ -use crate::{ChatMessage, ChatMessageReference}; +use crate::{ChatMessage, ChatMessageEdit, ChatMessageReference}; #[derive(Debug, Clone)] pub enum ChatEvent { NewMessage(Box), DeleteMessage(ChatMessageReference), + EditMessage(ChatMessageReference, Box), } diff --git a/mid-chat/src/lib.rs b/mid-chat/src/lib.rs index b59612b..f03140c 100644 --- a/mid-chat/src/lib.rs +++ b/mid-chat/src/lib.rs @@ -34,4 +34,11 @@ pub struct ChatMessage { pub replying: Option, } +#[derive(Debug, Clone)] +pub struct ChatMessageEdit { + pub origin: ChatMessageReference, + pub author: ChatAuthor, + pub new_content: ChatMessageContent, +} + pub mod event; diff --git a/phoebe-main/src/main.rs b/phoebe-main/src/main.rs index fff7420..c121297 100644 --- a/phoebe-main/src/main.rs +++ b/phoebe-main/src/main.rs @@ -73,6 +73,31 @@ async fn handle_events( } } } + ChatEvent::EditMessage(prev_origin, message_edit) => { + let messages = if let Ok(message_stream) = + get_linked_messages(&mut conn, dyn_service, &prev_origin).await + { + message_stream + .filter(|r| future::ready(r.channel.service == service.tag())) + .collect::>() + .await + } else { + vec![] + }; + + let mut resulting_messages = vec![]; + for message in messages { + resulting_messages.extend(service.edit_message(&message, &message_edit).await) + } + + if !resulting_messages.is_empty() { + if let Err(e) = + link_messages(&mut conn, &prev_origin, &resulting_messages).await + { + tracing::error!("Failed to link messages: {e}"); + } + } + } } } } diff --git a/phoebe/src/service.rs b/phoebe/src/service.rs index 3c18025..8a7f0f6 100644 --- a/phoebe/src/service.rs +++ b/phoebe/src/service.rs @@ -1,4 +1,4 @@ -use mid_chat::{ChatMessage, ChatMessageReference, ChatReference}; +use mid_chat::*; #[async_trait::async_trait] pub trait Service { @@ -10,4 +10,9 @@ pub trait Service { destination_channel: ChatReference, ) -> Vec; async fn delete_message(&mut self, message: &ChatMessageReference) -> bool; + async fn edit_message( + &mut self, + old_origin: &ChatMessageReference, + edit: &ChatMessageEdit, + ) -> Vec; } diff --git a/services/phoebe-discord/src/handler.rs b/services/phoebe-discord/src/handler.rs index c8cf85c..24b2b06 100644 --- a/services/phoebe-discord/src/handler.rs +++ b/services/phoebe-discord/src/handler.rs @@ -108,4 +108,40 @@ impl EventHandler for DiscordHandler { .send(ChatEvent::DeleteMessage(origin)) .expect("Failed to dispatch incoming Discord chat message deletion"); } + + async fn message_update( + &self, + ctx: Context, + _old_if_available: Option, + new: Option, + event: MessageUpdateEvent, + ) { + if let Ok(new_message) = { + if let Some(m) = new { + Ok(m) + } else { + event.channel_id.message(&ctx, event.id).await + } + } { + let origin = ChatMessageReference::new( + discord_reference(new_message.channel_id), + new_message.id, + ); + let author = self.get_author(&ctx, &new_message).await; + + let content = discord_message_format::parse(&new_message.content); + let content = super::chat_conv::convert(&content); + + let edit = ChatMessageEdit { + origin: origin.clone(), + author, + new_content: content, + }; + + let _ = self + .chat_event_tx + .send(ChatEvent::EditMessage(origin, Box::new(edit))) + .expect("Failed to dispatch incoming Discord chat message update"); + } + } } diff --git a/services/phoebe-discord/src/lib.rs b/services/phoebe-discord/src/lib.rs index ab2db5f..4acaae7 100644 --- a/services/phoebe-discord/src/lib.rs +++ b/services/phoebe-discord/src/lib.rs @@ -1,5 +1,5 @@ use phoebe::{ - mid_chat::{self, ChatMessage, ChatMessageReference, ChatReference}, + mid_chat::{self, ChatMessage, ChatMessageEdit, ChatMessageReference, ChatReference}, prelude::*, DynServiceLookup, }; @@ -93,4 +93,14 @@ impl Service for DiscordService { assert_eq!(message.channel.service, "discord"); sender::delete_discord_message(self, message).await.is_ok() } + + async fn edit_message( + &mut self, + prev_origin: &ChatMessageReference, + new_message: &ChatMessageEdit, + ) -> Vec { + assert_eq!(prev_origin.channel.service, "discord"); + let _ = sender::edit_discord_message(self, prev_origin, new_message).await; + vec![] + } } diff --git a/services/phoebe-discord/src/sender.rs b/services/phoebe-discord/src/sender.rs index c2ef766..9b3e485 100644 --- a/services/phoebe-discord/src/sender.rs +++ b/services/phoebe-discord/src/sender.rs @@ -1,6 +1,6 @@ use phoebe::{ attachments::attachment_to_url, - mid_chat::{ChatMessage, ChatMessageReference, ChatReference}, + mid_chat::{ChatMessage, ChatMessageEdit, ChatMessageReference, ChatReference}, prelude::*, }; @@ -137,6 +137,7 @@ pub async fn send_discord_message( )); } } + let content = format!( "{} ({}): {}", source.author.display_name, @@ -182,3 +183,37 @@ pub async fn delete_discord_message( channel_id.delete_message(&discord.ctx, message_id).await?; Ok(()) } + +pub async fn edit_discord_message( + discord: &mut DiscordService, + prev_origin: &ChatMessageReference, + edit: &ChatMessageEdit, +) -> Result<()> { + let channel_id = prev_origin.channel.id.parse::()?; + let message_id: MessageId = prev_origin.message_id.parse::()?.into(); + + if let Some(webhook) = get_or_create_webhook_for_channel(&mut *discord, &channel_id).await { + if webhook + .edit_message(&discord.ctx, message_id, |w| { + w.content(chat_conv::format(&edit.new_content)) + }) + .await + .is_ok() + { + return Ok(()); + } + } + + let content = format!( + "{} ({}): {}", + edit.author.display_name, + edit.author.reference.service, + chat_conv::format(&edit.new_content) + ); + + channel_id + .edit_message(&discord.ctx, message_id, |m| m.content(content)) + .await?; + + Ok(()) +}