Add message editing support & impl for Discord

main
Charlotte Som 2022-04-18 15:47:05 +01:00
parent 2652f52a49
commit 4fc8c15b07
7 changed files with 123 additions and 4 deletions

View File

@ -1,7 +1,8 @@
use crate::{ChatMessage, ChatMessageReference}; use crate::{ChatMessage, ChatMessageEdit, ChatMessageReference};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ChatEvent { pub enum ChatEvent {
NewMessage(Box<ChatMessage>), NewMessage(Box<ChatMessage>),
DeleteMessage(ChatMessageReference), DeleteMessage(ChatMessageReference),
EditMessage(ChatMessageReference, Box<ChatMessageEdit>),
} }

View File

@ -34,4 +34,11 @@ pub struct ChatMessage {
pub replying: Option<ChatMessageReference>, pub replying: Option<ChatMessageReference>,
} }
#[derive(Debug, Clone)]
pub struct ChatMessageEdit {
pub origin: ChatMessageReference,
pub author: ChatAuthor,
pub new_content: ChatMessageContent,
}
pub mod event; pub mod event;

View File

@ -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::<Vec<_>>()
.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}");
}
}
}
} }
} }
} }

View File

@ -1,4 +1,4 @@
use mid_chat::{ChatMessage, ChatMessageReference, ChatReference}; use mid_chat::*;
#[async_trait::async_trait] #[async_trait::async_trait]
pub trait Service { pub trait Service {
@ -10,4 +10,9 @@ pub trait Service {
destination_channel: ChatReference, destination_channel: ChatReference,
) -> Vec<ChatMessageReference>; ) -> Vec<ChatMessageReference>;
async fn delete_message(&mut self, message: &ChatMessageReference) -> bool; async fn delete_message(&mut self, message: &ChatMessageReference) -> bool;
async fn edit_message(
&mut self,
old_origin: &ChatMessageReference,
edit: &ChatMessageEdit,
) -> Vec<ChatMessageReference>;
} }

View File

@ -108,4 +108,40 @@ impl EventHandler for DiscordHandler {
.send(ChatEvent::DeleteMessage(origin)) .send(ChatEvent::DeleteMessage(origin))
.expect("Failed to dispatch incoming Discord chat message deletion"); .expect("Failed to dispatch incoming Discord chat message deletion");
} }
async fn message_update(
&self,
ctx: Context,
_old_if_available: Option<Message>,
new: Option<Message>,
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");
}
}
} }

View File

@ -1,5 +1,5 @@
use phoebe::{ use phoebe::{
mid_chat::{self, ChatMessage, ChatMessageReference, ChatReference}, mid_chat::{self, ChatMessage, ChatMessageEdit, ChatMessageReference, ChatReference},
prelude::*, prelude::*,
DynServiceLookup, DynServiceLookup,
}; };
@ -93,4 +93,14 @@ impl Service for DiscordService {
assert_eq!(message.channel.service, "discord"); assert_eq!(message.channel.service, "discord");
sender::delete_discord_message(self, message).await.is_ok() sender::delete_discord_message(self, message).await.is_ok()
} }
async fn edit_message(
&mut self,
prev_origin: &ChatMessageReference,
new_message: &ChatMessageEdit,
) -> Vec<ChatMessageReference> {
assert_eq!(prev_origin.channel.service, "discord");
let _ = sender::edit_discord_message(self, prev_origin, new_message).await;
vec![]
}
} }

View File

@ -1,6 +1,6 @@
use phoebe::{ use phoebe::{
attachments::attachment_to_url, attachments::attachment_to_url,
mid_chat::{ChatMessage, ChatMessageReference, ChatReference}, mid_chat::{ChatMessage, ChatMessageEdit, ChatMessageReference, ChatReference},
prelude::*, prelude::*,
}; };
@ -137,6 +137,7 @@ pub async fn send_discord_message(
)); ));
} }
} }
let content = format!( let content = format!(
"{} ({}): {}", "{} ({}): {}",
source.author.display_name, source.author.display_name,
@ -182,3 +183,37 @@ pub async fn delete_discord_message(
channel_id.delete_message(&discord.ctx, message_id).await?; channel_id.delete_message(&discord.ctx, message_id).await?;
Ok(()) Ok(())
} }
pub async fn edit_discord_message(
discord: &mut DiscordService,
prev_origin: &ChatMessageReference,
edit: &ChatMessageEdit,
) -> Result<()> {
let channel_id = prev_origin.channel.id.parse::<ChannelId>()?;
let message_id: MessageId = prev_origin.message_id.parse::<u64>()?.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(())
}