aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMishio595 <[email protected]>2018-08-06 20:15:11 -0600
committerMishio595 <[email protected]>2018-08-06 20:15:11 -0600
commitd910405d8f50fb381b7d9430b76f0b38ef4c9458 (patch)
tree1d09b965cf0447cce84384196e19c1eba562ef7c /src
parentMerge branch 'upstream' (diff)
parentDereference a destructure instead (diff)
downloadserenity-d910405d8f50fb381b7d9430b76f0b38ef4c9458.tar.xz
serenity-d910405d8f50fb381b7d9430b76f0b38ef4c9458.zip
Merge branch 'upstream'
Diffstat (limited to 'src')
-rw-r--r--src/client/dispatch.rs13
-rw-r--r--src/framework/standard/args.rs68
-rw-r--r--src/framework/standard/command.rs19
-rw-r--r--src/framework/standard/configuration.rs116
-rw-r--r--src/framework/standard/mod.rs3
-rw-r--r--src/http/mod.rs1501
-rw-r--r--src/http/ratelimiting.rs280
-rw-r--r--src/http/request.rs116
-rw-r--r--src/http/routing.rs1433
-rw-r--r--src/internal/macros.rs30
-rw-r--r--src/model/gateway.rs12
11 files changed, 2423 insertions, 1168 deletions
diff --git a/src/client/dispatch.rs b/src/client/dispatch.rs
index b8c5610..2bbe344 100644
--- a/src/client/dispatch.rs
+++ b/src/client/dispatch.rs
@@ -19,6 +19,8 @@ use typemap::ShareMap;
use framework::Framework;
#[cfg(feature = "cache")]
use model::id::GuildId;
+#[cfg(feature = "cache")]
+use std::time::Duration;
#[cfg(feature = "cache")]
use super::CACHE;
@@ -28,7 +30,16 @@ macro_rules! update {
{
#[cfg(feature = "cache")]
{
- CACHE.write().update(&mut $event)
+ CACHE.try_write_for(Duration::from_millis(10))
+ .and_then(|mut lock| lock.update(&mut $event))
+ .or_else(|| {
+ warn!(
+ "[dispatch] Possible deadlock: couldn't unlock cache to update with event: {:?}",
+ $event,
+ );
+
+ None
+ })
}
}
};
diff --git a/src/framework/standard/args.rs b/src/framework/standard/args.rs
index 8a622af..cec1f20 100644
--- a/src/framework/standard/args.rs
+++ b/src/framework/standard/args.rs
@@ -324,6 +324,29 @@ impl Args {
}
}
+ /// Retrieves the current argument. Does not parse.
+ ///
+ /// # Note
+ ///
+ /// This borrows `Args` for the entire lifetime of the returned argument.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use serenity::framework::standard::Args;
+ ///
+ /// let mut args = Args::new("42 69", &[" ".to_string()]);
+ ///
+ /// assert_eq!(args.current(), Some("42"));
+ /// args.next();
+ /// assert_eq!(args.current(), Some("69"));
+ /// args.next();
+ /// assert_eq!(args.current(), None);
+ /// ```
+ pub fn current(&self) -> Option<&str> {
+ self.args.get(self.offset).map(|t| t.lit.as_str())
+ }
+
/// Parses the current argument and advances.
///
/// # Examples
@@ -425,7 +448,6 @@ impl Args {
Some(vec)
}
-
/// Provides an iterator that will spew arguments until the end of the message.
///
/// # Examples
@@ -463,6 +485,30 @@ impl Args {
self.iter::<T>().collect()
}
+ /// Retrieves the current argument and also removes quotes around it if they're present.
+ /// Does not parse.
+ ///
+ /// # Note
+ ///
+ /// This borrows `Args` for the entire lifetime of the returned argument.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use serenity::framework::standard::Args;
+ ///
+ /// let mut args = Args::new("42 \"69\"", &[" ".to_string()]);
+ ///
+ /// assert_eq!(args.current_quoted(), Some("42"));
+ /// args.next();
+ /// assert_eq!(args.current_quoted(), Some("69"));
+ /// args.next();
+ /// assert_eq!(args.current_quoted(), None);
+ /// ```
+ pub fn current_quoted(&self) -> Option<&str> {
+ self.args.get(self.offset).map(|t| quotes_extract(t))
+ }
+
/// Like [`single`], but accounts quotes.
///
/// # Examples
@@ -790,6 +836,26 @@ impl Args {
self.len() - self.offset
}
+ /// Move to the next argument.
+ /// This increments the offset pointer.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use serenity::framework::standard::Args;
+ ///
+ /// let mut args = Args::new("42 69", &[" ".to_string()]);
+ ///
+ /// args.next();
+ ///
+ /// assert_eq!(args.single::<u32>().unwrap(), 69);
+ /// assert!(args.is_empty());
+ /// ```
+ #[inline]
+ pub fn next(&mut self) {
+ self.offset += 1;
+ }
+
/// Go one step behind.
///
/// # Examples
diff --git a/src/framework/standard/command.rs b/src/framework/standard/command.rs
index a6a6074..42264f2 100644
--- a/src/framework/standard/command.rs
+++ b/src/framework/standard/command.rs
@@ -338,15 +338,14 @@ impl Default for CommandOptions {
}
pub fn positions(ctx: &mut Context, msg: &Message, conf: &Configuration) -> Option<Vec<usize>> {
- if !conf.prefixes.is_empty() || conf.dynamic_prefix.is_some() {
- // Find out if they were mentioned. If not, determine if the prefix
- // was used. If not, return None.
- let mut positions: Vec<usize> = vec![];
+ // Mentions have the highest precedence.
+ if let Some(mention_end) = find_mention_end(&msg.content, conf) {
+ return Some(vec![mention_end]); // This can simply be returned without trying to find the end whitespaces as trim will remove it later
+ }
- if let Some(mention_end) = find_mention_end(&msg.content, conf) {
- positions.push(mention_end);
- return Some(positions);
- }
+ if !conf.prefixes.is_empty() || conf.dynamic_prefix.is_some() {
+ // Determine if a prefix was used. Otherwise return None.
+ let mut positions = Vec::new();
// Dynamic prefixes, if present and suitable, always have a higher priority.
if let Some(x) = conf.dynamic_prefix.as_ref().and_then(|f| f(ctx, msg)) {
@@ -390,10 +389,6 @@ pub fn positions(ctx: &mut Context, msg: &Message, conf: &Configuration) -> Opti
}
Some(positions)
- } else if conf.on_mention.is_some() {
- find_mention_end(&msg.content, conf).map(|mention_end| {
- vec![mention_end] // This can simply be returned without trying to find the end whitespaces as trim will remove it later
- })
} else {
None
}
diff --git a/src/framework/standard/configuration.rs b/src/framework/standard/configuration.rs
index f3d66d6..c237286 100644
--- a/src/framework/standard/configuration.rs
+++ b/src/framework/standard/configuration.rs
@@ -16,6 +16,8 @@ use super::command::PrefixCheck;
/// This allows setting configurations like the depth to search for commands,
/// whether to treat mentions like a command prefix, etc.
///
+/// To see the default values, refer to the [default implementation].
+///
/// # Examples
///
/// Responding to mentions and setting a command prefix of `"~"`:
@@ -39,6 +41,7 @@ use super::command::PrefixCheck;
///
/// [`Client`]: ../../client/struct.Client.html
/// [`Framework`]: struct.Framework.html
+/// [default implementation]: #impl-Default
pub struct Configuration {
#[doc(hidden)] pub allow_dm: bool,
#[doc(hidden)] pub allow_whitespace: bool,
@@ -60,6 +63,8 @@ pub struct Configuration {
impl Configuration {
/// If set to false, bot will ignore any private messages.
+ ///
+ /// **Note**: Defaults to `true`.
pub fn allow_dm(mut self, allow_dm: bool) -> Self {
self.allow_dm = allow_dm;
@@ -96,7 +101,9 @@ impl Configuration {
self
}
- /// HashSet of guild Ids where commands will be ignored.
+ /// HashSet of channels Ids where commands will be working.
+ ///
+ /// **Note**: Defaults to an empty HashSet.
///
/// # Examples
///
@@ -108,19 +115,21 @@ impl Configuration {
/// #
/// # impl EventHandler for Handler {}
/// # let mut client = Client::new("token", Handler).unwrap();
- /// use serenity::model::id::GuildId;
+ /// use serenity::model::id::ChannelId;
/// use serenity::framework::StandardFramework;
///
/// client.with_framework(StandardFramework::new().configure(|c| c
- /// .blocked_guilds(vec![GuildId(7), GuildId(77)].into_iter().collect())));
+ /// .allowed_channels(vec![ChannelId(7), ChannelId(77)].into_iter().collect())));
/// ```
- pub fn blocked_guilds(mut self, guilds: HashSet<GuildId>) -> Self {
- self.blocked_guilds = guilds;
+ pub fn allowed_channels(mut self, channels: HashSet<ChannelId>) -> Self {
+ self.allowed_channels = channels;
self
}
- /// HashSet of channels Ids where commands will be working.
+ /// HashSet of guild Ids where commands will be ignored.
+ ///
+ /// **Note**: Defaults to an empty HashSet.
///
/// # Examples
///
@@ -132,21 +141,24 @@ impl Configuration {
/// #
/// # impl EventHandler for Handler {}
/// # let mut client = Client::new("token", Handler).unwrap();
- /// use serenity::model::id::ChannelId;
+ /// use serenity::model::id::GuildId;
/// use serenity::framework::StandardFramework;
///
/// client.with_framework(StandardFramework::new().configure(|c| c
- /// .allowed_channels(vec![ChannelId(7), ChannelId(77)].into_iter().collect())));
+ /// .blocked_guilds(vec![GuildId(7), GuildId(77)].into_iter().collect())));
/// ```
- pub fn allowed_channels(mut self, channels: HashSet<ChannelId>) -> Self {
- self.allowed_channels = channels;
+ pub fn blocked_guilds(mut self, guilds: HashSet<GuildId>) -> Self {
+ self.blocked_guilds = guilds;
self
}
/// HashSet of user Ids whose commands will be ignored.
+ ///
/// Guilds owned by user Ids will also be ignored.
///
+ /// **Note**: Defaults to an empty HashSet.
+ ///
/// # Examples
///
/// Create a HashSet in-place:
@@ -169,9 +181,12 @@ impl Configuration {
self
}
- /// The default depth of the message to check for commands. Defaults to 5.
+ /// The default depth of the message to check for commands.
+ ///
/// This determines how "far" into a message to check for a valid command.
///
+ /// **Note**: Defaults to 5.
+ ///
/// # Examples
///
/// If you set a depth of `1`, and make a command of `"music play"`, but
@@ -185,6 +200,8 @@ impl Configuration {
/// HashSet of command names that won't be run.
///
+ /// **Note**: Defaults to an empty HashSet.
+ ///
/// # Examples
///
/// Ignore a set of commands, assuming they exist:
@@ -218,6 +235,8 @@ impl Configuration {
/// Return `None` to not have a special prefix for the dispatch, and to
/// instead use the inherited prefix.
///
+ /// **Note**: Defaults to no dynamic prefix check.
+ ///
/// # Examples
///
/// If the Id of the channel is divisible by 5, return a prefix of `"!"`,
@@ -256,6 +275,8 @@ impl Configuration {
///
/// For example, if this is set to false, then the bot will respond to any
/// other bots including itself.
+ ///
+ /// **Note**: Defaults to `true`.
pub fn ignore_bots(mut self, ignore_bots: bool) -> Self {
self.ignore_bots = ignore_bots;
@@ -263,7 +284,8 @@ impl Configuration {
}
/// If set to true, bot will ignore all commands called by webhooks.
- /// True by default.
+ ///
+ /// **Note**: Defaults to `true`.
pub fn ignore_webhooks(mut self, ignore_webhooks: bool) -> Self {
self.ignore_webhooks = ignore_webhooks;
@@ -273,7 +295,7 @@ impl Configuration {
/// Whether or not to respond to commands initiated with a mention. Note
/// that this can be used in conjunction with [`prefix`].
///
- /// By default this is set to `false`.
+ /// **Note**: Defaults to `false`.
///
/// # Examples
///
@@ -308,6 +330,8 @@ impl Configuration {
/// A `HashSet` of user Ids checks won't apply to.
///
+ /// **Note**: Defaults to an empty HashSet.
+ ///
/// # Examples
///
/// Create a HashSet in-place:
@@ -352,6 +376,8 @@ impl Configuration {
/// Sets the prefix to respond to. A prefix can be a string slice of any
/// non-zero length.
///
+ /// **Note**: Defaults to an empty vector.
+ ///
/// # Examples
///
/// Assign a basic prefix:
@@ -377,6 +403,8 @@ impl Configuration {
/// Sets the prefixes to respond to. Each can be a string slice of any
/// non-zero length.
///
+ /// **Note**: Refer to [`prefix`] for the default value.
+ ///
/// # Examples
///
/// Assign a set of prefixes the bot can respond to:
@@ -393,6 +421,8 @@ impl Configuration {
/// client.with_framework(StandardFramework::new().configure(|c| c
/// .prefixes(vec!["!", ">", "+"])));
/// ```
+ ///
+ /// [`prefix`]: #method.prefix
pub fn prefixes<T: ToString, It: IntoIterator<Item=T>>(mut self, prefixes: It) -> Self {
self.prefixes = prefixes.into_iter().map(|x| x.to_string()).collect();
@@ -401,7 +431,10 @@ impl Configuration {
/// Sets whether command execution can done without a prefix. Works only in private channels.
///
+ /// **Note**: Defaults to `false`.
+ ///
/// # Note
+ ///
/// Needs the `cache` feature to be enabled. Otherwise this does nothing.
pub fn no_dm_prefix(mut self, b: bool) -> Self {
self.no_dm_prefix = b;
@@ -411,6 +444,8 @@ impl Configuration {
/// Sets a delimiter to be used when splitting the content after a command.
///
+ /// **Note**: Defaults to a vector with a single element of `" "`.
+ ///
/// # Examples
///
/// Have the args be seperated by a comma and a space:
@@ -436,6 +471,8 @@ impl Configuration {
/// Sets multiple delimiters to be used when splitting the content after a command.
/// Additionally cleans the default delimiter from the vector.
///
+ /// **Note**: Refer to [`delimiter`] for the default value.
+ ///
/// # Examples
///
/// Have the args be seperated by a comma and a space; and a regular space:
@@ -452,6 +489,8 @@ impl Configuration {
/// client.with_framework(StandardFramework::new().configure(|c| c
/// .delimiters(vec![", ", " "])));
/// ```
+ ///
+ /// [`delimiter`]: #method.delimiter
pub fn delimiters<T: ToString, It: IntoIterator<Item=T>>(mut self, delimiters: It) -> Self {
self.delimiters.clear();
self.delimiters
@@ -460,9 +499,13 @@ impl Configuration {
self
}
- /// Whether the framework shouldn't care about the user's input if it's: `~command`,
- /// `~Command`, `~COMMAND`.
- /// Setting this to `true` will result in *all* command names to be case insensitive.
+ /// Whether the framework shouldn't care about the user's input if it's:
+ /// `~command`, `~Command`, or `~COMMAND`.
+ ///
+ /// Setting this to `true` will result in *all* command names to be case
+ /// insensitive.
+ ///
+ /// **Note**: Defaults to `false`.
pub fn case_insensitivity(mut self, cs: bool) -> Self {
self.case_insensitive = cs;
@@ -473,31 +516,40 @@ impl Configuration {
impl Default for Configuration {
/// Builds a default framework configuration, setting the following:
///
+ /// - **allow_dm** to `true`
/// - **allow_whitespace** to `false`
+ /// - **allowed_channels** to an empty HashSet
+ /// - **blocked_guilds** to an empty HashSet
+ /// - **blocked_users** to an empty HashSet
+ /// - **case_insensitive** to `false`
+ /// - **delimiters** to `vec![" "]`
/// - **depth** to `5`
- /// - **on_mention** to `false` (basically)
- /// - **prefix** to `None`
+ /// - **disabled_commands** to an empty HashSet
+ /// - **dynamic_prefix** to no dynamic prefix check
+ /// - **ignore_bots** to `true`
+ /// - **ignore_webhooks** to `true`
/// - **no_dm_prefix** to `false`
- /// - **delimiters** to vec![" "]
- /// - **case_insensitive** to `false`
+ /// - **on_mention** to `false` (basically)
+ /// - **owners** to an empty HashSet
+ /// - **prefix** to an empty vector
fn default() -> Configuration {
Configuration {
- depth: 5,
- on_mention: None,
- dynamic_prefix: None,
+ allow_dm: true,
allow_whitespace: false,
- prefixes: vec![],
- no_dm_prefix: false,
- ignore_bots: true,
- owners: HashSet::default(),
- blocked_users: HashSet::default(),
- blocked_guilds: HashSet::default(),
allowed_channels: HashSet::default(),
- disabled_commands: HashSet::default(),
- allow_dm: true,
- ignore_webhooks: true,
+ blocked_guilds: HashSet::default(),
+ blocked_users: HashSet::default(),
case_insensitive: false,
delimiters: vec![" ".to_string()],
+ depth: 5,
+ disabled_commands: HashSet::default(),
+ dynamic_prefix: None,
+ ignore_bots: true,
+ ignore_webhooks: true,
+ no_dm_prefix: false,
+ on_mention: None,
+ owners: HashSet::default(),
+ prefixes: vec![],
}
}
}
diff --git a/src/framework/standard/mod.rs b/src/framework/standard/mod.rs
index 0bb0309..4aa462e 100644
--- a/src/framework/standard/mod.rs
+++ b/src/framework/standard/mod.rs
@@ -1146,12 +1146,13 @@ impl Framework for StandardFramework {
}
if check_contains_group_prefix {
+
if let &Some(CommandOrAlias::Command(ref command)) = &group.default_command {
let command = Arc::clone(command);
threadpool.execute(move || {
if let Some(before) = before {
- if !(before)(&mut context, &message, &built) {
+ if !(before)(&mut context, &message, &to_check) {
return;
}
}
diff --git a/src/http/mod.rs b/src/http/mod.rs
index c50679a..7d0ca17 100644
--- a/src/http/mod.rs
+++ b/src/http/mod.rs
@@ -24,21 +24,22 @@
//! [model]: ../model/index.html
pub mod ratelimiting;
+pub mod request;
+pub mod routing;
mod error;
-pub use self::error::Error as HttpError;
pub use hyper::status::{StatusClass, StatusCode};
+pub use self::error::Error as HttpError;
use constants;
use hyper::{
client::{
Client as HyperClient,
- Request,
- RequestBuilder,
+ Request as HyperRequest,
Response as HyperResponse
},
- header::ContentType,
+ header::{ContentType, Headers},
method::Method,
mime::{Mime, SubLevel, TopLevel},
net::HttpsConnector,
@@ -52,25 +53,35 @@ use internal::prelude::*;
use model::prelude::*;
use multipart::client::Multipart;
use parking_lot::Mutex;
-use self::ratelimiting::Route;
+use self::{
+ request::Request,
+ routing::RouteInfo,
+};
+use serde::de::DeserializeOwned;
use serde_json;
use std::{
collections::BTreeMap,
default::Default,
- fmt::Write as FmtWrite,
fs::File,
io::ErrorKind as IoErrorKind,
path::{Path, PathBuf},
sync::Arc
};
+lazy_static! {
+ static ref CLIENT: HyperClient = {
+ let tc = NativeTlsClient::new().expect("Unable to make http client");
+ let connector = HttpsConnector::new(tc);
+
+ HyperClient::with_connector(connector)
+ };
+}
+
/// An method used for ratelimiting special routes.
///
/// This is needed because `hyper`'s `Method` enum does not derive Copy.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum LightMethod {
- /// Indicates that a route is for "any" method.
- Any,
/// Indicates that a route is for the `DELETE` method only.
Delete,
/// Indicates that a route is for the `GET` method only.
@@ -83,6 +94,18 @@ pub enum LightMethod {
Put,
}
+impl LightMethod {
+ pub fn hyper_method(&self) -> Method {
+ match *self {
+ LightMethod::Delete => Method::Delete,
+ LightMethod::Get => Method::Get,
+ LightMethod::Patch => Method::Patch,
+ LightMethod::Post => Method::Post,
+ LightMethod::Put => Method::Put,
+ }
+ }
+}
+
lazy_static! {
static ref TOKEN: Arc<Mutex<String>> = Arc::new(Mutex::new(String::default()));
}
@@ -121,16 +144,11 @@ pub fn set_token(token: &str) { TOKEN.lock().clone_from(&token.to_string()); }
/// [`Group::add_recipient`]: ../model/channel/struct.Group.html#method.add_recipient
/// [`User`]: ../model/user/struct.User.html
pub fn add_group_recipient(group_id: u64, user_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::None,
- put,
- "/channels/{}/recipients/{}",
- group_id,
- user_id
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::AddGroupRecipient { group_id, user_id },
+ })
}
/// Adds a single [`Role`] to a [`Member`] in a [`Guild`].
@@ -143,17 +161,11 @@ pub fn add_group_recipient(group_id: u64, user_id: u64) -> Result<()> {
/// [`Role`]: ../model/guild/struct.Role.html
/// [Manage Roles]: ../model/permissions/constant.MANAGE_ROLES.html
pub fn add_member_role(guild_id: u64, user_id: u64, role_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::GuildsIdMembersIdRolesId(guild_id),
- put,
- "/guilds/{}/members/{}/roles/{}",
- guild_id,
- user_id,
- role_id
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::AddMemberRole { guild_id, role_id, user_id },
+ })
}
/// Bans a [`User`] from a [`Guild`], removing their messages sent in the last
@@ -168,18 +180,16 @@ pub fn add_member_role(guild_id: u64, user_id: u64, role_id: u64) -> Result<()>
/// [`User`]: ../model/user/struct.User.html
/// [Ban Members]: ../model/permissions/constant.BAN_MEMBERS.html
pub fn ban_user(guild_id: u64, user_id: u64, delete_message_days: u8, reason: &str) -> Result<()> {
- verify(
- 204,
- request!(
- Route::GuildsIdBansUserId(guild_id),
- put,
- "/guilds/{}/bans/{}?delete_message_days={}&reason={}",
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GuildBanUser {
+ delete_message_days: Some(delete_message_days),
+ reason: Some(reason),
guild_id,
user_id,
- delete_message_days,
- reason
- ),
- )
+ },
+ })
}
/// Ban zeyla from a [`Guild`], removing her messages sent in the last X number
@@ -235,15 +245,11 @@ pub fn ban_servermoms(guild_id: u64, delete_message_days: u8, reason: &str) -> R
///
/// [`Channel`]: ../model/channel/enum.Channel.html
pub fn broadcast_typing(channel_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::ChannelsIdTyping(channel_id),
- post,
- "/channels/{}/typing",
- channel_id
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::BroadcastTyping { channel_id },
+ })
}
/// Creates a [`GuildChannel`] in the [`Guild`] given its Id.
@@ -257,16 +263,11 @@ pub fn broadcast_typing(channel_id: u64) -> Result<()> {
/// [docs]: https://discordapp.com/developers/docs/resources/guild#create-guild-channel
/// [Manage Channels]: ../model/permissions/constant.MANAGE_CHANNELS.html
pub fn create_channel(guild_id: u64, map: &Value) -> Result<GuildChannel> {
- let body = map.to_string();
- let response = request!(
- Route::GuildsIdChannels(guild_id),
- post(body),
- "/guilds/{}/channels",
- guild_id
- );
-
- serde_json::from_reader::<HyperResponse, GuildChannel>(response)
- .map_err(From::from)
+ fire(Request {
+ body: Some(map.to_string().as_bytes()),
+ headers: None,
+ route: RouteInfo::CreateChannel { guild_id },
+ })
}
/// Creates an emoji in the given [`Guild`] with the given data.
@@ -280,16 +281,11 @@ pub fn create_channel(guild_id: u64, map: &Value) -> Result<GuildChannel> {
/// [`Guild`]: ../model/guild/struct.Guild.html
/// [Manage Emojis]: ../model/permissions/constant.MANAGE_EMOJIS.html
pub fn create_emoji(guild_id: u64, map: &Value) -> Result<Emoji> {
- let body = map.to_string();
- let response = request!(
- Route::GuildsIdEmojis(guild_id),
- post(body),
- "/guilds/{}/emojis",
- guild_id
- );
-
- serde_json::from_reader::<HyperResponse, Emoji>(response)
- .map_err(From::from)
+ fire(Request {
+ body: Some(map.to_string().as_bytes()),
+ headers: None,
+ route: RouteInfo::CreateEmoji { guild_id },
+ })
}
/// Creates a guild with the data provided.
@@ -329,11 +325,11 @@ pub fn create_emoji(guild_id: u64, map: &Value) -> Result<Emoji> {
/// https://discordapp.com/developers/docs/resources/guild#create-guild
/// [whitelist]: https://discordapp.com/developers/docs/resources/guild#create-guild
pub fn create_guild(map: &Value) -> Result<PartialGuild> {
- let body = map.to_string();
- let response = request!(Route::Guilds, post(body), "/guilds");
-
- serde_json::from_reader::<HyperResponse, PartialGuild>(response)
- .map_err(From::from)
+ fire(Request {
+ body: Some(map.to_string().as_bytes()),
+ headers: None,
+ route: RouteInfo::CreateGuild,
+ })
}
/// Creates an [`Integration`] for a [`Guild`].
@@ -347,18 +343,11 @@ pub fn create_guild(map: &Value) -> Result<PartialGuild> {
/// [Manage Guild]: ../model/permissions/constant.MANAGE_GUILD.html
/// [docs]: https://discordapp.com/developers/docs/resources/guild#create-guild-integration
pub fn create_guild_integration(guild_id: u64, integration_id: u64, map: &Value) -> Result<()> {
- let body = map.to_string();
-
- verify(
- 204,
- request!(
- Route::GuildsIdIntegrations(guild_id),
- post(body),
- "/guilds/{}/integrations/{}",
- guild_id,
- integration_id
- ),
- )
+ wind(204, Request {
+ body: Some(map.to_string().as_bytes()),
+ headers: None,
+ route: RouteInfo::CreateGuildIntegration { guild_id, integration_id },
+ })
}
/// Creates a [`RichInvite`] for the given [channel][`GuildChannel`].
@@ -374,41 +363,35 @@ pub fn create_guild_integration(guild_id: u64, integration_id: u64, map: &Value)
/// [Create Invite]: ../model/permissions/constant.CREATE_INVITE.html
/// [docs]: https://discordapp.com/developers/docs/resources/channel#create-channel-invite
pub fn create_invite(channel_id: u64, map: &JsonMap) -> Result<RichInvite> {
- let body = serde_json::to_string(map)?;
- let response = request!(
- Route::ChannelsIdInvites(channel_id),
- post(body),
- "/channels/{}/invites",
- channel_id
- );
-
- serde_json::from_reader::<HyperResponse, RichInvite>(response)
- .map_err(From::from)
+ let body = serde_json::to_vec(map)?;
+
+ fire(Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::CreateInvite { channel_id },
+ })
}
/// Creates a permission override for a member or a role in a channel.
pub fn create_permission(channel_id: u64, target_id: u64, map: &Value) -> Result<()> {
- let body = map.to_string();
-
- verify(
- 204,
- request!(
- Route::ChannelsIdPermissionsOverwriteId(channel_id),
- put(body),
- "/channels/{}/permissions/{}",
- channel_id,
- target_id
- ),
- )
+ let body = serde_json::to_vec(map)?;
+
+ wind(204, Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::CreatePermission { channel_id, target_id },
+ })
}
/// Creates a private channel with a user.
pub fn create_private_channel(map: &Value) -> Result<PrivateChannel> {
- let body = map.to_string();
- let response = request!(Route::UsersMeChannels, post(body), "/users/@me/channels");
+ let body = serde_json::to_vec(map)?;
- serde_json::from_reader::<HyperResponse, PrivateChannel>(response)
- .map_err(From::from)
+ fire(Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::GetUserDmChannels,
+ })
}
/// Reacts to a message.
@@ -416,31 +399,26 @@ pub fn create_reaction(channel_id: u64,
message_id: u64,
reaction_type: &ReactionType)
-> Result<()> {
- verify(
- 204,
- request!(
- Route::ChannelsIdMessagesIdReactionsUserIdType(channel_id),
- put,
- "/channels/{}/messages/{}/reactions/{}/@me",
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::CreateReaction {
+ reaction: &reaction_type.as_data(),
channel_id,
message_id,
- reaction_type.as_data()
- ),
- )
+ },
+ })
}
/// Creates a role.
pub fn create_role(guild_id: u64, map: &JsonMap) -> Result<Role> {
- let body = serde_json::to_string(map)?;
- let response = request!(
- Route::GuildsIdRoles(guild_id),
- post(body),
- "/guilds/{}/roles",
- guild_id
- );
-
- serde_json::from_reader::<HyperResponse, Role>(response)
- .map_err(From::from)
+ let body = serde_json::to_vec(map)?;
+
+ fire(Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::CreateRole {guild_id },
+ })
}
/// Creates a webhook for the given [channel][`GuildChannel`]'s Id, passing in
@@ -474,103 +452,77 @@ pub fn create_role(guild_id: u64, map: &JsonMap) -> Result<Role> {
///
/// [`GuildChannel`]: ../model/channel/struct.GuildChannel.html
pub fn create_webhook(channel_id: u64, map: &Value) -> Result<Webhook> {
- let body = map.to_string();
- let response = request!(
- Route::ChannelsIdWebhooks(channel_id),
- post(body),
- "/channels/{}/webhooks",
- channel_id
- );
-
- serde_json::from_reader::<HyperResponse, Webhook>(response)
- .map_err(From::from)
+ let body = serde_json::to_vec(map)?;
+
+ fire(Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::CreateWebhook { channel_id },
+ })
}
/// Deletes a private channel or a channel in a guild.
pub fn delete_channel(channel_id: u64) -> Result<Channel> {
- let response = request!(
- Route::ChannelsId(channel_id),
- delete,
- "/channels/{}",
- channel_id
- );
-
- serde_json::from_reader::<HyperResponse, Channel>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::DeleteChannel { channel_id },
+ })
}
/// Deletes an emoji from a server.
pub fn delete_emoji(guild_id: u64, emoji_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::GuildsIdEmojisId(guild_id),
- delete,
- "/guilds/{}/emojis/{}",
- guild_id,
- emoji_id
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::DeleteEmoji { guild_id, emoji_id },
+ })
}
/// Deletes a guild, only if connected account owns it.
pub fn delete_guild(guild_id: u64) -> Result<PartialGuild> {
- let response = request!(Route::GuildsId(guild_id), delete, "/guilds/{}", guild_id);
-
- serde_json::from_reader::<HyperResponse, PartialGuild>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::DeleteGuild { guild_id },
+ })
}
/// Remvoes an integration from a guild.
pub fn delete_guild_integration(guild_id: u64, integration_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::GuildsIdIntegrationsId(guild_id),
- delete,
- "/guilds/{}/integrations/{}",
- guild_id,
- integration_id
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::DeleteGuildIntegration { guild_id, integration_id },
+ })
}
/// Deletes an invite by code.
pub fn delete_invite(code: &str) -> Result<Invite> {
- let response = request!(Route::InvitesCode, delete, "/invites/{}", code);
-
- serde_json::from_reader::<HyperResponse, Invite>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::DeleteInvite { code },
+ })
}
/// Deletes a message if created by us or we have
/// specific permissions.
pub fn delete_message(channel_id: u64, message_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::ChannelsIdMessagesId(LightMethod::Delete, channel_id),
- delete,
- "/channels/{}/messages/{}",
- channel_id,
- message_id
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::DeleteMessage { channel_id, message_id },
+ })
}
/// Deletes a bunch of messages, only works for bots.
pub fn delete_messages(channel_id: u64, map: &Value) -> Result<()> {
- let body = map.to_string();
-
- verify(
- 204,
- request!(
- Route::ChannelsIdMessagesBulkDelete(channel_id),
- post(body),
- "/channels/{}/messages/bulk-delete",
- channel_id
- ),
- )
+ wind(204, Request {
+ body: Some(map.to_string().as_bytes()),
+ headers: None,
+ route: RouteInfo::DeleteMessages { channel_id },
+ })
}
/// Deletes all of the [`Reaction`]s associated with a [`Message`].
@@ -591,30 +543,20 @@ pub fn delete_messages(channel_id: u64, map: &Value) -> Result<()> {
/// [`Message`]: ../model/channel/struct.Message.html
/// [`Reaction`]: ../model/channel/struct.Reaction.html
pub fn delete_message_reactions(channel_id: u64, message_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::ChannelsIdMessagesIdReactions(channel_id),
- delete,
- "/channels/{}/messages/{}/reactions",
- channel_id,
- message_id
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::DeleteMessageReactions { channel_id, message_id },
+ })
}
/// Deletes a permission override from a role or a member in a channel.
pub fn delete_permission(channel_id: u64, target_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::ChannelsIdPermissionsOverwriteId(channel_id),
- delete,
- "/channels/{}/permissions/{}",
- channel_id,
- target_id
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::DeletePermission { channel_id, target_id },
+ })
}
/// Deletes a reaction from a message if owned by us or
@@ -628,32 +570,25 @@ pub fn delete_reaction(channel_id: u64,
.map(|uid| uid.to_string())
.unwrap_or_else(|| "@me".to_string());
- verify(
- 204,
- request!(
- Route::ChannelsIdMessagesIdReactionsUserIdType(channel_id),
- delete,
- "/channels/{}/messages/{}/reactions/{}/{}",
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::DeleteReaction {
+ reaction: &reaction_type.as_data(),
+ user: &user,
channel_id,
message_id,
- reaction_type.as_data(),
- user
- ),
- )
+ },
+ })
}
/// Deletes a role from a server. Can't remove the default everyone role.
pub fn delete_role(guild_id: u64, role_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::GuildsIdRolesId(guild_id),
- delete,
- "/guilds/{}/roles/{}",
- guild_id,
- role_id
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::DeleteRole { guild_id, role_id },
+ })
}
/// Deletes a [`Webhook`] given its Id.
@@ -679,15 +614,11 @@ pub fn delete_role(guild_id: u64, role_id: u64) -> Result<()> {
/// [`Webhook`]: ../model/webhook/struct.Webhook.html
/// [`delete_webhook_with_token`]: fn.delete_webhook_with_token.html
pub fn delete_webhook(webhook_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::WebhooksId(webhook_id),
- delete,
- "/webhooks/{}",
- webhook_id,
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::DeleteWebhook { webhook_id },
+ })
}
/// Deletes a [`Webhook`] given its Id and unique token.
@@ -709,123 +640,93 @@ pub fn delete_webhook(webhook_id: u64) -> Result<()> {
///
/// [`Webhook`]: ../model/webhook/struct.Webhook.html
pub fn delete_webhook_with_token(webhook_id: u64, token: &str) -> Result<()> {
- let client = request_client!();
-
- verify(
- 204,
- retry(|| {
- client
- .delete(&format!(api!("/webhooks/{}/{}"), webhook_id, token))
- }).map_err(Error::Hyper)?,
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::DeleteWebhookWithToken { token, webhook_id },
+ })
}
/// Changes channel information.
pub fn edit_channel(channel_id: u64, map: &JsonMap) -> Result<GuildChannel> {
- let body = serde_json::to_string(map)?;
- let response = request!(
- Route::ChannelsId(channel_id),
- patch(body),
- "/channels/{}",
- channel_id
- );
-
- serde_json::from_reader::<HyperResponse, GuildChannel>(response)
- .map_err(From::from)
+ let body = serde_json::to_vec(map)?;
+
+ fire(Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::EditChannel {channel_id },
+ })
}
/// Changes emoji information.
pub fn edit_emoji(guild_id: u64, emoji_id: u64, map: &Value) -> Result<Emoji> {
- let body = map.to_string();
- let response = request!(
- Route::GuildsIdEmojisId(guild_id),
- patch(body),
- "/guilds/{}/emojis/{}",
- guild_id,
- emoji_id
- );
-
- serde_json::from_reader::<HyperResponse, Emoji>(response)
- .map_err(From::from)
+ let body = serde_json::to_vec(map)?;
+
+ fire(Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::EditEmoji { guild_id, emoji_id },
+ })
}
/// Changes guild information.
pub fn edit_guild(guild_id: u64, map: &JsonMap) -> Result<PartialGuild> {
- let body = serde_json::to_string(map)?;
- let response = request!(
- Route::GuildsId(guild_id),
- patch(body),
- "/guilds/{}",
- guild_id
- );
-
- serde_json::from_reader::<HyperResponse, PartialGuild>(response)
- .map_err(From::from)
+ let body = serde_json::to_vec(map)?;
+
+ fire(Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::EditGuild { guild_id },
+ })
}
/// Edits the positions of a guild's channels.
pub fn edit_guild_channel_positions(guild_id: u64, value: &Value)
-> Result<()> {
- let body = serde_json::to_string(value)?;
-
- verify(
- 204,
- request!(
- Route::GuildsIdChannels(guild_id),
- patch(body),
- "/guilds/{}/channels",
- guild_id,
- ),
- )
+ let body = serde_json::to_vec(value)?;
+
+ wind(204, Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::EditGuildChannels { guild_id },
+ })
}
/// Edits a [`Guild`]'s embed setting.
///
/// [`Guild`]: ../model/guild/struct.Guild.html
pub fn edit_guild_embed(guild_id: u64, map: &Value) -> Result<GuildEmbed> {
- let body = map.to_string();
- let response = request!(
- Route::GuildsIdEmbed(guild_id),
- patch(body),
- "/guilds/{}/embed",
- guild_id
- );
-
- serde_json::from_reader::<HyperResponse, GuildEmbed>(response)
- .map_err(From::from)
+ let body = serde_json::to_vec(map)?;
+
+ fire(Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::EditGuildEmbed { guild_id },
+ })
}
/// Does specific actions to a member.
pub fn edit_member(guild_id: u64, user_id: u64, map: &JsonMap) -> Result<()> {
- let body = serde_json::to_string(map)?;
-
- verify(
- 204,
- request!(
- Route::GuildsIdMembersId(guild_id),
- patch(body),
- "/guilds/{}/members/{}",
- guild_id,
- user_id
- ),
- )
+ let body = serde_json::to_vec(map)?;
+
+ wind(204, Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::EditMember { guild_id, user_id },
+ })
}
/// Edits a message by Id.
///
/// **Note**: Only the author of a message can modify it.
pub fn edit_message(channel_id: u64, message_id: u64, map: &Value) -> Result<Message> {
- let body = map.to_string();
- let response = request!(
- Route::ChannelsIdMessagesId(LightMethod::Any, channel_id),
- patch(body),
- "/channels/{}/messages/{}",
- channel_id,
- message_id
- );
+ let body = serde_json::to_vec(map)?;
- serde_json::from_reader::<HyperResponse, Message>(response)
- .map_err(From::from)
+ fire(Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::EditMessage { channel_id, message_id },
+ })
}
/// Edits the current user's nickname for the provided [`Guild`] via its Id.
@@ -835,15 +736,13 @@ pub fn edit_message(channel_id: u64, message_id: u64, map: &Value) -> Result<Mes
/// [`Guild`]: ../model/guild/struct.Guild.html
pub fn edit_nickname(guild_id: u64, new_nickname: Option<&str>) -> Result<()> {
let map = json!({ "nick": new_nickname });
- let body = map.to_string();
- let response = request!(
- Route::GuildsIdMembersMeNick(guild_id),
- patch(body),
- "/guilds/{}/members/@me/nick",
- guild_id
- );
+ let body = serde_json::to_vec(&map)?;
- verify(200, response)
+ wind(200, Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::EditNickname { guild_id },
+ })
}
/// Edits the current user's profile settings.
@@ -859,8 +758,13 @@ pub fn edit_nickname(guild_id: u64, new_nickname: Option<&str>) -> Result<()> {
/// change and when the token is internally changed to be invalid requests, as
/// the token may be outdated.
pub fn edit_profile(map: &JsonMap) -> Result<CurrentUser> {
- let body = serde_json::to_string(map)?;
- let response = request!(Route::UsersMe, patch(body), "/users/@me");
+ let body = serde_json::to_vec(map)?;
+
+ let response = request(Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::EditProfile,
+ })?;
let mut value = serde_json::from_reader::<HyperResponse, Value>(response)?;
@@ -872,41 +776,32 @@ pub fn edit_profile(map: &JsonMap) -> Result<CurrentUser> {
}
}
- serde_json::from_value::<CurrentUser>(value)
- .map_err(From::from)
+ serde_json::from_value::<CurrentUser>(value).map_err(From::from)
}
/// Changes a role in a guild.
pub fn edit_role(guild_id: u64, role_id: u64, map: &JsonMap) -> Result<Role> {
- let body = serde_json::to_string(map)?;
- let response = request!(
- Route::GuildsIdRolesId(guild_id),
- patch(body),
- "/guilds/{}/roles/{}",
- guild_id,
- role_id
- );
-
- serde_json::from_reader::<HyperResponse, Role>(response)
- .map_err(From::from)
+ let body = serde_json::to_vec(&map)?;
+
+ fire(Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::EditRole { guild_id, role_id },
+ })
}
/// Changes the position of a role in a guild.
pub fn edit_role_position(guild_id: u64, role_id: u64, position: u64) -> Result<Vec<Role>> {
- let body = serde_json::to_string(&json!({
+ let body = serde_json::to_vec(&json!({
"id": role_id,
"position": position,
}))?;
- let response = request!(
- Route::GuildsIdRolesId(guild_id),
- patch(body),
- "/guilds/{}/roles/{}",
- guild_id,
- role_id
- );
-
- serde_json::from_reader::<HyperResponse, Vec<Role>>(response)
- .map_err(From::from)
+
+ fire(Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::EditRole { guild_id, role_id },
+ })
}
/// Edits a the webhook with the given data.
@@ -949,16 +844,11 @@ pub fn edit_role_position(guild_id: u64, role_id: u64, position: u64) -> Result<
// The tests are ignored, rather than no_run'd, due to rustdoc tests with
// external crates being incredibly messy and misleading in the end user's view.
pub fn edit_webhook(webhook_id: u64, map: &Value) -> Result<Webhook> {
- let body = map.to_string();
- let response = request!(
- Route::WebhooksId(webhook_id),
- patch(body),
- "/webhooks/{}",
- webhook_id,
- );
-
- serde_json::from_reader::<HyperResponse, Webhook>(response)
- .map_err(From::from)
+ fire(Request {
+ body: Some(map.to_string().as_bytes()),
+ headers: None,
+ route: RouteInfo::EditWebhook { webhook_id },
+ })
}
/// Edits the webhook with the given data.
@@ -988,17 +878,13 @@ pub fn edit_webhook(webhook_id: u64, map: &Value) -> Result<Webhook> {
///
/// [`edit_webhook`]: fn.edit_webhook.html
pub fn edit_webhook_with_token(webhook_id: u64, token: &str, map: &JsonMap) -> Result<Webhook> {
- let body = serde_json::to_string(map)?;
- let client = request_client!();
-
- let response = retry(|| {
- client
- .patch(&format!(api!("/webhooks/{}/{}"), webhook_id, token))
- .body(&body)
- }).map_err(Error::Hyper)?;
+ let body = serde_json::to_vec(map)?;
- serde_json::from_reader::<HyperResponse, Webhook>(response)
- .map_err(From::from)
+ fire(Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::EditWebhookWithToken { token, webhook_id },
+ })
}
/// Executes a webhook, posting a [`Message`] in the webhook's associated
@@ -1066,23 +952,18 @@ pub fn execute_webhook(webhook_id: u64,
wait: bool,
map: &JsonMap)
-> Result<Option<Message>> {
- let body = serde_json::to_string(map)?;
-
- let client = request_client!();
-
- let response = retry(|| {
- client
- .post(&format!(
- api!("/webhooks/{}/{}?wait={}"),
- webhook_id,
- token,
- wait
- ))
- .body(&body)
- .header(ContentType(
- Mime(TopLevel::Application, SubLevel::Json, vec![]),
- ))
- }).map_err(Error::Hyper)?;
+ let body = serde_json::to_vec(map)?;
+
+ let mut headers = Headers::new();
+ headers.set(ContentType(
+ Mime(TopLevel::Application, SubLevel::Json, vec![]),
+ ));
+
+ let response = request(Request {
+ body: Some(&body),
+ headers: Some(headers),
+ route: RouteInfo::ExecuteWebhook { token, wait, webhook_id },
+ })?;
if response.status == StatusCode::NoContent {
return Ok(None);
@@ -1097,10 +978,10 @@ pub fn execute_webhook(webhook_id: u64,
///
/// Does not require authentication.
pub fn get_active_maintenances() -> Result<Vec<Maintenance>> {
- let client = request_client!();
-
- let response = retry(|| {
- client.get(status!("/scheduled-maintenances/active.json"))
+ let response = request(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetActiveMaintenance,
})?;
let mut map: BTreeMap<String, Value> = serde_json::from_reader(response)?;
@@ -1114,15 +995,11 @@ pub fn get_active_maintenances() -> Result<Vec<Maintenance>> {
/// Gets all the users that are banned in specific guild.
pub fn get_bans(guild_id: u64) -> Result<Vec<Ban>> {
- let response = request!(
- Route::GuildsIdBans(guild_id),
- get,
- "/guilds/{}/bans",
- guild_id
- );
-
- serde_json::from_reader::<HyperResponse, Vec<Ban>>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetBans { guild_id },
+ })
}
/// Gets all audit logs in a specific guild.
@@ -1131,57 +1008,35 @@ pub fn get_audit_logs(guild_id: u64,
user_id: Option<u64>,
before: Option<u64>,
limit: Option<u8>) -> Result<AuditLogs> {
- let mut params = Vec::with_capacity(4);
-
- if let Some(action_type) = action_type {
- params.push(format!("action_type={}", action_type));
- }
- if let Some(user_id) = user_id {
- params.push(format!("user_id={}", user_id));
- }
- if let Some(before) = before {
- params.push(format!("before={}", before));
- }
- if let Some(limit) = limit {
- params.push(format!("limit={}", limit));
- }
-
- let mut query_string = params.join("&");
- if !query_string.is_empty() {
- query_string.insert(0, '?');
- }
-
- let response = request!(
- Route::GuildsIdAuditLogs(guild_id),
- get,
- "/guilds/{}/audit-logs{}",
- guild_id,
- query_string
- );
-
- serde_json::from_reader::<HyperResponse, AuditLogs>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetAuditLogs {
+ action_type,
+ before,
+ guild_id,
+ limit,
+ user_id,
+ },
+ })
}
/// Gets current bot gateway.
pub fn get_bot_gateway() -> Result<BotGateway> {
- let response = request!(Route::GatewayBot, get, "/gateway/bot");
-
- serde_json::from_reader::<HyperResponse, BotGateway>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetBotGateway,
+ })
}
/// Gets all invites for a channel.
pub fn get_channel_invites(channel_id: u64) -> Result<Vec<RichInvite>> {
- let response = request!(
- Route::ChannelsIdInvites(channel_id),
- get,
- "/channels/{}/invites",
- channel_id
- );
-
- serde_json::from_reader::<HyperResponse, Vec<RichInvite>>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetChannelInvites { channel_id },
+ })
}
/// Retrieves the webhooks for the given [channel][`GuildChannel`]'s Id.
@@ -1203,114 +1058,94 @@ pub fn get_channel_invites(channel_id: u64) -> Result<Vec<RichInvite>> {
///
/// [`GuildChannel`]: ../model/channel/struct.GuildChannel.html
pub fn get_channel_webhooks(channel_id: u64) -> Result<Vec<Webhook>> {
- let response = request!(
- Route::ChannelsIdWebhooks(channel_id),
- get,
- "/channels/{}/webhooks",
- channel_id
- );
-
- serde_json::from_reader::<HyperResponse, Vec<Webhook>>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetChannelWebhooks { channel_id },
+ })
}
/// Gets channel information.
pub fn get_channel(channel_id: u64) -> Result<Channel> {
- let response = request!(
- Route::ChannelsId(channel_id),
- get,
- "/channels/{}",
- channel_id
- );
-
- serde_json::from_reader::<HyperResponse, Channel>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetChannel { channel_id },
+ })
}
/// Gets all channels in a guild.
pub fn get_channels(guild_id: u64) -> Result<Vec<GuildChannel>> {
- let response = request!(
- Route::ChannelsId(guild_id),
- get,
- "/guilds/{}/channels",
- guild_id
- );
-
- serde_json::from_reader::<HyperResponse, Vec<GuildChannel>>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetChannels { guild_id },
+ })
}
/// Gets information about the current application.
///
/// **Note**: Only applications may use this endpoint.
pub fn get_current_application_info() -> Result<CurrentApplicationInfo> {
- let response = request!(Route::None, get, "/oauth2/applications/@me");
-
- serde_json::from_reader::<HyperResponse, CurrentApplicationInfo>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetCurrentApplicationInfo,
+ })
}
/// Gets information about the user we're connected with.
pub fn get_current_user() -> Result<CurrentUser> {
- let response = request!(Route::UsersMe, get, "/users/@me");
-
- serde_json::from_reader::<HyperResponse, CurrentUser>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetCurrentUser,
+ })
}
/// Gets current gateway.
pub fn get_gateway() -> Result<Gateway> {
- let response = request!(Route::Gateway, get, "/gateway");
-
- serde_json::from_reader::<HyperResponse, Gateway>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetGateway,
+ })
}
/// Gets guild information.
pub fn get_guild(guild_id: u64) -> Result<PartialGuild> {
- let response = request!(Route::GuildsId(guild_id), get, "/guilds/{}", guild_id);
-
- serde_json::from_reader::<HyperResponse, PartialGuild>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetGuild { guild_id },
+ })
}
/// Gets a guild embed information.
pub fn get_guild_embed(guild_id: u64) -> Result<GuildEmbed> {
- let response = request!(
- Route::GuildsIdEmbed(guild_id),
- get,
- "/guilds/{}/embeds",
- guild_id
- );
-
- serde_json::from_reader::<HyperResponse, GuildEmbed>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetGuildEmbed { guild_id },
+ })
}
/// Gets integrations that a guild has.
pub fn get_guild_integrations(guild_id: u64) -> Result<Vec<Integration>> {
- let response = request!(
- Route::GuildsIdIntegrations(guild_id),
- get,
- "/guilds/{}/integrations",
- guild_id
- );
-
- serde_json::from_reader::<HyperResponse, Vec<Integration>>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetGuildIntegrations { guild_id },
+ })
}
/// Gets all invites to a guild.
pub fn get_guild_invites(guild_id: u64) -> Result<Vec<RichInvite>> {
- let response = request!(
- Route::GuildsIdInvites(guild_id),
- get,
- "/guilds/{}/invites",
- guild_id
- );
-
- serde_json::from_reader::<HyperResponse, Vec<RichInvite>>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetGuildInvites { guild_id },
+ })
}
/// Gets a guild's vanity URL if it has one.
@@ -1320,12 +1155,11 @@ pub fn get_guild_vanity_url(guild_id: u64) -> Result<String> {
code: String,
}
- let response = request!(
- Route::GuildsIdVanityUrl(guild_id),
- get,
- "/guilds/{}/vanity-url",
- guild_id
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetGuildVanityUrl { guild_id },
+ })?;
serde_json::from_reader::<HyperResponse, GuildVanityUrl>(response)
.map(|x| x.code)
@@ -1338,14 +1172,11 @@ pub fn get_guild_members(guild_id: u64,
limit: Option<u64>,
after: Option<u64>)
-> Result<Vec<Member>> {
- let response = request!(
- Route::GuildsIdMembers(guild_id),
- get,
- "/guilds/{}/members?limit={}&after={}",
- guild_id,
- limit.unwrap_or(500),
- after.unwrap_or(0)
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetGuildMembers { after, guild_id, limit },
+ })?;
let mut v = serde_json::from_reader::<HyperResponse, Value>(response)?;
@@ -1364,45 +1195,43 @@ pub fn get_guild_members(guild_id: u64,
/// Gets the amount of users that can be pruned.
pub fn get_guild_prune_count(guild_id: u64, map: &Value) -> Result<GuildPrune> {
- let body = map.to_string();
- let response = request!(
- Route::GuildsIdPrune(guild_id),
- get(body),
- "/guilds/{}/prune",
- guild_id
- );
-
- serde_json::from_reader::<HyperResponse, GuildPrune>(response)
- .map_err(From::from)
+ // Note for 0.6.x: turn this into a function parameter.
+ #[derive(Deserialize)]
+ struct GetGuildPruneCountRequest {
+ days: u64,
+ }
+
+ let req = serde_json::from_value::<GetGuildPruneCountRequest>(map.clone())?;
+
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetGuildPruneCount {
+ days: req.days,
+ guild_id,
+ },
+ })
}
/// Gets regions that a guild can use. If a guild has the `VIP_REGIONS` feature
/// enabled, then additional VIP-only regions are returned.
pub fn get_guild_regions(guild_id: u64) -> Result<Vec<VoiceRegion>> {
- let response = request!(
- Route::GuildsIdRegions(guild_id),
- get,
- "/guilds/{}/regions",
- guild_id
- );
-
- serde_json::from_reader::<HyperResponse, Vec<VoiceRegion>>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetGuildRegions { guild_id },
+ })
}
/// Retrieves a list of roles in a [`Guild`].
///
/// [`Guild`]: ../model/guild/struct.Guild.html
pub fn get_guild_roles(guild_id: u64) -> Result<Vec<Role>> {
- let response = request!(
- Route::GuildsIdRoles(guild_id),
- get,
- "/guilds/{}/roles",
- guild_id
- );
-
- serde_json::from_reader::<HyperResponse, Vec<Role>>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetGuildRoles { guild_id },
+ })
}
/// Retrieves the webhooks for the given [guild][`Guild`]'s Id.
@@ -1424,15 +1253,11 @@ pub fn get_guild_roles(guild_id: u64) -> Result<Vec<Role>> {
///
/// [`Guild`]: ../model/guild/struct.Guild.html
pub fn get_guild_webhooks(guild_id: u64) -> Result<Vec<Webhook>> {
- let response = request!(
- Route::GuildsIdWebhooks(guild_id),
- get,
- "/guilds/{}/webhooks",
- guild_id
- );
-
- serde_json::from_reader::<HyperResponse, Vec<Webhook>>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetGuildWebhooks { guild_id },
+ })
}
/// Gets a paginated list of the current user's guilds.
@@ -1456,54 +1281,40 @@ pub fn get_guild_webhooks(guild_id: u64) -> Result<Vec<Webhook>> {
///
/// [docs]: https://discordapp.com/developers/docs/resources/user#get-current-user-guilds
pub fn get_guilds(target: &GuildPagination, limit: u64) -> Result<Vec<GuildInfo>> {
- let mut uri = format!("/users/@me/guilds?limit={}", limit);
-
- match *target {
- GuildPagination::After(id) => {
- write!(uri, "&after={}", id)?;
- },
- GuildPagination::Before(id) => {
- write!(uri, "&before={}", id)?;
- },
- }
-
- let response = request!(Route::UsersMeGuilds, get, "{}", uri);
+ let (after, before) = match *target {
+ GuildPagination::After(id) => (Some(id.0), None),
+ GuildPagination::Before(id) => (None, Some(id.0)),
+ };
- serde_json::from_reader::<HyperResponse, Vec<GuildInfo>>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetGuilds { after, before, limit },
+ })
}
/// Gets information about a specific invite.
#[allow(unused_mut)]
-pub fn get_invite(code: &str, stats: bool) -> Result<Invite> {
- let mut invite = code;
-
+pub fn get_invite(mut code: &str, stats: bool) -> Result<Invite> {
#[cfg(feature = "utils")]
{
- invite = ::utils::parse_invite(invite);
- }
-
- let mut uri = format!("/invites/{}", invite);
-
- if stats {
- uri.push_str("?with_counts=true");
+ code = ::utils::parse_invite(code);
}
- let response = request!(Route::InvitesCode, get, "{}", uri);
-
- serde_json::from_reader::<HyperResponse, Invite>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetInvite { code, stats },
+ })
}
/// Gets member of a guild.
pub fn get_member(guild_id: u64, user_id: u64) -> Result<Member> {
- let response = request!(
- Route::GuildsIdMembersId(guild_id),
- get,
- "/guilds/{}/members/{}",
- guild_id,
- user_id
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetMember { guild_id, user_id },
+ })?;
let mut v = serde_json::from_reader::<HyperResponse, Value>(response)?;
@@ -1516,40 +1327,32 @@ pub fn get_member(guild_id: u64, user_id: u64) -> Result<Member> {
/// Gets a message by an Id, bots only.
pub fn get_message(channel_id: u64, message_id: u64) -> Result<Message> {
- let response = request!(
- Route::ChannelsIdMessagesId(LightMethod::Any, channel_id),
- get,
- "/channels/{}/messages/{}",
- channel_id,
- message_id
- );
-
- serde_json::from_reader::<HyperResponse, Message>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetMessage { channel_id, message_id },
+ })
}
/// Gets X messages from a channel.
pub fn get_messages(channel_id: u64, query: &str) -> Result<Vec<Message>> {
- let url = format!(api!("/channels/{}/messages{}"), channel_id, query);
- let client = request_client!();
-
- let response = request(Route::ChannelsIdMessages(channel_id), || client.get(&url))?;
-
- serde_json::from_reader::<HyperResponse, Vec<Message>>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetMessages {
+ query: query.to_owned(),
+ channel_id,
+ },
+ })
}
/// Gets all pins of a channel.
pub fn get_pins(channel_id: u64) -> Result<Vec<Message>> {
- let response = request!(
- Route::ChannelsIdPins(channel_id),
- get,
- "/channels/{}/pins",
- channel_id
- );
-
- serde_json::from_reader::<HyperResponse, Vec<Message>>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetPins { channel_id },
+ })
}
/// Gets user Ids based on their reaction to a message. This endpoint is dumb.
@@ -1559,36 +1362,30 @@ pub fn get_reaction_users(channel_id: u64,
limit: u8,
after: Option<u64>)
-> Result<Vec<User>> {
- let mut uri = format!(
- "/channels/{}/messages/{}/reactions/{}?limit={}",
- channel_id,
- message_id,
- reaction_type.as_data(),
- limit
- );
-
- if let Some(user_id) = after {
- write!(uri, "&after={}", user_id)?;
- }
-
- let response = request!(
- Route::ChannelsIdMessagesIdReactionsUserIdType(channel_id),
- get,
- "{}",
- uri
- );
+ let reaction = reaction_type.as_data();
- serde_json::from_reader::<HyperResponse, Vec<User>>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetReactionUsers {
+ after,
+ channel_id,
+ limit,
+ message_id,
+ reaction,
+ },
+ })
}
/// Gets the current unresolved incidents from Discord's Status API.
///
/// Does not require authentication.
pub fn get_unresolved_incidents() -> Result<Vec<Incident>> {
- let client = request_client!();
-
- let response = retry(|| client.get(status!("/incidents/unresolved.json")))?;
+ let response = request(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetUnresolvedIncidents,
+ })?;
let mut map: BTreeMap<String, Value> = serde_json::from_reader(response)?;
@@ -1603,10 +1400,10 @@ pub fn get_unresolved_incidents() -> Result<Vec<Incident>> {
///
/// Does not require authentication.
pub fn get_upcoming_maintenances() -> Result<Vec<Maintenance>> {
- let client = request_client!();
-
- let response = retry(|| {
- client.get(status!("/scheduled-maintenances/upcoming.json"))
+ let response = request(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetUpcomingMaintenances,
})?;
let mut map: BTreeMap<String, Value> = serde_json::from_reader(response)?;
@@ -1620,26 +1417,29 @@ pub fn get_upcoming_maintenances() -> Result<Vec<Maintenance>> {
/// Gets a user by Id.
pub fn get_user(user_id: u64) -> Result<User> {
- let response = request!(Route::UsersId, get, "/users/{}", user_id);
-
- serde_json::from_reader::<HyperResponse, User>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetUser { user_id },
+ })
}
/// Gets our DM channels.
pub fn get_user_dm_channels() -> Result<Vec<PrivateChannel>> {
- let response = request!(Route::UsersMeChannels, get, "/users/@me/channels");
-
- serde_json::from_reader::<HyperResponse, Vec<PrivateChannel>>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetUserDmChannels,
+ })
}
/// Gets all voice regions.
pub fn get_voice_regions() -> Result<Vec<VoiceRegion>> {
- let response = request!(Route::VoiceRegions, get, "/voice/regions");
-
- serde_json::from_reader::<HyperResponse, Vec<VoiceRegion>>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetVoiceRegions,
+ })
}
/// Retrieves a webhook given its Id.
@@ -1660,15 +1460,11 @@ pub fn get_voice_regions() -> Result<Vec<VoiceRegion>> {
///
/// [`get_webhook_with_token`]: fn.get_webhook_with_token.html
pub fn get_webhook(webhook_id: u64) -> Result<Webhook> {
- let response = request!(
- Route::WebhooksId(webhook_id),
- get,
- "/webhooks/{}",
- webhook_id,
- );
-
- serde_json::from_reader::<HyperResponse, Webhook>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetWebhook { webhook_id },
+ })
}
/// Retrieves a webhook given its Id and unique token.
@@ -1689,64 +1485,47 @@ pub fn get_webhook(webhook_id: u64) -> Result<Webhook> {
/// .expect("Error getting webhook");
/// ```
pub fn get_webhook_with_token(webhook_id: u64, token: &str) -> Result<Webhook> {
- let client = request_client!();
-
- let response = retry(|| {
- client
- .get(&format!(api!("/webhooks/{}/{}"), webhook_id, token))
- }).map_err(Error::Hyper)?;
-
- serde_json::from_reader::<HyperResponse, Webhook>(response)
- .map_err(From::from)
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::GetWebhookWithToken { token, webhook_id },
+ })
}
/// Kicks a member from a guild.
pub fn kick_member(guild_id: u64, user_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::GuildsIdMembersId(guild_id),
- delete,
- "/guilds/{}/members/{}",
- guild_id,
- user_id
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::KickMember { guild_id, user_id },
+ })
}
/// Leaves a group DM.
-pub fn leave_group(guild_id: u64) -> Result<Group> {
- let response = request!(Route::None, delete, "/channels/{}", guild_id);
-
- serde_json::from_reader::<HyperResponse, Group>(response)
- .map_err(From::from)
+pub fn leave_group(group_id: u64) -> Result<Group> {
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::LeaveGroup { group_id },
+ })
}
/// Leaves a guild.
pub fn leave_guild(guild_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::UsersMeGuildsId,
- delete,
- "/users/@me/guilds/{}",
- guild_id
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::LeaveGuild { guild_id },
+ })
}
/// Deletes a user from group DM.
pub fn remove_group_recipient(group_id: u64, user_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::None,
- delete,
- "/channels/{}/recipients/{}",
- group_id,
- user_id
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::RemoveGroupRecipient { group_id, user_id },
+ })
}
/// Sends file(s) to a channel.
@@ -1760,7 +1539,7 @@ pub fn remove_group_recipient(group_id: u64, user_id: u64) -> Result<()> {
/// [`HttpError::InvalidRequest`]: enum.HttpError.html#variant.InvalidRequest
pub fn send_files<'a, T, It: IntoIterator<Item=T>>(channel_id: u64, files: It, map: JsonMap) -> Result<Message>
where T: Into<AttachmentType<'a>> {
- let uri = format!(api!("/channels/{}/messages"), channel_id);
+ let uri = api!("/channels/{}/messages", channel_id);
let url = match Url::parse(&uri) {
Ok(url) => url,
Err(_) => return Err(Error::Url(uri)),
@@ -1768,7 +1547,7 @@ pub fn send_files<'a, T, It: IntoIterator<Item=T>>(channel_id: u64, files: It, m
let tc = NativeTlsClient::new()?;
let connector = HttpsConnector::new(tc);
- let mut request = Request::with_connector(Method::Post, url, &connector)?;
+ let mut request = HyperRequest::with_connector(Method::Post, url, &connector)?;
request
.headers_mut()
.set(header::Authorization(TOKEN.lock().clone()));
@@ -1817,50 +1596,36 @@ pub fn send_files<'a, T, It: IntoIterator<Item=T>>(channel_id: u64, files: It, m
return Err(Error::Http(HttpError::UnsuccessfulRequest(response)));
}
- serde_json::from_reader::<HyperResponse, Message>(response)
- .map_err(From::from)
+ serde_json::from_reader(response).map_err(From::from)
}
/// Sends a message to a channel.
pub fn send_message(channel_id: u64, map: &Value) -> Result<Message> {
- let body = map.to_string();
- let response = request!(
- Route::ChannelsIdMessages(channel_id),
- post(body),
- "/channels/{}/messages",
- channel_id
- );
+ let body = serde_json::to_vec(map)?;
- serde_json::from_reader::<HyperResponse, Message>(response)
- .map_err(From::from)
+ fire(Request {
+ body: Some(&body),
+ headers: None,
+ route: RouteInfo::CreateMessage { channel_id },
+ })
}
/// Pins a message in a channel.
pub fn pin_message(channel_id: u64, message_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::ChannelsIdPinsMessageId(channel_id),
- put,
- "/channels/{}/pins/{}",
- channel_id,
- message_id
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::PinMessage { channel_id, message_id },
+ })
}
/// Unbans a user from a guild.
pub fn remove_ban(guild_id: u64, user_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::GuildsIdBansUserId(guild_id),
- delete,
- "/guilds/{}/bans/{}",
- guild_id,
- user_id
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::RemoveBan { guild_id, user_id },
+ })
}
/// Deletes a single [`Role`] from a [`Member`] in a [`Guild`].
@@ -1873,67 +1638,144 @@ pub fn remove_ban(guild_id: u64, user_id: u64) -> Result<()> {
/// [`Role`]: ../model/guild/struct.Role.html
/// [Manage Roles]: ../model/permissions/constant.MANAGE_ROLES.html
pub fn remove_member_role(guild_id: u64, user_id: u64, role_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::GuildsIdMembersIdRolesId(guild_id),
- delete,
- "/guilds/{}/members/{}/roles/{}",
- guild_id,
- user_id,
- role_id
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::RemoveMemberRole { guild_id, user_id, role_id },
+ })
}
/// Starts removing some members from a guild based on the last time they've been online.
pub fn start_guild_prune(guild_id: u64, map: &Value) -> Result<GuildPrune> {
- let body = map.to_string();
- let response = request!(
- Route::GuildsIdPrune(guild_id),
- post(body),
- "/guilds/{}/prune",
- guild_id
- );
-
- serde_json::from_reader::<HyperResponse, GuildPrune>(response)
- .map_err(From::from)
+ // Note for 0.6.x: turn this into a function parameter.
+ #[derive(Deserialize)]
+ struct StartGuildPruneRequest {
+ days: u64,
+ }
+
+ let req = serde_json::from_value::<StartGuildPruneRequest>(map.clone())?;
+
+ fire(Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::StartGuildPrune {
+ days: req.days,
+ guild_id,
+ },
+ })
}
/// Starts syncing an integration with a guild.
pub fn start_integration_sync(guild_id: u64, integration_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::GuildsIdIntegrationsIdSync(guild_id),
- post,
- "/guilds/{}/integrations/{}/sync",
- guild_id,
- integration_id
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::StartIntegrationSync { guild_id, integration_id },
+ })
}
/// Unpins a message from a channel.
pub fn unpin_message(channel_id: u64, message_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::ChannelsIdPinsMessageId(channel_id),
- delete,
- "/channels/{}/pins/{}",
- channel_id,
- message_id
- ),
- )
+ wind(204, Request {
+ body: None,
+ headers: None,
+ route: RouteInfo::UnpinMessage { channel_id, message_id },
+ })
}
-fn request<'a, F>(route: Route, f: F) -> Result<HyperResponse>
- where F: Fn() -> RequestBuilder<'a> {
- let response = ratelimiting::perform(route, || {
- f().header(header::Authorization(TOKEN.lock().clone()))
- .header(header::ContentType::json())
- })?;
+/// Fires off a request, deserializing the response reader via the given type
+/// bound.
+///
+/// If you don't need to deserialize the response and want the response instance
+/// itself, use [`request`].
+///
+/// # Examples
+///
+/// Create a new message via the [`RouteInfo::CreateMessage`] endpoint and
+/// deserialize the response into a [`Message`]:
+///
+/// ```rust,no_run
+/// # extern crate serenity;
+/// #
+/// # use std::error::Error;
+/// #
+/// # fn main() -> Result<(), Box<Error>> {
+/// #
+/// use serenity::{
+/// http::{
+/// self,
+/// request::RequestBuilder,
+/// routing::RouteInfo,
+/// },
+/// model::channel::Message,
+/// };
+///
+/// let bytes = vec![
+/// // payload bytes here
+/// ];
+/// let channel_id = 381880193700069377;
+/// let route_info = RouteInfo::CreateMessage { channel_id };
+///
+/// let mut request = RequestBuilder::new(route_info);
+/// request.body(Some(&bytes));
+///
+/// let message = http::fire::<Message>(request.build())?;
+///
+/// println!("Message content: {}", message.content);
+/// #
+/// # Ok(())
+/// # }
+/// ```
+///
+/// [`request`]: fn.request.html
+pub fn fire<T: DeserializeOwned>(req: Request) -> Result<T> {
+ let response = request(req)?;
+
+ serde_json::from_reader(response).map_err(From::from)
+}
+
+/// Performs a request, ratelimiting it if necessary.
+///
+/// Returns the raw hyper Response. Use [`fire`] to deserialize the response
+/// into some type.
+///
+/// # Examples
+///
+/// Send a body of bytes over the [`RouteInfo::CreateMessage`] endpoint:
+///
+/// ```rust,no_run
+/// # extern crate serenity;
+/// #
+/// # use std::error::Error;
+/// #
+/// # fn main() -> Result<(), Box<Error>> {
+/// #
+/// use serenity::http::{
+/// self,
+/// request::RequestBuilder,
+/// routing::RouteInfo,
+/// };
+///
+/// let bytes = vec![
+/// // payload bytes here
+/// ];
+/// let channel_id = 381880193700069377;
+/// let route_info = RouteInfo::CreateMessage { channel_id };
+///
+/// let mut request = RequestBuilder::new(route_info);
+/// request.body(Some(&bytes));
+///
+/// let response = http::request(request.build())?;
+///
+/// println!("Response successful?: {}", response.status.is_success());
+/// #
+/// # Ok(())
+/// # }
+/// ```
+///
+/// [`fire`]: fn.fire.html
+pub fn request(req: Request) -> Result<HyperResponse> {
+ let response = ratelimiting::perform(req)?;
if response.status.class() == StatusClass::Success {
Ok(response)
@@ -1942,28 +1784,37 @@ fn request<'a, F>(route: Route, f: F) -> Result<HyperResponse>
}
}
-pub(crate) fn retry<'a, F>(f: F) -> HyperResult<HyperResponse>
- where F: Fn() -> RequestBuilder<'a> {
- let req = || {
- f().header(header::UserAgent(constants::USER_AGENT.to_string()))
- .send()
- };
-
- match req() {
- Err(HyperError::Io(ref io)) if io.kind() == IoErrorKind::ConnectionAborted => req(),
- other => other,
+fn retry(request: &Request) -> HyperResult<HyperResponse> {
+ // Retry the request twice in a loop until it succeeds.
+ //
+ // If it doesn't and the loop breaks, try one last time.
+ for _ in 0..3 {
+ match request.build().send() {
+ Err(HyperError::Io(ref io))
+ if io.kind() == IoErrorKind::ConnectionAborted => continue,
+ other => return other,
+ }
}
+
+ request.build().send()
}
-fn verify(expected: u16, response: HyperResponse) -> Result<()> {
- if response.status.to_u16() == expected {
+/// Performs a request and then verifies that the response status code is equal
+/// to the expected value.
+///
+/// This is a function that performs a light amount of work and returns an
+/// empty tuple, so it's called "wind" to denote that it's lightweight.
+fn wind(expected: u16, req: Request) -> Result<()> {
+ let resp = request(req)?;
+
+ if resp.status.to_u16() == expected {
return Ok(());
}
- debug!("Expected {}, got {}", expected, response.status);
- trace!("Unsuccessful response: {:?}", response);
+ debug!("Expected {}, got {}", expected, resp.status);
+ trace!("Unsuccessful response: {:?}", resp);
- Err(Error::Http(HttpError::UnsuccessfulRequest(response)))
+ Err(Error::Http(HttpError::UnsuccessfulRequest(resp)))
}
/// Enum that allows a user to pass a `Path` or a `File` type to `send_files`
diff --git a/src/http/ratelimiting.rs b/src/http/ratelimiting.rs
index b8152d1..309ba35 100644
--- a/src/http/ratelimiting.rs
+++ b/src/http/ratelimiting.rs
@@ -40,8 +40,10 @@
//! [Taken from]: https://discordapp.com/developers/docs/topics/rate-limits#rate-limits
#![allow(zero_ptr)]
+pub use super::routing::Route;
+
use chrono::{DateTime, Utc};
-use hyper::client::{RequestBuilder, Response};
+use hyper::client::Response;
use hyper::header::Headers;
use hyper::status::StatusCode;
use internal::prelude::*;
@@ -54,7 +56,7 @@ use std::{
thread,
i64
};
-use super::{HttpError, LightMethod};
+use super::{HttpError, Request};
/// Refer to [`offset`].
///
@@ -102,272 +104,22 @@ lazy_static! {
};
}
-/// A representation of all routes registered within the library. These are safe
-/// and memory-efficient representations of each path that functions exist for
-/// in the [`http`] module.
-///
-/// [`http`]: ../index.html
-#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
-pub enum Route {
- /// Route for the `/channels/:channel_id` path.
- ///
- /// The data is the relevant [`ChannelId`].
- ///
- /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
- ChannelsId(u64),
- /// Route for the `/channels/:channel_id/invites` path.
- ///
- /// The data is the relevant [`ChannelId`].
- ///
- /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
- ChannelsIdInvites(u64),
- /// Route for the `/channels/:channel_id/messages` path.
- ///
- /// The data is the relevant [`ChannelId`].
- ///
- /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
- ChannelsIdMessages(u64),
- /// Route for the `/channels/:channel_id/messages/bulk-delete` path.
- ///
- /// The data is the relevant [`ChannelId`].
- ///
- /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
- ChannelsIdMessagesBulkDelete(u64),
- /// Route for the `/channels/:channel_id/messages/:message_id` path.
- ///
- /// The data is the relevant [`ChannelId`].
- ///
- /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
- // This route is a unique case. The ratelimit for message _deletions_ is
- // different than the overall route ratelimit.
- //
- // Refer to the docs on [Rate Limits] in the yellow warning section.
- //
- // Additionally, this needs to be a `LightMethod` from the parent module
- // and _not_ a `hyper` `Method` due to `hyper`'s not deriving `Copy`.
- //
- // [Rate Limits]: https://discordapp.com/developers/docs/topics/rate-limits
- ChannelsIdMessagesId(LightMethod, u64),
- /// Route for the `/channels/:channel_id/messages/:message_id/ack` path.
- ///
- /// The data is the relevant [`ChannelId`].
- ///
- /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
- ChannelsIdMessagesIdAck(u64),
- /// Route for the `/channels/:channel_id/messages/:message_id/reactions`
- /// path.
- ///
- /// The data is the relevant [`ChannelId`].
- ///
- /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
- ChannelsIdMessagesIdReactions(u64),
- /// Route for the
- /// `/channels/:channel_id/messages/:message_id/reactions/:reaction/@me`
- /// path.
- ///
- /// The data is the relevant [`ChannelId`].
- ///
- /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
- ChannelsIdMessagesIdReactionsUserIdType(u64),
- /// Route for the `/channels/:channel_id/permissions/:target_id` path.
- ///
- /// The data is the relevant [`ChannelId`].
- ///
- /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
- ChannelsIdPermissionsOverwriteId(u64),
- /// Route for the `/channels/:channel_id/pins` path.
- ///
- /// The data is the relevant [`ChannelId`].
- ///
- /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
- ChannelsIdPins(u64),
- /// Route for the `/channels/:channel_id/pins/:message_id` path.
- ///
- /// The data is the relevant [`ChannelId`].
- ///
- /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
- ChannelsIdPinsMessageId(u64),
- /// Route for the `/channels/:channel_id/typing` path.
- ///
- /// The data is the relevant [`ChannelId`].
- ///
- /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
- ChannelsIdTyping(u64),
- /// Route for the `/channels/:channel_id/webhooks` path.
- ///
- /// The data is the relevant [`ChannelId`].
- ///
- /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
- ChannelsIdWebhooks(u64),
- /// Route for the `/gateway` path.
- Gateway,
- /// Route for the `/gateway/bot` path.
- GatewayBot,
- /// Route for the `/guilds` path.
- Guilds,
- /// Route for the `/guilds/:guild_id` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsId(u64),
- /// Route for the `/guilds/:guild_id/bans` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdBans(u64),
- /// Route for the `/guilds/:guild_id/audit-logs` path.
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdAuditLogs(u64),
- /// Route for the `/guilds/:guild_id/bans/:user_id` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdBansUserId(u64),
- /// Route for the `/guilds/:guild_id/channels/:channel_id` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdChannels(u64),
- /// Route for the `/guilds/:guild_id/embed` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdEmbed(u64),
- /// Route for the `/guilds/:guild_id/emojis` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdEmojis(u64),
- /// Route for the `/guilds/:guild_id/emojis/:emoji_id` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdEmojisId(u64),
- /// Route for the `/guilds/:guild_id/integrations` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdIntegrations(u64),
- /// Route for the `/guilds/:guild_id/integrations/:integration_id` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdIntegrationsId(u64),
- /// Route for the `/guilds/:guild_id/integrations/:integration_id/sync`
- /// path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdIntegrationsIdSync(u64),
- /// Route for the `/guilds/:guild_id/invites` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdInvites(u64),
- /// Route for the `/guilds/:guild_id/members` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdMembers(u64),
- /// Route for the `/guilds/:guild_id/members/:user_id` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdMembersId(u64),
- /// Route for the `/guilds/:guild_id/members/:user_id/roles/:role_id` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdMembersIdRolesId(u64),
- /// Route for the `/guilds/:guild_id/members/@me/nick` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdMembersMeNick(u64),
- /// Route for the `/guilds/:guild_id/prune` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdPrune(u64),
- /// Route for the `/guilds/:guild_id/regions` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdRegions(u64),
- /// Route for the `/guilds/:guild_id/roles` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdRoles(u64),
- /// Route for the `/guilds/:guild_id/roles/:role_id` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdRolesId(u64),
- /// Route for the `/guilds/:guild_id/vanity-url` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdVanityUrl(u64),
- /// Route for the `/guilds/:guild_id/webhooks` path.
- ///
- /// The data is the relevant [`GuildId`].
- ///
- /// [`GuildId`]: struct.GuildId.html
- GuildsIdWebhooks(u64),
- /// Route for the `/invites/:code` path.
- InvitesCode,
- /// Route for the `/users/:user_id` path.
- UsersId,
- /// Route for the `/users/@me` path.
- UsersMe,
- /// Route for the `/users/@me/channels` path.
- UsersMeChannels,
- /// Route for the `/users/@me/guilds` path.
- UsersMeGuilds,
- /// Route for the `/users/@me/guilds/:guild_id` path.
- UsersMeGuildsId,
- /// Route for the `/voice/regions` path.
- VoiceRegions,
- /// Route for the `/webhooks/:webhook_id` path.
- WebhooksId(u64),
- /// Route where no ratelimit headers are in place (i.e. user account-only
- /// routes).
- ///
- /// This is a special case, in that if the route is `None` then pre- and
- /// post-hooks are not executed.
- None,
-}
-
-pub(crate) fn perform<'a, F>(route: Route, f: F) -> Result<Response>
- where F: Fn() -> RequestBuilder<'a> {
+pub(super) fn perform(req: Request) -> Result<Response> {
loop {
// This will block if another thread already has the global
// unlocked already (due to receiving an x-ratelimit-global).
let _ = GLOBAL.lock();
+ // Destructure the tuple instead of retrieving the third value to
+ // take advantage of the type system. If `RouteInfo::deconstruct`
+ // returns a different number of tuple elements in the future, directly
+ // accessing a certain index (e.g. `req.route.deconstruct().1`) would
+ // mean this code would not indicate it might need to be updated for the
+ // new tuple element amount.
+ //
+ // This isn't normally important, but might be for ratelimiting.
+ let (_, route, _) = req.route.deconstruct();
+
// Perform pre-checking here:
//
// - get the route's relevant rate
@@ -390,7 +142,7 @@ pub(crate) fn perform<'a, F>(route: Route, f: F) -> Result<Response>
let mut lock = bucket.lock();
lock.pre_hook(&route);
- let response = super::retry(&f)?;
+ let response = super::retry(&req)?;
// Check if an offset has been calculated yet to determine the time
// difference from Discord can the client.
diff --git a/src/http/request.rs b/src/http/request.rs
new file mode 100644
index 0000000..92dd073
--- /dev/null
+++ b/src/http/request.rs
@@ -0,0 +1,116 @@
+use constants;
+use hyper::{
+ client::{Body, RequestBuilder as HyperRequestBuilder},
+ header::{Authorization, ContentType, Headers, UserAgent},
+};
+use super::{
+ CLIENT,
+ TOKEN,
+ routing::RouteInfo,
+};
+
+pub struct RequestBuilder<'a> {
+ body: Option<&'a [u8]>,
+ headers: Option<Headers>,
+ route: RouteInfo<'a>,
+}
+
+impl<'a> RequestBuilder<'a> {
+ pub fn new(route_info: RouteInfo<'a>) -> Self {
+ Self {
+ body: None,
+ headers: None,
+ route: route_info,
+ }
+ }
+
+ pub fn build(self) -> Request<'a> {
+ Request::new(self)
+ }
+
+ pub fn body(&mut self, body: Option<&'a [u8]>) -> &mut Self {
+ self.body = body;
+
+ self
+ }
+
+ pub fn headers(&mut self, headers: Option<Headers>) -> &mut Self {
+ self.headers = headers;
+
+ self
+ }
+
+ pub fn route(&mut self, route_info: RouteInfo<'a>) -> &mut Self {
+ self.route = route_info;
+
+ self
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct Request<'a> {
+ pub(super) body: Option<&'a [u8]>,
+ pub(super) headers: Option<Headers>,
+ pub(super) route: RouteInfo<'a>,
+}
+
+impl<'a> Request<'a> {
+ pub fn new(builder: RequestBuilder<'a>) -> Self {
+ let RequestBuilder { body, headers, route } = builder;
+
+ Self { body, headers, route }
+ }
+
+ pub fn build(&'a self) -> HyperRequestBuilder<'a> {
+ let Request {
+ body,
+ headers: ref request_headers,
+ route: ref route_info,
+ } = *self;
+ let (method, _, path) = route_info.deconstruct();
+
+ let mut builder = CLIENT.request(
+ method.hyper_method(),
+ &path.into_owned(),
+ );
+
+ if let Some(ref bytes) = body {
+ builder = builder.body(Body::BufBody(bytes, bytes.len()));
+ }
+
+ let mut headers = Headers::new();
+ headers.set(UserAgent(constants::USER_AGENT.to_string()));
+ headers.set(Authorization(TOKEN.lock().clone()));
+ headers.set(ContentType::json());
+
+ if let Some(request_headers) = request_headers.clone() {
+ headers.extend(request_headers.iter());
+ }
+
+ builder.headers(headers)
+ }
+
+ pub fn body_ref(&self) -> &Option<&'a [u8]> {
+ &self.body
+ }
+
+ pub fn body_mut(&mut self) -> &mut Option<&'a [u8]> {
+ &mut self.body
+ }
+
+ pub fn headers_ref(&self) -> &Option<Headers> {
+ &self.headers
+ }
+
+ pub fn headers_mut(&mut self) -> &mut Option<Headers> {
+ &mut self.headers
+ }
+
+ pub fn route_ref(&self) -> &RouteInfo {
+ &self.route
+ }
+
+ pub fn route_mut(&mut self) -> &mut RouteInfo<'a> {
+ &mut self.route
+ }
+}
diff --git a/src/http/routing.rs b/src/http/routing.rs
new file mode 100644
index 0000000..dfbbb7f
--- /dev/null
+++ b/src/http/routing.rs
@@ -0,0 +1,1433 @@
+use std::{
+ borrow::Cow,
+ fmt::{Display, Write},
+};
+use super::LightMethod;
+
+/// A representation of all routes registered within the library. These are safe
+/// and memory-efficient representations of each path that functions exist for
+/// in the [`http`] module.
+///
+/// [`http`]: ../index.html
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub enum Route {
+ /// Route for the `/channels/:channel_id` path.
+ ///
+ /// The data is the relevant [`ChannelId`].
+ ///
+ /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
+ ChannelsId(u64),
+ /// Route for the `/channels/:channel_id/invites` path.
+ ///
+ /// The data is the relevant [`ChannelId`].
+ ///
+ /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
+ ChannelsIdInvites(u64),
+ /// Route for the `/channels/:channel_id/messages` path.
+ ///
+ /// The data is the relevant [`ChannelId`].
+ ///
+ /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
+ ChannelsIdMessages(u64),
+ /// Route for the `/channels/:channel_id/messages/bulk-delete` path.
+ ///
+ /// The data is the relevant [`ChannelId`].
+ ///
+ /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
+ ChannelsIdMessagesBulkDelete(u64),
+ /// Route for the `/channels/:channel_id/messages/:message_id` path.
+ ///
+ /// The data is the relevant [`ChannelId`].
+ ///
+ /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
+ // This route is a unique case. The ratelimit for message _deletions_ is
+ // different than the overall route ratelimit.
+ //
+ // Refer to the docs on [Rate Limits] in the yellow warning section.
+ //
+ // Additionally, this needs to be a `LightMethod` from the parent module
+ // and _not_ a `hyper` `Method` due to `hyper`'s not deriving `Copy`.
+ //
+ // [Rate Limits]: https://discordapp.com/developers/docs/topics/rate-limits
+ ChannelsIdMessagesId(LightMethod, u64),
+ /// Route for the `/channels/:channel_id/messages/:message_id/ack` path.
+ ///
+ /// The data is the relevant [`ChannelId`].
+ ///
+ /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
+ ChannelsIdMessagesIdAck(u64),
+ /// Route for the `/channels/:channel_id/messages/:message_id/reactions`
+ /// path.
+ ///
+ /// The data is the relevant [`ChannelId`].
+ ///
+ /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
+ ChannelsIdMessagesIdReactions(u64),
+ /// Route for the
+ /// `/channels/:channel_id/messages/:message_id/reactions/:reaction/@me`
+ /// path.
+ ///
+ /// The data is the relevant [`ChannelId`].
+ ///
+ /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
+ ChannelsIdMessagesIdReactionsUserIdType(u64),
+ /// Route for the `/channels/:channel_id/permissions/:target_id` path.
+ ///
+ /// The data is the relevant [`ChannelId`].
+ ///
+ /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
+ ChannelsIdPermissionsOverwriteId(u64),
+ /// Route for the `/channels/:channel_id/pins` path.
+ ///
+ /// The data is the relevant [`ChannelId`].
+ ///
+ /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
+ ChannelsIdPins(u64),
+ /// Route for the `/channels/:channel_id/pins/:message_id` path.
+ ///
+ /// The data is the relevant [`ChannelId`].
+ ///
+ /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
+ ChannelsIdPinsMessageId(u64),
+ /// Route for the `/channels/:channel_id/typing` path.
+ ///
+ /// The data is the relevant [`ChannelId`].
+ ///
+ /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
+ ChannelsIdTyping(u64),
+ /// Route for the `/channels/:channel_id/webhooks` path.
+ ///
+ /// The data is the relevant [`ChannelId`].
+ ///
+ /// [`ChannelId`]: ../../model/id/struct.ChannelId.html
+ ChannelsIdWebhooks(u64),
+ /// Route for the `/gateway` path.
+ Gateway,
+ /// Route for the `/gateway/bot` path.
+ GatewayBot,
+ /// Route for the `/guilds` path.
+ Guilds,
+ /// Route for the `/guilds/:guild_id` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsId(u64),
+ /// Route for the `/guilds/:guild_id/bans` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdBans(u64),
+ /// Route for the `/guilds/:guild_id/audit-logs` path.
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdAuditLogs(u64),
+ /// Route for the `/guilds/:guild_id/bans/:user_id` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdBansUserId(u64),
+ /// Route for the `/guilds/:guild_id/channels/:channel_id` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdChannels(u64),
+ /// Route for the `/guilds/:guild_id/embed` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdEmbed(u64),
+ /// Route for the `/guilds/:guild_id/emojis` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdEmojis(u64),
+ /// Route for the `/guilds/:guild_id/emojis/:emoji_id` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdEmojisId(u64),
+ /// Route for the `/guilds/:guild_id/integrations` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdIntegrations(u64),
+ /// Route for the `/guilds/:guild_id/integrations/:integration_id` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdIntegrationsId(u64),
+ /// Route for the `/guilds/:guild_id/integrations/:integration_id/sync`
+ /// path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdIntegrationsIdSync(u64),
+ /// Route for the `/guilds/:guild_id/invites` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdInvites(u64),
+ /// Route for the `/guilds/:guild_id/members` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdMembers(u64),
+ /// Route for the `/guilds/:guild_id/members/:user_id` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdMembersId(u64),
+ /// Route for the `/guilds/:guild_id/members/:user_id/roles/:role_id` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdMembersIdRolesId(u64),
+ /// Route for the `/guilds/:guild_id/members/@me/nick` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdMembersMeNick(u64),
+ /// Route for the `/guilds/:guild_id/prune` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdPrune(u64),
+ /// Route for the `/guilds/:guild_id/regions` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdRegions(u64),
+ /// Route for the `/guilds/:guild_id/roles` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdRoles(u64),
+ /// Route for the `/guilds/:guild_id/roles/:role_id` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdRolesId(u64),
+ /// Route for the `/guilds/:guild_id/vanity-url` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdVanityUrl(u64),
+ /// Route for the `/guilds/:guild_id/webhooks` path.
+ ///
+ /// The data is the relevant [`GuildId`].
+ ///
+ /// [`GuildId`]: struct.GuildId.html
+ GuildsIdWebhooks(u64),
+ /// Route for the `/invites/:code` path.
+ InvitesCode,
+ /// Route for the `/users/:user_id` path.
+ UsersId,
+ /// Route for the `/users/@me` path.
+ UsersMe,
+ /// Route for the `/users/@me/channels` path.
+ UsersMeChannels,
+ /// Route for the `/users/@me/guilds` path.
+ UsersMeGuilds,
+ /// Route for the `/users/@me/guilds/:guild_id` path.
+ UsersMeGuildsId,
+ /// Route for the `/voice/regions` path.
+ VoiceRegions,
+ /// Route for the `/webhooks/:webhook_id` path.
+ WebhooksId(u64),
+ /// Route where no ratelimit headers are in place (i.e. user account-only
+ /// routes).
+ ///
+ /// This is a special case, in that if the route is `None` then pre- and
+ /// post-hooks are not executed.
+ None,
+}
+
+impl Route {
+ pub fn channel(channel_id: u64) -> String {
+ format!(api!("/channels/{}"), channel_id)
+ }
+
+ pub fn channel_invites(channel_id: u64) -> String {
+ format!(api!("/channels/{}/invites"), channel_id)
+ }
+
+ pub fn channel_message(channel_id: u64, message_id: u64) -> String {
+ format!(api!("/channels/{}/messages/{}"), channel_id, message_id)
+ }
+
+ pub fn channel_message_reaction<D, T>(
+ channel_id: u64,
+ message_id: u64,
+ user_id: D,
+ reaction_type: T
+ ) -> String where D: Display, T: Display {
+ format!(
+ api!("/channels/{}/messages/{}/reactions/{}/{}"),
+ channel_id,
+ message_id,
+ reaction_type,
+ user_id,
+ )
+ }
+
+ pub fn channel_message_reactions(
+ channel_id: u64,
+ message_id: u64,
+ ) -> String {
+ api!("/channels/{}/messages/{}/reactions", channel_id, message_id)
+ }
+
+ pub fn channel_message_reactions_list(
+ channel_id: u64,
+ message_id: u64,
+ reaction: &str,
+ limit: u8,
+ after: Option<u64>,
+ ) -> String {
+ let mut uri = format!(
+ api!("/channels/{}/messages/{}/reactions/{}?limit={}"),
+ channel_id,
+ message_id,
+ reaction,
+ limit,
+ );
+
+ if let Some(after) = after {
+ let _ = write!(uri, "&after={}", after);
+ }
+
+ uri
+ }
+
+ pub fn channel_messages(channel_id: u64, query: Option<&str>) -> String {
+ format!(
+ api!("/channels/{}/messages{}"),
+ channel_id,
+ query.unwrap_or(""),
+ )
+ }
+
+ pub fn channel_messages_bulk_delete(channel_id: u64) -> String {
+ format!(api!("/channels/{}/messages/bulk-delete"), channel_id)
+ }
+
+ pub fn channel_permission(channel_id: u64, target_id: u64) -> String {
+ format!(api!("/channels/{}/permissions/{}"), channel_id, target_id)
+ }
+
+ pub fn channel_pin(channel_id: u64, message_id: u64) -> String {
+ format!(api!("/channels/{}/pins/{}"), channel_id, message_id)
+ }
+
+ pub fn channel_pins(channel_id: u64) -> String {
+ format!(api!("/channels/{}/pins"), channel_id)
+ }
+
+ pub fn channel_typing(channel_id: u64) -> String {
+ format!(api!("/channels/{}/typing"), channel_id)
+ }
+
+ pub fn channel_webhooks(channel_id: u64) -> String {
+ format!(api!("/channels/{}/webhooks"), channel_id)
+ }
+
+ pub fn gateway() -> &'static str {
+ api!("/gateway")
+ }
+
+ pub fn gateway_bot() -> &'static str {
+ api!("/gateway/bot")
+ }
+
+ pub fn group_recipient(group_id: u64, user_id: u64) -> String {
+ format!(api!("/channels/{}/recipients/{}"), group_id, user_id)
+ }
+
+ pub fn guild(guild_id: u64) -> String {
+ format!(api!("/guilds/{}"), guild_id)
+ }
+
+ pub fn guild_audit_logs(
+ guild_id: u64,
+ action_type: Option<u8>,
+ user_id: Option<u64>,
+ before: Option<u64>,
+ limit: Option<u8>,
+ ) -> String {
+ let mut s = format!(
+ api!("/guilds/{}/audit-logs?"),
+ guild_id,
+ );
+
+ if let Some(action_type) = action_type {
+ let _ = write!(s, "&action_type={}", action_type);
+ }
+
+ if let Some(before) = before {
+ let _ = write!(s, "&before={}", before);
+ }
+
+ if let Some(limit) = limit {
+ let _ = write!(s, "&limit={}", limit);
+ }
+
+ if let Some(user_id) = user_id {
+ let _ = write!(s, "&user_id={}", user_id);
+ }
+
+ s
+ }
+
+ pub fn guild_ban(guild_id: u64, user_id: u64) -> String {
+ format!(api!("/guilds/{}/bans/{}"), guild_id, user_id)
+ }
+
+ pub fn guild_ban_optioned(
+ guild_id: u64,
+ user_id: u64,
+ delete_message_days: u8,
+ reason: &str,
+ ) -> String {
+ format!(
+ api!("/guilds/{}/bans/{}?delete_message_days={}&reason={}"),
+ guild_id,
+ user_id,
+ delete_message_days,
+ reason,
+ )
+ }
+
+ pub fn guild_bans(guild_id: u64) -> String {
+ format!(api!("/guilds/{}/bans"), guild_id)
+ }
+
+ pub fn guild_channels(guild_id: u64) -> String {
+ format!(api!("/guilds/{}/channels"), guild_id)
+ }
+
+ pub fn guild_embed(guild_id: u64) -> String {
+ format!(api!("/guilds/{}/embed"), guild_id)
+ }
+
+ pub fn guild_emojis(guild_id: u64) -> String {
+ format!(api!("/guilds/{}/emojis"), guild_id)
+ }
+
+ pub fn guild_emoji(guild_id: u64, emoji_id: u64) -> String {
+ format!(api!("/guilds/{}/emojis/{}"), guild_id, emoji_id)
+ }
+
+ pub fn guild_integration(
+ guild_id: u64,
+ integration_id: u64,
+ ) -> String {
+ format!(api!("/guilds/{}/integrations/{}"), guild_id, integration_id)
+ }
+
+ pub fn guild_integration_sync(
+ guild_id: u64,
+ integration_id: u64,
+ ) -> String {
+ format!(
+ api!("/guilds/{}/integrations/{}/sync"),
+ guild_id,
+ integration_id,
+ )
+ }
+
+ pub fn guild_integrations(guild_id: u64) -> String {
+ format!(api!("/guilds/{}/integrations"), guild_id)
+ }
+
+ pub fn guild_invites(guild_id: u64) -> String {
+ format!(api!("/guilds/{}/invites"), guild_id)
+ }
+
+ pub fn guild_member(guild_id: u64, user_id: u64) -> String {
+ format!(api!("/guilds/{}/members/{}"), guild_id, user_id)
+ }
+
+ pub fn guild_member_role(
+ guild_id: u64,
+ user_id: u64,
+ role_id: u64,
+ ) -> String {
+ format!(
+ api!("/guilds/{}/members/{}/roles/{}"),
+ guild_id,
+ user_id,
+ role_id,
+ )
+ }
+
+ pub fn guild_members(guild_id: u64) -> String {
+ format!(api!("/guilds/{}/members"), guild_id)
+ }
+
+ pub fn guild_members_optioned(
+ guild_id: u64,
+ after: Option<u64>,
+ limit: Option<u64>,
+ ) -> String {
+ let mut s = format!(api!("/guilds/{}/members?"), guild_id);
+
+ if let Some(after) = after {
+ let _ = write!(s, "&after={}", after);
+ }
+
+ if let Some(limit) = limit {
+ let _ = write!(s, "&limit={}", limit);
+ }
+
+ s
+ }
+
+ pub fn guild_nickname(guild_id: u64) -> String {
+ format!(api!("/guilds/{}/members/@me/nick"), guild_id)
+ }
+
+ pub fn guild_prune(guild_id: u64, days: u64) -> String {
+ format!(api!("/guilds/{}/prune?days={}"), guild_id, days)
+ }
+
+ pub fn guild_regions(guild_id: u64) -> String {
+ format!(api!("/guilds/{}/regions"), guild_id)
+ }
+
+ pub fn guild_role(guild_id: u64, role_id: u64) -> String {
+ format!(api!("/guilds/{}/roles/{}"), guild_id, role_id)
+ }
+
+ pub fn guild_roles(guild_id: u64) -> String {
+ format!(api!("/guilds/{}/roles"), guild_id)
+ }
+
+ pub fn guild_vanity_url(guild_id: u64) -> String {
+ format!(api!("/guilds/{}/vanity-url"), guild_id)
+ }
+
+ pub fn guild_webhooks(guild_id: u64) -> String {
+ format!(api!("/guilds/{}/webhooks"), guild_id)
+ }
+
+ pub fn guilds() -> &'static str {
+ api!("/guilds")
+ }
+
+ pub fn invite(code: &str) -> String {
+ format!(api!("/invites/{}"), code)
+ }
+
+ pub fn invite_optioned(code: &str, stats: bool) -> String {
+ format!(api!("/invites/{}?with_counts={}"), code, stats)
+ }
+
+ pub fn oauth2_application_current() -> &'static str {
+ api!("/oauth2/applications/@me")
+ }
+
+ pub fn private_channel() -> &'static str {
+ api!("/users/@me/channels")
+ }
+
+ pub fn status_incidents_unresolved() -> &'static str {
+ status!("/incidents/unresolved.json")
+ }
+
+ pub fn status_maintenances_active() -> &'static str {
+ status!("/scheduled-maintenances/active.json")
+ }
+
+ pub fn status_maintenances_upcoming() -> &'static str {
+ status!("/scheduled-maintenances/upcoming.json")
+ }
+
+ pub fn user<D: Display>(target: D) -> String {
+ format!(api!("/users/{}"), target)
+ }
+
+ pub fn user_dm_channels<D: Display>(target: D) -> String {
+ format!(api!("/users/{}/channels"), target)
+ }
+
+ pub fn user_guild<D: Display>(target: D, guild_id: u64) -> String {
+ format!(api!("/users/{}/guilds/{}"), target, guild_id)
+ }
+
+ pub fn user_guilds<D: Display>(target: D) -> String {
+ format!(api!("/users/{}/guilds"), target)
+ }
+
+ pub fn user_guilds_optioned<D: Display>(
+ target: D,
+ after: Option<u64>,
+ before: Option<u64>,
+ limit: u64,
+ ) -> String {
+ let mut s = format!(api!("/users/{}/guilds?limit={}&"), target, limit);
+
+ if let Some(after) = after {
+ let _ = write!(s, "&after={}", after);
+ }
+
+ if let Some(before) = before {
+ let _ = write!(s, "&before={}", before);
+ }
+
+ s
+ }
+
+ pub fn voice_regions() -> &'static str {
+ api!("/voice/regions")
+ }
+
+ pub fn webhook(webhook_id: u64) -> String {
+ format!(api!("/webhooks/{}"), webhook_id)
+ }
+
+ pub fn webhook_with_token<D>(webhook_id: u64, token: D) -> String
+ where D: Display {
+ format!(api!("/webhooks/{}/{}"), webhook_id, token)
+ }
+
+ pub fn webhook_with_token_optioned<D>(webhook_id: u64, token: D, wait: bool)
+ -> String where D: Display {
+ format!(api!("/webhooks/{}/{}?wait={}"), webhook_id, token, wait)
+ }
+}
+
+#[derive(Clone, Debug)]
+pub enum RouteInfo<'a> {
+ AddGroupRecipient {
+ group_id: u64,
+ user_id: u64,
+ },
+ AddMemberRole {
+ guild_id: u64,
+ role_id: u64,
+ user_id: u64,
+ },
+ GuildBanUser {
+ guild_id: u64,
+ user_id: u64,
+ delete_message_days: Option<u8>,
+ reason: Option<&'a str>,
+ },
+ BroadcastTyping {
+ channel_id: u64,
+ },
+ CreateChannel {
+ guild_id: u64,
+ },
+ CreateEmoji {
+ guild_id: u64,
+ },
+ CreateGuild,
+ CreateGuildIntegration {
+ guild_id: u64,
+ integration_id: u64,
+ },
+ CreateInvite {
+ channel_id: u64,
+ },
+ CreateMessage {
+ channel_id: u64,
+ },
+ CreatePermission {
+ channel_id: u64,
+ target_id: u64,
+ },
+ CreatePrivateChannel,
+ CreateReaction {
+ channel_id: u64,
+ message_id: u64,
+ reaction: &'a str,
+ },
+ CreateRole {
+ guild_id: u64,
+ },
+ CreateWebhook {
+ channel_id: u64,
+ },
+ DeleteChannel {
+ channel_id: u64,
+ },
+ DeleteEmoji {
+ guild_id: u64,
+ emoji_id: u64,
+ },
+ DeleteGuild {
+ guild_id: u64,
+ },
+ DeleteGuildIntegration {
+ guild_id: u64,
+ integration_id: u64,
+ },
+ DeleteInvite {
+ code: &'a str,
+ },
+ DeleteMessage {
+ channel_id: u64,
+ message_id: u64,
+ },
+ DeleteMessages {
+ channel_id: u64,
+ },
+ DeleteMessageReactions {
+ channel_id: u64,
+ message_id: u64,
+ },
+ DeletePermission {
+ channel_id: u64,
+ target_id: u64,
+ },
+ DeleteReaction {
+ channel_id: u64,
+ message_id: u64,
+ user: &'a str,
+ reaction: &'a str,
+ },
+ DeleteRole {
+ guild_id: u64,
+ role_id: u64,
+ },
+ DeleteWebhook {
+ webhook_id: u64,
+ },
+ DeleteWebhookWithToken {
+ token: &'a str,
+ webhook_id: u64,
+ },
+ EditChannel {
+ channel_id: u64,
+ },
+ EditEmoji {
+ guild_id: u64,
+ emoji_id: u64,
+ },
+ EditGuild {
+ guild_id: u64,
+ },
+ EditGuildChannels {
+ guild_id: u64,
+ },
+ EditGuildEmbed {
+ guild_id: u64,
+ },
+ EditMember {
+ guild_id: u64,
+ user_id: u64,
+ },
+ EditMessage {
+ channel_id: u64,
+ message_id: u64,
+ },
+ EditNickname {
+ guild_id: u64,
+ },
+ EditProfile,
+ EditRole {
+ guild_id: u64,
+ role_id: u64,
+ },
+ EditWebhook {
+ webhook_id: u64,
+ },
+ EditWebhookWithToken {
+ token: &'a str,
+ webhook_id: u64,
+ },
+ ExecuteWebhook {
+ token: &'a str,
+ wait: bool,
+ webhook_id: u64,
+ },
+ GetActiveMaintenance,
+ GetAuditLogs {
+ action_type: Option<u8>,
+ before: Option<u64>,
+ guild_id: u64,
+ limit: Option<u8>,
+ user_id: Option<u64>,
+ },
+ GetBans {
+ guild_id: u64,
+ },
+ GetBotGateway,
+ GetChannel {
+ channel_id: u64,
+ },
+ GetChannelInvites {
+ channel_id: u64,
+ },
+ GetChannelWebhooks {
+ channel_id: u64,
+ },
+ GetChannels {
+ guild_id: u64,
+ },
+ GetCurrentApplicationInfo,
+ GetCurrentUser,
+ GetGateway,
+ GetGuild {
+ guild_id: u64,
+ },
+ GetGuildEmbed {
+ guild_id: u64,
+ },
+ GetGuildIntegrations {
+ guild_id: u64,
+ },
+ GetGuildInvites {
+ guild_id: u64,
+ },
+ GetGuildMembers {
+ after: Option<u64>,
+ limit: Option<u64>,
+ guild_id: u64,
+ },
+ GetGuildPruneCount {
+ days: u64,
+ guild_id: u64,
+ },
+ GetGuildRegions {
+ guild_id: u64,
+ },
+ GetGuildRoles {
+ guild_id: u64,
+ },
+ GetGuildVanityUrl {
+ guild_id: u64,
+ },
+ GetGuildWebhooks {
+ guild_id: u64,
+ },
+ GetGuilds {
+ after: Option<u64>,
+ before: Option<u64>,
+ limit: u64,
+ },
+ GetInvite {
+ code: &'a str,
+ stats: bool,
+ },
+ GetMember {
+ guild_id: u64,
+ user_id: u64,
+ },
+ GetMessage {
+ channel_id: u64,
+ message_id: u64,
+ },
+ GetMessages {
+ channel_id: u64,
+ query: String,
+ },
+ GetPins {
+ channel_id: u64,
+ },
+ GetReactionUsers {
+ after: Option<u64>,
+ channel_id: u64,
+ limit: u8,
+ message_id: u64,
+ reaction: String,
+ },
+ GetUnresolvedIncidents,
+ GetUpcomingMaintenances,
+ GetUser {
+ user_id: u64,
+ },
+ GetUserDmChannels,
+ GetVoiceRegions,
+ GetWebhook {
+ webhook_id: u64,
+ },
+ GetWebhookWithToken {
+ token: &'a str,
+ webhook_id: u64,
+ },
+ KickMember {
+ guild_id: u64,
+ user_id: u64,
+ },
+ LeaveGroup {
+ group_id: u64,
+ },
+ LeaveGuild {
+ guild_id: u64,
+ },
+ RemoveGroupRecipient {
+ group_id: u64,
+ user_id: u64,
+ },
+ PinMessage {
+ channel_id: u64,
+ message_id: u64,
+ },
+ RemoveBan {
+ guild_id: u64,
+ user_id: u64,
+ },
+ RemoveMemberRole {
+ guild_id: u64,
+ role_id: u64,
+ user_id: u64,
+ },
+ StartGuildPrune {
+ days: u64,
+ guild_id: u64,
+ },
+ StartIntegrationSync {
+ guild_id: u64,
+ integration_id: u64,
+ },
+ StatusIncidentsUnresolved,
+ StatusMaintenancesActive,
+ StatusMaintenancesUpcoming,
+ UnpinMessage {
+ channel_id: u64,
+ message_id: u64,
+ },
+}
+
+impl<'a> RouteInfo<'a> {
+ pub fn deconstruct(&self) -> (LightMethod, Route, Cow<str>) {
+ match *self {
+ RouteInfo::AddGroupRecipient { group_id, user_id } => (
+ LightMethod::Post,
+ Route::None,
+ Cow::from(Route::group_recipient(group_id, user_id)),
+ ),
+ RouteInfo::AddMemberRole { guild_id, role_id, user_id } => (
+ LightMethod::Delete,
+ Route::GuildsIdMembersIdRolesId(guild_id),
+ Cow::from(Route::guild_member_role(guild_id, user_id, role_id)),
+ ),
+ RouteInfo::GuildBanUser {
+ guild_id,
+ delete_message_days,
+ reason,
+ user_id,
+ } => (
+ // TODO
+ LightMethod::Delete,
+ Route::GuildsIdBansUserId(guild_id),
+ Cow::from(Route::guild_ban_optioned(
+ guild_id,
+ user_id,
+ delete_message_days.unwrap_or(0),
+ reason.unwrap_or(""),
+ )),
+ ),
+ RouteInfo::BroadcastTyping { channel_id } => (
+ LightMethod::Post,
+ Route::ChannelsIdTyping(channel_id),
+ Cow::from(Route::channel_typing(channel_id)),
+ ),
+ RouteInfo::CreateChannel { guild_id } => (
+ LightMethod::Post,
+ Route::GuildsIdChannels(guild_id),
+ Cow::from(Route::guild_channels(guild_id)),
+ ),
+ RouteInfo::CreateEmoji { guild_id } => (
+ LightMethod::Post,
+ Route::GuildsIdEmojis(guild_id),
+ Cow::from(Route::guild_emojis(guild_id)),
+ ),
+ RouteInfo::CreateGuild => (
+ LightMethod::Post,
+ Route::Guilds,
+ Cow::from(Route::guilds()),
+ ),
+ RouteInfo::CreateGuildIntegration { guild_id, integration_id } => (
+ LightMethod::Post,
+ Route::GuildsIdIntegrationsId(guild_id),
+ Cow::from(Route::guild_integration(guild_id, integration_id)),
+ ),
+ RouteInfo::CreateInvite { channel_id } => (
+ LightMethod::Post,
+ Route::ChannelsIdInvites(channel_id),
+ Cow::from(Route::channel_invites(channel_id)),
+ ),
+ RouteInfo::CreateMessage { channel_id } => (
+ LightMethod::Post,
+ Route::ChannelsIdMessages(channel_id),
+ Cow::from(Route::channel_messages(channel_id, None)),
+ ),
+ RouteInfo::CreatePermission { channel_id, target_id } => (
+ LightMethod::Post,
+ Route::ChannelsIdPermissionsOverwriteId(channel_id),
+ Cow::from(Route::channel_permission(channel_id, target_id)),
+ ),
+ RouteInfo::CreatePrivateChannel => (
+ LightMethod::Post,
+ Route::UsersMeChannels,
+ Cow::from(Route::user_dm_channels("@me")),
+ ),
+ RouteInfo::CreateReaction { channel_id, message_id, reaction } => (
+ LightMethod::Put,
+ Route::ChannelsIdMessagesIdReactionsUserIdType(channel_id),
+ Cow::from(Route::channel_message_reaction(
+ channel_id,
+ message_id,
+ "@me",
+ reaction,
+ )),
+ ),
+ RouteInfo::CreateRole { guild_id } => (
+ LightMethod::Delete,
+ Route::GuildsIdRoles(guild_id),
+ Cow::from(Route::guild_roles(guild_id)),
+ ),
+ RouteInfo::CreateWebhook { channel_id } => (
+ LightMethod::Delete,
+ Route::ChannelsIdWebhooks(channel_id),
+ Cow::from(Route::channel_webhooks(channel_id)),
+ ),
+ RouteInfo::DeleteChannel { channel_id } => (
+ LightMethod::Delete,
+ Route::ChannelsId(channel_id),
+ Cow::from(Route::channel(channel_id)),
+ ),
+ RouteInfo::DeleteEmoji { emoji_id, guild_id } => (
+ LightMethod::Delete,
+ Route::GuildsIdEmojisId(guild_id),
+ Cow::from(Route::guild_emoji(guild_id, emoji_id)),
+ ),
+ RouteInfo::DeleteGuild { guild_id } => (
+ LightMethod::Delete,
+ Route::GuildsId(guild_id),
+ Cow::from(Route::guild(guild_id)),
+ ),
+ RouteInfo::DeleteGuildIntegration { guild_id, integration_id } => (
+ LightMethod::Delete,
+ Route::GuildsIdIntegrationsId(guild_id),
+ Cow::from(Route::guild_integration(guild_id, integration_id)),
+ ),
+ RouteInfo::DeleteInvite { code } => (
+ LightMethod::Delete,
+ Route::InvitesCode,
+ Cow::from(Route::invite(code)),
+ ),
+ RouteInfo::DeleteMessageReactions { channel_id, message_id } => (
+ LightMethod::Delete,
+ Route::ChannelsIdMessagesIdReactions(channel_id),
+ Cow::from(Route::channel_message_reactions(
+ channel_id,
+ message_id,
+ )),
+ ),
+ RouteInfo::DeleteMessage { channel_id, message_id } => (
+ LightMethod::Delete,
+ Route::ChannelsIdMessagesId(LightMethod::Delete, message_id),
+ Cow::from(Route::channel_message(channel_id, message_id)),
+ ),
+ RouteInfo::DeleteMessages { channel_id } => (
+ LightMethod::Delete,
+ Route::ChannelsIdMessagesBulkDelete(channel_id),
+ Cow::from(Route::channel_messages_bulk_delete(channel_id)),
+ ),
+ RouteInfo::DeletePermission { channel_id, target_id } => (
+ LightMethod::Delete,
+ Route::ChannelsIdPermissionsOverwriteId(channel_id),
+ Cow::from(Route::channel_permission(channel_id, target_id)),
+ ),
+ RouteInfo::DeleteReaction {
+ channel_id,
+ message_id,
+ reaction,
+ user,
+ } => (
+ LightMethod::Delete,
+ Route::ChannelsIdMessagesIdReactionsUserIdType(channel_id),
+ Cow::from(Route::channel_message_reaction(
+ channel_id,
+ message_id,
+ user,
+ reaction,
+ ))
+ ),
+ RouteInfo::DeleteRole { guild_id, role_id } => (
+ LightMethod::Delete,
+ Route::GuildsIdRolesId(guild_id),
+ Cow::from(Route::guild_role(guild_id, role_id)),
+ ),
+ RouteInfo::DeleteWebhook { webhook_id } => (
+ LightMethod::Delete,
+ Route::WebhooksId(webhook_id),
+ Cow::from(Route::webhook(webhook_id)),
+ ),
+ RouteInfo::DeleteWebhookWithToken { token, webhook_id } => (
+ LightMethod::Delete,
+ Route::WebhooksId(webhook_id),
+ Cow::from(Route::webhook_with_token(webhook_id, token)),
+ ),
+ RouteInfo::EditChannel { channel_id } => (
+ LightMethod::Patch,
+ Route::ChannelsId(channel_id),
+ Cow::from(Route::channel(channel_id)),
+ ),
+ RouteInfo::EditEmoji { emoji_id, guild_id } => (
+ LightMethod::Patch,
+ Route::GuildsIdEmojisId(guild_id),
+ Cow::from(Route::guild_emoji(guild_id, emoji_id)),
+ ),
+ RouteInfo::EditGuild { guild_id } => (
+ LightMethod::Patch,
+ Route::GuildsId(guild_id),
+ Cow::from(Route::guild(guild_id)),
+ ),
+ RouteInfo::EditGuildChannels { guild_id } => (
+ LightMethod::Patch,
+ Route::GuildsIdChannels(guild_id),
+ Cow::from(Route::guild_channels(guild_id)),
+ ),
+ RouteInfo::EditGuildEmbed { guild_id } => (
+ LightMethod::Patch,
+ Route::GuildsIdEmbed(guild_id),
+ Cow::from(Route::guild_embed(guild_id)),
+ ),
+ RouteInfo::EditMember { guild_id, user_id } => (
+ LightMethod::Patch,
+ Route::GuildsIdMembersId(guild_id),
+ Cow::from(Route::guild_member(guild_id, user_id)),
+ ),
+ RouteInfo::EditMessage { channel_id, message_id } => (
+ LightMethod::Patch,
+ Route::ChannelsIdMessagesId(LightMethod::Patch, channel_id),
+ Cow::from(Route::channel_message(channel_id, message_id)),
+ ),
+ RouteInfo::EditNickname { guild_id } => (
+ LightMethod::Patch,
+ Route::GuildsIdMembersMeNick(guild_id),
+ Cow::from(Route::guild_nickname(guild_id)),
+ ),
+ RouteInfo::EditProfile => (
+ LightMethod::Patch,
+ Route::UsersMe,
+ Cow::from(Route::user("@me")),
+ ),
+ RouteInfo::EditRole { guild_id, role_id } => (
+ LightMethod::Patch,
+ Route::GuildsIdRolesId(guild_id),
+ Cow::from(Route::guild_role(guild_id, role_id)),
+ ),
+ RouteInfo::EditWebhook { webhook_id } => (
+ LightMethod::Patch,
+ Route::WebhooksId(webhook_id),
+ Cow::from(Route::webhook(webhook_id)),
+ ),
+ RouteInfo::EditWebhookWithToken { token, webhook_id } => (
+ LightMethod::Patch,
+ Route::WebhooksId(webhook_id),
+ Cow::from(Route::webhook_with_token(webhook_id, token)),
+ ),
+ RouteInfo::ExecuteWebhook { token, wait, webhook_id } => (
+ LightMethod::Post,
+ Route::WebhooksId(webhook_id),
+ Cow::from(Route::webhook_with_token_optioned(
+ webhook_id,
+ token,
+ wait,
+ )),
+ ),
+ RouteInfo::GetActiveMaintenance => (
+ LightMethod::Get,
+ Route::None,
+ Cow::from(Route::status_maintenances_active()),
+ ),
+ RouteInfo::GetAuditLogs {
+ action_type,
+ before,
+ guild_id,
+ limit,
+ user_id,
+ } => (
+ LightMethod::Get,
+ Route::GuildsIdAuditLogs(guild_id),
+ Cow::from(Route::guild_audit_logs(
+ guild_id,
+ action_type,
+ user_id,
+ before,
+ limit,
+ )),
+ ),
+ RouteInfo::GetBans { guild_id } => (
+ LightMethod::Get,
+ Route::GuildsIdBans(guild_id),
+ Cow::from(Route::guild_bans(guild_id)),
+ ),
+ RouteInfo::GetBotGateway => (
+ LightMethod::Get,
+ Route::GatewayBot,
+ Cow::from(Route::gateway_bot()),
+ ),
+ RouteInfo::GetChannel { channel_id } => (
+ LightMethod::Get,
+ Route::ChannelsId(channel_id),
+ Cow::from(Route::channel(channel_id)),
+ ),
+ RouteInfo::GetChannelInvites { channel_id } => (
+ LightMethod::Get,
+ Route::ChannelsIdInvites(channel_id),
+ Cow::from(Route::channel_invites(channel_id)),
+ ),
+ RouteInfo::GetChannelWebhooks { channel_id } => (
+ LightMethod::Get,
+ Route::ChannelsIdWebhooks(channel_id),
+ Cow::from(Route::channel_webhooks(channel_id)),
+ ),
+ RouteInfo::GetChannels { guild_id } => (
+ LightMethod::Get,
+ Route::GuildsIdChannels(guild_id),
+ Cow::from(Route::guild_channels(guild_id)),
+ ),
+ RouteInfo::GetCurrentApplicationInfo => (
+ LightMethod::Get,
+ Route::None,
+ Cow::from(Route::oauth2_application_current()),
+ ),
+ RouteInfo::GetCurrentUser => (
+ LightMethod::Get,
+ Route::UsersMe,
+ Cow::from(Route::user("@me")),
+ ),
+ RouteInfo::GetGateway => (
+ LightMethod::Get,
+ Route::Gateway,
+ Cow::from(Route::gateway()),
+ ),
+ RouteInfo::GetGuild { guild_id } => (
+ LightMethod::Get,
+ Route::GuildsId(guild_id),
+ Cow::from(Route::guild(guild_id)),
+ ),
+ RouteInfo::GetGuildEmbed { guild_id } => (
+ LightMethod::Get,
+ Route::GuildsIdEmbed(guild_id),
+ Cow::from(Route::guild_embed(guild_id)),
+ ),
+ RouteInfo::GetGuildIntegrations { guild_id } => (
+ LightMethod::Get,
+ Route::GuildsIdIntegrations(guild_id),
+ Cow::from(Route::guild_integrations(guild_id)),
+ ),
+ RouteInfo::GetGuildInvites { guild_id } => (
+ LightMethod::Get,
+ Route::GuildsIdInvites(guild_id),
+ Cow::from(Route::guild_invites(guild_id)),
+ ),
+ RouteInfo::GetGuildMembers { after, guild_id, limit } => (
+ LightMethod::Get,
+ Route::GuildsIdMembers(guild_id),
+ Cow::from(Route::guild_members_optioned(guild_id, after, limit)),
+ ),
+ RouteInfo::GetGuildPruneCount { days, guild_id } => (
+ LightMethod::Get,
+ Route::GuildsIdPrune(guild_id),
+ Cow::from(Route::guild_prune(guild_id, days)),
+ ),
+ RouteInfo::GetGuildRegions { guild_id } => (
+ LightMethod::Get,
+ Route::GuildsIdRegions(guild_id),
+ Cow::from(Route::guild_regions(guild_id)),
+ ),
+ RouteInfo::GetGuildRoles { guild_id } => (
+ LightMethod::Get,
+ Route::GuildsIdRoles(guild_id),
+ Cow::from(Route::guild_roles(guild_id)),
+ ),
+ RouteInfo::GetGuildVanityUrl { guild_id } => (
+ LightMethod::Get,
+ Route::GuildsIdVanityUrl(guild_id),
+ Cow::from(Route::guild_vanity_url(guild_id)),
+ ),
+ RouteInfo::GetGuildWebhooks { guild_id } => (
+ LightMethod::Get,
+ Route::GuildsIdWebhooks(guild_id),
+ Cow::from(Route::guild_webhooks(guild_id)),
+ ),
+ RouteInfo::GetGuilds { after, before, limit } => (
+ LightMethod::Get,
+ Route::UsersMeGuilds,
+ Cow::from(Route::user_guilds_optioned(
+ "@me",
+ after,
+ before,
+ limit,
+ )),
+ ),
+ RouteInfo::GetInvite { code, stats } => (
+ LightMethod::Get,
+ Route::InvitesCode,
+ Cow::from(Route::invite_optioned(code, stats)),
+ ),
+ RouteInfo::GetMember { guild_id, user_id } => (
+ LightMethod::Get,
+ Route::GuildsIdMembersId(guild_id),
+ Cow::from(Route::guild_member(guild_id, user_id)),
+ ),
+ RouteInfo::GetMessage { channel_id, message_id } => (
+ LightMethod::Get,
+ Route::ChannelsIdMessagesId(LightMethod::Get, channel_id),
+ Cow::from(Route::channel_message(channel_id, message_id)),
+ ),
+ RouteInfo::GetMessages { channel_id, ref query } => (
+ LightMethod::Get,
+ Route::ChannelsIdMessages(channel_id),
+ Cow::from(Route::channel_messages(
+ channel_id,
+ Some(query.as_ref()),
+ )),
+ ),
+ RouteInfo::GetPins { channel_id } => (
+ LightMethod::Get,
+ Route::ChannelsIdPins(channel_id),
+ Cow::from(Route::channel_pins(channel_id)),
+ ),
+ RouteInfo::GetReactionUsers {
+ after,
+ channel_id,
+ limit,
+ message_id,
+ ref reaction,
+ } => (
+ LightMethod::Get,
+ Route::ChannelsIdMessagesIdReactions(channel_id),
+ Cow::from(Route::channel_message_reactions_list(
+ channel_id,
+ message_id,
+ reaction,
+ limit,
+ after,
+ )),
+ ),
+ RouteInfo::GetUnresolvedIncidents => (
+ LightMethod::Get,
+ Route::None,
+ Cow::from(Route::status_incidents_unresolved()),
+ ),
+ RouteInfo::GetUpcomingMaintenances => (
+ LightMethod::Get,
+ Route::None,
+ Cow::from(Route::status_maintenances_upcoming()),
+ ),
+ RouteInfo::GetUser { user_id } => (
+ LightMethod::Get,
+ Route::UsersId,
+ Cow::from(Route::user(user_id)),
+ ),
+ RouteInfo::GetUserDmChannels => (
+ LightMethod::Get,
+ Route::UsersMeChannels,
+ Cow::from(Route::user_dm_channels("@me")),
+ ),
+ RouteInfo::GetVoiceRegions => (
+ LightMethod::Get,
+ Route::VoiceRegions,
+ Cow::from(Route::voice_regions()),
+ ),
+ RouteInfo::GetWebhook { webhook_id } => (
+ LightMethod::Get,
+ Route::WebhooksId(webhook_id),
+ Cow::from(Route::webhook(webhook_id)),
+ ),
+ RouteInfo::GetWebhookWithToken { token, webhook_id } => (
+ LightMethod::Get,
+ Route::WebhooksId(webhook_id),
+ Cow::from(Route::webhook_with_token(webhook_id, token)),
+ ),
+ RouteInfo::KickMember { guild_id, user_id } => (
+ LightMethod::Delete,
+ Route::GuildsIdMembersId(guild_id),
+ Cow::from(Route::guild_member(guild_id, user_id)),
+ ),
+ RouteInfo::LeaveGroup { group_id } => (
+ LightMethod::Delete,
+ Route::ChannelsId(group_id),
+ Cow::from(Route::channel(group_id)),
+ ),
+ RouteInfo::LeaveGuild { guild_id } => (
+ LightMethod::Delete,
+ Route::UsersMeGuildsId,
+ Cow::from(Route::user_guild("@me", guild_id)),
+ ),
+ RouteInfo::RemoveGroupRecipient { group_id, user_id } => (
+ LightMethod::Delete,
+ Route::None,
+ Cow::from(Route::group_recipient(group_id, user_id)),
+ ),
+ RouteInfo::PinMessage { channel_id, message_id } => (
+ LightMethod::Put,
+ Route::ChannelsIdPins(channel_id),
+ Cow::from(Route::channel_pin(channel_id, message_id)),
+ ),
+ RouteInfo::RemoveBan { guild_id, user_id } => (
+ LightMethod::Delete,
+ Route::GuildsIdBansUserId(guild_id),
+ Cow::from(Route::guild_ban(guild_id, user_id)),
+ ),
+ RouteInfo::RemoveMemberRole { guild_id, role_id, user_id } => (
+ LightMethod::Delete,
+ Route::GuildsIdMembersIdRolesId(guild_id),
+ Cow::from(Route::guild_member_role(guild_id, user_id, role_id)),
+ ),
+ RouteInfo::StartGuildPrune { days, guild_id } => (
+ LightMethod::Post,
+ Route::GuildsIdPrune(guild_id),
+ Cow::from(Route::guild_prune(guild_id, days)),
+ ),
+ RouteInfo::StartIntegrationSync { guild_id, integration_id } => (
+ LightMethod::Post,
+ Route::GuildsIdIntegrationsId(guild_id),
+ Cow::from(Route::guild_integration_sync(
+ guild_id,
+ integration_id,
+ )),
+ ),
+ RouteInfo::StatusIncidentsUnresolved => (
+ LightMethod::Get,
+ Route::None,
+ Cow::from(Route::status_incidents_unresolved()),
+ ),
+ RouteInfo::StatusMaintenancesActive => (
+ LightMethod::Get,
+ Route::None,
+ Cow::from(Route::status_maintenances_active()),
+ ),
+ RouteInfo::StatusMaintenancesUpcoming => (
+ LightMethod::Get,
+ Route::None,
+ Cow::from(Route::status_maintenances_upcoming()),
+ ),
+ RouteInfo::UnpinMessage { channel_id, message_id } => (
+ LightMethod::Delete,
+ Route::ChannelsIdPinsMessageId(channel_id),
+ Cow::from(Route::channel_pin(channel_id, message_id)),
+ ),
+ }
+ }
+}
diff --git a/src/internal/macros.rs b/src/internal/macros.rs
index c4d2b6f..31b6b7d 100644
--- a/src/internal/macros.rs
+++ b/src/internal/macros.rs
@@ -1,36 +1,6 @@
//! A set of macros for easily working with internals.
#[cfg(feature = "http")]
-macro_rules! request {
- ($route:expr, $method:ident($body:expr), $url:expr, $($rest:tt)*) => {{
- let client = request_client!();
-
- request($route, || client
- .$method(&format!(api!($url), $($rest)*))
- .body(&$body))?
- }};
- ($route:expr, $method:ident($body:expr), $url:expr) => {{
- let client = request_client!();
-
- request($route, || client
- .$method(api!($url))
- .body(&$body))?
- }};
- ($route:expr, $method:ident, $url:expr, $($rest:tt)*) => {{
- let client = request_client!();
-
- request($route, || client
- .$method(&format!(api!($url), $($rest)*)))?
- }};
- ($route:expr, $method:ident, $url:expr) => {{
- let client = request_client!();
-
- request($route, || client
- .$method(api!($url)))?
- }};
-}
-
-#[cfg(feature = "http")]
macro_rules! request_client {
() => {{
use hyper::net::HttpsConnector;
diff --git a/src/model/gateway.rs b/src/model/gateway.rs
index 9af4a7e..989cff8 100644
--- a/src/model/gateway.rs
+++ b/src/model/gateway.rs
@@ -133,13 +133,21 @@ impl Game {
impl<'a> From<&'a str> for Game {
fn from(name: &'a str) -> Self {
- Game::playing(name)
+ Game {
+ kind: GameType::Playing,
+ name: name.to_owned(),
+ url: None,
+ }
}
}
impl From<String> for Game {
fn from(name: String) -> Self {
- Game::playing(&name)
+ Game {
+ kind: GameType::Playing,
+ url: None,
+ name,
+ }
}
}