diff options
| author | acdenisSK <[email protected]> | 2017-11-14 15:02:10 +0100 |
|---|---|---|
| committer | acdenisSK <[email protected]> | 2017-11-15 21:09:16 +0100 |
| commit | f10b9d77f0b94864fa20688e3c99de6cec7ca6f9 (patch) | |
| tree | cb7bcd4244ce9813f07cf5eabaa95c71f8c9bb81 /src/framework/standard/mod.rs | |
| parent | Use the threadpool for framework command execution (diff) | |
| download | serenity-f10b9d77f0b94864fa20688e3c99de6cec7ca6f9.tar.xz serenity-f10b9d77f0b94864fa20688e3c99de6cec7ca6f9.zip | |
Change most of the framework to use trait-based-commands
Diffstat (limited to 'src/framework/standard/mod.rs')
| -rw-r--r-- | src/framework/standard/mod.rs | 194 |
1 files changed, 127 insertions, 67 deletions
diff --git a/src/framework/standard/mod.rs b/src/framework/standard/mod.rs index dd7aaae..106d64c 100644 --- a/src/framework/standard/mod.rs +++ b/src/framework/standard/mod.rs @@ -10,7 +10,8 @@ mod args; pub use self::args::{Args, Iter, FromStrZc, Error as ArgError}; pub(crate) use self::buckets::{Bucket, Ratelimit}; -pub use self::command::{Command, CommandGroup, CommandType, Error as CommandError}; +pub(crate) use self::command::{A, Help}; +pub use self::command::{Command, CommandGroup, CommandOptions, Error as CommandError}; pub use self::command::CommandOrAlias; pub use self::configuration::Configuration; pub use self::create_command::CreateCommand; @@ -68,45 +69,65 @@ use model::Channel; #[macro_export] macro_rules! command { ($fname:ident($c:ident) $b:block) => { - #[allow(unreachable_code, unused_mut)] - pub fn $fname(mut $c: &mut $crate::client::Context, + #[allow(non_camel_case_types)] + struct $fname; + + impl $crate::framework::standard::Command for $fname { + #[allow(unreachable_code, unused_mut)] + fn execute(&self, mut $c: &mut $crate::client::Context, _: &$crate::model::Message, _: $crate::framework::standard::Args) -> ::std::result::Result<(), $crate::framework::standard::CommandError> { - $b + + $b - Ok(()) + Ok(()) + } } }; ($fname:ident($c:ident, $m:ident) $b:block) => { - #[allow(unreachable_code, unused_mut)] - pub fn $fname(mut $c: &mut $crate::client::Context, + #[allow(non_camel_case_types)] + struct $fname; + + impl $crate::framework::standard::Command for $fname { + #[allow(unreachable_code, unused_mut)] + fn execute(&self, mut $c: &mut $crate::client::Context, $m: &$crate::model::Message, _: $crate::framework::standard::Args) -> ::std::result::Result<(), $crate::framework::standard::CommandError> { - $b + + $b - Ok(()) + Ok(()) + } } }; ($fname:ident($c:ident, $m:ident, $a:ident) $b:block) => { - #[allow(unreachable_code, unused_mut)] - pub fn $fname(mut $c: &mut $crate::client::Context, + #[allow(non_camel_case_types)] + struct $fname; + + impl $crate::framework::standard::Command for $fname { + #[allow(unreachable_code, unused_mut)] + fn execute(&self, mut $c: &mut $crate::client::Context, $m: &$crate::model::Message, mut $a: $crate::framework::standard::Args) -> ::std::result::Result<(), $crate::framework::standard::CommandError> { - $b + + $b - Ok(()) + Ok(()) + } } }; } -/// A enum representing all possible fail conditions under which a command won't +/// An enum representing all possible fail conditions under which a command won't /// be executed. pub enum DispatchError { /// When a custom function check has failed. - CheckFailed(Arc<Command>), + // + // TODO: Bring back `Arc<Command>` as `CommandOptions` here somehow? + CheckFailed, /// When the requested command is disabled in bot configuration. CommandDisabled(String), /// When the user is blocked in bot configuration. @@ -146,7 +167,7 @@ impl fmt::Debug for DispatchError { use self::DispatchError::*; match *self { - CheckFailed(..) => write!(f, "DispatchError::CheckFailed"), + CheckFailed => write!(f, "DispatchError::CheckFailed"), CommandDisabled(ref s) => f.debug_tuple("DispatchError::CommandDisabled").field(&s).finish(), BlockedUser => write!(f, "DispatchError::BlockedUser"), BlockedGuild => write!(f, "DispatchError::BlockedGuild"), @@ -175,6 +196,7 @@ type DispatchErrorHook = Fn(Context, Message, DispatchError) + Send + Sync + 'st pub struct StandardFramework { configuration: Configuration, groups: HashMap<String, Arc<CommandGroup>>, + help: Option<Arc<Help>>, before: Option<Arc<BeforeHook>>, dispatch_error_handler: Option<Arc<DispatchErrorHook>>, buckets: HashMap<String, Bucket>, @@ -263,10 +285,9 @@ impl StandardFramework { /// .bucket("basic") /// .exec_str("pong!"))); /// ``` - pub fn bucket<S>(mut self, s: S, delay: i64, time_span: i64, limit: i32) -> Self - where S: Into<String> { + pub fn bucket(mut self, s: &str, delay: i64, time_span: i64, limit: i32) -> Self { self.buckets.insert( - s.into(), + s.to_string(), Bucket { ratelimit: Ratelimit { delay: delay, @@ -309,8 +330,8 @@ impl StandardFramework { /// /// [`bucket`]: #method.bucket #[cfg(feature = "cache")] - pub fn complex_bucket<S, Check>(mut self, - s: S, + pub fn complex_bucket<Check>(mut self, + s: &str, delay: i64, time_span: i64, limit: i32, @@ -319,10 +340,9 @@ impl StandardFramework { where Check: Fn(&mut Context, Option<GuildId>, ChannelId, UserId) -> bool + Send + Sync - + 'static, - S: Into<String> { + + 'static { self.buckets.insert( - s.into(), + s.to_string(), Bucket { ratelimit: Ratelimit { delay, @@ -363,17 +383,16 @@ impl StandardFramework { /// /// [`bucket`]: #method.bucket #[cfg(not(feature = "cache"))] - pub fn complex_bucket<S, Check>(mut self, - s: S, + pub fn complex_bucket<Check>(mut self, + s: &str, delay: i64, time_span: i64, limit: i32, check: Check) -> Self - where Check: Fn(&mut Context, ChannelId, UserId) -> bool + Send + Sync + 'static, - S: Into<String> { + where Check: Fn(&mut Context, ChannelId, UserId) -> bool + Send + Sync + 'static { self.buckets.insert( - s.into(), + s.to_string(), Bucket { ratelimit: Ratelimit { delay, @@ -408,10 +427,9 @@ impl StandardFramework { /// .bucket("simple") /// .exec_str("pong!"))); /// ``` - pub fn simple_bucket<S>(mut self, s: S, delay: i64) -> Self - where S: Into<String> { + pub fn simple_bucket<S>(mut self, s: &str, delay: i64) -> Self { self.buckets.insert( - s.into(), + s.to_string(), Bucket { ratelimit: Ratelimit { delay: delay, @@ -448,7 +466,7 @@ impl StandardFramework { fn should_fail(&mut self, mut context: &mut Context, message: &Message, - command: &Arc<Command>, + command: &Arc<CommandOptions>, args: &mut Args, to_check: &str, built: &str) @@ -559,7 +577,7 @@ impl StandardFramework { if all_passed { None } else { - Some(DispatchError::CheckFailed(Arc::clone(command))) + Some(DispatchError::CheckFailed) } } } @@ -616,7 +634,29 @@ impl StandardFramework { if let Some(ref mut group) = Arc::get_mut(ungrouped) { group .commands - .insert(name.to_string(), CommandOrAlias::Command(Arc::new(Command::new(f)))); + .insert(name.to_string(), CommandOrAlias::Command(Arc::new(A(f)))); + } + } + + self.initialized = true; + + self + } + + /// Same as [`on`], but accepts a [`Command`] directly. + /// + /// [`on`]: #method.on + /// [`Command`]: trait.Command.html + pub fn cmd<C: Command + 'static>(mut self, name: &str, c: C) -> Self { + { + let ungrouped = self.groups + .entry("Ungrouped".to_string()) + .or_insert_with(|| Arc::new(CommandGroup::default())); + + if let Some(ref mut group) = Arc::get_mut(ungrouped) { + group + .commands + .insert(name.to_string(), CommandOrAlias::Command(Arc::new(c))); } } @@ -636,26 +676,26 @@ impl StandardFramework { /// let _ = ctx.say("pong"); /// })); /// ``` - pub fn command<F, S>(mut self, command_name: S, f: F) -> Self - where F: FnOnce(CreateCommand) -> CreateCommand, S: Into<String> { + pub fn command<F, S>(mut self, command_name: &str, f: F) -> Self + where F: FnOnce(CreateCommand) -> CreateCommand { { let ungrouped = self.groups .entry("Ungrouped".to_string()) .or_insert_with(|| Arc::new(CommandGroup::default())); if let Some(ref mut group) = Arc::get_mut(ungrouped) { - let cmd = f(CreateCommand(Command::default())).0; - let name = command_name.into(); + let cmd = f(CreateCommand(CommandOptions::default(), |_, _, _| Ok(()))).finish(); + let name = command_name.to_string(); if let Some(ref prefix) = group.prefix { - for v in &cmd.aliases { + for v in &cmd.options().aliases { group.commands.insert( format!("{} {}", prefix, v), CommandOrAlias::Alias(format!("{} {}", prefix, name)), ); } } else { - for v in &cmd.aliases { + for v in &cmd.options().aliases { group .commands .insert(v.to_string(), CommandOrAlias::Alias(name.clone())); @@ -664,7 +704,7 @@ impl StandardFramework { group .commands - .insert(name, CommandOrAlias::Command(Arc::new(cmd))); + .insert(name, CommandOrAlias::Command(cmd)); } } @@ -673,6 +713,13 @@ impl StandardFramework { self } + /// Sets what code should be execute when a user requests for `(prefix)help`. + pub fn help(mut self, f: Help) -> Self { + self.help = Some(Arc::new(f)); + + self + } + /// Adds a group which can organize several related commands. /// Groups are taken into account when using /// `serenity::framework::standard::help_commands`. @@ -904,24 +951,47 @@ impl Framework for StandardFramework { to_check }; - if let Some(&CommandOrAlias::Command(ref command)) = - group.commands.get(&to_check) { - let before = self.before.clone(); - let command = Arc::clone(command); - let after = self.after.clone(); - let groups = self.groups.clone(); + let mut args = { + let mut content = message.content[position..].trim(); + content = content[command_length..].trim(); - let mut args = { - let mut content = message.content[position..].trim(); - content = content[command_length..].trim(); + Args::new(&content, self.configuration.delimiters.clone()) + }; - Args::new(&content, self.configuration.delimiters.clone()) - }; + let before = self.before.clone(); + let after = self.after.clone(); + + // This is a special case. + if to_check == "help" { + let help = self.help.clone(); + if let Some(help) = help { + let groups = self.groups.clone(); + threadpool.execute(move || { + if let Some(before) = before { + if !(before)(&mut context, &message, &built) { + return; + } + } + let result = (help)(&mut context, &message, groups, args); + + if let Some(after) = after { + (after)(&mut context, &message, &built, result); + } + }); + return; + } + + return; + } + + if let Some(&CommandOrAlias::Command(ref command)) = + group.commands.get(&to_check) { + let command = Arc::clone(command); if let Some(error) = self.should_fail( &mut context, &message, - &command, + &command.options(), &mut args, &to_check, &built, @@ -939,17 +1009,7 @@ impl Framework for StandardFramework { } } - 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) - }, - }; + let result = command.execute(&mut context, &message, args); if let Some(after) = after { (after)(&mut context, &message, &built, result); @@ -969,7 +1029,7 @@ impl Framework for StandardFramework { } #[cfg(feature = "cache")] -pub fn has_correct_permissions(command: &Command, message: &Message) -> bool { +pub fn has_correct_permissions(command: &Arc<CommandOptions>, message: &Message) -> bool { if !command.required_permissions.is_empty() { if let Some(guild) = message.guild() { let perms = guild @@ -983,7 +1043,7 @@ pub fn has_correct_permissions(command: &Command, message: &Message) -> bool { } #[cfg(feature = "cache")] -pub fn has_correct_roles(cmd: &Command, guild: &Guild, member: &Member) -> bool { +pub fn has_correct_roles(cmd: &Arc<CommandOptions>, guild: &Guild, member: &Member) -> bool { cmd.allowed_roles .iter() .flat_map(|r| guild.role_by_name(r)) |