aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/dispatch.rs103
-rw-r--r--src/framework/mod.rs59
2 files changed, 145 insertions, 17 deletions
diff --git a/src/client/dispatch.rs b/src/client/dispatch.rs
index f617b14..4021838 100644
--- a/src/client/dispatch.rs
+++ b/src/client/dispatch.rs
@@ -6,11 +6,11 @@ use super::Context;
use typemap::ShareMap;
use ::gateway::Shard;
use ::model::event::Event;
-use ::model::{Message, GuildId};
-use chrono::{UTC, Timelike};
+use ::model::{Message, Reaction, GuildId};
+use chrono::{Utc, Timelike};
#[cfg(feature="framework")]
-use ::ext::framework::Framework;
+use ::ext::framework::{Framework, ReactionAction};
#[cfg(feature="cache")]
use super::CACHE;
@@ -61,7 +61,7 @@ macro_rules! update {
}
macro_rules! now {
- () => (UTC::now().time().second() * 1000)
+ () => (Utc::now().time().second() * 1000)
}
fn context(conn: &Arc<Mutex<Shard>>,
@@ -90,6 +90,58 @@ pub fn dispatch(event: Event,
dispatch_message(context, event.message, event_store);
}
},
+ Event::ReactionAdd(event) => {
+ let context = context(conn, data);
+ let framework = framework.lock().unwrap();
+
+ if framework.initialized {
+ dispatch_reaction_add(context.clone(),
+ event.reaction.clone(),
+ event_store);
+
+ let res = framework.reaction_actions
+ .iter()
+ .find(|&(ra, ..)| {
+ if let ReactionAction::Add(ref kind) = *ra {
+ *kind == event.reaction.emoji
+ } else {
+ false
+ }
+ });
+
+ if let Some((_, f)) = res {
+ f(context, event.reaction.message_id, event.reaction.channel_id);
+ }
+ } else {
+ dispatch_reaction_add(context, event.reaction, event_store);
+ }
+ },
+ Event::ReactionRemove(event) => {
+ let context = context(conn, data);
+ let framework = framework.lock().unwrap();
+
+ if framework.initialized {
+ dispatch_reaction_remove(context.clone(),
+ event.reaction.clone(),
+ event_store);
+
+ let res = framework.reaction_actions
+ .iter()
+ .find(|&(ra, _)| {
+ if let ReactionAction::Remove(ref kind) = *ra {
+ *kind == event.reaction.emoji
+ } else {
+ false
+ }
+ });
+
+ if let Some((_, f)) = res {
+ f(context, event.reaction.message_id, event.reaction.channel_id);
+ }
+ } else {
+ dispatch_reaction_remove(context, event.reaction, event_store);
+ }
+ },
other => handle_event(other, conn, data, event_store),
}
}
@@ -106,6 +158,14 @@ pub fn dispatch(event: Event,
event.message,
event_store);
},
+ Event::ReactionAdd(event) => {
+ let context = context(conn, data);
+ dispatch_reaction_add(context, event.reaction);
+ },
+ Event::ReactionRemove(event) => {
+ let context = context(conn, data);
+ dispatch_reaction_remove(context, event.reaction);
+ },
other => handle_event(other, conn, data, event_store),
}
}
@@ -126,6 +186,26 @@ fn dispatch_message(context: Context,
}
}
+fn dispatch_reaction_add(context: Context,
+ reaction: Reaction,
+ event_store: &Arc<RwLock<EventStore>>) {
+ if let Some(handler) = handler!(on_reaction_add, event_store) {
+ thread::spawn(move || {
+ (handler)(context, reaction);
+ });
+ }
+}
+
+fn dispatch_reaction_remove(context: Context,
+ reaction: Reaction,
+ event_store: &Arc<RwLock<EventStore>>) {
+ if let Some(handler) = handler!(on_reaction_remove, event_store) {
+ thread::spawn(move || {
+ (handler)(context, reaction);
+ });
+ }
+}
+
#[allow(cyclomatic_complexity, unused_assignments, unused_mut)]
fn handle_event(event: Event,
conn: &Arc<Mutex<Shard>>,
@@ -457,20 +537,11 @@ fn handle_event(event: Event,
thread::spawn(move || (handler)(context, event));
}
},
- Event::ReactionAdd(event) => {
- if let Some(handler) = handler!(on_reaction_add, event_store) {
- let context = context(conn, data);
- thread::spawn(move || (handler)(context, event.reaction));
- }
- },
- Event::ReactionRemove(event) => {
- if let Some(handler) = handler!(on_reaction_remove, event_store) {
- let context = context(conn, data);
+ // Already handled by the framework check macro
+ Event::ReactionAdd(_) => {},
+ Event::ReactionRemove(_) => {},
- thread::spawn(move || (handler)(context, event.reaction));
- }
- },
Event::ReactionRemoveAll(event) => {
if let Some(handler) = handler!(on_reaction_remove_all, event_store) {
let context = context(conn, data);
diff --git a/src/framework/mod.rs b/src/framework/mod.rs
index 9a84b7f..aae518b 100644
--- a/src/framework/mod.rs
+++ b/src/framework/mod.rs
@@ -75,7 +75,7 @@ use std::default::Default;
use std::sync::Arc;
use std::thread;
use ::client::Context;
-use ::model::{Message, UserId};
+use ::model::{Message, MessageId, UserId, ChannelId, ReactionType};
use ::model::permissions::Permissions;
use ::utils;
@@ -209,6 +209,16 @@ pub enum DispatchError {
type DispatchErrorHook = Fn(Context, Message, DispatchError) + Send + Sync + 'static;
+pub(crate) type ActionFn = Fn(Context, MessageId, ChannelId) + Send + Sync + 'static;
+
+/// Defines wheter this action should be called when
+/// a reaction's added, or removed.
+#[derive(Clone, Eq, Hash, PartialEq)]
+pub enum ReactionAction {
+ Add(ReactionType),
+ Remove(ReactionType),
+}
+
/// A utility for easily managing dispatches to commands.
///
/// Refer to the [module-level documentation] for more information.
@@ -222,6 +232,7 @@ pub struct Framework {
before: Option<Arc<BeforeHook>>,
dispatch_error_handler: Option<Arc<DispatchErrorHook>>,
buckets: HashMap<String, Bucket>,
+ pub(crate) reaction_actions: HashMap<ReactionAction, Arc<ActionFn>>,
after: Option<Arc<AfterHook>>,
/// Whether the framework has been "initialized".
///
@@ -336,6 +347,52 @@ impl Framework {
self
}
+ /// Defines a "reaction action", that will be called if a reaction was
+ /// added; or deleted in a message.
+ ///
+ /// # Examples
+ /// ```rust,no_run
+ /// # use serenity::Client;
+ /// use serenity::model::ReactionType;
+ /// use serenity::framework::ReactionAction;
+ /// # let mut client = Client::new("token");
+ /// #
+ /// client.with_framework(|f| f
+ /// .action(ReactionAction::Add(ReactionType::Unicode("❤".to_string())), |_, _, channel_id| {
+ /// let _ = channel_id.say("love you too");
+ /// })
+ /// );
+ /// ```
+ pub fn action<F>(mut self, action: ReactionAction, f: F) -> Self
+ where F: Fn(Context, MessageId, ChannelId) + Send + Sync + 'static {
+ self.reaction_actions.insert(action, Arc::new(f));
+
+ self
+ }
+
+ /// Remove the action from any further usage by the framework.
+ ///
+ /// # Examples
+ /// ```rust,no_run
+ /// # use serenity::Client;
+ /// use serenity::model::ReactionType;
+ /// use serenity::framework::ReactionAction;
+ /// # let mut client = Client::new("token");
+ /// #
+ /// let action = ReactionAction::Add(ReactionType::Unicode("❤".to_string()));
+ /// client.with_framework(|f| f
+ /// .action(action.clone(), |_, _, channel_id| {
+ /// let _ = channel_id.say("love you too");
+ /// })
+ /// .remove_action(action)
+ /// );
+ /// ```
+ pub fn remove_action(mut self, action: ReactionAction) -> Self {
+ self.reaction_actions.remove(&action);
+
+ self
+ }
+
#[cfg(feature="cache")]
fn is_blocked_guild(&self, message: &Message) -> bool {
if let Some(Channel::Guild(channel)) = CACHE.read().unwrap().channel(message.channel_id) {