Implement message deletion
parent
4c37ec5f36
commit
cee7a551d1
|
@ -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 New Issue