Skip to content

Commit

Permalink
feat(http): add get voice state endpoints (#2398)
Browse files Browse the repository at this point in the history
Discord supports endpoints that allow to fetch voice state of the
current user or another user in a guild.
- discord/discord-api-docs#7061

---------

Co-authored-by: Quang Pham <73033278+BooTheDev@users.noreply.github.com>
  • Loading branch information
QuangBoo and QuangBoo authored Jan 4, 2025
1 parent d16782f commit dce54bd
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 12 deletions.
43 changes: 36 additions & 7 deletions twilight-http/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@ mod interaction;

pub use self::{builder::ClientBuilder, interaction::InteractionClient};

use crate::request::application::{
emoji::{
AddApplicationEmoji, DeleteApplicationEmoji, ListApplicationEmojis, UpdateApplicationEmoji,
},
monetization::{
CreateTestEntitlement, CreateTestEntitlementOwner, DeleteTestEntitlement, GetEntitlements,
GetSKUs,
use crate::request::{
application::{
emoji::{
AddApplicationEmoji, DeleteApplicationEmoji, ListApplicationEmojis,
UpdateApplicationEmoji,
},
monetization::{
CreateTestEntitlement, CreateTestEntitlementOwner, DeleteTestEntitlement,
GetEntitlements, GetSKUs,
},
},
guild::user::{GetCurrentUserVoiceState, GetUserVoiceState},
};
#[allow(deprecated)]
use crate::{
Expand Down Expand Up @@ -717,6 +721,18 @@ impl Client {
UpdateCurrentUser::new(self)
}

/// Get voice state of the current user in a guild.
///
/// # Caveats
///
/// - Current user must already have joined a voice/stage channel in this guild.
pub const fn current_user_voice_state(
&self,
guild_id: Id<GuildMarker>,
) -> GetCurrentUserVoiceState<'_> {
GetCurrentUserVoiceState::new(self, guild_id)
}

/// Update the current user's voice state.
///
/// All parameters are optional.
Expand Down Expand Up @@ -2060,6 +2076,19 @@ impl Client {
GetUser::new(self, user_id)
}

/// Get voice state of a user in a guild.
///
/// # Caveats
///
/// - User must already have joined a voice/stage channel in this guild.
pub const fn user_voice_state(
&self,
guild_id: Id<GuildMarker>,
user_id: Id<UserMarker>,
) -> GetUserVoiceState<'_> {
GetUserVoiceState::new(self, guild_id, user_id)
}

/// Update another user's voice state.
///
/// # Caveats
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use crate::{
client::Client,
error::Error,
request::{Request, TryIntoRequest},
response::{Response, ResponseFuture},
routing::Route,
};
use std::future::IntoFuture;
use twilight_model::{
id::{marker::GuildMarker, Id},
voice::VoiceState,
};

/// Get voice state of the current user by guild id.
#[must_use = "requests must be configured and executed"]
pub struct GetCurrentUserVoiceState<'a> {
http: &'a Client,
guild_id: Id<GuildMarker>,
}

impl<'a> GetCurrentUserVoiceState<'a> {
pub(crate) const fn new(http: &'a Client, guild_id: Id<GuildMarker>) -> Self {
Self { http, guild_id }
}
}

impl IntoFuture for GetCurrentUserVoiceState<'_> {
type Output = Result<Response<VoiceState>, Error>;

type IntoFuture = ResponseFuture<VoiceState>;

fn into_future(self) -> Self::IntoFuture {
let http = self.http;

match self.try_into_request() {
Ok(request) => http.request(request),
Err(source) => ResponseFuture::error(source),
}
}
}

impl TryIntoRequest for GetCurrentUserVoiceState<'_> {
fn try_into_request(self) -> Result<Request, Error> {
Ok(Request::from_route(&Route::GetCurrentUserVoiceState {
guild_id: self.guild_id.get(),
}))
}
}
61 changes: 61 additions & 0 deletions twilight-http/src/request/guild/user/get_user_voice_state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use crate::{
client::Client,
error::Error,
request::{Request, TryIntoRequest},
response::{Response, ResponseFuture},
routing::Route,
};
use std::future::IntoFuture;
use twilight_model::{
id::{
marker::{GuildMarker, UserMarker},
Id,
},
voice::VoiceState,
};

/// Get voice state of a user by guild and user ids.
#[must_use = "requests must be configured and executed"]
pub struct GetUserVoiceState<'a> {
http: &'a Client,
guild_id: Id<GuildMarker>,
user_id: Id<UserMarker>,
}

impl<'a> GetUserVoiceState<'a> {
pub(crate) const fn new(
http: &'a Client,
guild_id: Id<GuildMarker>,
user_id: Id<UserMarker>,
) -> Self {
Self {
http,
guild_id,
user_id,
}
}
}

impl IntoFuture for GetUserVoiceState<'_> {
type Output = Result<Response<VoiceState>, Error>;

type IntoFuture = ResponseFuture<VoiceState>;

fn into_future(self) -> Self::IntoFuture {
let http = self.http;

match self.try_into_request() {
Ok(request) => http.request(request),
Err(source) => ResponseFuture::error(source),
}
}
}

impl TryIntoRequest for GetUserVoiceState<'_> {
fn try_into_request(self) -> Result<Request, Error> {
Ok(Request::from_route(&Route::GetUserVoiceState {
guild_id: self.guild_id.get(),
user_id: self.user_id.get(),
}))
}
}
4 changes: 4 additions & 0 deletions twilight-http/src/request/guild/user/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
mod get_current_user_voice_state;
mod get_user_voice_state;
mod update_current_user_voice_state;
mod update_user_voice_state;

pub use self::{
get_current_user_voice_state::GetCurrentUserVoiceState,
get_user_voice_state::GetUserVoiceState,
update_current_user_voice_state::UpdateCurrentUserVoiceState,
update_user_voice_state::UpdateUserVoiceState,
};
7 changes: 6 additions & 1 deletion twilight-http/src/request/try_into_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ mod private {
UpdateGuildSticker,
},
update_guild_onboarding::UpdateGuildOnboarding,
user::{UpdateCurrentUserVoiceState, UpdateUserVoiceState},
user::{
GetCurrentUserVoiceState, GetUserVoiceState, UpdateCurrentUserVoiceState,
UpdateUserVoiceState,
},
CreateGuild, CreateGuildChannel, CreateGuildPrune, DeleteGuild, GetActiveThreads,
GetAuditLog, GetGuild, GetGuildChannels, GetGuildInvites, GetGuildOnboarding,
GetGuildPreview, GetGuildPruneCount, GetGuildVanityUrl, GetGuildVoiceRegions,
Expand Down Expand Up @@ -196,6 +199,7 @@ mod private {
impl Sealed for GetCurrentUserConnections<'_> {}
impl Sealed for GetCurrentUserGuildMember<'_> {}
impl Sealed for GetCurrentUserGuilds<'_> {}
impl Sealed for GetCurrentUserVoiceState<'_> {}
impl Sealed for GetEmoji<'_> {}
impl Sealed for GetEmojis<'_> {}
impl Sealed for GetEntitlements<'_> {}
Expand Down Expand Up @@ -248,6 +252,7 @@ mod private {
impl Sealed for GetThreadMembers<'_> {}
impl Sealed for GetUser<'_> {}
impl Sealed for GetUserApplicationInfo<'_> {}
impl Sealed for GetUserVoiceState<'_> {}
impl Sealed for GetVoiceRegions<'_> {}
impl Sealed for GetWebhook<'_> {}
impl Sealed for GetWebhookMessage<'_> {}
Expand Down
47 changes: 43 additions & 4 deletions twilight-http/src/routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,11 @@ pub enum Route<'a> {
/// ID of the guild.
guild_id: u64,
},
/// Route information to get the current user's voice state.
GetCurrentUserVoiceState {
/// ID of the guild.
guild_id: u64,
},
/// Route information to get an emoji by ID within a guild.
GetEmoji {
/// The ID of the emoji.
Expand Down Expand Up @@ -890,6 +895,13 @@ pub enum Route<'a> {
GetUserConnections,
/// Route information to get the current user's private channels and groups.
GetUserPrivateChannels,
/// Route information to get a user's voice state.
GetUserVoiceState {
/// The ID of the guild.
guild_id: u64,
/// ID of the target user.
user_id: u64,
},
/// Route information to get a list of the voice regions.
GetVoiceRegions,
/// Route information to get a webhook by ID, optionally with a token if the
Expand Down Expand Up @@ -1265,6 +1277,7 @@ impl Route<'_> {
| Self::GetCurrentUserApplicationInfo
| Self::GetCurrentUser
| Self::GetCurrentUserGuildMember { .. }
| Self::GetCurrentUserVoiceState { .. }
| Self::GetEmoji { .. }
| Self::GetEmojis { .. }
| Self::GetEntitlements { .. }
Expand Down Expand Up @@ -1316,9 +1329,10 @@ impl Route<'_> {
| Self::GetTemplates { .. }
| Self::GetThreadMember { .. }
| Self::GetThreadMembers { .. }
| Self::GetUser { .. }
| Self::GetUserConnections
| Self::GetUserPrivateChannels
| Self::GetUser { .. }
| Self::GetUserVoiceState { .. }
| Self::GetVoiceRegions
| Self::GetWebhook { .. }
| Self::GetWebhookMessage { .. }
Expand Down Expand Up @@ -1716,7 +1730,9 @@ impl Route<'_> {
Path::GuildsIdIntegrationsIdSync(guild_id)
}
Self::UnpinMessage { channel_id, .. } => Path::ChannelsIdPinsMessageId(channel_id),
Self::UpdateCurrentUserVoiceState { guild_id }
Self::GetCurrentUserVoiceState { guild_id, .. }
| Self::GetUserVoiceState { guild_id, .. }
| Self::UpdateCurrentUserVoiceState { guild_id }
| Self::UpdateUserVoiceState { guild_id, .. } => Path::GuildsIdVoiceStates(guild_id),
Self::UpdateMessage { channel_id, .. } => {
Path::ChannelsIdMessagesId(Method::Patch, channel_id)
Expand Down Expand Up @@ -2967,7 +2983,8 @@ impl Display for Route<'_> {

f.write_str("/members/@me")
}
Route::UpdateCurrentUserVoiceState { guild_id } => {
Route::GetCurrentUserVoiceState { guild_id }
| Route::UpdateCurrentUserVoiceState { guild_id } => {
f.write_str("guilds/")?;
Display::fmt(guild_id, f)?;

Expand All @@ -2993,7 +3010,8 @@ impl Display for Route<'_> {

f.write_str("/members/@me/nick")
}
Route::UpdateUserVoiceState { guild_id, user_id } => {
Route::GetUserVoiceState { guild_id, user_id }
| Route::UpdateUserVoiceState { guild_id, user_id } => {
f.write_str("guilds/")?;
Display::fmt(guild_id, f)?;
f.write_str("/voice-states/")?;
Expand Down Expand Up @@ -4445,6 +4463,15 @@ mod tests {
assert_eq!(route.to_string(), format!("guilds/{GUILD_ID}/members/@me"));
}

#[test]
fn get_current_user_voice_state() {
let route = Route::GetCurrentUserVoiceState { guild_id: GUILD_ID };
assert_eq!(
route.to_string(),
format!("guilds/{GUILD_ID}/voice-states/@me")
);
}

#[test]
fn update_current_user_voice_state() {
let route = Route::UpdateCurrentUserVoiceState { guild_id: GUILD_ID };
Expand All @@ -4463,6 +4490,18 @@ mod tests {
);
}

#[test]
fn get_user_voice_state() {
let route = Route::GetUserVoiceState {
guild_id: GUILD_ID,
user_id: USER_ID,
};
assert_eq!(
route.to_string(),
format!("guilds/{GUILD_ID}/voice-states/{USER_ID}")
);
}

#[test]
fn update_user_voice_state() {
let route = Route::UpdateUserVoiceState {
Expand Down

0 comments on commit dce54bd

Please sign in to comment.