aboutsummaryrefslogtreecommitdiff
path: root/src/framework/standard/mod.rs
diff options
context:
space:
mode:
authoracdenisSK <[email protected]>2017-11-14 15:02:10 +0100
committeracdenisSK <[email protected]>2017-11-15 21:09:16 +0100
commitf10b9d77f0b94864fa20688e3c99de6cec7ca6f9 (patch)
treecb7bcd4244ce9813f07cf5eabaa95c71f8c9bb81 /src/framework/standard/mod.rs
parentUse the threadpool for framework command execution (diff)
downloadserenity-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.rs194
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))