pub mod ratelimiting;
mod error;
pub use self::error::Error as HttpError;
pub use hyper::status::{StatusClass, StatusCode};
use hyper::client::{
Client as HyperClient,
RequestBuilder,
Response as HyperResponse,
Request,
};
use hyper::header::ContentType;
use hyper::method::Method;
use hyper::mime::{Mime, SubLevel, TopLevel};
use hyper::net::HttpsConnector;
use hyper::{Error as HyperError, Result as HyperResult, Url, header};
use hyper_native_tls::NativeTlsClient;
use multipart::client::Multipart;
use self::ratelimiting::Route;
use serde_json;
use std::collections::BTreeMap;
use std::default::Default;
use std::fmt::Write as FmtWrite;
use std::fs::File;
use std::io::{ErrorKind as IoErrorKind, Read};
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use ::constants;
use ::internal::prelude::*;
use ::model::*;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum LightMethod {
Any,
Delete,
Get,
Patch,
Post,
Put,
}
lazy_static! {
static ref TOKEN: Arc<Mutex<String>> = Arc::new(Mutex::new(String::default()));
}
#[doc(hidden)]
pub fn set_token(token: &str) {
TOKEN.lock().unwrap().clone_from(&token.to_owned());
}
pub fn add_group_recipient(group_id: u64, user_id: u64) -> Result<()> {
verify(204, request!(Route::None,
put,
"/channels/{}/recipients/{}",
group_id,
user_id))
}
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))
}
pub fn ban_user(guild_id: u64, user_id: u64, delete_message_days: u8) -> Result<()> {
verify(204, request!(Route::GuildsIdBansUserId(guild_id),
put,
"/guilds/{}/bans/{}?delete_message_days={}",
guild_id,
user_id,
delete_message_days))
}
pub fn broadcast_typing(channel_id: u64) -> Result<()> {
verify(204, request!(Route::ChannelsIdTyping(channel_id),
post,
"/channels/{}/typing",
channel_id))
}
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)
}
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)
}
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)
}
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))
}
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)
}
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))
}
pub fn create_private_channel(map: &Value) -> Result<PrivateChannel> {
let body = map.to_string();
let response = request!(Route::UsersMeChannels,
post(body),
"/users/@me/channels");
serde_json::from_reader::<HyperResponse, PrivateChannel>(response).map_err(From::from)
}
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",
channel_id,
message_id,
reaction_type.as_data()))
}
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)
}
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)
}
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)
}
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))
}
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)
}
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))
}
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)
}
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))
}
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))
}
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))
}
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))
}
pub fn delete_reaction(channel_id: u64,
message_id: u64,
user_id: Option<u64>,
reaction_type: &ReactionType)
-> Result<()> {
let user = user_id.map(|uid| uid.to_string()).unwrap_or_else(|| "@me".to_string());
verify(204, request!(Route::ChannelsIdMessagesIdReactionsUserIdType(channel_id),
delete,
"/channels/{}/messages/{}/reactions/{}/{}",
channel_id,
message_id,
reaction_type.as_data(),
user))
}
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))
}
pub fn delete_webhook(webhook_id: u64) -> Result<()> {
verify(204, request!(Route::WebhooksId, delete, "/webhooks/{}", webhook_id))
}
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)?)
}
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)
}
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)
}
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)
}
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)
}
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))
}
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);
serde_json::from_reader::<HyperResponse, Message>(response).map_err(From::from)
}
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)
}
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 mut value = serde_json::from_reader::<HyperResponse, Value>(response)?;
if let Some(map) = value.as_object_mut() {
if !TOKEN.lock().unwrap().starts_with("Bot ") {
if let Some(Value::String(token)) = map.remove("token") {
set_token(&token);
}
}
}
serde_json::from_value::<CurrentUser>(value).map_err(From::from)
}
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)
}
pub fn edit_webhook(webhook_id: u64, map: &Value) -> Result<Webhook> {
let body = map.to_string();
let response = request!(Route::WebhooksId,
patch(body),
"/webhooks/{}",
webhook_id);
serde_json::from_reader::<HyperResponse, Webhook>(response).map_err(From::from)
}
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)?;
serde_json::from_reader::<HyperResponse, Webhook>(response).map_err(From::from)
}
pub fn execute_webhook(webhook_id: u64, token: &str, 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)?;
if response.status == StatusCode::NoContent {
return Ok(None);
}
serde_json::from_reader::<HyperResponse, Message>(response).map(Some).map_err(From::from)
}
pub fn get_active_maintenances() -> Result<Vec<Maintenance>> {
let client = request_client!();
let response = retry(|| client.get(
status!("/scheduled-maintenances/active.json")))?;
let mut map: BTreeMap<String, Value> = serde_json::from_reader(response)?;
match map.remove("scheduled_maintenances") {
Some(v) => serde_json::from_value::<Vec<Maintenance>>(v).map_err(From::from),
None => Ok(vec![]),
}
}
pub fn get_application_info(id: u64) -> Result<ApplicationInfo> {
let response = request!(Route::None, get, "/oauth2/applications/{}", id);
serde_json::from_reader::<HyperResponse, ApplicationInfo>(response).map_err(From::from)
}
pub fn get_applications() -> Result<Vec<ApplicationInfo>> {
let response = request!(Route::None, get, "/oauth2/applications");
serde_json::from_reader::<HyperResponse, Vec<ApplicationInfo>>(response).map_err(From::from)
}
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)
}
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)
}
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)
}
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)
}
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)
}
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)
}
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)
}
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)
}
pub fn get_gateway() -> Result<Gateway> {
let response = request!(Route::Gateway, get, "/gateway");
serde_json::from_reader::<HyperResponse, Gateway>(response).map_err(From::from)
}
pub fn get_emoji(guild_id: u64, emoji_id: u64) -> Result<Emoji> {
let response = request!(Route::GuildsIdEmojisId(guild_id),
get,
"/guilds/{}/emojis/{}",
guild_id,
emoji_id);
serde_json::from_reader::<HyperResponse, Emoji>(response).map_err(From::from)
}
pub fn get_emojis(guild_id: u64) -> Result<Vec<Emoji>> {
let response = request!(Route::GuildsIdEmojis(guild_id),
get,
"/guilds/{}/emojis",
guild_id);
serde_json::from_reader::<HyperResponse, Vec<Emoji>>(response).map_err(From::from)
}
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)
}
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)
}
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)
}
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)
}
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 mut v = serde_json::from_reader::<HyperResponse, Value>(response)?;
if let Some(values) = v.as_array_mut() {
let num = Value::Number(Number::from(guild_id));
for value in values {
if let Some(element) = value.as_object_mut() {
element.insert("guild_id".to_owned(), num.clone());
}
}
}
serde_json::from_value::<Vec<Member>>(v).map_err(From::from)
}
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)
}
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)
}
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)
}
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)
}
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);
serde_json::from_reader::<HyperResponse, Vec<GuildInfo>>(response).map_err(From::from)
}
#[allow(unused_mut)]
pub fn get_invite(code: &str, stats: bool) -> Result<Invite> {
let mut invite = code;
#[cfg(feature="utils")]
{
invite = ::utils::parse_invite(invite);
}
let mut uri = format!("/invites/{}", invite);
if stats {
uri.push_str("?with_counts=true");
}
let response = request!(Route::InvitesCode, get, "{}", uri);
serde_json::from_reader::<HyperResponse, Invite>(response).map_err(From::from)
}
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 mut v = serde_json::from_reader::<HyperResponse, Value>(response)?;
if let Some(map) = v.as_object_mut() {
map.insert("guild_id".to_owned(), Value::Number(Number::from(guild_id)));
}
serde_json::from_value::<Member>(v).map_err(From::from)
}
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)
}
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)
}
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)
}
pub fn get_reaction_users(channel_id: u64,
message_id: u64,
reaction_type: &ReactionType,
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);
serde_json::from_reader::<HyperResponse, Vec<User>>(response).map_err(From::from)
}
pub fn get_unresolved_incidents() -> Result<Vec<Incident>> {
let client = request_client!();
let response = retry(|| client.get(
status!("/incidents/unresolved.json")))?;
let mut map: BTreeMap<String, Value> = serde_json::from_reader(response)?;
match map.remove("incidents") {
Some(v) => serde_json::from_value::<Vec<Incident>>(v).map_err(From::from),
None => Ok(vec![]),
}
}
pub fn get_upcoming_maintenances() -> Result<Vec<Maintenance>> {
let client = request_client!();
let response = retry(|| client.get(
status!("/scheduled-maintenances/upcoming.json")))?;
let mut map: BTreeMap<String, Value> = serde_json::from_reader(response)?;
match map.remove("scheduled_maintenances") {
Some(v) => serde_json::from_value::<Vec<Maintenance>>(v).map_err(From::from),
None => Ok(vec![]),
}
}
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)
}
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)
}
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)
}
pub fn get_webhook(webhook_id: u64) -> Result<Webhook> {
let response = request!(Route::WebhooksId, get, "/webhooks/{}", webhook_id);
serde_json::from_reader::<HyperResponse, Webhook>(response).map_err(From::from)
}
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)
}
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))
}
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_guild(guild_id: u64) -> Result<()> {
verify(204, request!(Route::UsersMeGuildsId, delete, "/users/@me/guilds/{}", guild_id))
}
pub fn remove_group_recipient(group_id: u64, user_id: u64) -> Result<()> {
verify(204, request!(Route::None,
delete,
"/channels/{}/recipients/{}",
group_id,
user_id))
}
#[deprecated(since="0.2.0", note="Please use `send_files` instead.")]
pub fn send_file<R: Read>(channel_id: u64, mut file: R, filename: &str, map: JsonMap)
-> Result<Message> {
let mut bytes = vec![];
file.read_to_end(&mut bytes)?;
send_files(channel_id, vec![AttachmentType::Bytes((&bytes, filename))], map)
}
pub fn send_files<'a, T>(channel_id: u64, files: Vec<T>, map: JsonMap)
-> Result<Message> where T: Into<AttachmentType<'a>> {
let uri = format!(api!("/channels/{}/messages"), channel_id);
let url = match Url::parse(&uri) {
Ok(url) => url,
Err(_) => return Err(Error::Url(uri)),
};
let tc = NativeTlsClient::new()?;
let connector = HttpsConnector::new(tc);
let mut request = Request::with_connector(Method::Post, url, &connector)?;
request.headers_mut()
.set(header::Authorization(TOKEN.lock().unwrap().clone()));
request.headers_mut()
.set(header::UserAgent(constants::USER_AGENT.to_owned()));
let mut request = Multipart::from_request(request)?;
let mut file_num = String::from("0".to_owned());
for file in files {
match file.into() {
AttachmentType::Bytes((mut bytes, filename)) => {
request.write_stream(&file_num, &mut bytes, Some(filename), None)?;
},
AttachmentType::File((mut f, filename)) => {
request.write_stream(&file_num, &mut f, Some(filename), None)?;
},
AttachmentType::Path(p) => {
request.write_file(&file_num, &p)?;
},
}
unsafe {
let vec = file_num.as_mut_vec();
vec[0] += 1;
}
}
for (k, v) in map {
match v {
Value::Bool(false) => request.write_text(&k, "false")?,
Value::Bool(true) => request.write_text(&k, "true")?,
Value::Number(inner) => request.write_text(&k, inner.to_string())?,
Value::String(inner) => request.write_text(&k, inner)?,
_ => continue,
};
}
let response = request.send()?;
if response.status.class() != StatusClass::Success {
return Err(Error::Http(HttpError::InvalidRequest(response.status)));
}
serde_json::from_reader::<HyperResponse, Message>(response).map_err(From::from)
}
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);
serde_json::from_reader::<HyperResponse, Message>(response).map_err(From::from)
}
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))
}
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))
}
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))
}
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)
}
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))
}
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))
}
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().unwrap().clone()))
.header(header::ContentType::json()))?;
if response.status.class() == StatusClass::Success {
Ok(response)
} else {
Err(Error::Http(HttpError::InvalidRequest(response.status)))
}
}
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_owned()))
.send();
match req() {
Err(HyperError::Io(ref io))
if io.kind() == IoErrorKind::ConnectionAborted => req(),
other => other,
}
}
fn verify(expected_status_code: u16, mut response: HyperResponse) -> Result<()> {
let expected_status = match expected_status_code {
200 => StatusCode::Ok,
204 => StatusCode::NoContent,
401 => StatusCode::Unauthorized,
_ => {
let client_error = HttpError::UnknownStatus(expected_status_code);
return Err(Error::Http(client_error));
},
};
if response.status == expected_status {
return Ok(());
}
debug!("Expected {}, got {}", expected_status_code, response.status);
let mut s = String::default();
response.read_to_string(&mut s)?;
debug!("Content: {}", s);
Err(Error::Http(HttpError::InvalidRequest(response.status)))
}
pub enum AttachmentType<'a> {
Bytes((&'a [u8], &'a str)),
File((&'a File, &'a str)),
Path(&'a Path),
}
impl<'a> From<(&'a [u8], &'a str)> for AttachmentType<'a> {
fn from(params: (&'a [u8], &'a str)) -> AttachmentType {
AttachmentType::Bytes(params)
}
}
impl<'a> From<&'a str> for AttachmentType<'a> {
fn from(s: &'a str) -> AttachmentType {
AttachmentType::Path(Path::new(s))
}
}
impl<'a> From<&'a PathBuf> for AttachmentType<'a> {
fn from(pathbuf: &'a PathBuf) -> AttachmentType {
AttachmentType::Path(pathbuf.as_path())
}
}
impl<'a> From<(&'a File, &'a str)> for AttachmentType<'a> {
fn from(f: (&'a File, &'a str)) -> AttachmentType<'a> {
AttachmentType::File((f.0, f.1))
}
}
pub enum GuildPagination {
After(GuildId),
Before(GuildId),
}