#![allow(clippy::missing_errors_doc)]
use std::borrow::Cow;
use std::convert::TryFrom;
use std::fmt;
use std::str::FromStr;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
use reqwest::header::{HeaderMap as Headers, HeaderValue, CONTENT_TYPE};
use reqwest::{Client, ClientBuilder, Response as ReqwestResponse, StatusCode, Url};
use serde::de::DeserializeOwned;
use tracing::{debug, instrument, trace};
use super::multipart::Multipart;
use super::ratelimiting::{RatelimitedRequest, Ratelimiter};
use super::request::Request;
use super::routing::RouteInfo;
use super::typing::Typing;
use super::{AttachmentType, GuildPagination, HttpError, UserPagination};
use crate::internal::prelude::*;
use crate::json::prelude::*;
use crate::model::application::command::{Command, CommandPermission};
use crate::model::guild::automod::Rule;
use crate::model::prelude::*;
use crate::{constants, utils};
pub struct HttpBuilder {
client: Option<Client>,
ratelimiter: Option<Ratelimiter>,
ratelimiter_disabled: bool,
token: String,
proxy: Option<Url>,
application_id: Option<u64>,
}
impl HttpBuilder {
pub fn new(token: impl AsRef<str>) -> Self {
Self {
client: None,
ratelimiter: None,
ratelimiter_disabled: false,
token: parse_token(token),
proxy: None,
application_id: None,
}
}
#[must_use]
pub fn application_id(mut self, application_id: u64) -> Self {
self.application_id = Some(application_id);
self
}
#[must_use]
pub fn token(mut self, token: impl AsRef<str>) -> Self {
self.token = parse_token(token);
self
}
#[must_use]
pub fn client(mut self, client: Client) -> Self {
self.client = Some(client);
self
}
#[must_use]
pub fn ratelimiter(mut self, ratelimiter: Ratelimiter) -> Self {
self.ratelimiter = Some(ratelimiter);
self
}
#[must_use]
pub fn ratelimiter_disabled(mut self, ratelimiter_disabled: bool) -> Self {
self.ratelimiter_disabled = ratelimiter_disabled;
self
}
pub fn proxy(mut self, proxy: impl Into<String>) -> Result<Self> {
let proxy = Url::from_str(&proxy.into()).map_err(HttpError::Url)?;
self.proxy = Some(proxy);
Ok(self)
}
#[must_use]
pub fn build(self) -> Http {
let token = self.token;
let application_id = AtomicU64::new(self.application_id.unwrap_or_default());
let client = self.client.unwrap_or_else(|| {
let builder = configure_client_backend(Client::builder());
builder.build().expect("Cannot build reqwest::Client")
});
let ratelimiter = self.ratelimiter.unwrap_or_else(|| {
let client = client.clone();
Ratelimiter::new(client, token.to_string())
});
let ratelimiter_disabled = self.ratelimiter_disabled;
Http {
client,
ratelimiter,
ratelimiter_disabled,
proxy: self.proxy,
token,
application_id,
}
}
}
fn parse_token(token: impl AsRef<str>) -> String {
let token = token.as_ref().trim();
if token.starts_with("Bot ") || token.starts_with("Bearer ") {
token.to_string()
} else {
format!("Bot {}", token)
}
}
fn reason_into_header(reason: &str) -> Headers {
let mut headers = Headers::new();
let header_value = match Cow::from(utf8_percent_encode(reason, NON_ALPHANUMERIC)) {
Cow::Borrowed(value) => HeaderValue::from_str(value),
Cow::Owned(value) => HeaderValue::try_from(value),
}
.expect("Invalid header value even after percent encode");
headers.insert("X-Audit-Log-Reason", header_value);
headers
}
pub struct Http {
pub(crate) client: Client,
pub ratelimiter: Ratelimiter,
pub ratelimiter_disabled: bool,
pub proxy: Option<Url>,
pub token: String,
application_id: AtomicU64,
}
impl fmt::Debug for Http {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Http")
.field("client", &self.client)
.field("ratelimiter", &self.ratelimiter)
.field("ratelimiter_disabled", &self.ratelimiter_disabled)
.field("proxy", &self.proxy)
.finish()
}
}
impl Http {
#[must_use]
pub fn new(token: &str) -> Self {
let builder = configure_client_backend(Client::builder());
let client = builder.build().expect("Cannot build reqwest::Client");
let client2 = client.clone();
let token = parse_token(token);
Http {
client,
ratelimiter: Ratelimiter::new(client2, token.to_string()),
ratelimiter_disabled: false,
proxy: None,
token,
application_id: AtomicU64::new(0),
}
}
#[must_use]
pub fn new_with_application_id(token: &str, application_id: u64) -> Self {
let http = Self::new(token);
http.set_application_id(application_id);
http
}
pub fn application_id(&self) -> Option<u64> {
let application_id = self.application_id.load(Ordering::Relaxed);
if application_id == 0 {
None
} else {
Some(application_id)
}
}
fn try_application_id(&self) -> Result<u64> {
self.application_id().ok_or_else(|| HttpError::ApplicationIdMissing.into())
}
pub fn set_application_id(&self, application_id: u64) {
self.application_id.store(application_id, Ordering::Relaxed);
}
pub async fn add_guild_member(
&self,
guild_id: u64,
user_id: u64,
map: &JsonMap,
) -> Result<Option<Member>> {
let body = to_vec(map)?;
let response = self
.request(Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::AddGuildMember {
guild_id,
user_id,
},
})
.await?;
if response.status() == 204 {
Ok(None)
} else {
Ok(Some(response.json().await?))
}
}
pub async fn add_member_role(
&self,
guild_id: u64,
user_id: u64,
role_id: u64,
audit_log_reason: Option<&str>,
) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::AddMemberRole {
guild_id,
role_id,
user_id,
},
})
.await
}
pub async fn ban_user(
&self,
guild_id: u64,
user_id: u64,
delete_message_days: u8,
reason: &str,
) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: Some(reason_into_header(reason)),
route: RouteInfo::GuildBanUser {
delete_message_days: Some(delete_message_days),
guild_id,
user_id,
},
})
.await
}
pub async fn broadcast_typing(&self, channel_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::BroadcastTyping {
channel_id,
},
})
.await
}
pub async fn create_channel(
&self,
guild_id: u64,
map: &JsonMap,
audit_log_reason: Option<&str>,
) -> Result<GuildChannel> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::CreateChannel {
guild_id,
},
})
.await
}
pub async fn create_stage_instance(&self, map: &Value) -> Result<StageInstance> {
self.fire(Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: None,
route: RouteInfo::CreateStageInstance,
})
.await
}
pub async fn create_public_thread(
&self,
channel_id: u64,
message_id: u64,
map: &JsonMap,
) -> Result<GuildChannel> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::CreatePublicThread {
channel_id,
message_id,
},
})
.await
}
pub async fn create_private_thread(
&self,
channel_id: u64,
map: &JsonMap,
) -> Result<GuildChannel> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::CreatePrivateThread {
channel_id,
},
})
.await
}
pub async fn create_emoji(
&self,
guild_id: u64,
map: &Value,
audit_log_reason: Option<&str>,
) -> Result<Emoji> {
self.fire(Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::CreateEmoji {
guild_id,
},
})
.await
}
pub async fn create_followup_message(
&self,
interaction_token: &str,
map: &Value,
) -> Result<Message> {
self.fire(Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: None,
route: RouteInfo::CreateFollowupMessage {
application_id: self.try_application_id()?,
interaction_token,
},
})
.await
}
pub async fn create_followup_message_with_files(
&self,
interaction_token: &str,
map: &Value,
files: impl IntoIterator<Item = AttachmentType<'_>>,
) -> Result<Message> {
self.fire(Request {
body: None,
multipart: Some(Multipart {
files: files.into_iter().map(Into::into).collect(),
payload_json: Some(map.clone()),
fields: vec![],
}),
headers: None,
route: RouteInfo::CreateFollowupMessage {
application_id: self.try_application_id()?,
interaction_token,
},
})
.await
}
pub async fn create_global_application_command(&self, map: &Value) -> Result<Command> {
self.fire(Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: None,
route: RouteInfo::CreateGlobalApplicationCommand {
application_id: self.try_application_id()?,
},
})
.await
}
pub async fn create_global_application_commands(&self, map: &Value) -> Result<Vec<Command>> {
self.fire(Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: None,
route: RouteInfo::CreateGlobalApplicationCommands {
application_id: self.try_application_id()?,
},
})
.await
}
pub async fn create_guild_application_commands(
&self,
guild_id: u64,
map: &Value,
) -> Result<Vec<Command>> {
self.fire(Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: None,
route: RouteInfo::CreateGuildApplicationCommands {
application_id: self.try_application_id()?,
guild_id,
},
})
.await
}
pub async fn create_guild(&self, map: &Value) -> Result<PartialGuild> {
self.fire(Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: None,
route: RouteInfo::CreateGuild,
})
.await
}
pub async fn create_guild_application_command(
&self,
guild_id: u64,
map: &Value,
) -> Result<Command> {
self.fire(Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: None,
route: RouteInfo::CreateGuildApplicationCommand {
application_id: self.try_application_id()?,
guild_id,
},
})
.await
}
pub async fn create_guild_integration(
&self,
guild_id: u64,
integration_id: u64,
map: &Value,
audit_log_reason: Option<&str>,
) -> Result<()> {
self.wind(204, Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::CreateGuildIntegration {
guild_id,
integration_id,
},
})
.await
}
pub async fn create_interaction_response(
&self,
interaction_id: u64,
interaction_token: &str,
map: &Value,
) -> Result<()> {
self.wind(204, Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: None,
route: RouteInfo::CreateInteractionResponse {
interaction_id,
interaction_token,
},
})
.await
}
pub async fn create_interaction_response_with_files(
&self,
interaction_id: u64,
interaction_token: &str,
map: &Value,
files: impl IntoIterator<Item = AttachmentType<'_>>,
) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: Some(Multipart {
files: files.into_iter().map(Into::into).collect(),
payload_json: Some(to_value(map)?),
fields: vec![],
}),
headers: None,
route: RouteInfo::CreateInteractionResponse {
interaction_id,
interaction_token,
},
})
.await
}
pub async fn create_invite(
&self,
channel_id: u64,
map: &JsonMap,
audit_log_reason: Option<&str>,
) -> Result<RichInvite> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::CreateInvite {
channel_id,
},
})
.await
}
pub async fn create_permission(
&self,
channel_id: u64,
target_id: u64,
map: &Value,
) -> Result<()> {
let body = to_vec(map)?;
self.wind(204, Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::CreatePermission {
channel_id,
target_id,
},
})
.await
}
pub async fn create_private_channel(&self, map: &Value) -> Result<PrivateChannel> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::CreatePrivateChannel,
})
.await
}
pub async fn create_reaction(
&self,
channel_id: u64,
message_id: u64,
reaction_type: &ReactionType,
) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::CreateReaction {
reaction: &reaction_type.as_data(),
channel_id,
message_id,
},
})
.await
}
pub async fn create_role(
&self,
guild_id: u64,
map: &JsonMap,
audit_log_reason: Option<&str>,
) -> Result<Role> {
let body = to_vec(map)?;
let mut value = self
.request(Request {
body: Some(&body),
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::CreateRole {
guild_id,
},
})
.await?
.json::<Value>()
.await?;
if let Some(map) = value.as_object_mut() {
map.insert("guild_id".to_string(), from_number(guild_id));
}
from_value(value).map_err(From::from)
}
pub async fn create_scheduled_event(
&self,
guild_id: u64,
map: &JsonMap,
audit_log_reason: Option<&str>,
) -> Result<ScheduledEvent> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::CreateScheduledEvent {
guild_id,
},
})
.await
}
pub async fn create_sticker<'a>(
&self,
guild_id: u64,
map: JsonMap,
file: impl Into<AttachmentType<'a>>,
audit_log_reason: Option<&str>,
) -> Result<Sticker> {
self.fire(Request {
body: None,
multipart: Some(Multipart {
files: vec![file.into()],
fields: map
.into_iter()
.map(|(name, value)| {
(
name.into(),
value
.as_str()
.expect("Create_sticker map must be strings")
.to_string()
.into(),
)
})
.collect(),
payload_json: None,
}),
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::CreateSticker {
guild_id,
},
})
.await
}
pub async fn create_webhook(
&self,
channel_id: u64,
map: &Value,
audit_log_reason: Option<&str>,
) -> Result<Webhook> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::CreateWebhook {
channel_id,
},
})
.await
}
pub async fn delete_channel(&self, channel_id: u64) -> Result<Channel> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteChannel {
channel_id,
},
})
.await
}
pub async fn delete_stage_instance(&self, channel_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteStageInstance {
channel_id,
},
})
.await
}
pub async fn delete_emoji(&self, guild_id: u64, emoji_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteEmoji {
guild_id,
emoji_id,
},
})
.await
}
pub async fn delete_followup_message(
&self,
interaction_token: &str,
message_id: u64,
) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteFollowupMessage {
application_id: self.try_application_id()?,
interaction_token,
message_id,
},
})
.await
}
pub async fn delete_global_application_command(&self, command_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteGlobalApplicationCommand {
application_id: self.try_application_id()?,
command_id,
},
})
.await
}
pub async fn delete_guild(&self, guild_id: u64) -> Result<PartialGuild> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteGuild {
guild_id,
},
})
.await
}
pub async fn delete_guild_application_command(
&self,
guild_id: u64,
command_id: u64,
) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteGuildApplicationCommand {
application_id: self.try_application_id()?,
guild_id,
command_id,
},
})
.await
}
pub async fn delete_guild_integration(&self, guild_id: u64, integration_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteGuildIntegration {
guild_id,
integration_id,
},
})
.await
}
pub async fn delete_invite(&self, code: &str) -> Result<Invite> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteInvite {
code,
},
})
.await
}
pub async fn delete_message(&self, channel_id: u64, message_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteMessage {
channel_id,
message_id,
},
})
.await
}
pub async fn delete_messages(&self, channel_id: u64, map: &Value) -> Result<()> {
self.wind(204, Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: None,
route: RouteInfo::DeleteMessages {
channel_id,
},
})
.await
}
pub async fn delete_message_reactions(&self, channel_id: u64, message_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteMessageReactions {
channel_id,
message_id,
},
})
.await
}
pub async fn delete_message_reaction_emoji(
&self,
channel_id: u64,
message_id: u64,
reaction_type: &ReactionType,
) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteMessageReactionEmoji {
reaction: &reaction_type.as_data(),
channel_id,
message_id,
},
})
.await
}
pub async fn delete_original_interaction_response(
&self,
interaction_token: &str,
) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteOriginalInteractionResponse {
application_id: self.try_application_id()?,
interaction_token,
},
})
.await
}
pub async fn delete_permission(&self, channel_id: u64, target_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeletePermission {
channel_id,
target_id,
},
})
.await
}
pub async fn delete_reaction(
&self,
channel_id: u64,
message_id: u64,
user_id: Option<u64>,
reaction_type: &ReactionType,
) -> Result<()> {
let user = user_id.map_or_else(|| "@me".to_string(), |uid| uid.to_string());
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteReaction {
reaction: &reaction_type.as_data(),
user: &user,
channel_id,
message_id,
},
})
.await
}
pub async fn delete_role(&self, guild_id: u64, role_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteRole {
guild_id,
role_id,
},
})
.await
}
pub async fn delete_scheduled_event(&self, guild_id: u64, event_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteScheduledEvent {
guild_id,
event_id,
},
})
.await
}
pub async fn delete_sticker(
&self,
guild_id: u64,
sticker_id: u64,
audit_log_reason: Option<&str>,
) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::DeleteSticker {
guild_id,
sticker_id,
},
})
.await
}
pub async fn delete_webhook(&self, webhook_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteWebhook {
webhook_id,
},
})
.await
}
pub async fn delete_webhook_with_token(&self, webhook_id: u64, token: &str) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteWebhookWithToken {
token,
webhook_id,
},
})
.await
}
pub async fn edit_channel(
&self,
channel_id: u64,
map: &JsonMap,
audit_log_reason: Option<&str>,
) -> Result<GuildChannel> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::EditChannel {
channel_id,
},
})
.await
}
pub async fn edit_stage_instance(&self, channel_id: u64, map: &Value) -> Result<StageInstance> {
self.fire(Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: None,
route: RouteInfo::EditStageInstance {
channel_id,
},
})
.await
}
pub async fn edit_emoji(
&self,
guild_id: u64,
emoji_id: u64,
map: &Value,
audit_log_reason: Option<&str>,
) -> Result<Emoji> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::EditEmoji {
guild_id,
emoji_id,
},
})
.await
}
pub async fn edit_followup_message(
&self,
interaction_token: &str,
message_id: u64,
map: &Value,
) -> Result<Message> {
self.fire(Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: None,
route: RouteInfo::EditFollowupMessage {
application_id: self.try_application_id()?,
interaction_token,
message_id,
},
})
.await
}
pub async fn edit_followup_message_and_attachments(
&self,
interaction_token: &str,
message_id: u64,
map: &Value,
new_attachments: impl IntoIterator<Item = AttachmentType<'_>>,
) -> Result<Message> {
self.fire(Request {
body: None,
multipart: Some(Multipart {
files: new_attachments.into_iter().map(Into::into).collect(),
payload_json: Some(map.clone()),
fields: vec![],
}),
headers: None,
route: RouteInfo::EditFollowupMessage {
application_id: self.try_application_id()?,
interaction_token,
message_id,
},
})
.await
}
pub async fn get_followup_message(
&self,
interaction_token: &str,
message_id: u64,
) -> Result<Message> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetFollowupMessage {
application_id: self.try_application_id()?,
interaction_token,
message_id,
},
})
.await
}
pub async fn edit_global_application_command(
&self,
command_id: u64,
map: &Value,
) -> Result<Command> {
self.fire(Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: None,
route: RouteInfo::EditGlobalApplicationCommand {
application_id: self.try_application_id()?,
command_id,
},
})
.await
}
pub async fn edit_guild(
&self,
guild_id: u64,
map: &JsonMap,
audit_log_reason: Option<&str>,
) -> Result<PartialGuild> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::EditGuild {
guild_id,
},
})
.await
}
pub async fn edit_guild_application_command(
&self,
guild_id: u64,
command_id: u64,
map: &Value,
) -> Result<Command> {
self.fire(Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: None,
route: RouteInfo::EditGuildApplicationCommand {
application_id: self.try_application_id()?,
guild_id,
command_id,
},
})
.await
}
pub async fn edit_guild_application_command_permissions(
&self,
guild_id: u64,
command_id: u64,
map: &Value,
) -> Result<CommandPermission> {
self.fire(Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: None,
route: RouteInfo::EditGuildApplicationCommandPermission {
application_id: self.try_application_id()?,
guild_id,
command_id,
},
})
.await
}
pub async fn edit_guild_application_commands_permissions(
&self,
guild_id: u64,
map: &Value,
) -> Result<Vec<CommandPermission>> {
self.fire(Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: None,
route: RouteInfo::EditGuildApplicationCommandsPermissions {
application_id: self.try_application_id()?,
guild_id,
},
})
.await
}
pub async fn edit_guild_channel_positions(&self, guild_id: u64, value: &Value) -> Result<()> {
let body = to_vec(value)?;
self.wind(204, Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::EditGuildChannels {
guild_id,
},
})
.await
}
pub async fn edit_guild_widget(&self, guild_id: u64, map: &Value) -> Result<GuildWidget> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::EditGuildWidget {
guild_id,
},
})
.await
}
pub async fn edit_guild_welcome_screen(
&self,
guild_id: u64,
map: &Value,
) -> Result<GuildWelcomeScreen> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::EditGuildWelcomeScreen {
guild_id,
},
})
.await
}
pub async fn edit_member(
&self,
guild_id: u64,
user_id: u64,
map: &JsonMap,
audit_log_reason: Option<&str>,
) -> Result<Member> {
let body = to_vec(map)?;
let mut value = self
.request(Request {
body: Some(&body),
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::EditMember {
guild_id,
user_id,
},
})
.await?
.json::<Value>()
.await?;
if let Some(map) = value.as_object_mut() {
map.insert("guild_id".to_string(), from_number(guild_id));
}
from_value::<Member>(value).map_err(From::from)
}
pub async fn edit_message(
&self,
channel_id: u64,
message_id: u64,
map: &Value,
) -> Result<Message> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::EditMessage {
channel_id,
message_id,
},
})
.await
}
pub async fn edit_message_and_attachments(
&self,
channel_id: u64,
message_id: u64,
map: &Value,
new_attachments: impl IntoIterator<Item = AttachmentType<'_>>,
) -> Result<Message> {
self.fire(Request {
body: None,
multipart: Some(Multipart {
files: new_attachments.into_iter().map(Into::into).collect(),
payload_json: Some(map.clone()),
fields: vec![],
}),
headers: None,
route: RouteInfo::EditMessage {
channel_id,
message_id,
},
})
.await
}
pub async fn crosspost_message(&self, channel_id: u64, message_id: u64) -> Result<Message> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::CrosspostMessage {
channel_id,
message_id,
},
})
.await
}
pub async fn edit_member_me(&self, guild_id: u64, map: &JsonMap) -> Result<Member> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::EditMemberMe {
guild_id,
},
})
.await
}
pub async fn edit_nickname(&self, guild_id: u64, new_nickname: Option<&str>) -> Result<()> {
let map = json!({ "nick": new_nickname });
let body = to_vec(&map)?;
self.wind(200, Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::EditMemberMe {
guild_id,
},
})
.await
}
pub async fn follow_news_channel(
&self,
news_channel_id: u64,
target_channel_id: u64,
) -> Result<FollowedChannel> {
let map = json!({ "webhook_channel_id": target_channel_id });
let body = to_vec(&map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::FollowNewsChannel {
channel_id: news_channel_id,
},
})
.await
}
pub async fn get_original_interaction_response(
&self,
interaction_token: &str,
) -> Result<Message> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetOriginalInteractionResponse {
application_id: self.try_application_id()?,
interaction_token,
},
})
.await
}
pub async fn edit_original_interaction_response(
&self,
interaction_token: &str,
map: &Value,
) -> Result<Message> {
self.fire(Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: None,
route: RouteInfo::EditOriginalInteractionResponse {
application_id: self.try_application_id()?,
interaction_token,
},
})
.await
}
pub async fn edit_profile(&self, map: &JsonMap) -> Result<CurrentUser> {
let body = to_vec(map)?;
let request = self
.request(Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::EditProfile,
})
.await?;
Ok(request.json::<CurrentUser>().await?)
}
pub async fn edit_role(
&self,
guild_id: u64,
role_id: u64,
map: &JsonMap,
audit_log_reason: Option<&str>,
) -> Result<Role> {
let body = to_vec(&map)?;
let mut value = self
.request(Request {
body: Some(&body),
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::EditRole {
guild_id,
role_id,
},
})
.await?
.json::<Value>()
.await?;
if let Some(map) = value.as_object_mut() {
map.insert("guild_id".to_string(), from_number(guild_id));
}
from_value(value).map_err(From::from)
}
pub async fn edit_role_position(
&self,
guild_id: u64,
role_id: u64,
position: u64,
audit_log_reason: Option<&str>,
) -> Result<Vec<Role>> {
let body = to_vec(&json!([{
"id": role_id,
"position": position,
}]))?;
let mut value = self
.request(Request {
body: Some(&body),
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::EditRolePosition {
guild_id,
},
})
.await?
.json::<Value>()
.await?;
if let Some(array) = value.as_array_mut() {
for role in array {
if let Some(map) = role.as_object_mut() {
map.insert("guild_id".to_string(), from_number(guild_id));
}
}
}
from_value(value).map_err(From::from)
}
pub async fn edit_scheduled_event(
&self,
guild_id: u64,
event_id: u64,
map: &JsonMap,
audit_log_reason: Option<&str>,
) -> Result<ScheduledEvent> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::EditScheduledEvent {
guild_id,
event_id,
},
})
.await
}
pub async fn edit_sticker(
&self,
guild_id: u64,
sticker_id: u64,
map: &JsonMap,
audit_log_reason: Option<&str>,
) -> Result<Sticker> {
let body = to_vec(&map)?;
let mut value = self
.request(Request {
body: Some(&body),
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::EditSticker {
guild_id,
sticker_id,
},
})
.await?
.json::<Value>()
.await?;
if let Some(map) = value.as_object_mut() {
map.insert("guild_id".to_string(), from_number(guild_id));
}
from_value(value).map_err(From::from)
}
pub async fn edit_thread(&self, channel_id: u64, map: &JsonMap) -> Result<GuildChannel> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::EditThread {
channel_id,
},
})
.await
}
pub async fn edit_voice_state(&self, guild_id: u64, user_id: u64, map: &JsonMap) -> Result<()> {
let body = to_vec(map)?;
self.wind(204, Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::EditVoiceState {
guild_id,
user_id,
},
})
.await
}
pub async fn edit_voice_state_me(&self, guild_id: u64, map: &JsonMap) -> Result<()> {
let body = to_vec(map)?;
self.wind(204, Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::EditVoiceStateMe {
guild_id,
},
})
.await
}
pub async fn edit_webhook(
&self,
webhook_id: u64,
map: &Value,
audit_log_reason: Option<&str>,
) -> Result<Webhook> {
self.fire(Request {
body: Some(to_string(map)?.as_bytes()),
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::EditWebhook {
webhook_id,
},
})
.await
}
pub async fn edit_webhook_with_token(
&self,
webhook_id: u64,
token: &str,
map: &JsonMap,
) -> Result<Webhook> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::EditWebhookWithToken {
token,
webhook_id,
},
})
.await
}
pub async fn execute_webhook(
&self,
webhook_id: u64,
token: &str,
wait: bool,
map: &JsonMap,
) -> Result<Option<Message>> {
let body = to_vec(map)?;
let mut headers = Headers::new();
headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
let response = self
.request(Request {
body: Some(&body),
multipart: None,
headers: Some(headers),
route: RouteInfo::ExecuteWebhook {
token,
wait,
webhook_id,
},
})
.await?;
if response.status() == StatusCode::NO_CONTENT {
return Ok(None);
}
response.json::<Message>().await.map(Some).map_err(From::from)
}
pub async fn execute_webhook_with_files<'a, T, It: IntoIterator<Item = T>>(
&self,
webhook_id: u64,
token: &str,
wait: bool,
files: It,
map: &JsonMap,
) -> Result<Option<Message>>
where
T: Into<AttachmentType<'a>>,
{
self.fire(Request {
body: None,
multipart: Some(Multipart {
files: files.into_iter().map(Into::into).collect(),
payload_json: Some(to_value(map)?),
fields: vec![],
}),
headers: None,
route: RouteInfo::ExecuteWebhook {
token,
wait,
webhook_id,
},
})
.await
}
pub async fn get_webhook_message(
&self,
webhook_id: u64,
token: &str,
message_id: u64,
) -> Result<Message> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetWebhookMessage {
token,
webhook_id,
message_id,
},
})
.await
}
pub async fn edit_webhook_message(
&self,
webhook_id: u64,
token: &str,
message_id: u64,
map: &JsonMap,
) -> Result<Message> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::EditWebhookMessage {
token,
webhook_id,
message_id,
},
})
.await
}
pub async fn delete_webhook_message(
&self,
webhook_id: u64,
token: &str,
message_id: u64,
) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteWebhookMessage {
token,
webhook_id,
message_id,
},
})
.await
}
pub async fn get_active_maintenances(&self) -> Result<Vec<Maintenance>> {
#[derive(Deserialize)]
struct StatusResponse {
#[serde(default)]
scheduled_maintenances: Vec<Maintenance>,
}
let response = self
.request(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetActiveMaintenance,
})
.await?;
let status: StatusResponse = response.json().await?;
Ok(status.scheduled_maintenances)
}
pub async fn get_bans(&self, guild_id: u64) -> Result<Vec<Ban>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetBans {
guild_id,
},
})
.await
}
pub async fn get_audit_logs(
&self,
guild_id: u64,
action_type: Option<u8>,
user_id: Option<u64>,
before: Option<u64>,
limit: Option<u8>,
) -> Result<AuditLogs> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetAuditLogs {
action_type,
before,
guild_id,
limit,
user_id,
},
})
.await
}
pub async fn get_automod_rules(&self, guild_id: u64) -> Result<Vec<Rule>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetAutoModRules {
guild_id,
},
})
.await
}
pub async fn get_automod_rule(&self, guild_id: u64, rule_id: u64) -> Result<Rule> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetAutoModRule {
guild_id,
rule_id,
},
})
.await
}
pub async fn create_automod_rule(&self, guild_id: u64, map: &JsonMap) -> Result<Rule> {
let body = to_vec(&map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::CreateAutoModRule {
guild_id,
},
})
.await
}
pub async fn edit_automod_rule(
&self,
guild_id: u64,
rule_id: u64,
map: &JsonMap,
) -> Result<Rule> {
let body = to_vec(&map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::EditAutoModRule {
guild_id,
rule_id,
},
})
.await
}
pub async fn delete_automod_rule(&self, guild_id: u64, rule_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::DeleteAutoModRule {
guild_id,
rule_id,
},
})
.await
}
pub async fn get_bot_gateway(&self) -> Result<BotGateway> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetBotGateway,
})
.await
}
pub async fn get_channel_invites(&self, channel_id: u64) -> Result<Vec<RichInvite>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetChannelInvites {
channel_id,
},
})
.await
}
pub async fn get_channel_thread_members(&self, channel_id: u64) -> Result<Vec<ThreadMember>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetChannelThreadMembers {
channel_id,
},
})
.await
}
pub async fn get_guild_active_threads(&self, guild_id: u64) -> Result<ThreadsData> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildActiveThreads {
guild_id,
},
})
.await
}
pub async fn get_channel_archived_public_threads(
&self,
channel_id: u64,
before: Option<u64>,
limit: Option<u64>,
) -> Result<ThreadsData> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetChannelArchivedPublicThreads {
channel_id,
before,
limit,
},
})
.await
}
pub async fn get_channel_archived_private_threads(
&self,
channel_id: u64,
before: Option<u64>,
limit: Option<u64>,
) -> Result<ThreadsData> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetChannelArchivedPrivateThreads {
channel_id,
before,
limit,
},
})
.await
}
pub async fn get_channel_joined_archived_private_threads(
&self,
channel_id: u64,
before: Option<u64>,
limit: Option<u64>,
) -> Result<ThreadsData> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetChannelJoinedPrivateArchivedThreads {
channel_id,
before,
limit,
},
})
.await
}
pub async fn join_thread_channel(&self, channel_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::JoinThread {
channel_id,
},
})
.await
}
pub async fn leave_thread_channel(&self, channel_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::LeaveThread {
channel_id,
},
})
.await
}
pub async fn add_thread_channel_member(&self, channel_id: u64, user_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::AddThreadMember {
channel_id,
user_id,
},
})
.await
}
pub async fn remove_thread_channel_member(&self, channel_id: u64, user_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::RemoveThreadMember {
channel_id,
user_id,
},
})
.await
}
pub async fn get_channel_webhooks(&self, channel_id: u64) -> Result<Vec<Webhook>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetChannelWebhooks {
channel_id,
},
})
.await
}
pub async fn get_channel(&self, channel_id: u64) -> Result<Channel> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetChannel {
channel_id,
},
})
.await
}
pub async fn get_channels(&self, guild_id: u64) -> Result<Vec<GuildChannel>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetChannels {
guild_id,
},
})
.await
}
pub async fn get_stage_instance(&self, channel_id: u64) -> Result<StageInstance> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetStageInstance {
channel_id,
},
})
.await
}
pub async fn get_current_application_info(&self) -> Result<CurrentApplicationInfo> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetCurrentApplicationInfo,
})
.await
}
pub async fn get_current_user(&self) -> Result<CurrentUser> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetCurrentUser,
})
.await
}
pub async fn get_emojis(&self, guild_id: u64) -> Result<Vec<Emoji>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetEmojis {
guild_id,
},
})
.await
}
pub async fn get_emoji(&self, guild_id: u64, emoji_id: u64) -> Result<Emoji> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetEmoji {
guild_id,
emoji_id,
},
})
.await
}
pub async fn get_gateway(&self) -> Result<Gateway> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGateway,
})
.await
}
pub async fn get_global_application_commands(&self) -> Result<Vec<Command>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGlobalApplicationCommands {
application_id: self.try_application_id()?,
with_localizations: false,
},
})
.await
}
pub async fn get_global_application_commands_with_localizations(&self) -> Result<Vec<Command>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGlobalApplicationCommands {
application_id: self.try_application_id()?,
with_localizations: true,
},
})
.await
}
pub async fn get_global_application_command(&self, command_id: u64) -> Result<Command> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGlobalApplicationCommand {
application_id: self.try_application_id()?,
command_id,
},
})
.await
}
pub async fn get_guild(&self, guild_id: u64) -> Result<PartialGuild> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuild {
guild_id,
},
})
.await
}
pub async fn get_guild_with_counts(&self, guild_id: u64) -> Result<PartialGuild> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildWithCounts {
guild_id,
},
})
.await
}
pub async fn get_guild_application_commands(&self, guild_id: u64) -> Result<Vec<Command>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildApplicationCommands {
application_id: self.try_application_id()?,
guild_id,
with_localizations: false,
},
})
.await
}
pub async fn get_guild_application_commands_with_localizations(
&self,
guild_id: u64,
) -> Result<Vec<Command>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildApplicationCommands {
application_id: self.try_application_id()?,
guild_id,
with_localizations: true,
},
})
.await
}
pub async fn get_guild_application_command(
&self,
guild_id: u64,
command_id: u64,
) -> Result<Command> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildApplicationCommand {
application_id: self.try_application_id()?,
guild_id,
command_id,
},
})
.await
}
pub async fn get_guild_application_commands_permissions(
&self,
guild_id: u64,
) -> Result<Vec<CommandPermission>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildApplicationCommandsPermissions {
application_id: self.try_application_id()?,
guild_id,
},
})
.await
}
pub async fn get_guild_application_command_permissions(
&self,
guild_id: u64,
command_id: u64,
) -> Result<CommandPermission> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildApplicationCommandPermissions {
application_id: self.try_application_id()?,
guild_id,
command_id,
},
})
.await
}
pub async fn get_guild_widget(&self, guild_id: u64) -> Result<GuildWidget> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildWidget {
guild_id,
},
})
.await
}
pub async fn get_guild_preview(&self, guild_id: u64) -> Result<GuildPreview> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildPreview {
guild_id,
},
})
.await
}
pub async fn get_guild_welcome_screen(&self, guild_id: u64) -> Result<GuildWelcomeScreen> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildWelcomeScreen {
guild_id,
},
})
.await
}
pub async fn get_guild_integrations(&self, guild_id: u64) -> Result<Vec<Integration>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildIntegrations {
guild_id,
},
})
.await
}
pub async fn get_guild_invites(&self, guild_id: u64) -> Result<Vec<RichInvite>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildInvites {
guild_id,
},
})
.await
}
pub async fn get_guild_vanity_url(&self, guild_id: u64) -> Result<String> {
#[derive(Deserialize)]
struct GuildVanityUrl {
code: String,
}
self.request(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildVanityUrl {
guild_id,
},
})
.await?
.json::<GuildVanityUrl>()
.await
.map(|x| x.code)
.map_err(From::from)
}
pub async fn get_guild_members(
&self,
guild_id: u64,
limit: Option<u64>,
after: Option<u64>,
) -> Result<Vec<Member>> {
if let Some(l) = limit {
if !(1..=constants::MEMBER_FETCH_LIMIT).contains(&l) {
return Err(Error::NotInRange("limit", l, 1, constants::MEMBER_FETCH_LIMIT));
}
}
let mut value = self
.request(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildMembers {
after,
guild_id,
limit,
},
})
.await?
.json::<Value>()
.await?;
if let Some(values) = value.as_array_mut() {
let num = from_number(guild_id);
for value in values {
if let Some(element) = value.as_object_mut() {
element.insert("guild_id".to_string(), num.clone());
}
}
}
from_value::<Vec<Member>>(value).map_err(From::from)
}
pub async fn get_guild_prune_count(&self, guild_id: u64, map: &Value) -> Result<GuildPrune> {
#[derive(Deserialize)]
struct GetGuildPruneCountRequest {
days: u64,
}
let req = from_value::<GetGuildPruneCountRequest>(map.clone())?;
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildPruneCount {
days: req.days,
guild_id,
},
})
.await
}
pub async fn get_guild_regions(&self, guild_id: u64) -> Result<Vec<VoiceRegion>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildRegions {
guild_id,
},
})
.await
}
pub async fn get_guild_roles(&self, guild_id: u64) -> Result<Vec<Role>> {
let mut value = self
.request(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildRoles {
guild_id,
},
})
.await?
.json::<Value>()
.await?;
if let Some(array) = value.as_array_mut() {
for sticker in array {
if let Some(map) = sticker.as_object_mut() {
map.insert("guild_id".to_string(), from_number(guild_id));
}
}
}
from_value(value).map_err(From::from)
}
pub async fn get_scheduled_event(
&self,
guild_id: u64,
event_id: u64,
with_user_count: bool,
) -> Result<ScheduledEvent> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetScheduledEvent {
guild_id,
event_id,
with_user_count,
},
})
.await
}
pub async fn get_scheduled_events(
&self,
guild_id: u64,
with_user_count: bool,
) -> Result<Vec<ScheduledEvent>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetScheduledEvents {
guild_id,
with_user_count,
},
})
.await
}
pub async fn get_scheduled_event_users(
&self,
guild_id: u64,
event_id: u64,
limit: Option<u64>,
target: Option<UserPagination>,
with_member: Option<bool>,
) -> Result<Vec<ScheduledEventUser>> {
let (after, before) = match target {
None => (None, None),
Some(p) => match p {
UserPagination::After(id) => (Some(id.0), None),
UserPagination::Before(id) => (None, Some(id.0)),
},
};
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetScheduledEventUsers {
guild_id,
event_id,
after,
before,
limit,
with_member,
},
})
.await
}
pub async fn get_guild_stickers(&self, guild_id: u64) -> Result<Vec<Sticker>> {
let mut value = self
.request(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildStickers {
guild_id,
},
})
.await?
.json::<Value>()
.await?;
if let Some(array) = value.as_array_mut() {
for role in array {
if let Some(map) = role.as_object_mut() {
map.insert("guild_id".to_string(), from_number(guild_id));
}
}
}
from_value(value).map_err(From::from)
}
pub async fn get_guild_sticker(&self, guild_id: u64, sticker_id: u64) -> Result<Sticker> {
let mut value = self
.request(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildSticker {
guild_id,
sticker_id,
},
})
.await?
.json::<Value>()
.await?;
if let Some(map) = value.as_object_mut() {
map.insert("guild_id".to_string(), from_number(guild_id));
}
from_value(value).map_err(From::from)
}
pub async fn get_guild_webhooks(&self, guild_id: u64) -> Result<Vec<Webhook>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuildWebhooks {
guild_id,
},
})
.await
}
pub async fn get_guilds(
&self,
target: Option<&GuildPagination>,
limit: Option<u64>,
) -> Result<Vec<GuildInfo>> {
let (after, before) = match target {
None => (None, None),
Some(gp) => match gp {
GuildPagination::After(id) => (Some(id.0), None),
GuildPagination::Before(id) => (None, Some(id.0)),
},
};
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetGuilds {
after,
before,
limit,
},
})
.await
}
pub async fn get_invite(
&self,
mut code: &str,
member_counts: bool,
expiration: bool,
event_id: Option<u64>,
) -> Result<Invite> {
#[cfg(feature = "utils")]
{
code = utils::parse_invite(code);
}
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetInvite {
code,
member_counts,
expiration,
event_id,
},
})
.await
}
pub async fn get_member(&self, guild_id: u64, user_id: u64) -> Result<Member> {
let mut value = self
.request(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetMember {
guild_id,
user_id,
},
})
.await?
.json::<Value>()
.await?;
if let Some(map) = value.as_object_mut() {
map.insert("guild_id".to_string(), from_number(guild_id));
}
from_value::<Member>(value).map_err(From::from)
}
pub async fn get_message(&self, channel_id: u64, message_id: u64) -> Result<Message> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetMessage {
channel_id,
message_id,
},
})
.await
}
pub async fn get_messages(&self, channel_id: u64, query: &str) -> Result<Vec<Message>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetMessages {
query: query.to_owned(),
channel_id,
},
})
.await
}
pub async fn get_nitro_stickers(&self) -> Result<Vec<StickerPack>> {
#[derive(Deserialize)]
struct StickerPacks {
sticker_packs: Vec<StickerPack>,
}
self.request(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetStickerPacks,
})
.await?
.json::<StickerPacks>()
.await
.map(|s| s.sticker_packs)
.map_err(From::from)
}
pub async fn get_pins(&self, channel_id: u64) -> Result<Vec<Message>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetPins {
channel_id,
},
})
.await
}
pub async fn get_reaction_users(
&self,
channel_id: u64,
message_id: u64,
reaction_type: &ReactionType,
limit: u8,
after: Option<u64>,
) -> Result<Vec<User>> {
let reaction = reaction_type.as_data();
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetReactionUsers {
after,
channel_id,
limit,
message_id,
reaction,
},
})
.await
}
pub async fn get_sticker(&self, sticker_id: u64) -> Result<Sticker> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetSticker {
sticker_id,
},
})
.await
}
pub async fn get_unresolved_incidents(&self) -> Result<Vec<Incident>> {
#[derive(Deserialize)]
struct StatusResponse {
#[serde(default)]
incidents: Vec<Incident>,
}
let response = self
.request(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetUnresolvedIncidents,
})
.await?;
let status: StatusResponse = response.json().await?;
Ok(status.incidents)
}
pub async fn get_upcoming_maintenances(&self) -> Result<Vec<Maintenance>> {
#[derive(Deserialize)]
struct StatusResponse {
#[serde(default)]
scheduled_maintenances: Vec<Maintenance>,
}
let response = self
.request(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetUpcomingMaintenances,
})
.await?;
let status: StatusResponse = response.json().await?;
Ok(status.scheduled_maintenances)
}
pub async fn get_user(&self, user_id: u64) -> Result<User> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetUser {
user_id,
},
})
.await
}
pub async fn get_user_connections(&self) -> Result<Vec<Connection>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetUserConnections,
})
.await
}
pub async fn get_user_dm_channels(&self) -> Result<Vec<PrivateChannel>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetUserDmChannels,
})
.await
}
pub async fn get_voice_regions(&self) -> Result<Vec<VoiceRegion>> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetVoiceRegions,
})
.await
}
pub async fn get_webhook(&self, webhook_id: u64) -> Result<Webhook> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetWebhook {
webhook_id,
},
})
.await
}
pub async fn get_webhook_with_token(&self, webhook_id: u64, token: &str) -> Result<Webhook> {
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetWebhookWithToken {
token,
webhook_id,
},
})
.await
}
pub async fn get_webhook_from_url(&self, url: &str) -> Result<Webhook> {
let url = Url::parse(url).map_err(HttpError::Url)?;
let (webhook_id, token) = utils::parse_webhook(&url).ok_or(HttpError::InvalidWebhook)?;
self.fire(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::GetWebhookWithToken {
token,
webhook_id,
},
})
.await
}
pub async fn kick_member(&self, guild_id: u64, user_id: u64) -> Result<()> {
self.kick_member_with_reason(guild_id, user_id, "").await
}
pub async fn kick_member_with_reason(
&self,
guild_id: u64,
user_id: u64,
reason: &str,
) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: Some(reason_into_header(reason)),
route: RouteInfo::KickMember {
guild_id,
user_id,
},
})
.await
}
pub async fn leave_guild(&self, guild_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::LeaveGuild {
guild_id,
},
})
.await
}
pub async fn send_files<'a, T, It: IntoIterator<Item = T>>(
&self,
channel_id: u64,
files: It,
map: &JsonMap,
) -> Result<Message>
where
T: Into<AttachmentType<'a>>,
{
self.fire(Request {
body: None,
multipart: Some(Multipart {
files: files.into_iter().map(Into::into).collect(),
payload_json: Some(to_value(map)?),
fields: vec![],
}),
headers: None,
route: RouteInfo::CreateMessage {
channel_id,
},
})
.await
}
pub async fn send_message(&self, channel_id: u64, map: &Value) -> Result<Message> {
let body = to_vec(map)?;
self.fire(Request {
body: Some(&body),
multipart: None,
headers: None,
route: RouteInfo::CreateMessage {
channel_id,
},
})
.await
}
pub async fn pin_message(
&self,
channel_id: u64,
message_id: u64,
audit_log_reason: Option<&str>,
) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::PinMessage {
channel_id,
message_id,
},
})
.await
}
pub async fn remove_ban(
&self,
guild_id: u64,
user_id: u64,
audit_log_reason: Option<&str>,
) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::RemoveBan {
guild_id,
user_id,
},
})
.await
}
pub async fn remove_member_role(
&self,
guild_id: u64,
user_id: u64,
role_id: u64,
audit_log_reason: Option<&str>,
) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::RemoveMemberRole {
guild_id,
user_id,
role_id,
},
})
.await
}
pub async fn search_guild_members(
&self,
guild_id: u64,
query: &str,
limit: Option<u64>,
) -> Result<Vec<Member>> {
let mut value = self
.request(Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::SearchGuildMembers {
guild_id,
query,
limit,
},
})
.await?
.json::<Value>()
.await?;
if let Some(members) = value.as_array_mut() {
for member in members {
if let Some(map) = member.as_object_mut() {
map.insert("guild_id".to_string(), from_number(guild_id));
}
}
}
from_value(value).map_err(From::from)
}
pub async fn start_guild_prune(
&self,
guild_id: u64,
days: u64,
audit_log_reason: Option<&str>,
) -> Result<GuildPrune> {
self.fire(Request {
body: None,
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::StartGuildPrune {
days,
guild_id,
},
})
.await
}
pub async fn start_integration_sync(&self, guild_id: u64, integration_id: u64) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: None,
route: RouteInfo::StartIntegrationSync {
guild_id,
integration_id,
},
})
.await
}
pub fn start_typing(self: &Arc<Self>, channel_id: u64) -> Result<Typing> {
Typing::start(self.clone(), channel_id)
}
pub async fn unpin_message(
&self,
channel_id: u64,
message_id: u64,
audit_log_reason: Option<&str>,
) -> Result<()> {
self.wind(204, Request {
body: None,
multipart: None,
headers: audit_log_reason.map(reason_into_header),
route: RouteInfo::UnpinMessage {
channel_id,
message_id,
},
})
.await
}
pub async fn fire<T: DeserializeOwned>(&self, req: Request<'_>) -> Result<T> {
let response = self.request(req).await?;
response.json::<T>().await.map_err(From::from)
}
#[instrument]
pub async fn request(&self, mut req: Request<'_>) -> Result<ReqwestResponse> {
let response = if self.ratelimiter_disabled {
let request =
req.build(&self.client, &self.token, self.proxy.as_ref()).await?.build()?;
self.client.execute(request).await?
} else {
let ratelimiting_req = RatelimitedRequest::from(req);
self.ratelimiter.perform(ratelimiting_req).await?
};
if response.status().is_success() {
Ok(response)
} else {
Err(Error::Http(Box::new(HttpError::from_response(response).await)))
}
}
pub(super) async fn wind(&self, expected: u16, req: Request<'_>) -> Result<()> {
let response = self.request(req).await?;
if response.status().as_u16() == expected {
return Ok(());
}
debug!("Expected {}, got {}", expected, response.status());
trace!("Unsuccessful response: {:?}", response);
Err(Error::Http(Box::new(HttpError::from_response(response).await)))
}
}
#[cfg(not(feature = "native_tls_backend"))]
fn configure_client_backend(builder: ClientBuilder) -> ClientBuilder {
builder.use_rustls_tls()
}
#[cfg(feature = "native_tls_backend")]
fn configure_client_backend(builder: ClientBuilder) -> ClientBuilder {
builder.use_native_tls()
}
impl AsRef<Http> for Http {
fn as_ref(&self) -> &Http {
self
}
}