diff options
| author | acdenisSK <[email protected]> | 2017-07-22 16:59:10 +0200 |
|---|---|---|
| committer | acdenisSK <[email protected]> | 2017-07-22 16:59:10 +0200 |
| commit | 2b053ea007d6ca9cc820cb910597e8b5dad89d70 (patch) | |
| tree | c0664957758043b80fc7e40d9acc7923da53d3c1 /src | |
| parent | Remove the uneccessary function and `Send + Sync` bounds (diff) | |
| download | serenity-2b053ea007d6ca9cc820cb910597e8b5dad89d70.tar.xz serenity-2b053ea007d6ca9cc820cb910597e8b5dad89d70.zip | |
Fix #130
Removed action support from the builtin one as well, due to it adding some uneccassery complexity and it being only asked upon by one user
Diffstat (limited to 'src')
| -rw-r--r-- | src/client/dispatch.rs | 113 | ||||
| -rw-r--r-- | src/client/mod.rs | 80 | ||||
| -rw-r--r-- | src/framework/configuration.rs | 30 | ||||
| -rw-r--r-- | src/framework/help_commands.rs | 9 | ||||
| -rw-r--r-- | src/framework/mod.rs | 384 | ||||
| -rw-r--r-- | src/model/channel/message.rs | 3 |
6 files changed, 314 insertions, 305 deletions
diff --git a/src/client/dispatch.rs b/src/client/dispatch.rs index 68190d1..6c732d7 100644 --- a/src/client/dispatch.rs +++ b/src/client/dispatch.rs @@ -7,12 +7,12 @@ use super::Context; use typemap::ShareMap; use ::gateway::Shard; use ::model::event::Event; -use ::model::{Message, Reaction, GuildId, Channel}; +use ::model::{Message, GuildId, Channel}; use chrono::{Utc, Timelike}; use tokio_core::reactor::Handle; #[cfg(feature="framework")] -use ::ext::framework::{Framework, ReactionAction}; +use ::ext::framework::Framework; #[cfg(feature="cache")] use super::CACHE; @@ -61,66 +61,37 @@ fn context(conn: &Arc<Mutex<Shard>>, Context::new(conn.clone(), data.clone()) } -// Heck you macro hygiene. -macro_rules! impl_reaction_events { - (($event:ident, $conn:ident, $data:ident, $event_handler:ident, $framework:ident, $handle:ident), $type_of_action:ident, $dispatch_name:ident) => { - let context = context($conn, $data); - let framework = $framework.lock().unwrap(); - - if framework.initialized { - $dispatch_name(context.clone(), - $event.reaction.clone(), - $event_handler, - $handle); - - let res = framework.reaction_actions - .iter() - .find(|&(ra, _)| { - if let ReactionAction::$type_of_action(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_name(context, $event.reaction, $event_handler, $handle); - } - } -} - #[cfg(feature="framework")] pub fn dispatch<H: EventHandler + 'static>(event: Event, conn: &Arc<Mutex<Shard>>, - framework: &Arc<sync::Mutex<Framework>>, + framework: &Arc<sync::Mutex<Option<Box<Framework>>>>, data: &Arc<Mutex<ShareMap>>, event_handler: &Arc<H>, tokio_handle: &Handle) { match event { Event::MessageCreate(event) => { let context = context(conn, data); - let mut framework = framework.lock().unwrap(); - - if framework.initialized { + if let Some(ref mut framework) = *framework.lock().unwrap() { + if framework.initialized() { + dispatch_message(context.clone(), + event.message.clone(), + event_handler, + tokio_handle); + + framework.dispatch(context, event.message, tokio_handle); + } else { + dispatch_message(context.clone(), + event.message.clone(), + event_handler, + tokio_handle); + } + } else { dispatch_message(context.clone(), event.message.clone(), event_handler, tokio_handle); - - framework.dispatch(context, event.message, tokio_handle); - } else { - dispatch_message(context, event.message, event_handler, tokio_handle); } }, - Event::ReactionAdd(event) => { - impl_reaction_events!((event, conn, data, event_handler, framework, tokio_handle), Add, dispatch_reaction_add); - }, - Event::ReactionRemove(event) => { - impl_reaction_events!((event, conn, data, event_handler, framework, tokio_handle), Remove, dispatch_reaction_remove); - }, other => handle_event(other, conn, data, event_handler, tokio_handle), } } @@ -139,14 +110,6 @@ pub fn dispatch<H: EventHandler + 'static>(event: Event, event_handler, tokio_handle); }, - Event::ReactionAdd(event) => { - let context = context(conn, data); - dispatch_reaction_add(context, event.reaction, tokio_handle); - }, - Event::ReactionRemove(event) => { - let context = context(conn, data); - dispatch_reaction_remove(context, event.reaction, tokio_handle); - }, other => handle_event(other, conn, data, event_handler, tokio_handle), } } @@ -169,28 +132,6 @@ fn dispatch_message<H: EventHandler + 'static>(context: Context, }); } -fn dispatch_reaction_add<H: EventHandler + 'static>(context: Context, - reaction: Reaction, - event_handler: &Arc<H>, - tokio_handle: &Handle) { - let h = event_handler.clone(); - tokio_handle.spawn_fn(move || { - h.on_reaction_add(context, reaction); - Ok(()) - }); -} - -fn dispatch_reaction_remove<H: EventHandler + 'static>(context: Context, - reaction: Reaction, - event_handler: &Arc<H>, - tokio_handle: &Handle) { - let h = event_handler.clone(); - tokio_handle.spawn_fn(move || { - h.on_reaction_remove(context, reaction); - Ok(()) - }); -} - #[allow(cyclomatic_complexity, unused_assignments, unused_mut)] fn handle_event<H: EventHandler + 'static>(event: Event, conn: &Arc<Mutex<Shard>>, @@ -603,8 +544,22 @@ fn handle_event<H: EventHandler + 'static>(event: Event, }, // Already handled by the framework check macro - Event::ReactionAdd(_) => {}, - Event::ReactionRemove(_) => {}, + Event::ReactionAdd(event) => { + let h = event_handler.clone(); + let context = context(conn, data); + tokio_handle.spawn_fn(move || { + h.on_reaction_add(context, event.reaction); + Ok(()) + }); + }, + Event::ReactionRemove(event) => { + let h = event_handler.clone(); + let context = context(conn, data); + tokio_handle.spawn_fn(move || { + h.on_reaction_remove(context, event.reaction); + Ok(()) + }); + }, Event::ReactionRemoveAll(event) => { let context = context(conn, data); diff --git a/src/client/mod.rs b/src/client/mod.rs index 93e09ce..6241b5b 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -51,7 +51,7 @@ use ::internal::prelude::*; use ::internal::ws_impl::ReceiverExt; use ::model::event::*; -#[cfg(feature="framework")] +#[cfg(any(feature="framework", feature="builtin_framework"))] use ::framework::Framework; static HANDLE_STILL: AtomicBool = ATOMIC_BOOL_INIT; @@ -193,7 +193,7 @@ pub struct Client<H: EventHandler + 'static> { /// [`on_ready`]: #method.on_ready event_handler: Arc<H>, #[cfg(feature="framework")] - framework: Arc<sync::Mutex<Framework>>, + framework: Arc<sync::Mutex<Option<Box<Framework>>>>, token: Arc<sync::Mutex<String>>, } @@ -241,7 +241,7 @@ impl<H: EventHandler + 'static> Client<H> { Client { data: Arc::new(Mutex::new(ShareMap::custom())), event_handler: Arc::new(handler), - framework: Arc::new(sync::Mutex::new(Framework::default())), + framework: Arc::new(sync::Mutex::new(None)), token: locked, } } else { @@ -268,6 +268,8 @@ impl<H: EventHandler + 'static> Client<H> { /// # use serenity::prelude::EventHandler; /// # use std::error::Error; /// # + /// use serenity::framework::BuiltinFramework; + /// /// struct Handler; /// /// impl EventHandler for Handler {} @@ -276,7 +278,7 @@ impl<H: EventHandler + 'static> Client<H> { /// use std::env; /// /// let mut client = Client::new(&env::var("DISCORD_TOKEN")?, Handler); - /// client.with_framework(|f| f + /// client.with_framework(BuiltinFramework::new() /// .configure(|c| c.prefix("~")) /// .command("ping", |c| c.exec_str("Pong!"))); /// # Ok(()) @@ -286,16 +288,69 @@ impl<H: EventHandler + 'static> Client<H> { /// # try_main().unwrap(); /// # } /// ``` + /// + /// Using your own framework: + /// + /// ```rust,ignore + /// # use serenity::prelude::EventHandler; + /// # use std::error::Error; + /// # + /// use serenity::framework::Framework; + /// use serenity::client::Context; + /// use serenity::model::*; + /// use tokio_core::reactor::Handle; + /// use std::collections::HashMap; + /// + /// + /// struct MyFramework { + /// commands: HashMap<String, Box<Fn(Message, Vec<String>)>>, + /// } + /// + /// impl Framework for MyFramework { + /// fn dispatch(&mut self, _: Context, msg: Message, tokio_handle: &Handle) { + /// let args = msg.content.split_whitespace(); + /// let command = match args.next() { + /// Some(command) => { + /// if !command.starts_with('*') { return; } + /// command + /// }, + /// None => return, + /// }; + /// + /// let command = match self.commands.get(&command) { + /// Some(command) => command, None => return, + /// }; + /// + /// tokio_handle.spawn_fn(move || { (command)(msg, args); Ok() }); + /// } + /// } + /// + /// struct Handler; + /// + /// impl EventHandler for Handler {} + /// + /// + /// # fn try_main() -> Result<(), Box<Error>> { + /// use serenity::Client; + /// use std::env; /// + /// let mut client = Client::new(&env::var("DISCORD_TOKEN")?, Handler); + /// client.with_framework(MyFramework { commands: { let mut map = HashMap::new(); map.insert("ping".to_string(), Box::new(|msg, _| msg.channel_id.say("pong!"))); map }}); + /// # Ok(()) + /// # } + /// # + /// # fn main() { + /// # try_main().unwrap(); + /// # } + /// ``` /// Refer to the documentation for the `framework` module for more in-depth /// information. /// /// [`on_message`]: #method.on_message /// [framework docs]: ../framework/index.html #[cfg(feature="framework")] - pub fn with_framework<F>(&mut self, f: F) - where F: FnOnce(Framework) -> Framework + Send + Sync + 'static { - self.framework = Arc::new(sync::Mutex::new(f(Framework::default()))); + pub fn with_framework<F: Framework + 'static>(&mut self, f: F) { + self.framework = Arc::new(sync::Mutex::new(Some(Box::new(f)))); } /// Establish the connection and start listening for events. @@ -631,13 +686,13 @@ impl<H: EventHandler + 'static> Client<H> { // Update the framework's current user if the feature is enabled. // // This also acts as a form of check to ensure the token is correct. - #[cfg(feature="framework")] + #[cfg(all(feature="builtin_framework", feature="framework"))] { let user = http::get_current_user()?; - self.framework.lock() - .unwrap() - .update_current_user(user.id, user.bot); + if let Some(ref mut framework) = *self.framework.lock().unwrap() { + framework.update_current_user(user.id, user.bot); + } } let gateway_url = Arc::new(sync::Mutex::new(url)); @@ -678,6 +733,7 @@ impl<H: EventHandler + 'static> Client<H> { shard: shard, shard_info: shard_info, token: self.token.clone(), + _pd: std::marker::PhantomData, } }}; @@ -718,7 +774,7 @@ struct BootInfo { struct MonitorInfo<H: EventHandler + 'static> { data: Arc<Mutex<ShareMap>>, event_handler: Arc<H>, - framework: Arc<sync::Mutex<Framework>>, + framework: Arc<sync::Mutex<Option<Box<Framework>>>>, gateway_url: Arc<sync::Mutex<String>>, shard: Arc<Mutex<Shard>>, shard_info: [u64; 2], diff --git a/src/framework/configuration.rs b/src/framework/configuration.rs index 16c595f..c74739e 100644 --- a/src/framework/configuration.rs +++ b/src/framework/configuration.rs @@ -22,10 +22,11 @@ use ::model::{GuildId, Message, UserId}; /// impl EventHandler for Handler {} /// use serenity::Client; /// use std::env; +/// use serenity::framework::BuiltinFramework; /// /// let mut client = Client::new(&env::var("DISCORD_BOT_TOKEN").unwrap(), Handler); /// -/// client.with_framework(|f| f +/// client.with_framework(BuiltinFramework::new() /// .configure(|c| c.on_mention(true).prefix("~"))); /// ``` /// @@ -109,8 +110,9 @@ impl Configuration { /// # impl EventHandler for Handler {} /// # let mut client = Client::new("token", Handler); /// use serenity::model::GuildId; + /// use serenity::framework::BuiltinFramework; /// - /// client.with_framework(|f| f.configure(|c| c + /// client.with_framework(BuiltinFramework::new().configure(|c| c /// .blocked_guilds(vec![GuildId(7), GuildId(77)].into_iter().collect()))); /// ``` pub fn blocked_guilds(mut self, guilds: HashSet<GuildId>) -> Self { @@ -133,8 +135,9 @@ impl Configuration { /// # impl EventHandler for Handler {} /// # let mut client = Client::new("token", Handler); /// use serenity::model::UserId; + /// use serenity::framework::BuiltinFramework; /// - /// client.with_framework(|f| f.configure(|c| c + /// client.with_framework(BuiltinFramework::new().configure(|c| c /// .blocked_users(vec![UserId(7), UserId(77)].into_iter().collect()))); /// ``` pub fn blocked_users(mut self, users: HashSet<UserId>) -> Self { @@ -169,10 +172,11 @@ impl Configuration { /// # /// # impl EventHandler for Handler {} /// # let mut client = Client::new("token", Handler); + /// use serenity::framework::BuiltinFramework; /// /// let disabled = vec!["ping"].into_iter().map(|x| x.to_owned()).collect(); /// - /// client.with_framework(|f| f + /// client.with_framework(BuiltinFramework::new() /// .command("ping", |c| c.exec_str("pong!")) /// .configure(|c| c.disabled_commands(disabled))); /// ``` @@ -198,7 +202,9 @@ impl Configuration { /// # /// # impl EventHandler for Handler {} /// # let mut client = Client::new("token", Handler); - /// client.with_framework(|f| f + /// use serenity::framework::BuiltinFramework; + /// + /// client.with_framework(BuiltinFramework::new() /// .command("ping", |c| c.exec_str("Pong!")) /// .configure(|c| c.dynamic_prefix(|_, msg| { /// Some(if msg.channel_id.0 % 5 == 0 { @@ -282,8 +288,9 @@ impl Configuration { /// # impl EventHandler for Handler {} /// # let mut client = Client::new("token", Handler); /// use serenity::model::UserId; + /// use serenity::framework::BuiltinFramework; /// - /// client.with_framework(|f| f.configure(|c| c + /// client.with_framework(BuiltinFramework::new().configure(|c| c /// .owners(vec![UserId(7), UserId(77)].into_iter().collect()))); /// ``` /// @@ -297,12 +304,13 @@ impl Configuration { /// # let mut client = Client::new("token", Handler); /// use serenity::model::UserId; /// use std::collections::HashSet; + /// use serenity::framework::BuiltinFramework; /// /// let mut set = HashSet::new(); /// set.insert(UserId(7)); /// set.insert(UserId(77)); /// - /// client.with_framework(|f| f.configure(|c| c.owners(set))); + /// client.with_framework(BuiltinFramework::new().configure(|c| c.owners(set))); /// ``` pub fn owners(mut self, user_ids: HashSet<UserId>) -> Self { self.owners = user_ids; @@ -324,7 +332,9 @@ impl Configuration { /// # impl EventHandler for Handler {} /// # let mut client = Client::new("token", Handler); /// # - /// client.with_framework(|f| f.configure(|c| c + /// use serenity::framework::BuiltinFramework; + /// + /// client.with_framework(BuiltinFramework::new().configure(|c| c /// .prefix("!"))); /// ``` pub fn prefix(mut self, prefix: &str) -> Self { @@ -347,7 +357,9 @@ impl Configuration { /// # impl EventHandler for Handler {} /// # let mut client = Client::new("token", Handler); /// # - /// client.with_framework(|f| f.configure(|c| c + /// use serenity::framework::BuiltinFramework; + /// + /// client.with_framework(BuiltinFramework::new().configure(|c| c /// .prefixes(vec!["!", ">", "+"]))); /// ``` pub fn prefixes(mut self, prefixes: Vec<&str>) -> Self { diff --git a/src/framework/help_commands.rs b/src/framework/help_commands.rs index a35ce7d..d589ded 100644 --- a/src/framework/help_commands.rs +++ b/src/framework/help_commands.rs @@ -11,8 +11,9 @@ //! use std::env; //! //! let mut client = Client::new(&env::var("DISCORD_TOKEN").unwrap()); +//! use serenity::framework::BuiltinFramework; //! -//! client.with_framework(|f| f +//! client.with_framework(BuiltinFramework::new() //! .command("help", |c| c.exec_help(help_commands::with_embeds))); //! ``` //! @@ -65,8 +66,9 @@ fn remove_aliases(cmds: &HashMap<String, CommandOrAlias>) -> HashMap<&String, &I /// # let mut client = Client::new("token", Handler); /// # /// use serenity::ext::framework::help_commands; +/// use serenity::framework::BuiltinFramework; /// -/// client.with_framework(|f| f +/// client.with_framework(BuiltinFramework::new() /// .command("help", |c| c.exec_help(help_commands::with_embeds))); /// ``` pub fn with_embeds(_: &mut Context, @@ -217,8 +219,9 @@ pub fn with_embeds(_: &mut Context, /// # let mut client = Client::new("token", Handler); /// # /// use serenity::ext::framework::help_commands; +/// use serenity::framework::BuiltinFramework; /// -/// client.with_framework(|f| f +/// client.with_framework(BuiltinFramework::new() /// .command("help", |c| c.exec_help(help_commands::plain))); /// ``` pub fn plain(_: &mut Context, diff --git a/src/framework/mod.rs b/src/framework/mod.rs index 73188ca..d04f60f 100644 --- a/src/framework/mod.rs +++ b/src/framework/mod.rs @@ -74,7 +74,7 @@ use std::collections::HashMap; use std::default::Default; use std::sync::Arc; use ::client::Context; -use ::model::{Message, MessageId, UserId, GuildId, ChannelId, ReactionType}; +use ::model::{Message, UserId, GuildId, ChannelId}; use ::model::permissions::Permissions; use ::utils; use tokio_core::reactor::Handle; @@ -84,6 +84,20 @@ use ::client::CACHE; #[cfg(feature="cache")] use ::model::Channel; +/// This trait allows for serenity to either use its builtin framework, or yours. +/// +/// When implementing, be sure to use `tokio_handle.spawn_fn(|| ...; Ok())` when dispatching commands. +/// +/// Note that you may see some other methods in here as well, but they're meant to be internal only for the builtin framework. +pub trait Framework { + fn dispatch(&mut self, Context, Message, &Handle); + + #[cfg(feature="builtin_framework")] + fn update_current_user(&mut self, UserId, bool) {} + #[cfg(feature="builtin_framework")] + fn initialized(&self) -> bool { false } +} + /// A macro to generate "named parameters". This is useful to avoid manually /// using the "arguments" parameter and manually parsing types. /// @@ -209,16 +223,6 @@ pub enum DispatchError { type DispatchErrorHook = Fn(Context, Message, DispatchError) + 'static; -pub(crate) type ActionFn = Fn(Context, MessageId, ChannelId) + '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. @@ -226,13 +230,12 @@ pub enum ReactionAction { /// [module-level documentation]: index.html #[allow(type_complexity)] #[derive(Default)] -pub struct Framework { +pub struct BuiltinFramework { configuration: Configuration, groups: HashMap<String, Arc<CommandGroup>>, 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". /// @@ -253,7 +256,11 @@ pub struct Framework { user_info: (u64, bool), } -impl Framework { +impl BuiltinFramework { + pub fn new() -> Self { + BuiltinFramework::default() + } + /// Configures the framework, setting non-default values. All fields are /// optional. Refer to [`Configuration::default`] for more information on /// the default values. @@ -268,10 +275,11 @@ impl Framework { /// # struct Handler; /// # impl EventHandler for Handler {} /// use serenity::Client; + /// use serenity::framework::BuiltinFramework; /// use std::env; /// /// let mut client = Client::new(&env::var("DISCORD_TOKEN").unwrap(), Handler); - /// client.with_framework(|f| f + /// client.with_framework(BuiltinFramework::new() /// .configure(|c| c /// .depth(3) /// .allow_whitespace(true) @@ -305,7 +313,9 @@ impl Framework { /// # impl EventHandler for Handler {} /// # let mut client = Client::new("token", Handler); /// # - /// client.with_framework(|f| f + /// use serenity::framework::BuiltinFramework; + /// + /// client.with_framework(BuiltinFramework::new() /// .bucket("basic", 2, 10, 3) /// .command("ping", |c| c /// .bucket("basic") @@ -336,12 +346,14 @@ impl Framework { /// # impl EventHandler for Handler {} /// # let mut client = Client::new("token", Handler); /// # - /// client.with_framework(|f| f + /// use serenity::framework::BuiltinFramework; + /// + /// client.with_framework(BuiltinFramework::new() /// .complex_bucket("basic", 2, 10, 3, |_, guild_id, channel_id, user_id| { /// // check if the guild is `123` and the channel where the command(s) was called: `456` /// // and if the user who called the command(s) is `789` /// // otherwise don't apply the bucket at all. - /// guild_id == 123 && channel_id == 456 && user_id == 789 + /// guild_id.is_some() && guild_id.unwrap() == 123 && channel_id == 456 && user_id == 789 /// }) /// .command("ping", |c| c /// .bucket("basic") @@ -376,7 +388,9 @@ impl Framework { /// # impl EventHandler for Handler {} /// # let mut client = Client::new("token", Handler); /// # - /// client.with_framework(|f| f + /// use serenity::framework::BuiltinFramework; + /// + /// client.with_framework(BuiltinFramework::new() /// .complex_bucket("basic", 2, 10, 3, |_, channel_id, user_id| { /// // check if the channel's id where the command(s) was called is `456` /// // and if the user who called the command(s) is `789` @@ -418,7 +432,9 @@ impl Framework { /// # impl EventHandler for Handler {} /// # let mut client = Client::new("token", Handler); /// # - /// client.with_framework(|f| f + /// use serenity::framework::BuiltinFramework; + /// + /// client.with_framework(BuiltinFramework::new() /// .simple_bucket("simple", 2) /// .command("ping", |c| c /// .bucket("simple") @@ -438,58 +454,6 @@ 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::model::ReactionType; - /// use serenity::framework::ReactionAction; - /// # use serenity::prelude::*; - /// # struct Handler; - /// # - /// # impl EventHandler for Handler {} - /// # let mut client = Client::new("token", Handler); - /// # - /// 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::model::ReactionType; - /// use serenity::framework::ReactionAction; - /// # use serenity::prelude::*; - /// # struct Handler; - /// # - /// # impl EventHandler for Handler {} - /// # let mut client = Client::new("token", Handler); - /// # - /// 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) { @@ -613,126 +577,6 @@ impl Framework { } } - #[allow(cyclomatic_complexity)] - pub(crate) fn dispatch(&mut self, mut context: Context, message: Message, tokio_handle: &Handle) { - let res = command::positions(&mut context, &message, &self.configuration); - - let positions = match res { - Some(mut positions) => { - // First, take out the prefixes that are as long as _or_ longer - // than the message, to avoid character boundary violations. - positions.retain(|p| *p < message.content.len()); - - // Ensure that there is _at least one_ position remaining. There - // is no point in continuing if there is not. - if positions.is_empty() { - return; - } - - positions - }, - None => return, - }; - - 'outer: for position in positions { - let mut built = String::new(); - let round = message.content.chars() - .skip(position) - .collect::<String>(); - let round = round.trim() - .split_whitespace() - .collect::<Vec<&str>>(); - - for i in 0..self.configuration.depth { - if i != 0 { - built.push(' '); - } - - built.push_str(match round.get(i) { - Some(piece) => piece, - None => continue 'outer, - }); - - let groups = self.groups.clone(); - - for group in groups.values() { - let command_length = built.len(); - - if let Some(&CommandOrAlias::Alias(ref points_to)) = group.commands.get(&built) { - built = points_to.to_owned(); - } - - let to_check = if let Some(ref prefix) = group.prefix { - if built.starts_with(prefix) && command_length > prefix.len() + 1 { - built[(prefix.len() + 1)..].to_owned() - } else { - continue; - } - } else { - built.clone() - }; - - if let Some(&CommandOrAlias::Command(ref command)) = group.commands.get(&to_check) { - let before = self.before.clone(); - let command = command.clone(); - let after = self.after.clone(); - let groups = self.groups.clone(); - - let args = { - let content = message.content[position..].trim(); - - if command.use_quotes { - utils::parse_quotes(&content[command_length..]) - } else { - content[command_length..] - .split_whitespace() - .map(|arg| arg.to_owned()) - .collect::<Vec<String>>() - } - }; - - if let Some(error) = self.should_fail(&mut context, &message, &command, args.len(), &to_check, &built) { - if let Some(ref handler) = self.dispatch_error_handler { - handler(context, message, error); - } - return; - } - - tokio_handle.spawn_fn(move || { - if let Some(before) = before { - if !(before)(&mut context, &message, &built) { - return Ok(()); - } - } - - let result = match command.exec { - CommandType::StringResponse(ref x) => { - let _ = message.channel_id.say(x); - - Ok(()) - }, - CommandType::Basic(ref x) => { - (x)(&mut context, &message, args) - }, - CommandType::WithCommands(ref x) => { - (x)(&mut context, &message, groups, &args) - } - }; - - if let Some(after) = after { - (after)(&mut context, &message, &built, result); - } - - Ok(()) - }); - - return; - } - } - } - } - } - /// Adds a function to be associated with a command, which will be called /// when a command is used in a message. /// @@ -763,7 +607,9 @@ impl Framework { /// # impl EventHandler for Handler {} /// # let mut client = Client::new("token", Handler); /// # - /// client.with_framework(|f| f.on("ping", ping)); + /// use serenity::framework::BuiltinFramework; + /// + /// client.with_framework(BuiltinFramework::new().on("ping", ping)); /// /// command!(ping(_ctx, msg) { /// let _ = msg.channel_id.say("pong!"); @@ -771,7 +617,7 @@ impl Framework { /// # } /// ``` pub fn on<F, S>(mut self, command_name: S, f: F) -> Self - where F: Fn(&mut Context, &Message, Vec<String>) -> Result<(), String> + Send + Sync + 'static, + where F: Fn(&mut Context, &Message, Vec<String>) -> Result<(), String> + 'static, S: Into<String> { { let ungrouped = self.groups.entry("Ungrouped".to_owned()) @@ -844,7 +690,9 @@ impl Framework { /// # impl EventHandler for Handler {} /// # let mut client = Client::new("token", Handler); /// # - /// client.with_framework(|f| f + /// use serenity::framework::BuiltinFramework; + /// + /// client.with_framework(BuiltinFramework::new() /// .group("ping-pong", |g| g /// .command("ping", |c| c.exec_str("pong!")) /// .command("pong", |c| c.exec_str("ping!")))); @@ -875,8 +723,9 @@ impl Framework { /// # impl EventHandler for Handler {} /// # let mut client = Client::new("token", Handler); /// use serenity::framework::DispatchError::{NotEnoughArguments, TooManyArguments}; + /// use serenity::framework::BuiltinFramework; /// - /// client.with_framework(|f| f + /// client.with_framework(BuiltinFramework::new() /// .on_dispatch_error(|_, msg, error| { /// match error { /// NotEnoughArguments { min, given } => { @@ -914,7 +763,9 @@ impl Framework { /// # impl EventHandler for Handler {} /// # let mut client = Client::new("token", Handler); /// # - /// client.with_framework(|f| f + /// use serenity::framework::BuiltinFramework; + /// + /// client.with_framework(BuiltinFramework::new() /// .before(|ctx, msg, cmd_name| { /// println!("Running command {}", cmd_name); /// true @@ -930,7 +781,9 @@ impl Framework { /// # impl EventHandler for Handler {} /// # let mut client = Client::new("token", Handler); /// # - /// client.with_framework(|f| f + /// use serenity::framework::BuiltinFramework; + /// + /// client.with_framework(BuiltinFramework::new() /// .before(|_, msg, cmd_name| { /// if let Ok(channel) = msg.channel_id.get() { /// // Don't run unless in nsfw channel @@ -966,7 +819,9 @@ impl Framework { /// # impl EventHandler for Handler {} /// # let mut client = Client::new("token", Handler); /// # - /// client.with_framework(|f| f + /// use serenity::framework::BuiltinFramework; + /// + /// client.with_framework(BuiltinFramework::new() /// .after(|ctx, msg, cmd_name, error| { /// // Print out an error if it happened /// if let Err(why) = error { @@ -980,8 +835,135 @@ impl Framework { self } +} + +impl Framework for BuiltinFramework { + fn dispatch(&mut self, mut context: Context, message: Message, tokio_handle: &Handle) { + let res = command::positions(&mut context, &message, &self.configuration); + + let positions = match res { + Some(mut positions) => { + // First, take out the prefixes that are as long as _or_ longer + // than the message, to avoid character boundary violations. + positions.retain(|p| *p < message.content.len()); + + // Ensure that there is _at least one_ position remaining. There + // is no point in continuing if there is not. + if positions.is_empty() { + return; + } - pub(crate) fn update_current_user(&mut self, user_id: UserId, is_bot: bool) { + positions + }, + None => return, + }; + + 'outer: for position in positions { + let mut built = String::new(); + let round = message.content.chars() + .skip(position) + .collect::<String>(); + let round = round.trim() + .split_whitespace() + .collect::<Vec<&str>>(); + + for i in 0..self.configuration.depth { + if i != 0 { + built.push(' '); + } + + built.push_str(match round.get(i) { + Some(piece) => piece, + None => continue 'outer, + }); + + let groups = self.groups.clone(); + + for group in groups.values() { + let command_length = built.len(); + + if let Some(&CommandOrAlias::Alias(ref points_to)) = group.commands.get(&built) { + built = points_to.to_owned(); + } + + let to_check = if let Some(ref prefix) = group.prefix { + if built.starts_with(prefix) && command_length > prefix.len() + 1 { + built[(prefix.len() + 1)..].to_owned() + } else { + continue; + } + } else { + built.clone() + }; + + if let Some(&CommandOrAlias::Command(ref command)) = group.commands.get(&to_check) { + let before = self.before.clone(); + let command = command.clone(); + let after = self.after.clone(); + let groups = self.groups.clone(); + + let args = { + let content = message.content[position..].trim(); + + if command.use_quotes { + utils::parse_quotes(&content[command_length..]) + } else { + content[command_length..] + .split_whitespace() + .map(|arg| arg.to_owned()) + .collect::<Vec<String>>() + } + }; + + if let Some(error) = self.should_fail(&mut context, &message, &command, args.len(), &to_check, &built) { + if let Some(ref handler) = self.dispatch_error_handler { + handler(context, message, error); + } + return; + } + + tokio_handle.spawn_fn(move || { + if let Some(before) = before { + if !(before)(&mut context, &message, &built) { + return Ok(()); + } + } + + let result = match command.exec { + CommandType::StringResponse(ref x) => { + let _ = message.channel_id.say(x); + + Ok(()) + }, + CommandType::Basic(ref x) => { + (x)(&mut context, &message, args) + }, + CommandType::WithCommands(ref x) => { + (x)(&mut context, &message, groups, &args) + } + }; + + if let Some(after) = after { + (after)(&mut context, &message, &built, result); + } + + Ok(()) + }); + + return; + } + } + } + } + } + + #[cfg(feature="builtin_framework")] + fn update_current_user(&mut self, user_id: UserId, is_bot: bool) { self.user_info = (user_id.0, is_bot); } -} + + #[cfg(feature="builtin_framework")] + fn initialized(&self) -> bool { + self.initialized + } +}
\ No newline at end of file diff --git a/src/model/channel/message.rs b/src/model/channel/message.rs index e1eccf0..372c3de 100644 --- a/src/model/channel/message.rs +++ b/src/model/channel/message.rs @@ -88,8 +88,9 @@ impl Message { /// # let mut client = Client::new("token", Handler); /// # /// use serenity::model::Channel; + /// use serenity::framework::BuiltinFramework; /// - /// client.with_framework(|f| f + /// client.with_framework(BuiltinFramework::new() /// .configure(|c| c.prefix("~")) /// .command("channelname", |c| c.exec(channel_name))); /// |