fix: handle reaction remove emoji, remove all events
All checks were successful
Build / Build (push) Successful in 44s
Build / docker (push) Successful in 16s

This commit is contained in:
파링 2026-01-07 16:05:18 +09:00
parent a48bb14509
commit e934da887f
Signed by: paring
SSH key fingerprint: SHA256:8uCHhCpn/gVOLEaTolmbub9kfM6XBxWkIWmHxUZoWWk

View file

@ -54,12 +54,12 @@ pub struct Handler {
#[async_trait] #[async_trait]
impl EventHandler for Handler { impl EventHandler for Handler {
async fn dispatch(&self, context: &Context, event: &FullEvent) { async fn dispatch(&self, ctx: &Context, event: &FullEvent) {
match event { match event {
FullEvent::Ready { data_about_bot, .. } => { FullEvent::Ready { data_about_bot, .. } => {
info!("Bot is ready as {}", data_about_bot.user.tag()); info!("Bot is ready as {}", data_about_bot.user.tag());
if let Err(e) = context if let Err(e) = ctx
.http .http
.create_global_commands(&vec![ .create_global_commands(&vec![
commands::config_command(), commands::config_command(),
@ -71,15 +71,34 @@ impl EventHandler for Handler {
} }
} }
FullEvent::ReactionAdd { add_reaction, .. } => { FullEvent::ReactionAdd { add_reaction, .. } => {
self.process_reaction(context, add_reaction, false).await; self.process_reaction(ctx, add_reaction, false).await;
} }
FullEvent::ReactionRemove { FullEvent::ReactionRemove {
removed_reaction, .. removed_reaction, ..
} => { } => {
self.process_reaction(context, removed_reaction, true).await; self.process_reaction(ctx, removed_reaction, true).await;
}
FullEvent::ReactionRemoveEmoji { removed_reactions } => {
self.process_reaction(ctx, removed_reactions, true).await;
}
FullEvent::ReactionRemoveAll {
guild_id,
channel_id,
removed_from_message_id,
} => {
if let Some(guild_id) = guild_id {
self.process_reaction_message(
ctx,
*channel_id,
*removed_from_message_id,
*guild_id,
true,
)
.await;
}
} }
FullEvent::InteractionCreate { interaction } => { FullEvent::InteractionCreate { interaction } => {
if let Err(e) = self.interaction_create(context, interaction).await { if let Err(e) = self.interaction_create(ctx, interaction).await {
error!("Error while processing interaction: {e:?}"); error!("Error while processing interaction: {e:?}");
} }
} }
@ -117,9 +136,31 @@ impl Handler {
} }
async fn process_reaction(&self, ctx: &Context, reaction: &Reaction, is_remove: bool) { async fn process_reaction(&self, ctx: &Context, reaction: &Reaction, is_remove: bool) {
let Some(guild_id) = reaction.guild_id else {
return;
};
self.process_reaction_message(
ctx,
reaction.channel_id,
reaction.message_id,
guild_id,
is_remove,
)
.await;
}
async fn process_reaction_message(
&self,
ctx: &Context,
channel_id: GenericChannelId,
message_id: MessageId,
guild_id: GuildId,
is_remove: bool,
) {
let semaphore = { let semaphore = {
self.message_lock self.message_lock
.entry(reaction.message_id) .entry(message_id)
.or_insert_with(|| Arc::new(Semaphore::new(1))) .or_insert_with(|| Arc::new(Semaphore::new(1)))
.value() .value()
.clone() .clone()
@ -130,28 +171,27 @@ impl Handler {
Err(_) => return, Err(_) => return,
}; };
if let Err(e) = self.process_reaction_inner(ctx, reaction, is_remove).await { if let Err(e) = self
.process_reaction_inner(ctx, channel_id, message_id, guild_id, is_remove)
.await
{
error!("Error while processing reaction add event: {e:?}"); error!("Error while processing reaction add event: {e:?}");
} }
if Arc::strong_count(&semaphore) <= 2 { if Arc::strong_count(&semaphore) <= 2 {
self.message_lock self.message_lock
.remove_if(&reaction.message_id, |_, val| Arc::strong_count(val) <= 2); .remove_if(&message_id, |_, val| Arc::strong_count(val) <= 2);
} }
} }
async fn process_reaction_inner( async fn process_reaction_inner(
&self, &self,
ctx: &Context, ctx: &Context,
reaction: &Reaction, channel_id: GenericChannelId,
message_id: MessageId,
guild_id: GuildId,
is_remove: bool, is_remove: bool,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
if reaction.user((ctx.cache(), ctx.http())).await?.bot() {
return Ok(());
}
let Some(guild_id) = reaction.guild_id else {
return Ok(());
};
let Some(guild) = get_guild(&self.db, guild_id).await? else { let Some(guild) = get_guild(&self.db, guild_id).await? else {
return Ok(()); return Ok(());
}; };
@ -159,13 +199,19 @@ impl Handler {
return Ok(()); return Ok(());
}; };
let existing_message = get_message(&self.db, reaction.message_id).await?; let existing_message = get_message(&self.db, message_id).await?;
if is_remove && existing_message.is_none() { if is_remove && existing_message.is_none() {
return Ok(()); return Ok(());
} }
let msg = reaction.message((ctx.cache(), ctx.http())).await?; let msg = channel_id
.message((ctx.cache(), ctx.http()), message_id)
.await?;
if msg.author.bot() {
return Ok(());
}
let reactions: HashMap<String, i64> = msg let reactions: HashMap<String, i64> = msg
.reactions .reactions
@ -179,14 +225,16 @@ impl Handler {
CloneBuilderMessage::from(msg.clone()) CloneBuilderMessage::from(msg.clone())
}; };
let channel = reaction.channel((ctx.cache(), ctx.http())).await?; let channel = channel_id
.to_channel((ctx.cache(), ctx.http()), Some(guild_id))
.await?;
debug!("channel: {channel:?}"); debug!("channel: {channel:?}");
let Some(result) = paringboard::script::check( let Some(result) = paringboard::script::check(
script, script,
reactions, reactions,
reaction.channel_id.to_string(), channel_id.to_string(),
channel channel
.guild() .guild()
.and_then(|x| x.parent_id) .and_then(|x| x.parent_id)