From 247001f8c779e82d05733c8a9423f5c5308ee1d5 Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Sat, 22 Feb 2025 16:37:48 +0100 Subject: [PATCH] interaction_collector: rename from Paginator, implement Guard, is now generic --- youmubot-prelude/src/interaction_collector.rs | 90 +++++++++++++++++++ youmubot-prelude/src/lib.rs | 2 + youmubot-prelude/src/pagination.rs | 73 +-------------- youmubot/src/main.rs | 4 +- 4 files changed, 97 insertions(+), 72 deletions(-) create mode 100644 youmubot-prelude/src/interaction_collector.rs diff --git a/youmubot-prelude/src/interaction_collector.rs b/youmubot-prelude/src/interaction_collector.rs new file mode 100644 index 0000000..3de42ac --- /dev/null +++ b/youmubot-prelude/src/interaction_collector.rs @@ -0,0 +1,90 @@ +use crate::{Context, Result}; +use serenity::{ + all::{CreateInteractionResponse, Interaction, MessageId}, + prelude::TypeMapKey, +}; +use std::{ops::Deref, sync::Arc}; + +#[derive(Debug, Clone)] +/// Handles distributing interaction to the handlers. +pub struct InteractionCollector { + pub(crate) channels: Arc>>, +} + +/// Wraps the interfaction receiver channel, automatically cleaning up upon drop. +#[derive(Debug)] +struct InteractionCollectorGuard { + msg_id: MessageId, + ch: flume::Receiver, + collector: InteractionCollector, +} + +impl Deref for InteractionCollectorGuard { + type Target = flume::Receiver; + + fn deref(&self) -> &Self::Target { + &self.ch + } +} + +impl Drop for InteractionCollectorGuard { + fn drop(&mut self) { + self.collector.channels.remove(&self.msg_id); + } +} + +impl InteractionCollector { + pub fn new() -> Self { + Self { + channels: Arc::new(dashmap::DashMap::new()), + } + } + /// Create a new collector, returning a receiver. + pub fn create_collector(&self, msg: MessageId) -> impl Deref> { + let (send, recv) = flume::unbounded(); + self.channels.insert(msg.clone(), send); + InteractionCollectorGuard { + msg_id: msg, + ch: recv, + collector: self.clone(), + } + } + + /// Create a new collector, returning a receiver. + pub(crate) async fn create( + ctx: &Context, + msg: MessageId, + ) -> Result>> { + Ok(ctx + .data + .read() + .await + .get::() + .unwrap() + .create_collector(msg)) + } +} + +impl TypeMapKey for InteractionCollector { + type Value = InteractionCollector; +} + +#[async_trait::async_trait] +impl crate::hook::InteractionHook for InteractionCollector { + async fn call(&self, ctx: &Context, interaction: &Interaction) -> Result<()> { + match interaction { + Interaction::Component(component_interaction) => { + if let Some(ch) = self.channels.get(&component_interaction.message.id) { + component_interaction + .create_response(ctx, CreateInteractionResponse::Acknowledge) + .await?; + ch.send_async(component_interaction.data.custom_id.clone()) + .await + .ok(); + } + Ok(()) + } + _ => Ok(()), + } + } +} diff --git a/youmubot-prelude/src/lib.rs b/youmubot-prelude/src/lib.rs index c536b2a..3d32cfd 100644 --- a/youmubot-prelude/src/lib.rs +++ b/youmubot-prelude/src/lib.rs @@ -17,6 +17,7 @@ pub use args::{ChannelId, Duration, RoleId, UserId, UsernameArg}; pub use debugging_ok::OkPrint; pub use flags::Flags; pub use hook::Hook; +pub use interaction_collector::InteractionCollector; pub use member_cache::MemberCache; pub use pagination::{paginate, paginate_from_fn, paginate_reply, CanEdit, Paginate}; pub use poise::CreateReply; @@ -25,6 +26,7 @@ pub mod announcer; pub mod args; pub mod flags; pub mod hook; +pub mod interaction_collector; pub mod member_cache; pub mod pagination; pub mod ratelimit; diff --git a/youmubot-prelude/src/pagination.rs b/youmubot-prelude/src/pagination.rs index e8356b2..43a9400 100644 --- a/youmubot-prelude/src/pagination.rs +++ b/youmubot-prelude/src/pagination.rs @@ -3,17 +3,11 @@ use futures_util::future::Future; use poise::{CreateReply, ReplyHandle}; use serenity::{ all::{ - ComponentInteraction, CreateActionRow, CreateButton, CreateInteractionResponse, - EditInteractionResponse, EditMessage, Interaction, MessageId, + ComponentInteraction, CreateActionRow, CreateButton, EditInteractionResponse, EditMessage, }, builder::CreateMessage, - model::{ - channel::{Message, ReactionType}, - id::ChannelId, - }, - prelude::TypeMapKey, + model::{channel::Message, id::ChannelId}, }; -use std::{convert::TryFrom, sync::Arc}; use tokio::time as tokio_time; // const ARROW_RIGHT: &str = "➡️"; @@ -264,8 +258,7 @@ pub async fn paginate_with_first_message( timeout: std::time::Duration, ) -> Result<()> { let msg_id = message.get_message().await?.id; - let (send, recv) = flume::unbounded::(); - Paginator::push(ctx, msg_id, send).await?; + let recv = crate::InteractionCollector::create(ctx, msg_id).await?; do_render(&mut pager, 0, &mut message).await?; // Just quit if there is only one page @@ -296,7 +289,6 @@ pub async fn paginate_with_first_message( do_render_with_btns(&mut pager, page, &mut message, vec![]) .await .pls_ok(); - Paginator::pop(ctx, msg_id).await?; res } @@ -331,62 +323,3 @@ pub async fn handle_pagination_reaction( page }) } - -#[derive(Debug, Clone)] -/// Handles distributing pagination interaction to the handlers. -pub struct Paginator { - pub(crate) channels: Arc>>, -} - -impl Paginator { - pub fn new() -> Self { - Self { - channels: Arc::new(dashmap::DashMap::new()), - } - } - async fn push(ctx: &Context, msg: MessageId, channel: flume::Sender) -> Result<()> { - ctx.data - .read() - .await - .get::() - .unwrap() - .channels - .insert(msg, channel); - Ok(()) - } - - async fn pop(ctx: &Context, msg: MessageId) -> Result<()> { - ctx.data - .read() - .await - .get::() - .unwrap() - .channels - .remove(&msg); - Ok(()) - } -} - -impl TypeMapKey for Paginator { - type Value = Paginator; -} - -#[async_trait::async_trait] -impl crate::hook::InteractionHook for Paginator { - async fn call(&self, ctx: &Context, interaction: &Interaction) -> Result<()> { - match interaction { - Interaction::Component(component_interaction) => { - if let Some(ch) = self.channels.get(&component_interaction.message.id) { - component_interaction - .create_response(ctx, CreateInteractionResponse::Acknowledge) - .await?; - ch.send_async(component_interaction.data.custom_id.clone()) - .await - .ok(); - } - Ok(()) - } - _ => Ok(()), - } - } -} diff --git a/youmubot/src/main.rs b/youmubot/src/main.rs index 4c983c2..9404011 100644 --- a/youmubot/src/main.rs +++ b/youmubot/src/main.rs @@ -237,9 +237,9 @@ async fn main() { }; // Paginator - let paginator = youmubot_prelude::pagination::Paginator::new(); + let paginator = youmubot_prelude::InteractionCollector::new(); handler.push_interaction_hook(paginator.clone()); - data.insert::(paginator); + data.insert::(paginator); data.insert::(env.clone());