aboutsummaryrefslogtreecommitdiff
path: root/src/ext
diff options
context:
space:
mode:
authorAustin Hellyer <[email protected]>2016-11-26 11:37:18 -0800
committerAustin Hellyer <[email protected]>2016-11-26 11:37:18 -0800
commit77354ab321bec1ff66af0e27eb87a7eec3e3db24 (patch)
tree693b43ae7be07be11426faf6e6282d838e426a04 /src/ext
parentMake Cache::get_channel return a reference (diff)
downloadserenity-77354ab321bec1ff66af0e27eb87a7eec3e3db24.tar.xz
serenity-77354ab321bec1ff66af0e27eb87a7eec3e3db24.zip
Add a bit more docs
Diffstat (limited to 'src/ext')
-rw-r--r--src/ext/cache/mod.rs289
-rw-r--r--src/ext/framework/command.rs1
-rw-r--r--src/ext/framework/configuration.rs22
-rw-r--r--src/ext/framework/mod.rs99
-rw-r--r--src/ext/mod.rs6
5 files changed, 408 insertions, 9 deletions
diff --git a/src/ext/cache/mod.rs b/src/ext/cache/mod.rs
index a8d62c9..923c55a 100644
--- a/src/ext/cache/mod.rs
+++ b/src/ext/cache/mod.rs
@@ -1,3 +1,81 @@
+//! A cache of events received over a [`Shard`], where storing at least some
+//! data from the event is possible.
+//!
+//! This acts as a hot cache, to avoid making requests over the REST API through
+//! the [`http`] module where possible. All fields are public, and do not have
+//! getters, to allow you more flexibility with the stored data. However, this
+//! allows data to be "corrupted", and _may or may not_ cause misfunctions
+//! within the library. Mutate data at your own discretion.
+//!
+//! A "globally available" instance of the Cache is available at
+//! [`client::CACHE`]. This is the instance that is updated by the library,
+//! meaning you should _not_ need to maintain updating it yourself in any case.
+//!
+//! # Use by the Context
+//!
+//! The [`Context`] will automatically attempt to pull from the cache for you.
+//! For example, the [`Context::get_channel`] method will attempt to find the
+//! channel in the cache. If it can not find it, it will perform a request
+//! through the REST API, and then insert a clone of the channel - if found -
+//! into the Cache, giving you the original.
+//!
+//! This allows you to save a step, by only needing to perform the
+//! [`Context::get_channel`] call and not need to first search through the cache
+//! - and if not found - _then_ perform an HTTP request through the Context or
+//! [`http`] module.
+//!
+//! Additionally, note that some information received through events can _not_
+//! be retrieved through the REST API. This is information such as [`Role`]s in
+//! [`LiveGuild`]s.
+//!
+//! # Use by Models
+//!
+//! Most models of Discord objects, such as the [`Message`], [`PublicChannel`],
+//! or [`Emoji`], have methods for interacting with that single instance. This
+//! feature is only compiled if the `methods` feature is enabled. An example of
+//! this is [`LiveGuild::edit`], which performs a check to ensure that the
+//! current user is the owner of the guild, prior to actually performing the
+//! HTTP request. The cache is involved due to the function's use of unlocking
+//! the cache and retrieving the Id of the current user, and comparing it to
+//! the Id of the user that owns the guild. This is an inexpensive method of
+//! being able to access data required by these sugary methods.
+//!
+//! # Do I need the Cache?
+//!
+//! If you're asking this, the answer is likely "definitely yes" or
+//! "definitely no"; any in-between tends to be "yes". If you are low on RAM,
+//! and need to run on only a couple MB, then the answer is "definitely no". If
+//! you do not care about RAM and want your bot to be able to access data
+//! while needing to hit the REST API as little as possible, then the answer
+//! is "yes".
+//!
+//! # Special cases in the Cache
+//!
+//! Some items in the cache, notably [`Call`]s and [`Group`]s, will "always be
+//! empty". The exception to this rule, is for:
+//!
+//! 1. Bots which used to be userbots prior to the conversion made available by
+//! Discord when the official Bot API was introduced;
+//! 2. For groups and calls:
+//! 2a. Bots that have friends from before the conversion that have not been
+//! removed, as those users can still add the bots to groups;
+//! 2b. Bots that have the "Create Group" endpoint whitelisted specifically for
+//! them.
+//!
+//! [`Call`]: ../../model/struct.Call.html
+//! [`Context`]: ../../client/struct.Context.html
+//! [`Context::get_channel`]: ../../client/struct.Context.html#method.get_channel
+//! [`Emoji`]: ../../model/struct.Emoji.html
+//! [`Group`]: ../../model/struct.Group.html
+//! [`LiveGuild`]: ../../model/struct.LiveGuild.html
+//! [`LiveGuild::edit`]: ../../model/struct.LiveGuild.html#method.edit
+//! [`Message`]: ../../model/struct.Message.html
+//! [`PublicChannel`]: ../../model/struct.PublicChannel.html
+//! [`Role`]: ../../model/struct.Role.html
+//! [`Shard`]: ../../client/gateway/struct.Shard.html
+//! [`client::CACHE`]: ../../client/struct.CACHE.html
+//! [`http`]: ../../client/http/index.html
+
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::default::Default;
@@ -42,31 +120,86 @@ pub struct Cache {
/// where the key is the Id of the [`PrivateChannel`] or [`Group`] hosting
/// the call.
///
- /// For bot users this will almost always be empty.
+ /// For bot users this will always be empty, except for in [special cases].
+ ///
+ /// [`Group`]: ../../model/struct.Group.html
+ /// [`PrivateChannel`]: ../../model/struct.PrivateChannel.html
+ /// [special cases]: index.html#special-cases-in-the-cache
pub calls: HashMap<ChannelId, Call>,
/// A map of the groups that the current user is in.
///
- /// For bot users this will almost always be empty.
+ /// For bot users this will always be empty, except for in [special cases].
+ ///
+ /// [special cases]: index.html#special-cases-in-the-cache
pub groups: HashMap<ChannelId, Group>,
/// Settings specific to a guild.
///
- /// This will always be empty for bot accounts.
+ /// This will always be empty for bot users.
pub guild_settings: HashMap<Option<GuildId>, UserGuildSettings>,
+ /// A map of guilds with full data available. This includes data like
+ /// [`Role`]s and [`Emoji`]s that are not available through the REST API.
+ ///
+ /// [`Emoji`]: ../../model/struct.Emoji.html
+ /// [`Role`]: ../../model/struct.Role.html
pub guilds: HashMap<GuildId, Guild>,
- /// A list of notes that a user has made for individual users.
+ /// A map of notes that a user has made for individual users.
+ ///
+ /// An empty note is equivilant to having no note, and creating an empty
+ /// note is equivilant to deleting a note.
///
- /// This will always be empty for bot accounts.
+ /// This will always be empty for bot users.
pub notes: HashMap<UserId, String>,
+ /// A map of users' presences. This is updated in real-time. Note that
+ /// status updates are often "eaten" by the gateway, and this should not
+ /// be treated as being entirely 100% accurate.
pub presences: HashMap<UserId, Presence>,
+ /// A map of direct message channels that the current user has open with
+ /// other users.
pub private_channels: HashMap<ChannelId, PrivateChannel>,
+ /// A map of relationships that the current user has with other users.
+ ///
+ /// For bot users this will always be empty, except for in [special cases].
+ ///
+ /// [special cases]: index.html#special-cases-in-the-cache
pub relationships: HashMap<UserId, Relationship>,
/// Account-specific settings for a user account.
pub settings: Option<UserSettings>,
+ /// A list of guilds which are "unavailable". Refer to the documentation for
+ /// [`Event::GuildUnavailable`] for more information on when this can occur.
+ ///
+ /// Additionally, guilds are always unavailable for bot users when a Ready
+ /// is received. Guilds are "sent in" over time through the receiving of
+ /// [`Event::GuildCreate`]s.
+ ///
+ /// [`Event::GuildCreate`]: ../../model/enum.Event.html#variant.GuildCreate
+ /// [`Event::GuildUnavailable`]: ../../model/enum.Event.html#variant.GuildUnavailable
pub unavailable_guilds: Vec<GuildId>,
+ /// The current user "logged in" and for which events are being received
+ /// for.
+ ///
+ /// The current user contains information that a regular [`User`] does not,
+ /// such as whether it is a bot, whether the user is verified, etc.
+ ///
+ /// Refer to the documentation for [`CurrentUser`] for more information.
+ ///
+ /// [`CurrentUser`]: ../../model/struct.CurrentUser.html
+ /// [`User`]: ../../model/struct.User.html
pub user: CurrentUser,
}
impl Cache {
+ /// Calculates the number of [`Member`]s that have not had data received.
+ ///
+ /// The important detail to note here is that this is the number of
+ /// _member_s that have not had data downloaded. A single [`User`] may have
+ /// multiple associated member objects that have not been received.
+ ///
+ /// This can be used in combination with [`Shard::sync_guilds`], and can be
+ /// used to determine how many members have not yet been downloaded.
+ ///
+ /// [`Member`]: ../../model/struct.Member.html
+ /// [`Shard::sync_guilds`]: ../../client/gateway/struct.Shard.html#method.sync_guilds
+ /// [`User`]: ../../model/struct.User.html
pub fn unknown_members(&self) -> u64 {
let mut total = 0;
@@ -81,6 +214,16 @@ impl Cache {
total
}
+ /// Calculates a vector of all [`PrivateChannel`] and [`Group`] Ids that are
+ /// stored in the cache.
+ ///
+ /// # Examples
+ ///
+ /// If there are 6 private channels and 2 groups in the cache, then `8` Ids
+ /// will be returned.
+ ///
+ /// [`Group`]: ../../model/struct.Group.html
+ /// [`PrivateChannel`]: ../../model/struct.PrivateChannel.html
pub fn all_private_channels(&self) -> Vec<ChannelId> {
self.groups
.keys()
@@ -89,6 +232,15 @@ impl Cache {
.collect()
}
+ /// Calculates a vector of all [`Guild`]s' Ids that are stored in the cache.
+ ///
+ /// Note that if you are utilizing multiple [`Shard`]s, then the guilds
+ /// retrieved over all shards are included in this count -- not just the
+ /// current [`Context`]'s shard, if accessing from one.
+ ///
+ /// [`Context`]: ../../client/struct.Context.html
+ /// [`Guild`]: ../../model/struct.Guild.html
+ /// [`Shard`]: ../../client/gateway/struct.Shard.html
pub fn all_guilds(&self) -> Vec<GuildId> {
self.guilds
.values()
@@ -110,10 +262,25 @@ impl Cache {
.collect::<Vec<_>>()
}
+ /// Retrieves a reference to a [`Call`] from the cache based on the
+ /// associated [`Group`]'s channel Id.
+ ///
+ /// [`Call`]: ../../model/struct.Call.html
+ /// [`Group`]: ../../model/struct.Group.html
pub fn get_call<C: Into<ChannelId>>(&self, group_id: C) -> Option<&Call> {
self.calls.get(&group_id.into())
}
+ /// Retrieves a [`Channel`] from the cache based on the given Id.
+ ///
+ /// This will search the [`groups`] map, the [`private_channels`] map, and
+ /// then the map of [`guilds`] to find the channel.
+ ///
+ /// [`Channel`]: ../../model/enum.Channel.html
+ /// [`Guild`]: ../../model/struct.Guild.html
+ /// [`groups`]: #structfield.groups
+ /// [`private_channels`]: #structfield.private_channels
+ /// [`guilds`]: #structfield.guilds
pub fn get_channel<C: Into<ChannelId>>(&self, id: C) -> Option<ChannelRef> {
let id = id.into();
@@ -136,10 +303,38 @@ impl Cache {
None
}
+ /// Retrieves a reference to a guild from the cache based on the given Id.
pub fn get_guild<G: Into<GuildId>>(&self, id: G) -> Option<&Guild> {
self.guilds.get(&id.into())
}
+ /// Retrieves a reference to a [`Guild`]'s channel. Unlike [`get_channel`],
+ /// this will only search guilds for the given channel.
+ ///
+ /// # Examples
+ ///
+ /// Getting a guild's channel via the Id of the message received through a
+ /// [`Client::on_message`] event dispatch:
+ ///
+ /// ```rust,ignore
+ /// use serenity::cache::CACHE;
+ ///
+ /// let cache = CACHE.read().unwrap();
+ ///
+ /// let channel = match cache.get_guild_channel(message.channel_id) {
+ /// Some(channel) => channel,
+ /// None => {
+ /// context.say("Could not find guild's channel data")
+ /// .map_err(|why| println!("Err sending message: {:?}", why));
+ ///
+ /// return;
+ /// },
+ /// };
+ /// ```
+ ///
+ /// [`Client::on_message`]: ../../client/struct.Client.html#method.on_message
+ /// [`Guild`]: ../../model/struct.Guild.html
+ /// [`get_channel`]: #method.get_channel
pub fn get_guild_channel<C: Into<ChannelId>>(&self, id: C) -> Option<&GuildChannel> {
let id = id.into();
@@ -152,10 +347,57 @@ impl Cache {
None
}
+ /// Retrieves a reference to a [`Group`] from the cache based on the given
+ /// associated channel Id.
+ ///
+ /// [`Group`]: ../../model/struct.Group.html
pub fn get_group<C: Into<ChannelId>>(&self, id: C) -> Option<&Group> {
self.groups.get(&id.into())
}
+ /// Retrieves a reference to a [`Guild`]'s member from the cache based on
+ /// the guild's and user's given Ids.
+ ///
+ /// # Examples
+ ///
+ /// Retrieving the member object of the user that posted a message, in a
+ /// [`Client::on_message`] context:
+ ///
+ /// ```rust,ignore
+ /// use serenity::client::CACHE;
+ ///
+ /// // assuming you are in a context
+ ///
+ /// let cache = CACHE.read().unwrap();
+ /// let member = {
+ /// let channel = match cache.get_guild_channel(message.channel_id) {
+ /// Some(channel) => channel,
+ /// None => {
+ /// if let Err(why) = context.say("Err finding channel data") {
+ /// println!("Err sending message: {:?}", why);
+ /// }
+ /// },
+ /// };
+ ///
+ /// match cache.get_member(channel.guild_id, message.author.id) {
+ /// Some(member) => member,
+ /// None => {
+ /// if let Err(why) = context.say("Err finding member data") {
+ /// println!("Err sending message: {:?}", why);
+ /// }
+ /// },
+ /// }
+ /// };
+ ///
+ /// let msg = format!("You have {} roles", member.roles.len());
+ ///
+ /// if let Err(why) = context.say(&msg) {
+ /// println!("Err sending message: {:?}", why);
+ /// }
+ /// ```
+ ///
+ /// [`Client::on_message`]: ../../client/struct.Client.html#method.on_message
+ /// [`Guild`]: ../../model/struct.Guild.html
pub fn get_member<G, U>(&self, guild_id: G, user_id: U) -> Option<&Member>
where G: Into<GuildId>, U: Into<UserId> {
self.guilds
@@ -168,6 +410,9 @@ impl Cache {
})
}
+ /// Retrieves a reference to a [`Guild`]'s role by their Ids.
+ ///
+ /// [`Guild`]: ../../model/struct.Guild.html
pub fn get_role<G, R>(&self, guild_id: G, role_id: R) -> Option<&Role>
where G: Into<GuildId>, R: Into<RoleId> {
if let Some(guild) = self.guilds.get(&guild_id.into()) {
@@ -180,6 +425,7 @@ impl Cache {
/// Update the cache according to the changes described in the given event.
#[allow(cyclomatic_complexity)]
#[allow(unneeded_field_pattern)]
+ #[doc(hidden)]
pub fn update(&mut self, event: &Event) {
match *event {
Event::CallCreate(ref event) => {
@@ -300,6 +546,7 @@ impl Cache {
}
}
+ #[doc(hidden)]
pub fn update_with_call_create(&mut self, event: &CallCreateEvent) {
match self.calls.entry(event.call.channel_id) {
Entry::Vacant(e) => {
@@ -311,11 +558,13 @@ impl Cache {
}
}
+ #[doc(hidden)]
pub fn update_with_call_delete(&mut self, event: &CallDeleteEvent)
-> Option<Call> {
self.calls.remove(&event.channel_id)
}
+ #[doc(hidden)]
pub fn update_with_call_update(&mut self, event: &CallUpdateEvent, old: bool)
-> Option<Call> {
let item = if old {
@@ -334,6 +583,7 @@ impl Cache {
item
}
+ #[doc(hidden)]
pub fn update_with_channel_create(&mut self, event: &ChannelCreateEvent)
-> Option<Channel> {
match event.channel {
@@ -364,6 +614,7 @@ impl Cache {
}
}
+ #[doc(hidden)]
pub fn update_with_channel_delete(&mut self, event: &ChannelDeleteEvent)
-> Option<Channel> {
match event.channel {
@@ -387,6 +638,7 @@ impl Cache {
}
}
+ #[doc(hidden)]
pub fn update_with_channel_pins_update(&mut self,
event: &ChannelPinsUpdateEvent) {
if let Some(channel) = self.private_channels.get_mut(&event.channel_id) {
@@ -414,6 +666,7 @@ impl Cache {
}
}
+ #[doc(hidden)]
pub fn update_with_channel_recipient_add(&mut self,
event: &ChannelRecipientAddEvent) {
self.groups
@@ -422,6 +675,7 @@ impl Cache {
event.user.clone()));
}
+ #[doc(hidden)]
pub fn update_with_channel_recipient_remove(&mut self,
event: &ChannelRecipientRemoveEvent) {
self.groups
@@ -429,6 +683,7 @@ impl Cache {
.map(|group| group.recipients.remove(&event.user.id));
}
+ #[doc(hidden)]
pub fn update_with_channel_update(&mut self, event: &ChannelUpdateEvent) {
match event.channel {
Channel::Group(ref group) => {
@@ -465,15 +720,18 @@ impl Cache {
}
}
+ #[doc(hidden)]
pub fn update_with_guild_create(&mut self, event: &GuildCreateEvent) {
self.guilds.insert(event.guild.id, event.guild.clone());
}
+ #[doc(hidden)]
pub fn update_with_guild_delete(&mut self, event: &GuildDeleteEvent)
-> Option<Guild> {
self.guilds.remove(&event.guild.id)
}
+ #[doc(hidden)]
pub fn update_with_guild_emojis_update(&mut self,
event: &GuildEmojisUpdateEvent) {
self.guilds
@@ -481,6 +739,7 @@ impl Cache {
.map(|guild| guild.emojis.extend(event.emojis.clone()));
}
+ #[doc(hidden)]
pub fn update_with_guild_member_add(&mut self,
event: &GuildMemberAddEvent) {
self.guilds
@@ -492,6 +751,7 @@ impl Cache {
});
}
+ #[doc(hidden)]
pub fn update_with_guild_member_remove(&mut self,
event: &GuildMemberRemoveEvent)
-> Option<Member> {
@@ -508,6 +768,7 @@ impl Cache {
}
}
+ #[doc(hidden)]
pub fn update_with_guild_member_update(&mut self,
event: &GuildMemberUpdateEvent)
-> Option<Member> {
@@ -545,6 +806,7 @@ impl Cache {
}
}
+ #[doc(hidden)]
pub fn update_with_guild_members_chunk(&mut self,
event: &GuildMembersChunkEvent) {
self.guilds
@@ -552,6 +814,7 @@ impl Cache {
.map(|guild| guild.members.extend(event.members.clone()));
}
+ #[doc(hidden)]
pub fn update_with_guild_role_create(&mut self,
event: &GuildRoleCreateEvent) {
self.guilds
@@ -559,6 +822,7 @@ impl Cache {
.map(|guild| guild.roles.insert(event.role.id, event.role.clone()));
}
+ #[doc(hidden)]
pub fn update_with_guild_role_delete(&mut self,
event: &GuildRoleDeleteEvent)
-> Option<Role> {
@@ -572,6 +836,7 @@ impl Cache {
}
}
+ #[doc(hidden)]
pub fn update_with_guild_role_update(&mut self,
event: &GuildRoleUpdateEvent)
-> Option<Role> {
@@ -587,6 +852,7 @@ impl Cache {
}
}
+ #[doc(hidden)]
pub fn update_with_guild_sync(&mut self, event: &GuildSyncEvent) {
self.guilds
.get_mut(&event.guild_id)
@@ -597,6 +863,7 @@ impl Cache {
});
}
+ #[doc(hidden)]
pub fn update_with_guild_unavailable(&mut self,
event: &GuildUnavailableEvent) {
if !self.unavailable_guilds.contains(&event.guild_id) {
@@ -604,6 +871,7 @@ impl Cache {
}
}
+ #[doc(hidden)]
pub fn update_with_guild_update(&mut self, event: &GuildUpdateEvent) {
self.guilds
.get_mut(&event.guild.id)
@@ -619,6 +887,7 @@ impl Cache {
});
}
+ #[doc(hidden)]
pub fn update_with_presences_replace(&mut self, event: &PresencesReplaceEvent) {
self.presences.clone_from(&{
let mut p = HashMap::default();
@@ -631,6 +900,7 @@ impl Cache {
});
}
+ #[doc(hidden)]
pub fn update_with_presence_update(&mut self, event: &PresenceUpdateEvent) {
if let Some(guild_id) = event.guild_id {
if let Some(guild) = self.guilds.get_mut(&guild_id) {
@@ -646,6 +916,7 @@ impl Cache {
}
}
+ #[doc(hidden)]
pub fn update_with_ready(&mut self, ready: &ReadyEvent) {
let ready = ready.ready.clone();
@@ -695,16 +966,19 @@ impl Cache {
self.user = ready.user;
}
+ #[doc(hidden)]
pub fn update_with_relationship_add(&mut self, event: &RelationshipAddEvent) {
self.relationships.insert(event.relationship.id,
event.relationship.clone());
}
+ #[doc(hidden)]
pub fn update_with_relationship_remove(&mut self,
event: &RelationshipRemoveEvent) {
self.relationships.remove(&event.user_id);
}
+ #[doc(hidden)]
pub fn update_with_user_guild_settings_update(&mut self,
event: &UserGuildSettingsUpdateEvent)
-> Option<UserGuildSettings> {
@@ -713,6 +987,7 @@ impl Cache {
.map(|guild_setting| mem::replace(guild_setting, event.settings.clone()))
}
+ #[doc(hidden)]
pub fn update_with_user_note_update(&mut self,
event: &UserNoteUpdateEvent)
-> Option<String> {
@@ -723,6 +998,7 @@ impl Cache {
}
}
+ #[doc(hidden)]
pub fn update_with_user_settings_update(&mut self,
event: &UserSettingsUpdateEvent,
old: bool)
@@ -751,11 +1027,13 @@ impl Cache {
item
}
+ #[doc(hidden)]
pub fn update_with_user_update(&mut self, event: &UserUpdateEvent)
-> CurrentUser {
mem::replace(&mut self.user, event.current_user.clone())
}
+ #[doc(hidden)]
pub fn update_with_voice_state_update(&mut self,
event: &VoiceStateUpdateEvent) {
if let Some(guild_id) = event.guild_id {
@@ -857,7 +1135,6 @@ fn update_presence(presences: &mut HashMap<UserId, Presence>,
}
/// A reference to a private channel, guild's channel, or group.
-#[derive(Clone, Copy, Debug)]
pub enum ChannelRef<'a> {
/// A group's channel
Group(&'a Group),
diff --git a/src/ext/framework/command.rs b/src/ext/framework/command.rs
index 6a9a713..0c595b3 100644
--- a/src/ext/framework/command.rs
+++ b/src/ext/framework/command.rs
@@ -3,6 +3,7 @@ use super::{CommandType, Configuration};
use ::client::Context;
use ::model::Message;
+#[doc(hidden)]
pub type Command = Fn(Context, Message, Vec<String>) + Send + Sync;
#[doc(hidden)]
pub type InternalCommand = Arc<Command>;
diff --git a/src/ext/framework/configuration.rs b/src/ext/framework/configuration.rs
index 6dd4fd2..6a6c5e5 100644
--- a/src/ext/framework/configuration.rs
+++ b/src/ext/framework/configuration.rs
@@ -1,6 +1,28 @@
use std::default::Default;
use ::client::rest;
+/// The configuration to use for a [`Framework`] associated with a [`Client`]
+/// instance.
+///
+/// This allows setting configurations like the depth to search for commands,
+/// whether to treat mentions like a command prefix, etc.
+///
+/// # Examples
+///
+/// Responding to mentions and setting a command prefix of `"~"`:
+///
+/// ```rust,no_run
+/// use serenity::Client;
+/// use std::env;
+///
+/// let mut client = Client::login_bot(&env::var("DISCORD_BOT_TOKEN").unwrap());
+///
+/// client.with_framework(|f| f
+/// .configure(|c| c.on_mention(true).prefix("~")));
+/// ```
+///
+/// [`Client`]: ../../client/struct.Client.html
+/// [`Framework`]: struct.Framework.html
pub struct Configuration {
#[doc(hidden)]
pub depth: usize,
diff --git a/src/ext/framework/mod.rs b/src/ext/framework/mod.rs
index 361fdd8..2a92840 100644
--- a/src/ext/framework/mod.rs
+++ b/src/ext/framework/mod.rs
@@ -1,3 +1,58 @@
+//! The framework is a customizable method of separating commands, used in
+//! combination with [`Client::with_framework`].
+//!
+//! The framework has a number of configurations, and can have any number of
+//! commands bound to it. The primary purpose of it is to offer the utility of
+//! not needing to manually match message content strings to determine if a
+//! message is a command.
+//!
+//! Additionally, "checks" can be added to commands, to ensure that a certain
+//! condition is met prior to calling a command; this could be a check that the
+//! user who posted a message owns the bot, for example.
+//!
+//! Each command has a given named, and an associated function/closure. For
+//! example, you might have two commands: `"ping"` and `"weather"`. These each
+//! have an associated function that are called if the framework determines
+//! that a message is of that command.
+//!
+//! Assuming a command prefix of `"~"`, then the following would occur with the
+//! two previous commands:
+//!
+//! ```ignore
+//! ~ping // calls the ping command's function
+//! ~pin // does not
+//! ~ ping // _does_ call it _if_ the `allow_whitespace` option is enabled
+//! ~~ping // does not
+//! ```
+//!
+//! # Examples
+//!
+//! Configuring a Client with a framework, which has a prefix of `"~"` and a
+//! ping and about command:
+//!
+//! ```rust,no_run
+//! use serenity::client::{Client, Context};
+//! use serenity::model::Message;
+//! use std::env;
+//!
+//! let mut client = Client::login_bot(&env::var("DISCORD_BOT_TOKEN").unwrap());
+//!
+//! client.with_framework(|f| f
+//! .configure(|c| c.prefix("~"))
+//! .on("about", about)
+//! .on("ping", ping));
+//!
+//! fn about(context: Context, _message: Message, _args: Vec<String>) {
+//! let _ = context.say("A simple test bot");
+//! }
+//!
+//! fn ping(context: Context, _message: Message, _args: Vec<String>) {
+//! let _ = context.say("Pong!");
+//! }
+//! ```
+//!
+//! [`Client::with_framework`]: ../../client/struct.Client.html#method.with_framework
+
mod command;
mod configuration;
@@ -98,6 +153,11 @@ pub enum CommandType {
Prefix,
}
+/// A utility for easily managing dispatches to commands.
+///
+/// Refer to the [module-level documentation] for more information.
+///
+/// [module-level documentation]: index.html
#[allow(type_complexity)]
#[derive(Default)]
pub struct Framework {
@@ -218,6 +278,16 @@ impl Framework {
}
}
+ /// Adds a function to be associated with a command, which will be called
+ /// when a command is used in a message.
+ ///
+ /// This requires that a check - if one exists - passes, prior to being
+ /// called.
+ ///
+ /// Refer to the [module-level documentation] for more information and
+ /// usage.
+ ///
+ /// [module-level documentation]: index.html
pub fn on<F, S>(mut self, command_name: S, f: F) -> Self
where F: Fn(Context, Message, Vec<String>) + Send + Sync + 'static,
S: Into<String> {
@@ -227,6 +297,35 @@ impl Framework {
self
}
+ /// Adds a "check" to a command, which checks whether or not the command's
+ /// associated function should be called.
+ ///
+ /// # Examples
+ ///
+ /// Ensure that the user who created a message, calling a "ping" command,
+ /// is the owner.
+ ///
+ /// ```rust,no_run
+ /// use serenity::client::{Client, Context};
+ /// use serenity::model::Message;
+ /// use std::env;
+ ///
+ /// let mut client = Client::login_bot(&env::var("DISCORD_TOKEN").unwrap());
+ ///
+ /// client.with_framework(|f| f
+ /// .configure(|c| c.prefix("~"))
+ /// .on("ping", ping)
+ /// .set_check("ping", owner_check));
+ ///
+ /// fn ping(context: Context, _message: Message, _args: Vec<String>) {
+ /// context.say("Pong!");
+ /// }
+ ///
+ /// fn owner_check(_context: &Context, message: &Message) -> bool {
+ /// // replace with your user ID
+ /// message.author.id == 7
+ /// }
+ /// ```
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> {
diff --git a/src/ext/mod.rs b/src/ext/mod.rs
index 4484b0b..9605466 100644
--- a/src/ext/mod.rs
+++ b/src/ext/mod.rs
@@ -1,5 +1,5 @@
-//! The set of extensions is functionality that is not required for a
-//! [`Client`] and/or [`Connection`] to properly function.
+//! A set of extended functionality that is not required for a [`Client`] and/or
+//! [`Shard`] to properly function.
//!
//! These are flagged behind feature-gates and can be enabled and disabled.
//!
@@ -11,7 +11,7 @@
//! to be enabled (disabled by default).
//!
//! [`Client`]: ../client/struct.Client.html
-//! [`Connection`]: ../client/struct.Connection.html
+//! [`Shard`]: ../client/gateway/struct.Shard.html
#[cfg(feature = "cache")]
pub mod cache;