pub use super::{ Args, Command, CommandGroup, CommandOptions, CommandError, Check, }; use client::Context; use model::{ channel::Message, Permissions }; use std::sync::Arc; pub enum FnOrCommand { Fn(fn(&mut Context, &Message, Args) -> Result<(), CommandError>), Command(Arc), CommandWithOptions(Arc), } impl Default for FnOrCommand { fn default() -> Self { FnOrCommand::Fn(|_, _, _| Ok(())) } } type Init = Fn() + Send + Sync + 'static; type Before = Fn(&mut Context, &Message) -> bool + Send + Sync + 'static; type After = Fn(&mut Context, &Message, &Result<(), CommandError>) + Send + Sync + 'static; #[derive(Default)] pub struct Handlers { init: Option>, before: Option>, after: Option>, } #[derive(Default)] pub struct CreateCommand(pub CommandOptions, pub FnOrCommand, pub Handlers); impl CreateCommand { /// Adds multiple aliases. pub fn batch_known_as>(mut self, names: It) -> Self { self.0 .aliases .extend(names.into_iter().map(|n| n.to_string())); self } /// Adds a ratelimit bucket. pub fn bucket(mut self, bucket: &str) -> Self { self.0.bucket = Some(bucket.to_string()); self } /// Adds a "check" to a command, which checks whether or not the command's /// function should be called. /// /// **Note**: These checks are bypassed for commands sent by the application owner. /// /// # Examples /// /// Ensure that the user who created a message, calling a "ping" command, /// is the owner. /// /// ```rust,no_run /// # use serenity::prelude::EventHandler; /// # struct Handler; /// # impl EventHandler for Handler {} /// use serenity::client::{Client, Context}; /// use serenity::framework::standard::{ /// Args, /// CommandOptions, /// CommandError, /// StandardFramework, /// }; /// use serenity::model::channel::Message; /// use std::env; /// /// let token = env::var("DISCORD_TOKEN").unwrap(); /// let mut client = Client::new(&token, Handler).unwrap(); /// /// client.with_framework(StandardFramework::new() /// .configure(|c| c.prefix("~")) /// .command("ping", |c| c /// .check(owner_check) /// .desc("Replies to a ping with a pong") /// .exec(ping))); /// /// fn ping(_context: &mut Context, message: &Message, _args: Args) -> Result<(), /// CommandError> { /// message.channel_id.say("Pong!")?; /// /// Ok(()) /// } /// /// fn owner_check(_context: &mut Context, message: &Message, _: &mut Args, _: /// &CommandOptions) -> bool { /// // replace with your user ID /// message.author.id == 7 /// } /// ``` pub fn check(mut self, check: F) -> Self where F: Fn(&mut Context, &Message, &mut Args, &CommandOptions) -> bool + Send + Sync + 'static { self.0.checks.push(Check::new(check)); self } /// Description, used by other commands. pub fn desc(mut self, desc: &str) -> Self { self.0.desc = Some(desc.to_string()); 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; self } /// Example arguments, used by other commands. pub fn example(mut self, example: &str) -> Self { self.0.example = Some(example.to_string()); self } /// A function that can be called when a command is received. /// You can return `Err(string)` if there's an error. pub fn exec(mut self, func: fn(&mut Context, &Message, Args) -> Result<(), CommandError>) -> Self { self.1 = FnOrCommand::Fn(func); self } /// Like [`exec`] but accepts a `Command` directly. /// /// [`exec`]: #method.exec pub fn cmd(mut self, c: C) -> Self { self.1 = FnOrCommand::Command(Arc::new(c)); self } /// Like [`cmd`] but says to the builder to use this command's options instead of its own. /// /// [`cmd`]: #method.cmd pub fn cmd_with_options(mut self, c: C) -> Self { self.1 = FnOrCommand::CommandWithOptions(Arc::new(c)); 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 } /// Adds an alias, allowing users to use the command under a different name. pub fn known_as(mut self, name: &str) -> Self { self.0.aliases.push(name.to_string()); 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 } /// Exact number of arguments that should be passed. pub fn num_args(mut self, num_args: i32) -> Self { self.0.min_args = Some(num_args); self.0.max_args = Some(num_args); self } /// Whether command can be used only privately or not. pub fn owners_only(mut self, owners_only: bool) -> Self { self.0.owners_only = owners_only; self } /// The permissions that a user must have in the contextual channel in order /// for the command to be processed. pub fn required_permissions(mut self, permissions: Permissions) -> Self { self.0.required_permissions = permissions; self } /// Command usage schema, used by other commands. pub fn usage(mut self, usage: &str) -> Self { self.0.usage = Some(usage.to_string()); self } /// Sets roles that are allowed to use the command. #[cfg(feature="cache")] pub fn allowed_roles>(mut self, allowed_roles: It) -> Self { self.0.allowed_roles = allowed_roles.into_iter().map(|x| x.to_string()).collect(); self } /// Sets an initialise middleware to be called upon the command's actual registration. /// /// This is similiar to implementing the `init` function on `Command`. pub fn init(mut self, f: F) -> Self { self.2.init = Some(Arc::new(f)); self } /// Sets a before middleware to be called before the command's execution. /// /// This is similiar to implementing the `before` function on `Command`. pub fn before(mut self, f: F) -> Self where F: Fn(&mut Context, &Message) -> bool { self.2.before = Some(Arc::new(f)); self } /// Sets an after middleware to be called after the command's execution. /// /// This is similiar to implementing the `after` function on `Command`. pub fn after(mut self, f: F) -> Self where F: Fn(&mut Context, &Message, &Result<(), CommandError>) { self.2.after = Some(Arc::new(f)); self } pub(crate) fn finish(self) -> Arc { struct A(Arc, C, Handlers); impl Command for A { fn execute(&self, c: &mut Context, m: &Message, a: Args) -> Result<(), CommandError> { self.1.execute(c, m, a) } fn options(&self) -> Arc { Arc::clone(&self.0) } fn init(&self) { if let Some(ref init) = self.2.init { (init)(); } } fn before(&self, c: &mut Context, m: &Message) -> bool { if let Some(ref before) = self.2.before { return (before)(c, m); } true } fn after(&self, c: &mut Context, m: &Message, res: &Result<(), CommandError>) { if let Some(ref after) = self.2.after { (after)(c, m, res); } } } let CreateCommand(options, fc, handlers) = self; match fc { FnOrCommand::Fn(func) => { Arc::new(A(Arc::new(options), func, handlers)) }, FnOrCommand::Command(cmd) => { Arc::new(A(Arc::new(options), cmd, handlers)) }, FnOrCommand::CommandWithOptions(cmd) => cmd, } } }