serenity/framework/mod.rs
1//! The framework is a customizable method of separating commands.
2//!
3//! This is used in combination with [`ClientBuilder::framework`].
4//!
5//! The framework has a number of configurations, and can have any number of commands bound to it.
6//! The primary purpose of it is to offer the utility of not needing to manually match message
7//! content strings to determine if a message is a command.
8//!
9//! Additionally, "checks" can be added to commands, to ensure that a certain condition is met
10//! prior to calling a command; this could be a check that the user who posted a message owns the
11//! bot, for example.
12//!
13//! Each command has a given name, and an associated function/closure. For example, you might have
14//! two commands: `"ping"` and `"weather"`. These each have an associated function that are called
15//! if the framework determines that a message is of that command.
16//!
17//! Assuming a command prefix of `"~"`, then the following would occur with the two previous
18//! commands:
19//!
20//! ```ignore
21//! ~ping // calls the ping command's function
22//! ~pin // does not
23//! ~ ping // _does_ call it _if_ the `allow_whitespace` option is enabled
24//! ~~ping // does not
25//! ```
26//!
27//! # Examples
28//!
29//! Configuring a Client with a framework, which has a prefix of `"~"` and a ping and about
30//! command:
31//!
32//! ```rust,no_run
33//! use serenity::framework::standard::macros::{command, group};
34//! use serenity::framework::standard::{CommandResult, Configuration, StandardFramework};
35//! use serenity::model::channel::Message;
36//! use serenity::prelude::*;
37//!
38//! #[command]
39//! async fn about(ctx: &Context, msg: &Message) -> CommandResult {
40//! msg.channel_id.say(&ctx.http, "A simple test bot").await?;
41//!
42//! Ok(())
43//! }
44//!
45//! #[command]
46//! async fn ping(ctx: &Context, msg: &Message) -> CommandResult {
47//! msg.channel_id.say(&ctx.http, "pong!").await?;
48//!
49//! Ok(())
50//! }
51//!
52//! #[group]
53//! #[commands(about, ping)]
54//! struct General;
55//!
56//! struct Handler;
57//!
58//! impl EventHandler for Handler {}
59//!
60//! # async fn run() -> Result<(), Box<dyn std::error::Error>> {
61//! let token = std::env::var("DISCORD_TOKEN")?;
62//!
63//! let framework = StandardFramework::new()
64//! // The `#[group]` (and similarly, `#[command]`) macro generates static instances
65//! // containing any options you gave it. For instance, the group `name` and its `commands`.
66//! // Their identifiers, names you can use to refer to these instances in code, are an
67//! // all-uppercased version of the `name` with a `_GROUP` suffix appended at the end.
68//! .group(&GENERAL_GROUP);
69//!
70//! framework.configure(Configuration::new().prefix("~"));
71//!
72//! let mut client = Client::builder(&token, GatewayIntents::default())
73//! .event_handler(Handler)
74//! .framework(framework)
75//! .await?;
76//! # Ok(())
77//! # }
78//! ```
79//!
80//! [`ClientBuilder::framework`]: crate::client::ClientBuilder::framework
81
82#[cfg(feature = "standard_framework")]
83pub mod standard;
84
85use async_trait::async_trait;
86
87#[cfg(feature = "standard_framework")]
88#[allow(deprecated)]
89pub use self::standard::StandardFramework;
90use crate::client::{Client, Context, FullEvent};
91
92/// A trait for defining your own framework for serenity to use.
93///
94/// Should you implement this trait, or define a `message` handler, depends on you. However, using
95/// this will benefit you by abstracting the [`EventHandler`] away.
96///
97/// [`EventHandler`]: crate::client::EventHandler
98#[async_trait]
99pub trait Framework: Send + Sync {
100 /// Called directly after the `Client` is created.
101 async fn init(&mut self, client: &Client) {
102 let _: &Client = client;
103 }
104 /// Called on every incoming event.
105 async fn dispatch(&self, ctx: Context, event: FullEvent);
106}
107
108#[async_trait]
109impl<F> Framework for Box<F>
110where
111 F: Framework + ?Sized,
112{
113 async fn init(&mut self, client: &Client) {
114 (**self).init(client).await;
115 }
116 async fn dispatch(&self, ctx: Context, event: FullEvent) {
117 (**self).dispatch(ctx, event).await;
118 }
119}
120
121#[async_trait]
122impl<F> Framework for &mut F
123where
124 F: Framework + ?Sized,
125{
126 async fn init(&mut self, client: &Client) {
127 (**self).init(client).await;
128 }
129 async fn dispatch(&self, ctx: Context, event: FullEvent) {
130 (**self).dispatch(ctx, event).await;
131 }
132}