aboutsummaryrefslogtreecommitdiff
path: root/src/http
diff options
context:
space:
mode:
authorZeyla Hellyer <[email protected]>2018-08-04 21:30:08 -0700
committerZeyla Hellyer <[email protected]>2018-08-04 21:30:08 -0700
commita0b0dd226f9ad2476729fa79dbc680bd08aa44b3 (patch)
treeac4b45b1c629c8149e74dfdf762f1543cefb9321 /src/http
parentMaintain a single, re-used HTTP client (diff)
downloadserenity-a0b0dd226f9ad2476729fa79dbc680bd08aa44b3.tar.xz
serenity-a0b0dd226f9ad2476729fa79dbc680bd08aa44b3.zip
Redo how requests are formed in HTTP module
Instead of passing around a function that builds an HTTP client request builder, pass around a struct that contains the necessary information _to_ build that request builder. Additionally, instead of using a macro to generate requests, just call a request function. This saves some required code expansion and is just easier to read and maintain.
Diffstat (limited to 'src/http')
-rw-r--r--src/http/mod.rs1263
-rw-r--r--src/http/ratelimiting.rs19
2 files changed, 688 insertions, 594 deletions
diff --git a/src/http/mod.rs b/src/http/mod.rs
index 05b198a..9151cfd 100644
--- a/src/http/mod.rs
+++ b/src/http/mod.rs
@@ -33,12 +33,13 @@ pub use hyper::status::{StatusClass, StatusCode};
use constants;
use hyper::{
client::{
+ Body as HyperBody,
Client as HyperClient,
- Request,
RequestBuilder,
+ Request as HyperRequest,
Response as HyperResponse
},
- header::ContentType,
+ header::{ContentType, Headers},
method::Method,
mime::{Mime, SubLevel, TopLevel},
net::HttpsConnector,
@@ -73,6 +74,14 @@ lazy_static! {
};
}
+struct Request {
+ body: Option<Vec<u8>>,
+ headers: Option<Headers>,
+ method: Method,
+ route: Route,
+ url: String,
+}
+
/// An method used for ratelimiting special routes.
///
/// This is needed because `hyper`'s `Method` enum does not derive Copy.
@@ -130,16 +139,13 @@ 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
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Put,
+ route: Route::None,
+ url: api!("/channels/{}/recipients/{}", group_id, user_id),
+ })?)
}
/// Adds a single [`Role`] to a [`Member`] in a [`Guild`].
@@ -152,17 +158,13 @@ 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
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Put,
+ route: Route::GuildsIdMembersIdRolesId(guild_id),
+ url: api!("/guilds/{}/members/{}/roles/{}", guild_id, user_id, role_id),
+ })?)
}
/// Bans a [`User`] from a [`Guild`], removing their messages sent in the last
@@ -177,18 +179,19 @@ 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,
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Put,
+ route: Route::GuildsIdBansUserId(guild_id),
+ url: api!(
"/guilds/{}/bans/{}?delete_message_days={}&reason={}",
guild_id,
user_id,
delete_message_days,
- reason
+ reason,
),
- )
+ })?)
}
/// Ban zeyla from a [`Guild`], removing her messages sent in the last X number
@@ -244,15 +247,13 @@ 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
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Post,
+ route: Route::ChannelsIdTyping(channel_id),
+ url: api!("/channels/{}/typing", channel_id),
+ })?)
}
/// Creates a [`GuildChannel`] in the [`Guild`] given its Id.
@@ -266,13 +267,13 @@ 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
- );
+ let response = request(Request {
+ body: Some(map.to_string().into_bytes()),
+ headers: None,
+ method: Method::Post,
+ route: Route::GuildsIdChannels(guild_id),
+ url: api!("/guilds/{}/channels", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, GuildChannel>(response)
.map_err(From::from)
@@ -289,13 +290,13 @@ 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
- );
+ let response = request(Request {
+ body: Some(map.to_string().into_bytes()),
+ headers: None,
+ method: Method::Post,
+ route: Route::GuildsIdEmojis(guild_id),
+ url: api!("/guilds/{}/emojis", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, Emoji>(response)
.map_err(From::from)
@@ -338,8 +339,13 @@ 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");
+ let response = request(Request {
+ body: Some(map.to_string().into_bytes()),
+ headers: None,
+ method: Method::Post,
+ route: Route::Guilds,
+ url: api!("/guilds").to_owned(),
+ })?;
serde_json::from_reader::<HyperResponse, PartialGuild>(response)
.map_err(From::from)
@@ -356,18 +362,13 @@ 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
- ),
- )
+ verify(204, request(Request {
+ body: Some(map.to_string().into_bytes()),
+ headers: None,
+ method: Method::Post,
+ route: Route::GuildsIdIntegrations(guild_id),
+ url: api!("/guilds/{}/integrations/{}", guild_id, integration_id),
+ })?)
}
/// Creates a [`RichInvite`] for the given [channel][`GuildChannel`].
@@ -383,13 +384,15 @@ 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
- );
+ let body = serde_json::to_vec(map)?;
+
+ let response = request(Request {
+ body: Some(body),
+ headers: None,
+ method: Method::Post,
+ route: Route::ChannelsIdInvites(channel_id),
+ url: api!("/channels/{}/invites", channel_id),
+ })?;
serde_json::from_reader::<HyperResponse, RichInvite>(response)
.map_err(From::from)
@@ -397,24 +400,24 @@ pub fn create_invite(channel_id: u64, map: &JsonMap) -> Result<RichInvite> {
/// 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
- ),
- )
+ verify(204, request(Request {
+ body: Some(map.to_string().into_bytes()),
+ headers: None,
+ method: Method::Put,
+ route: Route::ChannelsIdPermissionsOverwriteId(channel_id),
+ url: api!("/channels/{}/permissions/{}", 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 response = request(Request {
+ body: Some(map.to_string().into_bytes()),
+ headers: None,
+ method: Method::Post,
+ route: Route::UsersMeChannels,
+ url: api!("/users/@me/channels").to_owned(),
+ })?;
serde_json::from_reader::<HyperResponse, PrivateChannel>(response)
.map_err(From::from)
@@ -425,28 +428,31 @@ pub fn create_reaction(channel_id: u64,
message_id: u64,
reaction_type: &ReactionType)
-> Result<()> {
- verify(
- 204,
- request!(
- Route::ChannelsIdMessagesIdReactionsUserIdType(channel_id),
- put,
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Put,
+ route: Route::ChannelsIdMessagesIdReactionsUserIdType(channel_id),
+ url: api!(
"/channels/{}/messages/{}/reactions/{}/@me",
channel_id,
message_id,
- reaction_type.as_data()
+ 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
- );
+ let body = serde_json::to_vec(map)?;
+
+ let response = request(Request {
+ body: Some(body),
+ headers: None,
+ method: Method::Post,
+ route: Route::GuildsIdRoles(guild_id),
+ url: api!("/guilds/{}/roles", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, Role>(response)
.map_err(From::from)
@@ -483,13 +489,13 @@ 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
- );
+ let response = request(Request {
+ body: Some(map.to_string().into_bytes()),
+ headers: None,
+ method: Method::Post,
+ route: Route::ChannelsIdWebhooks(channel_id),
+ url: api!("/channels/{}/webhooks", channel_id),
+ })?;
serde_json::from_reader::<HyperResponse, Webhook>(response)
.map_err(From::from)
@@ -497,12 +503,13 @@ pub fn create_webhook(channel_id: u64, map: &Value) -> Result<Webhook> {
/// 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
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ route: Route::ChannelsId(channel_id),
+ method: Method::Delete,
+ url: api!("/channels/{}", channel_id),
+ })?;
serde_json::from_reader::<HyperResponse, Channel>(response)
.map_err(From::from)
@@ -510,21 +517,24 @@ pub fn delete_channel(channel_id: u64) -> Result<Channel> {
/// 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
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::GuildsIdEmojisId(guild_id),
+ url: api!("/guilds/{}/emojis/{}", 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);
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::GuildsId(guild_id),
+ url: api!("/guilds/{}", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, PartialGuild>(response)
.map_err(From::from)
@@ -532,21 +542,24 @@ pub fn delete_guild(guild_id: u64) -> Result<PartialGuild> {
/// 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
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::GuildsIdIntegrationsId(guild_id),
+ url: api!("/guilds/{}/integrations/{}", 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);
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::InvitesCode,
+ url: api!("/invites/{}", code),
+ })?;
serde_json::from_reader::<HyperResponse, Invite>(response)
.map_err(From::from)
@@ -555,31 +568,24 @@ pub fn delete_invite(code: &str) -> Result<Invite> {
/// 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
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::ChannelsIdMessagesId(LightMethod::Delete, channel_id),
+ url: api!("/channels/{}/messages/{}", 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
- ),
- )
+ verify(204, request(Request {
+ body: Some(map.to_string().into_bytes()),
+ headers: None,
+ method: Method::Delete,
+ route: Route::ChannelsIdMessagesBulkDelete(channel_id),
+ url: api!("/channels/{}/messages/bulk-delete", channel_id),
+ })?)
}
/// Deletes all of the [`Reaction`]s associated with a [`Message`].
@@ -600,30 +606,24 @@ 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
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::ChannelsIdMessagesIdReactions(channel_id),
+ url: api!("/channels/{}/messages/{}/reactions", 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
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::ChannelsIdPermissionsOverwriteId(channel_id),
+ url: api!("/channels/{}/permissions/{}", channel_id, target_id),
+ })?)
}
/// Deletes a reaction from a message if owned by us or
@@ -637,32 +637,30 @@ 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,
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::ChannelsIdMessagesIdReactionsUserIdType(channel_id),
+ url: api!(
"/channels/{}/messages/{}/reactions/{}/{}",
channel_id,
message_id,
reaction_type.as_data(),
- user
+ 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
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::GuildsIdRolesId(guild_id),
+ url: api!("/guilds/{}/roles/{}", guild_id, role_id),
+ })?)
}
/// Deletes a [`Webhook`] given its Id.
@@ -688,15 +686,13 @@ 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,
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::WebhooksId(webhook_id),
+ url: api!("/webhooks/{}", webhook_id),
+ })?)
}
/// Deletes a [`Webhook`] given its Id and unique token.
@@ -718,24 +714,26 @@ 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<()> {
- verify(
- 204,
- retry(|| {
- CLIENT
- .delete(&format!(api!("/webhooks/{}/{}"), webhook_id, token))
- }).map_err(Error::Hyper)?,
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::None,
+ url: api!("/webhooks/{}/{}", webhook_id, token),
+ })?)
}
/// 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
- );
+ let body = serde_json::to_vec(map)?;
+
+ let response = request(Request {
+ body: Some(body),
+ headers: None,
+ method: Method::Patch,
+ route: Route::ChannelsId(channel_id),
+ url: api!("/channels/{}", channel_id),
+ })?;
serde_json::from_reader::<HyperResponse, GuildChannel>(response)
.map_err(From::from)
@@ -743,14 +741,13 @@ pub fn edit_channel(channel_id: u64, map: &JsonMap) -> Result<GuildChannel> {
/// 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
- );
+ let response = request(Request {
+ body: Some(map.to_string().into_bytes()),
+ headers: None,
+ method: Method::Patch,
+ route: Route::GuildsIdEmojisId(guild_id),
+ url: api!("/guilds/{}/emojis/{}", guild_id, emoji_id),
+ })?;
serde_json::from_reader::<HyperResponse, Emoji>(response)
.map_err(From::from)
@@ -758,13 +755,15 @@ pub fn edit_emoji(guild_id: u64, emoji_id: u64, map: &Value) -> Result<Emoji> {
/// 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
- );
+ let body = serde_json::to_vec(map)?;
+
+ let response = request(Request {
+ body: Some(body),
+ headers: None,
+ method: Method::Patch,
+ route: Route::GuildsId(guild_id),
+ url: api!("/guilds/{}", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, PartialGuild>(response)
.map_err(From::from)
@@ -773,30 +772,26 @@ pub fn edit_guild(guild_id: u64, map: &JsonMap) -> Result<PartialGuild> {
/// 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,
- ),
- )
+ verify(204, request(Request {
+ body: Some(value.to_string().into_bytes()),
+ headers: None,
+ method: Method::Patch,
+ route: Route::GuildsIdChannels(guild_id),
+ url: api!("/guilds/{}/channels", 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
- );
+ let response = request(Request {
+ body: Some(map.to_string().into_bytes()),
+ headers: None,
+ method: Method::Patch,
+ route: Route::GuildsIdEmbed(guild_id),
+ url: api!("/guilds/{}/embed", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, GuildEmbed>(response)
.map_err(From::from)
@@ -804,32 +799,28 @@ pub fn edit_guild_embed(guild_id: u64, map: &Value) -> Result<GuildEmbed> {
/// 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)?;
+
+ verify(204, request(Request {
+ body: Some(body),
+ headers: None,
+ method: Method::Patch,
+ route: Route::GuildsIdMembersId(guild_id),
+ url: api!("/guilds/{}/members/{}", 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 response = request(Request {
+ body: Some(map.to_string().into_bytes()),
+ headers: None,
+ method: Method::Patch,
+ route: Route::ChannelsIdMessagesId(LightMethod::Any, channel_id),
+ url: api!("/channels/{}/messages/{}", channel_id, message_id),
+ })?;
serde_json::from_reader::<HyperResponse, Message>(response)
.map_err(From::from)
@@ -842,15 +833,14 @@ 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
- );
- verify(200, response)
+ verify(200, request(Request {
+ body: Some(map.to_string().into_bytes()),
+ headers: None,
+ method: Method::Patch,
+ route: Route::GuildsIdMembersMeNick(guild_id),
+ url: api!("/guilds/{}/members/@me/nick", guild_id),
+ })?)
}
/// Edits the current user's profile settings.
@@ -866,8 +856,15 @@ 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,
+ method: Method::Patch,
+ route: Route::UsersMe,
+ url: api!("/users/@me").to_owned(),
+ })?;
let mut value = serde_json::from_reader::<HyperResponse, Value>(response)?;
@@ -885,14 +882,15 @@ pub fn edit_profile(map: &JsonMap) -> Result<CurrentUser> {
/// 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
- );
+ let body = serde_json::to_vec(&map)?;
+
+ let response = request(Request {
+ body: Some(body),
+ headers: None,
+ method: Method::Patch,
+ route: Route::GuildsIdRolesId(guild_id),
+ url: api!("/guilds/{}/roles/{}", guild_id, role_id),
+ })?;
serde_json::from_reader::<HyperResponse, Role>(response)
.map_err(From::from)
@@ -904,13 +902,14 @@ pub fn edit_role_position(guild_id: u64, role_id: u64, position: u64) -> Result<
"id": role_id,
"position": position,
}))?;
- let response = request!(
- Route::GuildsIdRolesId(guild_id),
- patch(body),
- "/guilds/{}/roles/{}",
- guild_id,
- role_id
- );
+
+ let response = request(Request {
+ body: Some(body.into_bytes()),
+ headers: None,
+ method: Method::Patch,
+ route: Route::GuildsIdRolesId(guild_id),
+ url: api!("/guilds/{}/roles/{}", guild_id, role_id),
+ })?;
serde_json::from_reader::<HyperResponse, Vec<Role>>(response)
.map_err(From::from)
@@ -956,13 +955,13 @@ 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,
- );
+ let response = request(Request {
+ body: Some(map.to_string().into_bytes()),
+ headers: None,
+ method: Method::Patch,
+ route: Route::WebhooksId(webhook_id),
+ url: api!("/webhooks/{}", webhook_id),
+ })?;
serde_json::from_reader::<HyperResponse, Webhook>(response)
.map_err(From::from)
@@ -995,13 +994,15 @@ 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 response = retry(|| {
- CLIENT
- .patch(&format!(api!("/webhooks/{}/{}"), webhook_id, token))
- .body(&body)
- }).map_err(Error::Hyper)?;
+ let body = serde_json::to_vec(map)?;
+
+ let response = request(Request {
+ body: Some(body),
+ headers: None,
+ method: Method::Patch,
+ route: Route::None,
+ url: api!("/webhooks/{}/{}", webhook_id, token),
+ })?;
serde_json::from_reader::<HyperResponse, Webhook>(response)
.map_err(From::from)
@@ -1072,21 +1073,20 @@ pub fn execute_webhook(webhook_id: u64,
wait: bool,
map: &JsonMap)
-> Result<Option<Message>> {
- let body = serde_json::to_string(map)?;
-
- 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),
+ method: Method::Get,
+ route: Route::None,
+ url: api!("/webhooks/{}/{}?wait={}", webhook_id, token, wait),
+ })?;
if response.status == StatusCode::NoContent {
return Ok(None);
@@ -1101,8 +1101,12 @@ pub fn execute_webhook(webhook_id: u64,
///
/// Does not require authentication.
pub fn get_active_maintenances() -> Result<Vec<Maintenance>> {
- let response = retry(|| {
- CLIENT.get(status!("/scheduled-maintenances/active.json"))
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::None,
+ url: status!("/scheduled-maintenances/active.json").to_owned(),
})?;
let mut map: BTreeMap<String, Value> = serde_json::from_reader(response)?;
@@ -1116,12 +1120,13 @@ 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
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ route: Route::GuildsIdBans(guild_id),
+ method: Method::Get,
+ url: api!("/guilds/{}/bans", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, Vec<Ban>>(response)
.map_err(From::from)
@@ -1153,13 +1158,13 @@ pub fn get_audit_logs(guild_id: u64,
query_string.insert(0, '?');
}
- let response = request!(
- Route::GuildsIdAuditLogs(guild_id),
- get,
- "/guilds/{}/audit-logs{}",
- guild_id,
- query_string
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ route: Route::GuildsIdAuditLogs(guild_id),
+ method: Method::Get,
+ url: api!("/guilds/{}/audit-logs{}", guild_id, query_string),
+ })?;
serde_json::from_reader::<HyperResponse, AuditLogs>(response)
.map_err(From::from)
@@ -1167,7 +1172,13 @@ pub fn get_audit_logs(guild_id: u64,
/// Gets current bot gateway.
pub fn get_bot_gateway() -> Result<BotGateway> {
- let response = request!(Route::GatewayBot, get, "/gateway/bot");
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::GatewayBot,
+ url: api!("/gateway/bot").to_owned(),
+ })?;
serde_json::from_reader::<HyperResponse, BotGateway>(response)
.map_err(From::from)
@@ -1175,12 +1186,13 @@ pub fn get_bot_gateway() -> Result<BotGateway> {
/// 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
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::ChannelsIdInvites(channel_id),
+ url: api!("/channels/{}/invites", channel_id),
+ })?;
serde_json::from_reader::<HyperResponse, Vec<RichInvite>>(response)
.map_err(From::from)
@@ -1205,12 +1217,13 @@ 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
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::ChannelsIdWebhooks(channel_id),
+ url: api!("/channels/{}/webhooks", channel_id),
+ })?;
serde_json::from_reader::<HyperResponse, Vec<Webhook>>(response)
.map_err(From::from)
@@ -1218,12 +1231,13 @@ pub fn get_channel_webhooks(channel_id: u64) -> Result<Vec<Webhook>> {
/// Gets channel information.
pub fn get_channel(channel_id: u64) -> Result<Channel> {
- let response = request!(
- Route::ChannelsId(channel_id),
- get,
- "/channels/{}",
- channel_id
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::ChannelsId(channel_id),
+ url: api!("/channels/{}", channel_id),
+ })?;
serde_json::from_reader::<HyperResponse, Channel>(response)
.map_err(From::from)
@@ -1231,12 +1245,13 @@ pub fn get_channel(channel_id: u64) -> Result<Channel> {
/// 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
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ route: Route::ChannelsId(guild_id),
+ method: Method::Get,
+ url: api!("/guilds/{}/channels", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, Vec<GuildChannel>>(response)
.map_err(From::from)
@@ -1246,7 +1261,13 @@ pub fn get_channels(guild_id: u64) -> Result<Vec<GuildChannel>> {
///
/// **Note**: Only applications may use this endpoint.
pub fn get_current_application_info() -> Result<CurrentApplicationInfo> {
- let response = request!(Route::None, get, "/oauth2/applications/@me");
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::None,
+ url: api!("/oauth2/applications/@me").to_owned(),
+ })?;
serde_json::from_reader::<HyperResponse, CurrentApplicationInfo>(response)
.map_err(From::from)
@@ -1254,7 +1275,13 @@ pub fn get_current_application_info() -> Result<CurrentApplicationInfo> {
/// Gets information about the user we're connected with.
pub fn get_current_user() -> Result<CurrentUser> {
- let response = request!(Route::UsersMe, get, "/users/@me");
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::UsersMe,
+ url: api!("/users/@me").to_owned(),
+ })?;
serde_json::from_reader::<HyperResponse, CurrentUser>(response)
.map_err(From::from)
@@ -1262,7 +1289,13 @@ pub fn get_current_user() -> Result<CurrentUser> {
/// Gets current gateway.
pub fn get_gateway() -> Result<Gateway> {
- let response = request!(Route::Gateway, get, "/gateway");
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::Gateway,
+ url: api!("/gateway").to_owned(),
+ })?;
serde_json::from_reader::<HyperResponse, Gateway>(response)
.map_err(From::from)
@@ -1270,7 +1303,13 @@ pub fn get_gateway() -> Result<Gateway> {
/// Gets guild information.
pub fn get_guild(guild_id: u64) -> Result<PartialGuild> {
- let response = request!(Route::GuildsId(guild_id), get, "/guilds/{}", guild_id);
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::GuildsId(guild_id),
+ url: api!("/guilds/{}", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, PartialGuild>(response)
.map_err(From::from)
@@ -1278,12 +1317,13 @@ pub fn get_guild(guild_id: u64) -> Result<PartialGuild> {
/// 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
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::GuildsIdEmbed(guild_id),
+ url: api!("/guilds/{}/embeds", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, GuildEmbed>(response)
.map_err(From::from)
@@ -1291,12 +1331,13 @@ pub fn get_guild_embed(guild_id: u64) -> Result<GuildEmbed> {
/// 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
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::GuildsIdIntegrations(guild_id),
+ url: api!("/guilds/{}/integrations", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, Vec<Integration>>(response)
.map_err(From::from)
@@ -1304,12 +1345,13 @@ pub fn get_guild_integrations(guild_id: u64) -> Result<Vec<Integration>> {
/// 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
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::GuildsIdInvites(guild_id),
+ url: api!("/guilds/{}/invites", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, Vec<RichInvite>>(response)
.map_err(From::from)
@@ -1322,12 +1364,13 @@ 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,
+ method: Method::Get,
+ route: Route::GuildsIdVanityUrl(guild_id),
+ url: api!("/guilds/{}/vanity-url", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, GuildVanityUrl>(response)
.map(|x| x.code)
@@ -1340,14 +1383,18 @@ 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,
+ method: Method::Get,
+ route: Route::GuildsIdMembers(guild_id),
+ url: api!(
+ "/guilds/{}/members?limit={}&after={}",
+ guild_id,
+ limit.unwrap_or(500),
+ after.unwrap_or(0),
+ ),
+ })?;
let mut v = serde_json::from_reader::<HyperResponse, Value>(response)?;
@@ -1366,13 +1413,13 @@ 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
- );
+ let response = request(Request {
+ body: Some(map.to_string().into_bytes()),
+ headers: None,
+ method: Method::Get,
+ route: Route::GuildsIdPrune(guild_id),
+ url: api!("/guilds/{}/prune", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, GuildPrune>(response)
.map_err(From::from)
@@ -1381,12 +1428,13 @@ pub fn get_guild_prune_count(guild_id: u64, map: &Value) -> Result<GuildPrune> {
/// 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
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::GuildsIdRegions(guild_id),
+ url: api!("/guilds/{}/regions", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, Vec<VoiceRegion>>(response)
.map_err(From::from)
@@ -1396,12 +1444,13 @@ pub fn get_guild_regions(guild_id: u64) -> Result<Vec<VoiceRegion>> {
///
/// [`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
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::GuildsIdRoles(guild_id),
+ url: api!("/guilds/{}/roles", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, Vec<Role>>(response)
.map_err(From::from)
@@ -1426,12 +1475,13 @@ 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
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::GuildsIdWebhooks(guild_id),
+ url: api!("/guilds/{}/webhooks", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, Vec<Webhook>>(response)
.map_err(From::from)
@@ -1469,7 +1519,13 @@ pub fn get_guilds(target: &GuildPagination, limit: u64) -> Result<Vec<GuildInfo>
},
}
- let response = request!(Route::UsersMeGuilds, get, "{}", uri);
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::UsersMeGuilds,
+ url: api!("{}", uri),
+ })?;
serde_json::from_reader::<HyperResponse, Vec<GuildInfo>>(response)
.map_err(From::from)
@@ -1491,7 +1547,13 @@ pub fn get_invite(code: &str, stats: bool) -> Result<Invite> {
uri.push_str("?with_counts=true");
}
- let response = request!(Route::InvitesCode, get, "{}", uri);
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::InvitesCode,
+ url: api!("{}", uri),
+ })?;
serde_json::from_reader::<HyperResponse, Invite>(response)
.map_err(From::from)
@@ -1499,13 +1561,13 @@ pub fn get_invite(code: &str, stats: bool) -> Result<Invite> {
/// 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,
+ method: Method::Get,
+ route: Route::GuildsIdMembersId(guild_id),
+ url: api!("/guilds/{}/members/{}", guild_id, user_id),
+ })?;
let mut v = serde_json::from_reader::<HyperResponse, Value>(response)?;
@@ -1518,13 +1580,13 @@ 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
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::ChannelsIdMessagesId(LightMethod::Any, channel_id),
+ url: api!("/channels/{}/messages/{}", channel_id, message_id),
+ })?;
serde_json::from_reader::<HyperResponse, Message>(response)
.map_err(From::from)
@@ -1532,9 +1594,13 @@ pub fn get_message(channel_id: u64, message_id: u64) -> Result<Message> {
/// 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 response = request(Route::ChannelsIdMessages(channel_id), || CLIENT.get(&url))?;
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::ChannelsIdMessages(channel_id),
+ url: api!("/channels/{}/messages{}", channel_id, query),
+ })?;
serde_json::from_reader::<HyperResponse, Vec<Message>>(response)
.map_err(From::from)
@@ -1542,12 +1608,13 @@ pub fn get_messages(channel_id: u64, query: &str) -> Result<Vec<Message>> {
/// 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
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::ChannelsIdPins(channel_id),
+ url: api!("/channels/{}/pins", channel_id),
+ })?;
serde_json::from_reader::<HyperResponse, Vec<Message>>(response)
.map_err(From::from)
@@ -1572,12 +1639,13 @@ pub fn get_reaction_users(channel_id: u64,
write!(uri, "&after={}", user_id)?;
}
- let response = request!(
- Route::ChannelsIdMessagesIdReactionsUserIdType(channel_id),
- get,
- "{}",
- uri
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::ChannelsIdMessagesIdReactionsUserIdType(channel_id),
+ url: api!("{}", uri),
+ })?;
serde_json::from_reader::<HyperResponse, Vec<User>>(response)
.map_err(From::from)
@@ -1587,7 +1655,13 @@ pub fn get_reaction_users(channel_id: u64,
///
/// Does not require authentication.
pub fn get_unresolved_incidents() -> Result<Vec<Incident>> {
- let response = retry(|| CLIENT.get(status!("/incidents/unresolved.json")))?;
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::None,
+ url: status!("/incidents/unresolved.json").to_owned(),
+ })?;
let mut map: BTreeMap<String, Value> = serde_json::from_reader(response)?;
@@ -1602,8 +1676,12 @@ pub fn get_unresolved_incidents() -> Result<Vec<Incident>> {
///
/// Does not require authentication.
pub fn get_upcoming_maintenances() -> Result<Vec<Maintenance>> {
- let response = retry(|| {
- CLIENT.get(status!("/scheduled-maintenances/upcoming.json"))
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::None,
+ url: status!("/scheduled-maintenances/upcoming.json").to_owned(),
})?;
let mut map: BTreeMap<String, Value> = serde_json::from_reader(response)?;
@@ -1617,7 +1695,13 @@ 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);
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::UsersId,
+ url: api!("/users/{}", user_id),
+ })?;
serde_json::from_reader::<HyperResponse, User>(response)
.map_err(From::from)
@@ -1625,7 +1709,13 @@ pub fn get_user(user_id: u64) -> Result<User> {
/// Gets our DM channels.
pub fn get_user_dm_channels() -> Result<Vec<PrivateChannel>> {
- let response = request!(Route::UsersMeChannels, get, "/users/@me/channels");
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::UsersMeChannels,
+ url: api!("/users/@me/channels").to_owned(),
+ })?;
serde_json::from_reader::<HyperResponse, Vec<PrivateChannel>>(response)
.map_err(From::from)
@@ -1633,7 +1723,13 @@ pub fn get_user_dm_channels() -> Result<Vec<PrivateChannel>> {
/// Gets all voice regions.
pub fn get_voice_regions() -> Result<Vec<VoiceRegion>> {
- let response = request!(Route::VoiceRegions, get, "/voice/regions");
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::VoiceRegions,
+ url: api!("/voice/regions").to_owned(),
+ })?;
serde_json::from_reader::<HyperResponse, Vec<VoiceRegion>>(response)
.map_err(From::from)
@@ -1657,12 +1753,13 @@ 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,
- );
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::WebhooksId(webhook_id),
+ url: api!("/webhooks/{}", webhook_id),
+ })?;
serde_json::from_reader::<HyperResponse, Webhook>(response)
.map_err(From::from)
@@ -1686,9 +1783,13 @@ 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 response = retry(|| {
- CLIENT.get(&format!(api!("/webhooks/{}/{}"), webhook_id, token))
- }).map_err(Error::Hyper)?;
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Get,
+ route: Route::None,
+ url: api!("/webhooks/{}/{}", webhook_id, token),
+ })?;
serde_json::from_reader::<HyperResponse, Webhook>(response)
.map_err(From::from)
@@ -1696,21 +1797,24 @@ pub fn get_webhook_with_token(webhook_id: u64, token: &str) -> Result<Webhook> {
/// 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
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::GuildsIdMembersId(guild_id),
+ url: api!("/guilds/{}/members/{}", 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);
+ let response = request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::None,
+ url: api!("/channels/{}", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, Group>(response)
.map_err(From::from)
@@ -1718,29 +1822,24 @@ pub fn leave_group(guild_id: u64) -> Result<Group> {
/// Leaves a guild.
pub fn leave_guild(guild_id: u64) -> Result<()> {
- verify(
- 204,
- request!(
- Route::UsersMeGuildsId,
- delete,
- "/users/@me/guilds/{}",
- guild_id
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::UsersMeGuildsId,
+ url: api!("/users/@me/guilds/{}", 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
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::None,
+ url: api!("/channels/{}/recipients/{}", group_id, user_id),
+ })?)
}
/// Sends file(s) to a channel.
@@ -1754,7 +1853,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)),
@@ -1762,7 +1861,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,13 +1916,13 @@ pub fn send_files<'a, T, It: IntoIterator<Item=T>>(channel_id: u64, files: It, m
/// 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 response = request(Request {
+ body: Some(map.to_string().into_bytes()),
+ headers: None,
+ method: Method::Post,
+ route: Route::ChannelsIdMessages(channel_id),
+ url: api!("/channels/{}/messages", channel_id),
+ })?;
serde_json::from_reader::<HyperResponse, Message>(response)
.map_err(From::from)
@@ -1831,30 +1930,24 @@ pub fn send_message(channel_id: u64, map: &Value) -> Result<Message> {
/// 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
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Put,
+ route: Route::ChannelsIdPinsMessageId(channel_id),
+ url: api!("/channels/{}/pins/{}", 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
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::GuildsIdBansUserId(guild_id),
+ url: api!("/guilds/{}/bans/{}", guild_id, user_id),
+ })?)
}
/// Deletes a single [`Role`] from a [`Member`] in a [`Guild`].
@@ -1867,28 +1960,24 @@ 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
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::GuildsIdMembersIdRolesId(guild_id),
+ url: api!("/guilds/{}/members/{}/roles/{}", 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
- );
+ let response = request(Request {
+ body: Some(map.to_string().into_bytes()),
+ headers: None,
+ method: Method::Post,
+ route: Route::GuildsIdPrune(guild_id),
+ url: api!("/guilds/{}/prune", guild_id),
+ })?;
serde_json::from_reader::<HyperResponse, GuildPrune>(response)
.map_err(From::from)
@@ -1896,38 +1985,28 @@ pub fn start_guild_prune(guild_id: u64, map: &Value) -> Result<GuildPrune> {
/// 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
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Post,
+ route: Route::GuildsIdIntegrationsIdSync(guild_id),
+ url: api!("/guilds/{}/integrations/{}/sync", 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
- ),
- )
+ verify(204, request(Request {
+ body: None,
+ headers: None,
+ method: Method::Delete,
+ route: Route::ChannelsIdPinsMessageId(channel_id),
+ url: api!("/channels/{}/pins/{}", 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())
- })?;
+fn request(req: Request) -> Result<HyperResponse> {
+ let response = ratelimiting::perform(req)?;
if response.status.class() == StatusClass::Success {
Ok(response)
@@ -1936,17 +2015,33 @@ 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()
- };
+fn build_req(req: &Request) -> RequestBuilder {
+ let mut builder = CLIENT.request(req.method.clone(), &req.url);
+
+ if let Some(ref bytes) = req.body {
+ builder = builder.body(HyperBody::BufBody(bytes, bytes.len()));
+ }
- match req() {
- Err(HyperError::Io(ref io)) if io.kind() == IoErrorKind::ConnectionAborted => req(),
- other => other,
+ if let Some(headers) = req.headers.clone() {
+ builder = builder.headers(headers);
}
+
+ builder
+}
+
+fn retry<'a>(req: &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..=2 {
+ match build_req(req).send() {
+ Err(HyperError::Io(ref io))
+ if io.kind() == IoErrorKind::ConnectionAborted => continue,
+ other => return other,
+ }
+ }
+
+ build_req(req).send()
}
fn verify(expected: u16, response: HyperResponse) -> Result<()> {
diff --git a/src/http/ratelimiting.rs b/src/http/ratelimiting.rs
index b8152d1..1c31c9f 100644
--- a/src/http/ratelimiting.rs
+++ b/src/http/ratelimiting.rs
@@ -41,7 +41,7 @@
#![allow(zero_ptr)]
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 +54,7 @@ use std::{
thread,
i64
};
-use super::{HttpError, LightMethod};
+use super::{HttpError, LightMethod, Request};
/// Refer to [`offset`].
///
@@ -361,8 +361,7 @@ pub enum Route {
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).
@@ -378,7 +377,7 @@ pub(crate) fn perform<'a, F>(route: Route, f: F) -> Result<Response>
// - then, perform the request
let bucket = Arc::clone(ROUTES
.lock()
- .entry(route)
+ .entry(req.route)
.or_insert_with(|| {
Arc::new(Mutex::new(RateLimit {
limit: i64::MAX,
@@ -388,9 +387,9 @@ pub(crate) fn perform<'a, F>(route: Route, f: F) -> Result<Response>
}));
let mut lock = bucket.lock();
- lock.pre_hook(&route);
+ lock.pre_hook(&req.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.
@@ -416,7 +415,7 @@ pub(crate) fn perform<'a, F>(route: Route, f: F) -> Result<Response>
// It _may_ be possible for the limit to be raised at any time,
// so check if it did from the value of the 'x-ratelimit-limit'
// header. If the limit was 5 and is now 7, add 2 to the 'remaining'
- if route == Route::None {
+ if req.route == Route::None {
return Ok(response);
} else {
let redo = if response.headers.get_raw("x-ratelimit-global").is_some() {
@@ -424,7 +423,7 @@ pub(crate) fn perform<'a, F>(route: Route, f: F) -> Result<Response>
Ok(
if let Some(retry_after) = parse_header(&response.headers, "retry-after")? {
- debug!("Ratelimited on route {:?} for {:?}ms", route, retry_after);
+ debug!("Ratelimited on route {:?} for {:?}ms", req.route, retry_after);
thread::sleep(Duration::from_millis(retry_after as u64));
true
@@ -433,7 +432,7 @@ pub(crate) fn perform<'a, F>(route: Route, f: F) -> Result<Response>
},
)
} else {
- lock.post_hook(&response, &route)
+ lock.post_hook(&response, &req.route)
};
if !redo.unwrap_or(true) {