diff options
| author | Austin Hellyer <[email protected]> | 2016-12-14 08:54:41 -0800 |
|---|---|---|
| committer | Austin Hellyer <[email protected]> | 2016-12-14 08:54:41 -0800 |
| commit | d9e585f008c26f1908982e75b0cdece73d1ade2c (patch) | |
| tree | 9298a1f34ee9d7ab6c96123f48ec40e213eedbee /src | |
| parent | Don't mutate token for bots on profile change (diff) | |
| download | serenity-d9e585f008c26f1908982e75b0cdece73d1ade2c.tar.xz serenity-d9e585f008c26f1908982e75b0cdece73d1ade2c.zip | |
Slightly rework framework buckets
Diffstat (limited to 'src')
| -rw-r--r-- | src/ext/framework/buckets.rs | 26 | ||||
| -rw-r--r-- | src/ext/framework/configuration.rs | 151 | ||||
| -rw-r--r-- | src/ext/framework/create_command.rs | 87 | ||||
| -rw-r--r-- | src/ext/framework/create_group.rs | 38 | ||||
| -rw-r--r-- | src/ext/framework/help_commands.rs | 30 | ||||
| -rw-r--r-- | src/ext/framework/mod.rs | 75 |
6 files changed, 200 insertions, 207 deletions
diff --git a/src/ext/framework/buckets.rs b/src/ext/framework/buckets.rs index 2e42250..c0d0017 100644 --- a/src/ext/framework/buckets.rs +++ b/src/ext/framework/buckets.rs @@ -10,7 +10,7 @@ pub struct Ratelimit { #[doc(hidden)] pub struct MemberRatelimit { - pub count: i32, + pub tickets: i32, pub last_time: i64, pub set_time: i64, } @@ -18,7 +18,7 @@ pub struct MemberRatelimit { impl Default for MemberRatelimit { fn default() -> Self { MemberRatelimit { - count: 0, + tickets: 0, last_time: 0, set_time: 0, } @@ -28,31 +28,31 @@ impl Default for MemberRatelimit { #[doc(hidden)] pub struct Bucket { pub ratelimit: Ratelimit, - pub limits: HashMap<u64, MemberRatelimit>, + pub users: HashMap<u64, MemberRatelimit>, } impl Bucket { pub fn take(&mut self, user_id: u64) -> i64 { let time =- time::get_time().sec; - let member = self.limits.entry(user_id) + let user = self.users.entry(user_id) .or_insert_with(MemberRatelimit::default); if let Some((timespan, limit)) = self.ratelimit.limit { - if (member.count + 1) > limit { - if time < (member.set_time + timespan) { - return (member.set_time + timespan) - time; + if (user.tickets + 1) > limit { + if time < (user.set_time + timespan) { + return (user.set_time + timespan) - time; } else { - member.count = 0; - member.set_time = time; + user.tickets = 0; + user.set_time = time; } } } - if time < member.last_time + self.ratelimit.delay { - (member.last_time + self.ratelimit.delay) - time + if time < user.last_time + self.ratelimit.delay { + (user.last_time + self.ratelimit.delay) - time } else { - member.count += 1; - member.last_time = time; + user.tickets += 1; + user.last_time = time; 0 } diff --git a/src/ext/framework/configuration.rs b/src/ext/framework/configuration.rs index f841a85..cd48e44 100644 --- a/src/ext/framework/configuration.rs +++ b/src/ext/framework/configuration.rs @@ -67,6 +67,44 @@ pub struct Configuration { } impl Configuration { + /// Allows you to change what accounts to ignore. + pub fn account_type(mut self, account_type: AccountType) -> Self { + self.account_type = account_type; + + self + } + + /// Whether to allow whitespace being optional between a mention/prefix and + /// a command. + /// + /// **Note**: Defaults to `false`. + /// + /// # Examples + /// + /// Setting this to `false` will _only_ allow this scenario to occur: + /// + /// ```ignore + /// <@245571012924538880> about + /// !about + /// + /// // bot processes and executes the "about" command if it exists + /// ``` + /// + /// while setting this to `true` will _also_ allow this scenario to occur: + /// + /// ```ignore + /// <@245571012924538880>about + /// ! about + /// + /// // bot processes and executes the "about" command if it exists + /// ``` + pub fn allow_whitespace(mut self, allow_whitespace: bool) + -> Self { + self.allow_whitespace = allow_whitespace; + + self + } + /// The default depth of the message to check for commands. Defaults to 5. /// This determines how "far" into a message to check for a valid command. /// @@ -81,57 +119,49 @@ impl Configuration { self } - /// Message that's sent when a command is on cooldown. - /// See framework documentation to see where is this utilized. - /// - /// %time% will be replaced with waiting time in seconds. - pub fn rate_limit_message<S>(mut self, rate_limit_message: S) -> Self - where S: Into<String> { - self.rate_limit_message = Some(rate_limit_message.into()); + /// Sets the prefix to respond to. This can either be a single-char or + /// multi-char string. + pub fn dynamic_prefix<F>(mut self, dynamic_prefix: F) -> Self + where F: Fn(&Context) -> Option<String> + Send + Sync + 'static { + self.dynamic_prefix = Some(Box::new(dynamic_prefix)); self } - /// Message that's sent when a user with wrong permissions calls a command. - pub fn invalid_permission_message<S>(mut self, invalid_permission_message: S) -> Self - where S: Into<String> { - self.invalid_permission_message = Some(invalid_permission_message.into()); + /// Message that's sent when one of a command's checks doesn't succeed. + pub fn invalid_check_message(mut self, content: &str) -> Self { + self.invalid_check_message = Some(content.to_owned()); self } - /// Message that's sent when one of a command's checks doesn't succeed. - pub fn invalid_check_message<S>(mut self, invalid_check_message: S) -> Self - where S: Into<String> { - self.invalid_check_message = Some(invalid_check_message.into()); + /// Message that's sent when a user with wrong permissions calls a command. + pub fn invalid_permission_message(mut self, content: &str) -> Self { + self.invalid_permission_message = Some(content.to_owned()); self } - /// Message that's sent when a command isn't available in DM. - pub fn no_dm_message<S>(mut self, no_dm_message: S) -> Self - where S: Into<String> { - self.no_dm_message = Some(no_dm_message.into()); + /// Message that's sent when a command is on cooldown. + /// See framework documentation to see where is this utilized. + /// + /// %time% will be replaced with waiting time in seconds. + pub fn rate_limit_message(mut self, content: &str) -> Self { + self.rate_limit_message = Some(content.to_owned()); self } - /// Message that's sent when a command isn't available in guilds. - pub fn no_guild_message<S>(mut self, no_guild_message: S) -> Self - where S: Into<String> { - self.no_guild_message = Some(no_guild_message.into()); + /// Message that's sent when a command isn't available in DM. + pub fn no_dm_message(mut self, content: &str) -> Self { + self.no_dm_message = Some(content.to_owned()); self } - /// Message that's sent when user sends too many arguments to a command. - /// - /// %max% will be replaced with maximum allowed amount of arguments. - /// - /// %given% will be replced with the given amount of arguments. - pub fn too_many_args_message<S>(mut self, too_many_args_message: S) -> Self - where S: Into<String> { - self.too_many_args_message = Some(too_many_args_message.into()); + /// Message that's sent when a command isn't available in guilds. + pub fn no_guild_message(mut self, content: &str) -> Self { + self.no_guild_message = Some(content.to_owned()); self } @@ -141,9 +171,8 @@ impl Configuration { /// %min% will be replaced with minimum allowed amount of arguments. /// /// %given% will be replced with the given amount of arguments. - pub fn not_enough_args_message<S>(mut self, not_enough_args_message: S) -> Self - where S: Into<String> { - self.not_enough_args_message = Some(not_enough_args_message.into()); + pub fn not_enough_args_message(mut self, content: &str) -> Self { + self.not_enough_args_message = Some(content.to_owned()); self } @@ -184,41 +213,10 @@ impl Configuration { self } - /// Whether to allow whitespace being optional between a mention/prefix and - /// a command. - /// - /// **Note**: Defaults to `false`. - /// - /// # Examples - /// - /// Setting this to `false` will _only_ allow this scenario to occur: - /// - /// ```ignore - /// <@245571012924538880> about - /// !about - /// - /// // bot processes and executes the "about" command if it exists - /// ``` - /// - /// while setting this to `true` will _also_ allow this scenario to occur: - /// - /// ```ignore - /// <@245571012924538880>about - /// ! about - /// - /// // bot processes and executes the "about" command if it exists - /// ``` - pub fn allow_whitespace(mut self, allow_whitespace: bool) - -> Self { - self.allow_whitespace = allow_whitespace; - - self - } - /// Sets the prefix to respond to. This can either be a single-char or /// multi-char string. - pub fn prefix<S: Into<String>>(mut self, prefix: S) -> Self { - self.prefixes = vec![prefix.into()]; + pub fn prefix(mut self, prefix: &str) -> Self { + self.prefixes = vec![prefix.to_owned()]; self } @@ -231,18 +229,13 @@ impl Configuration { self } - /// Allows you to change what accounts to ignore. - pub fn account_type(mut self, account_type: AccountType) -> Self { - self.account_type = account_type; - - self - } - - /// Sets the prefix to respond to. This can either be a single-char or - /// multi-char string. - pub fn dynamic_prefix<F>(mut self, dynamic_prefix: F) -> Self - where F: Fn(&Context) -> Option<String> + Send + Sync + 'static { - self.dynamic_prefix = Some(Box::new(dynamic_prefix)); + /// Message that's sent when user sends too many arguments to a command. + /// + /// %max% will be replaced with maximum allowed amount of arguments. + /// + /// %given% will be replced with the given amount of arguments. + pub fn too_many_args_message(mut self, content: &str) -> Self { + self.too_many_args_message = Some(content.to_owned()); self } diff --git a/src/ext/framework/create_command.rs b/src/ext/framework/create_command.rs index e3faffd..7a1d744 100644 --- a/src/ext/framework/create_command.rs +++ b/src/ext/framework/create_command.rs @@ -4,12 +4,18 @@ use std::collections::HashMap; use std::default::Default; use std::sync::Arc; use ::client::Context; -use ::model::Message; -use ::model::Permissions; +use ::model::{Message, Permissions}; pub struct CreateCommand(pub Command); impl CreateCommand { + /// Adds a ratelimit bucket. + pub fn bucket(mut self, bucket: &str) -> Self { + self.0.bucket = Some(bucket.to_owned()); + + self + } + /// Adds a "check" to a command, which checks whether or not the command's /// function should be called. /// @@ -57,20 +63,6 @@ impl CreateCommand { self } - /// Adds a ratelimit bucket. - pub fn bucket(mut self, bucket: &str) -> Self { - self.0.bucket = Some(bucket.to_owned()); - - self - } - - /// Whether command should be displayed in help list or not, used by other commands. - pub fn help_available(mut self, help_available: bool) -> Self { - self.0.help_available = help_available; - - self - } - /// Whether command can be used only privately or not. pub fn dm_only(mut self, dm_only: bool) -> Self { self.0.dm_only = dm_only; @@ -78,34 +70,6 @@ impl CreateCommand { self } - /// Whether command can be used only in guilds or not. - pub fn guild_only(mut self, guild_only: bool) -> Self { - self.0.guild_only = guild_only; - - self - } - - /// Minumum amount of arguments that should be passed. - pub fn min_args(mut self, min_args: i32) -> Self { - self.0.min_args = Some(min_args); - - self - } - - /// Maximum amount of arguments that can be passed. - pub fn max_args(mut self, max_args: i32) -> Self { - self.0.max_args = Some(max_args); - - self - } - - /// Maximum amount of arguments that can be passed. - pub fn required_permissions(mut self, required_permissions: Permissions) -> Self { - self.0.required_permissions = required_permissions; - - self - } - /// A function that can be called when a command is received. /// You can return Err(string) if there's an error. /// @@ -148,6 +112,41 @@ impl CreateCommand { self } + /// Whether command can be used only in guilds or not. + pub fn guild_only(mut self, guild_only: bool) -> Self { + self.0.guild_only = guild_only; + + self + } + + /// Whether command should be displayed in help list or not, used by other commands. + pub fn help_available(mut self, help_available: bool) -> Self { + self.0.help_available = help_available; + + self + } + + /// Maximum amount of arguments that can be passed. + pub fn max_args(mut self, max_args: i32) -> Self { + self.0.max_args = Some(max_args); + + self + } + + /// Minumum amount of arguments that should be passed. + pub fn min_args(mut self, min_args: i32) -> Self { + self.0.min_args = Some(min_args); + + self + } + + /// Maximum amount of arguments that can be passed. + pub fn required_permissions(mut self, required_permissions: Permissions) -> Self { + self.0.required_permissions = required_permissions; + + self + } + /// Command usage schema, used by other commands. pub fn usage(mut self, usage: &str) -> Self { self.0.usage = Some(usage.to_owned()); diff --git a/src/ext/framework/create_group.rs b/src/ext/framework/create_group.rs index db2832b..8374e8b 100644 --- a/src/ext/framework/create_group.rs +++ b/src/ext/framework/create_group.rs @@ -24,34 +24,34 @@ pub struct CreateGroup(pub CommandGroup); /// .exec_str("meew0"))) /// ``` impl CreateGroup { - /// If prefix is set, it will be required before all command names. - /// For example, if bot prefix is "~" and group prefix is "image" - /// we'd call a subcommand named "hibiki" by sending "~image hibiki". - /// - /// **Note**: serenity automatically puts a space after group prefix. - pub fn prefix(mut self, desc: &str) -> Self { - self.0.prefix = Some(desc.to_owned()); - - self - } - /// Adds a command to group. - 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>(mut self, command_name: &str, f: F) -> Self + where F: FnOnce(CreateCommand) -> CreateCommand { let cmd = f(CreateCommand(Command::default())).0; - self.0.commands.insert(command_name.into(), Arc::new(cmd)); + self.0.commands.insert(command_name.to_owned(), Arc::new(cmd)); self } /// Adds a command to group with simplified API. /// You can return Err(string) if there's an error. - pub fn on<F, S>(mut self, command_name: S, f: F) -> Self - where F: Fn(&Context, &Message, Vec<String>) -> Result<(), String> + Send + Sync + 'static, - S: Into<String> { - self.0.commands.insert(command_name.into(), Arc::new(Command::new(f))); + pub fn on<F>(mut self, command_name: &str, f: F) -> Self + where F: Fn(&Context, &Message, Vec<String>) -> Result<(), String> + Send + Sync + 'static { + let cmd = Arc::new(Command::new(f)); + + self.0.commands.insert(command_name.to_owned(), cmd); + + self + } + + /// If prefix is set, it will be required before all command names. + /// For example, if bot prefix is "~" and group prefix is "image" + /// we'd call a subcommand named "hibiki" by sending "~image hibiki". + /// + /// **Note**: serenity automatically puts a space after group prefix. + pub fn prefix(mut self, desc: &str) -> Self { + self.0.prefix = Some(desc.to_owned()); self } diff --git a/src/ext/framework/help_commands.rs b/src/ext/framework/help_commands.rs index 375b8dc..385afe4 100644 --- a/src/ext/framework/help_commands.rs +++ b/src/ext/framework/help_commands.rs @@ -1,8 +1,7 @@ -pub use super::{Command, CommandGroup}; - use std::collections::HashMap; use std::sync::Arc; use std::fmt::Write; +use super::{Command, CommandGroup}; use ::client::Context; use ::model::Message; use ::utils::Colour; @@ -41,6 +40,7 @@ pub fn with_embeds(ctx: &Context, if let Some((command_name, command)) = found { if !command.help_available { error_embed(ctx, message, "**Error**: No help available."); + return Ok(()); } @@ -96,6 +96,7 @@ pub fn with_embeds(ctx: &Context, return Ok(()); } + let _ = ctx.send_message(message.channel_id, |m| { m.embed(|mut e| { e = e.colour(Colour::rosewater()) @@ -109,8 +110,9 @@ pub fn with_embeds(ctx: &Context, let _ = write!(desc, "Prefix: {}\n", x); } + desc.push_str("Commands:\n"); + let mut no_commands = true; - let _ = write!(desc, "Commands:\n"); for (n, cmd) in &group.commands { if cmd.help_available { @@ -143,6 +145,7 @@ pub fn plain(ctx: &Context, for (group_name, group) in groups { let mut found: Option<(&String, &Command)> = None; + if let Some(ref prefix) = group.prefix { for (command_name, command) in &group.commands { if name == format!("{} {}", prefix, command_name) { @@ -177,16 +180,15 @@ pub fn plain(ctx: &Context, let _ = write!(result, "**Group:** {}\n", group_name); } - let available = if command.dm_only { + result.push_str("**Available:** "); + result.push_str(if command.dm_only { "Only in DM" } else if command.guild_only { "Only in guilds" } else { "In DM and guilds" - }; - - let _ = write!(result, "**Available:** {}\n", available); - let _ = ctx.say(&result); + }); + result.push_str("\n"); return Ok(()); } @@ -196,31 +198,31 @@ pub fn plain(ctx: &Context, return Ok(()); } + let mut result = "**Commands**\nTo get help about individual command, pass \ its name as an argument to this command.\n\n" .to_string(); for (group_name, group) in groups { - let mut desc = String::new(); + let _ = write!(result, "**{}:** ", group_name); if let Some(ref x) = group.prefix { - let _ = write!(desc, "(prefix: `{}`): ", x); + let _ = write!(result, "(prefix: `{}`): ", x); } let mut no_commands = true; for (n, cmd) in &group.commands { if cmd.help_available { - let _ = write!(desc, "`{}` ", n); + let _ = write!(result, "`{}` ", n); + no_commands = false; } } if no_commands { - let _ = write!(desc, "*[No commands]*"); + result.push_str("*[No Commands]*"); } - - let _ = write!(result, "**{}:** {}\n", group_name, desc); } let _ = ctx.say(&result); diff --git a/src/ext/framework/mod.rs b/src/ext/framework/mod.rs index 6cd222f..796f1a3 100644 --- a/src/ext/framework/mod.rs +++ b/src/ext/framework/mod.rs @@ -61,11 +61,11 @@ mod create_command; mod create_group; mod buckets; +pub use self::buckets::{Bucket, MemberRatelimit, Ratelimit}; pub use self::command::{Command, CommandType, CommandGroup}; pub use self::configuration::{AccountType, Configuration}; pub use self::create_command::CreateCommand; pub use self::create_group::CreateGroup; -pub use self::buckets::{Bucket, MemberRatelimit, Ratelimit}; use self::command::{AfterHook, Hook}; use std::collections::HashMap; @@ -225,9 +225,9 @@ impl Framework { self.buckets.insert(s.into(), Bucket { ratelimit: Ratelimit { delay: delay, - limit: Some((time_span, limit)) + limit: Some((time_span, limit)), }, - limits: HashMap::new() + users: HashMap::new(), }); self @@ -239,22 +239,14 @@ impl Framework { self.buckets.insert(s.into(), Bucket { ratelimit: Ratelimit { delay: delay, - limit: None + limit: None, }, - limits: HashMap::new() + users: HashMap::new(), }); self } - #[allow(map_entry)] - fn ratelimit_time(&mut self, bucket_name: &str, user_id: u64) -> i64 { - self.buckets - .get_mut(bucket_name) - .map(|bucket| bucket.take(user_id)) - .unwrap_or(0) - } - #[allow(cyclomatic_complexity)] #[doc(hidden)] pub fn dispatch(&mut self, context: Context, message: Message) { @@ -264,10 +256,8 @@ impl Framework { return; } }, - AccountType::Bot => { - if message.author.bot { - return; - } + AccountType::Bot => if message.author.bot { + return; }, AccountType::Automatic => { let cache = CACHE.read().unwrap(); @@ -481,13 +471,14 @@ impl Framework { pub fn on<F, S>(mut self, command_name: S, f: F) -> Self where F: Fn(&Context, &Message, Vec<String>) -> Result<(), String> + Send + Sync + 'static, S: Into<String> { - if !self.groups.contains_key("Ungrouped") { - self.groups.insert("Ungrouped".to_string(), Arc::new(CommandGroup::default())); - } + { + let ungrouped = self.groups.entry("Ungrouped".to_owned()) + .or_insert_with(|| Arc::new(CommandGroup::default())); - if let Some(ref mut x) = self.groups.get_mut("Ungrouped") { - if let Some(ref mut y) = Arc::get_mut(x) { - y.commands.insert(command_name.into(), Arc::new(Command::new(f))); + if let Some(ref mut group) = Arc::get_mut(ungrouped) { + let name = command_name.into(); + + group.commands.insert(name, Arc::new(Command::new(f))); } } @@ -510,15 +501,15 @@ impl Framework { pub fn command<F, S>(mut self, command_name: S, f: F) -> Self where F: FnOnce(CreateCommand) -> CreateCommand, S: Into<String> { - let cmd = f(CreateCommand(Command::default())).0; + { + let ungrouped = self.groups.entry("Ungrouped".to_owned()) + .or_insert_with(|| Arc::new(CommandGroup::default())); - if !self.groups.contains_key("Ungrouped") { - self.groups.insert("Ungrouped".to_string(), 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(); - if let Some(ref mut x) = self.groups.get_mut("Ungrouped") { - if let Some(ref mut y) = Arc::get_mut(x) { - y.commands.insert(command_name.into(), Arc::new(cmd)); + group.commands.insert(name, Arc::new(cmd)); } } @@ -588,15 +579,16 @@ impl Framework { pub fn set_check<F, S>(mut self, command: S, check: F) -> Self where F: Fn(&Context, &Message) -> bool + Send + Sync + 'static, S: Into<String> { - if !self.groups.contains_key("Ungrouped") { - self.groups.insert("Ungrouped".to_string(), Arc::new(CommandGroup::default())); - } + { + let ungrouped = self.groups.entry("Ungrouped".to_owned()) + .or_insert_with(|| Arc::new(CommandGroup::default())); - if let Some(ref mut group) = self.groups.get_mut("Ungrouped") { - if let Some(group_mut) = Arc::get_mut(group) { - if let Some(ref mut command) = group_mut.commands.get_mut(&command.into()) { - if let Some(c) = Arc::get_mut(command) { - c.checks.push(Box::new(check)); + if let Some(group) = Arc::get_mut(ungrouped) { + let name = command.into(); + + if let Some(ref mut command) = group.commands.get_mut(&name) { + if let Some(command) = Arc::get_mut(command) { + command.checks.push(Box::new(check)); } } } @@ -604,4 +596,11 @@ impl Framework { self } + + fn ratelimit_time(&mut self, bucket_name: &str, user_id: u64) -> i64 { + self.buckets + .get_mut(bucket_name) + .map(|bucket| bucket.take(user_id)) + .unwrap_or(0) + } } |