Implement message deletion
This commit is contained in:
		
							parent
							
								
									4c37ec5f36
								
							
						
					
					
						commit
						cee7a551d1
					
				
					 7 changed files with 90 additions and 9 deletions
				
			
		|  | @ -1,6 +1,7 @@ | ||||||
| use crate::ChatMessage; | use crate::{ChatMessage, ChatMessageReference}; | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
| pub enum ChatEvent { | pub enum ChatEvent { | ||||||
|     NewMessage(ChatMessage), |     NewMessage(Box<ChatMessage>), | ||||||
|  |     DeleteMessage(ChatMessageReference), | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,12 +1,13 @@ | ||||||
| use color_eyre::Result; | use color_eyre::Result; | ||||||
|  | use futures::{future, StreamExt}; | ||||||
| use tracing::info; | use tracing::info; | ||||||
| use tracing_subscriber::EnvFilter; | use tracing_subscriber::EnvFilter; | ||||||
| 
 | 
 | ||||||
| use phoebe::{ | use phoebe::{ | ||||||
|     get_linked_channels, link_messages, |     get_linked_channels, get_linked_messages, link_messages, | ||||||
|     prelude::{ChatEvent, SqlitePool}, |     prelude::{ChatEvent, SqlitePool}, | ||||||
|     service::Service, |     service::Service, | ||||||
|     DynServiceLookup, |     unlink_message, DynServiceLookup, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| async fn handle_events( | async fn handle_events( | ||||||
|  | @ -24,7 +25,7 @@ async fn handle_events( | ||||||
| 
 | 
 | ||||||
|     while let Ok(event) = rx.recv().await { |     while let Ok(event) = rx.recv().await { | ||||||
|         match event { |         match event { | ||||||
|             phoebe::prelude::ChatEvent::NewMessage(message) => { |             ChatEvent::NewMessage(message) => { | ||||||
|                 let linked_channels = |                 let linked_channels = | ||||||
|                     get_linked_channels(&mut conn, dyn_service, &message.origin.channel).await; |                     get_linked_channels(&mut conn, dyn_service, &message.origin.channel).await; | ||||||
| 
 | 
 | ||||||
|  | @ -45,6 +46,33 @@ async fn handle_events( | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | 
 | ||||||
|  |             ChatEvent::DeleteMessage(origin) => { | ||||||
|  |                 let messages = if let Ok(message_stream) = | ||||||
|  |                     get_linked_messages(&mut conn, dyn_service, &origin).await | ||||||
|  |                 { | ||||||
|  |                     message_stream | ||||||
|  |                         .filter(|r| future::ready(r.channel.service == service.tag())) | ||||||
|  |                         .collect::<Vec<_>>() | ||||||
|  |                         .await | ||||||
|  |                 } else { | ||||||
|  |                     vec![] | ||||||
|  |                 }; | ||||||
|  | 
 | ||||||
|  |                 if !messages.is_empty() { | ||||||
|  |                     if let Err(e) = unlink_message(&mut conn, &origin).await { | ||||||
|  |                         tracing::error!("Failed to unlink origin message: {e}"); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     for message in messages { | ||||||
|  |                         if service.delete_message(&message).await { | ||||||
|  |                             if let Err(e) = unlink_message(&mut conn, &message).await { | ||||||
|  |                                 tracing::error!("Failed to unlink related message: {e}"); | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -78,7 +106,7 @@ async fn main() -> Result<()> { | ||||||
|         .into_iter() |         .into_iter() | ||||||
|         .map(|srv| tokio::spawn(handle_events(dyn_service, db.clone(), srv, tx.subscribe()))); |         .map(|srv| tokio::spawn(handle_events(dyn_service, db.clone(), srv, tx.subscribe()))); | ||||||
| 
 | 
 | ||||||
|     let _ = futures::future::join_all(handles).await; |     let _ = future::join_all(handles).await; | ||||||
| 
 | 
 | ||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -92,6 +92,27 @@ pub async fn link_messages( | ||||||
|     Ok(()) |     Ok(()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | pub async fn unlink_message( | ||||||
|  |     conn: &mut SqliteConnection, | ||||||
|  |     message: &ChatMessageReference, | ||||||
|  | ) -> sqlx::Result<()> { | ||||||
|  |     let service = &message.channel.service; | ||||||
|  |     let channel = &message.channel.id; | ||||||
|  |     let message_id = &message.message_id; | ||||||
|  |     let query = sqlx::query!( | ||||||
|  |         "DELETE FROM messages WHERE service = ? AND channel = ? AND message = ?", | ||||||
|  |         service, | ||||||
|  |         channel, | ||||||
|  |         message_id | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     if query.execute(&mut *conn).await?.rows_affected() == 0 { | ||||||
|  |         return Err(sqlx::Error::RowNotFound); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| pub async fn get_message_link_id( | pub async fn get_message_link_id( | ||||||
|     conn: &mut SqliteConnection, |     conn: &mut SqliteConnection, | ||||||
|     message: &ChatMessageReference, |     message: &ChatMessageReference, | ||||||
|  |  | ||||||
|  | @ -3,9 +3,11 @@ use mid_chat::{ChatMessage, ChatMessageReference, ChatReference}; | ||||||
| #[async_trait::async_trait] | #[async_trait::async_trait] | ||||||
| pub trait Service { | pub trait Service { | ||||||
|     fn tag(&self) -> &'static str; |     fn tag(&self) -> &'static str; | ||||||
|  | 
 | ||||||
|     async fn send_chat_message( |     async fn send_chat_message( | ||||||
|         &mut self, |         &mut self, | ||||||
|         source: &ChatMessage, |         source: &ChatMessage, | ||||||
|         destination_channel: ChatReference, |         destination_channel: ChatReference, | ||||||
|     ) -> Vec<ChatMessageReference>; |     ) -> Vec<ChatMessageReference>; | ||||||
|  |     async fn delete_message(&mut self, message: &ChatMessageReference) -> bool; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -91,7 +91,21 @@ impl EventHandler for DiscordHandler { | ||||||
| 
 | 
 | ||||||
|         let _ = self |         let _ = self | ||||||
|             .chat_event_tx |             .chat_event_tx | ||||||
|             .send(ChatEvent::NewMessage(chat_message)) |             .send(ChatEvent::NewMessage(Box::new(chat_message))) | ||||||
|             .expect("Failed to dispatch incoming Discord chat message"); |             .expect("Failed to dispatch incoming Discord chat message"); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     async fn message_delete( | ||||||
|  |         &self, | ||||||
|  |         _ctx: Context, | ||||||
|  |         channel_id: ChannelId, | ||||||
|  |         deleted_message_id: MessageId, | ||||||
|  |         _guild_id: Option<GuildId>, | ||||||
|  |     ) { | ||||||
|  |         let origin = ChatMessageReference::new(discord_reference(channel_id), deleted_message_id); | ||||||
|  |         let _ = self | ||||||
|  |             .chat_event_tx | ||||||
|  |             .send(ChatEvent::DeleteMessage(origin)) | ||||||
|  |             .expect("Failed to dispatch incoming Discord chat message deletion"); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -72,6 +72,10 @@ pub async fn setup( | ||||||
| 
 | 
 | ||||||
| #[async_trait] | #[async_trait] | ||||||
| impl Service for DiscordService { | impl Service for DiscordService { | ||||||
|  |     fn tag(&self) -> &'static str { | ||||||
|  |         "discord" | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     async fn send_chat_message( |     async fn send_chat_message( | ||||||
|         &mut self, |         &mut self, | ||||||
|         source: &ChatMessage, |         source: &ChatMessage, | ||||||
|  | @ -85,7 +89,8 @@ impl Service for DiscordService { | ||||||
|             .collect() |             .collect() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn tag(&self) -> &'static str { |     async fn delete_message(&mut self, message: &ChatMessageReference) -> bool { | ||||||
|         "discord" |         assert_eq!(message.channel.service, "discord"); | ||||||
|  |         sender::delete_discord_message(self, message).await.is_ok() | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -161,3 +161,13 @@ pub async fn send_discord_message( | ||||||
|         sent_message.id, |         sent_message.id, | ||||||
|     )) |     )) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | pub async fn delete_discord_message( | ||||||
|  |     discord: &mut DiscordService, | ||||||
|  |     message: &ChatMessageReference, | ||||||
|  | ) -> Result<()> { | ||||||
|  |     let channel_id = message.channel.id.parse::<ChannelId>()?; | ||||||
|  |     let message_id: MessageId = message.message_id.parse::<u64>()?.into(); | ||||||
|  |     channel_id.delete_message(&discord.ctx, message_id).await?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue