Make ReactionHandler handle even reaction removals

This commit is contained in:
Natsu Kagami 2020-02-06 20:26:19 -05:00
parent d8305df52a
commit 472ebf9d2d
Signed by: nki
GPG key ID: 73376E117CD20735
2 changed files with 24 additions and 10 deletions

View file

@ -8,22 +8,24 @@ use std::sync::{Arc, Mutex};
pub trait ReactionHandler { pub trait ReactionHandler {
/// Handle a reaction. This is fired on EVERY reaction. /// Handle a reaction. This is fired on EVERY reaction.
/// You do the filtering yourself. /// You do the filtering yourself.
fn handle_reaction(&mut self, reaction: &Reaction) -> CommandResult; ///
/// If `is_added` is false, the reaction was removed instead of added.
fn handle_reaction(&mut self, reaction: &Reaction, is_added: bool) -> CommandResult;
} }
impl<T> ReactionHandler for T impl<T> ReactionHandler for T
where where
T: FnMut(&Reaction) -> CommandResult, T: FnMut(&Reaction, bool) -> CommandResult,
{ {
fn handle_reaction(&mut self, reaction: &Reaction) -> CommandResult { fn handle_reaction(&mut self, reaction: &Reaction, is_added: bool) -> CommandResult {
self(reaction) self(reaction, is_added)
} }
} }
/// The store for a set of dynamic reaction handlers. /// The store for a set of dynamic reaction handlers.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ReactionWatcher { pub struct ReactionWatcher {
channels: Arc<Mutex<Vec<Sender<Arc<Reaction>>>>>, channels: Arc<Mutex<Vec<Sender<(Arc<Reaction>, bool)>>>>,
} }
impl TypeMapKey for ReactionWatcher { impl TypeMapKey for ReactionWatcher {
@ -38,12 +40,13 @@ impl ReactionWatcher {
} }
} }
/// Send a reaction. /// Send a reaction.
pub fn send(&self, r: Reaction) { /// If `is_added` is false, the reaction was removed.
pub fn send(&self, r: Reaction, is_added: bool) {
let r = Arc::new(r); let r = Arc::new(r);
self.channels self.channels
.lock() .lock()
.expect("Poisoned!") .expect("Poisoned!")
.retain(|e| e.send(r.clone()).is_ok()); .retain(|e| e.send((r.clone(), is_added)).is_ok());
} }
/// React! to a series of reaction /// React! to a series of reaction
/// ///
@ -60,7 +63,7 @@ impl ReactionWatcher {
let timeout = after(duration); let timeout = after(duration);
loop { loop {
let r = select! { let r = select! {
recv(reactions) -> r => h.handle_reaction(&*r.unwrap()), recv(reactions) -> r => { let (r, is_added) = r.unwrap(); h.handle_reaction(&*r, is_added) },
recv(timeout) -> _ => break, recv(timeout) -> _ => break,
}; };
if let Err(v) = r { if let Err(v) = r {

View file

@ -2,7 +2,10 @@ use dotenv;
use dotenv::var; use dotenv::var;
use serenity::{ use serenity::{
framework::standard::{DispatchError, StandardFramework}, framework::standard::{DispatchError, StandardFramework},
model::{channel::{Message, Reaction}, gateway}, model::{
channel::{Message, Reaction},
gateway,
},
}; };
use youmubot_prelude::*; use youmubot_prelude::*;
@ -27,7 +30,15 @@ impl EventHandler for Handler {
} }
fn reaction_add(&self, ctx: Context, reaction: Reaction) { fn reaction_add(&self, ctx: Context, reaction: Reaction) {
ctx.data.get_cloned::<ReactionWatcher>().send(reaction); ctx.data
.get_cloned::<ReactionWatcher>()
.send(reaction, true);
}
fn reaction_remove(&self, ctx: Context, reaction: Reaction) {
ctx.data
.get_cloned::<ReactionWatcher>()
.send(reaction, false);
} }
} }