diff --git a/src/cache/event.rs b/src/cache/event.rs index a8b00cecaa8..87723707329 100644 --- a/src/cache/event.rs +++ b/src/cache/event.rs @@ -28,6 +28,7 @@ use crate::model::event::{ ThreadDeleteEvent, ThreadUpdateEvent, UserUpdateEvent, + VoiceChannelStatusUpdateEvent, VoiceStateUpdateEvent, }; use crate::model::gateway::ShardInfo; @@ -624,3 +625,19 @@ impl CacheUpdate for VoiceStateUpdateEvent { } } } + +impl CacheUpdate for VoiceChannelStatusUpdateEvent { + type Output = String; + + fn update(&mut self, cache: &Cache) -> Option { + if let Some(mut channel) = cache.channels.get_mut(&self.id) { + let old = channel.status.clone(); + channel.status = self.status.clone(); + // Discord updates topic but doesn't fire ChannelUpdate. + channel.topic = self.status.clone(); + old + } else { + None + } + } +} diff --git a/src/client/dispatch.rs b/src/client/dispatch.rs index a503043fbe2..cb231f38e05 100644 --- a/src/client/dispatch.rs +++ b/src/client/dispatch.rs @@ -424,6 +424,18 @@ fn update_cache_with_event(ctx: Context, event: Event) -> Option<(FullEvent, Opt new: event.voice_state, } }, + Event::VoiceChannelStatusUpdate(mut event) => { + let old = if_cache!(update_cache(&ctx, &mut event)); + + FullEvent::VoiceChannelStatusUpdate { + ctx, + old, + status: event.status, + id: event.id, + guild_id: event.guild_id, + } + }, + Event::WebhookUpdate(event) => FullEvent::WebhookUpdate { ctx, guild_id: event.guild_id, diff --git a/src/client/event_handler.rs b/src/client/event_handler.rs index 49357acbea2..1faf82cd07c 100644 --- a/src/client/event_handler.rs +++ b/src/client/event_handler.rs @@ -337,6 +337,11 @@ event_handler! { /// [`GatewayIntents::GUILDS`] is enabled) and the new state of the guild's voice channels. async fn voice_state_update(&self, VoiceStateUpdate { ctx: Context, old: Option, new: VoiceState }); + /// Dispatched when a voice channel's status is updated. + /// + /// Provides the status, channel's id and the guild's id. + async fn voice_channel_status_update(&self, VoiceChannelStatusUpdate { ctx: Context, old: Option, status: Option, id: ChannelId, guild_id: GuildId }); + /// Dispatched when a guild's webhook is updated. /// /// Provides the guild's id and the channel's id the webhook belongs in. diff --git a/src/model/channel/guild_channel.rs b/src/model/channel/guild_channel.rs index ec8c2b6b5b8..17537d1f379 100644 --- a/src/model/channel/guild_channel.rs +++ b/src/model/channel/guild_channel.rs @@ -159,6 +159,10 @@ pub struct GuildChannel { /// /// **Note**: This is only available in a forum or text channel. pub default_thread_rate_limit_per_user: Option, + /// The status of a voice channel. + /// + /// **Note**: This is only available in voice channels. + pub status: Option, /// The default sort order type used to order posts /// /// **Note**: This is only available in a forum. diff --git a/src/model/event.rs b/src/model/event.rs index 1bc3fe0256e..03ed30bd8b6 100644 --- a/src/model/event.rs +++ b/src/model/event.rs @@ -734,6 +734,17 @@ pub struct VoiceStateUpdateEvent { pub voice_state: VoiceState, } +/// Requires [`GatewayIntents::GUILDS`]. +/// +/// [Incomplete documentation](https://github.com/discord/discord-api-docs/pull/6398) +#[derive(Clone, Debug, Deserialize, Serialize)] +#[non_exhaustive] +pub struct VoiceChannelStatusUpdateEvent { + pub status: Option, + pub id: ChannelId, + pub guild_id: GuildId, +} + /// Requires [`GatewayIntents::GUILD_WEBHOOKS`]. /// /// [Discord docs](https://discord.com/developers/docs/topics/gateway-events#webhooks-update). @@ -1149,6 +1160,8 @@ pub enum Event { VoiceStateUpdate(VoiceStateUpdateEvent), /// Voice server information is available VoiceServerUpdate(VoiceServerUpdateEvent), + /// Fired when the status of a Voice Channel changes. + VoiceChannelStatusUpdate(VoiceChannelStatusUpdateEvent), /// A webhook for a [channel][`GuildChannel`] was updated in a [`Guild`]. WebhookUpdate(WebhookUpdateEvent), /// An interaction was created. diff --git a/src/model/guild/audit_log/mod.rs b/src/model/guild/audit_log/mod.rs index 9bb7dc0564e..562d36e0e14 100644 --- a/src/model/guild/audit_log/mod.rs +++ b/src/model/guild/audit_log/mod.rs @@ -35,6 +35,7 @@ pub enum Action { ScheduledEvent(ScheduledEventAction), Thread(ThreadAction), AutoMod(AutoModAction), + VoiceChannelStatus(VoiceChannelStatusAction), Unknown(u8), } @@ -57,6 +58,7 @@ impl Action { Self::ScheduledEvent(x) => x as u8, Self::Thread(x) => x as u8, Self::AutoMod(x) => x as u8, + Self::VoiceChannelStatus(x) => x as u8, Self::Unknown(x) => x, } } @@ -79,6 +81,7 @@ impl Action { 100..=102 => Action::ScheduledEvent(unsafe { transmute(value) }), 110..=112 => Action::Thread(unsafe { transmute(value) }), 140..=145 => Action::AutoMod(unsafe { transmute(value) }), + 192..=193 => Action::VoiceChannelStatus(unsafe { transmute(value) }), _ => Action::Unknown(value), } } @@ -248,6 +251,15 @@ pub enum AutoModAction { UserCommunicationDisabled = 145, } +/// [Incomplete documentation](https://github.com/discord/discord-api-docs/pull/6398) +#[derive(Copy, Clone, Debug)] +#[non_exhaustive] +#[repr(u8)] +pub enum VoiceChannelStatusAction { + StatusUpdate = 192, + StatusDelete = 193, +} + /// [Discord docs](https://discord.com/developers/docs/resources/audit-log#audit-log-object). #[derive(Debug, Deserialize, Serialize)] #[non_exhaustive] @@ -346,6 +358,9 @@ pub struct Options { /// Name of the role if type is "role" #[serde(default)] pub role_name: Option, + /// The status of a voice channel when set. + #[serde(default)] + pub status: Option, } #[cfg(test)]