Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
3231e45
feat(gateway): add REQUEST_SOUNDBOARD_SOUNDS
HTGAzureX1212 Jul 8, 2025
4ee0e51
feat: update event type flags and gateway intents
HTGAzureX1212 Jul 8, 2025
5e4b6be
fix: request soundboard sounds is not an event from the gatway
HTGAzureX1212 Jul 8, 2025
255ad44
model: add soundboard sound and incoming payloads
HTGAzureX1212 Jul 8, 2025
c30d51e
model: voice channel effect send event
HTGAzureX1212 Jul 8, 2025
bac701b
fmt
HTGAzureX1212 Jul 8, 2025
288a4c4
model: static tests for soundboard
HTGAzureX1212 Jul 8, 2025
4f3922b
gateway, model: add incoming events for guild soundboard sound CRUD a…
HTGAzureX1212 Jul 9, 2025
3f81bbc
gateway, model: add SOUNDBOARD_SOUNDS event
HTGAzureX1212 Jul 9, 2025
9fb32de
fix: soundboard model test
HTGAzureX1212 Jul 9, 2025
4e32089
fix: soundboard model test
HTGAzureX1212 Jul 9, 2025
ed7168b
gateway: assert impl Command
HTGAzureX1212 Jul 9, 2025
0064b31
cache: soundboards not to be cached
HTGAzureX1212 Jul 9, 2025
5d7a627
http-ratelimiting: add paths for http requests
HTGAzureX1212 Jul 9, 2025
8b76d64
http: add send soundboard sound endpoint
HTGAzureX1212 Jul 9, 2025
b9161e4
cache: add soundboard (stubs)
HTGAzureX1212 Jul 13, 2025
108bb95
cache: add create event update cache and fix example
HTGAzureX1212 Jul 13, 2025
3a743b2
cache: use from impl
HTGAzureX1212 Jul 13, 2025
629c54b
fixes
HTGAzureX1212 Jul 13, 2025
7e0b29f
examples: fix
HTGAzureX1212 Jul 13, 2025
2a811b2
cache: add delete event update
HTGAzureX1212 Jul 13, 2025
fcbbd79
fmt
HTGAzureX1212 Jul 13, 2025
15d4ec6
cache: add updates
HTGAzureX1212 Jul 14, 2025
88787ce
http: List Soundboard Default Sounds
HTGAzureX1212 Jul 14, 2025
fbe29ec
fmt
HTGAzureX1212 Jul 14, 2025
5a764b9
http: List Guild Soundboard Sounds
HTGAzureX1212 Jul 14, 2025
54c01ec
http: Get Guild Soundboard Sound
HTGAzureX1212 Jul 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/cache-optimization/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub mod member;
pub mod message;
pub mod presence;
pub mod role;
pub mod soundboard;
pub mod stage_instance;
pub mod sticker;
pub mod user;
Expand All @@ -32,6 +33,7 @@ impl CacheableModels for CustomCacheModels {
type Message = message::MinimalCachedMessage;
type Presence = presence::MinimalCachedPresence;
type Role = role::MinimalCachedRole;
type SoundboardSound = soundboard::MinimalCachedSoundboardSound;
type StageInstance = stage_instance::MinimalCachedStageInstance;
type Sticker = sticker::MinimalCachedSticker;
type User = user::MinimalCachedUser;
Expand Down
35 changes: 35 additions & 0 deletions examples/cache-optimization/models/soundboard.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use twilight_cache_inmemory::traits::CacheableSoundboardSound;
use twilight_model::{
guild::SoundboardSound,
id::{
marker::{GuildMarker, SoundboardSoundMarker},
Id,
},
};

#[derive(Clone, Debug, PartialEq)]
pub struct MinimalCachedSoundboardSound {
pub guild_id: Option<Id<GuildMarker>>,
pub sound_id: Id<SoundboardSoundMarker>,
}

impl CacheableSoundboardSound for MinimalCachedSoundboardSound {
fn guild_id(&self) -> Option<Id<GuildMarker>> {
self.guild_id
}
}

impl From<SoundboardSound> for MinimalCachedSoundboardSound {
fn from(sound: SoundboardSound) -> Self {
Self {
guild_id: sound.guild_id,
sound_id: sound.sound_id,
}
}
}

impl PartialEq<SoundboardSound> for MinimalCachedSoundboardSound {
fn eq(&self, other: &SoundboardSound) -> bool {
self.sound_id == other.sound_id
}
}
2 changes: 2 additions & 0 deletions twilight-cache-inmemory/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ bitflags! {
const STICKER = 1 << 13;
/// Information relating to guild scheduled events.
const GUILD_SCHEDULED_EVENT = 1 << 14;
/// information relating to guild soundboard sounds
const SOUNDBOARD_SOUNDS = 1 << 15;
}
}

Expand Down
1 change: 1 addition & 0 deletions twilight-cache-inmemory/src/event/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod message;
pub mod presence;
pub mod reaction;
pub mod role;
pub mod soundboard;
pub mod stage_instance;
pub mod sticker;
pub mod thread;
Expand Down
76 changes: 76 additions & 0 deletions twilight-cache-inmemory/src/event/soundboard.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use crate::traits::CacheableSoundboardSound;
use crate::{traits::CacheableModels, InMemoryCache, ResourceType, UpdateCache};
use twilight_model::{
gateway::payload::incoming::{
GuildSoundboardSoundCreate, GuildSoundboardSoundDelete, GuildSoundboardSoundUpdate,
GuildSoundboardSoundsUpdate,
},
guild::SoundboardSound,
id::{marker::SoundboardSoundMarker, Id},
};

impl<CacheModels: CacheableModels> InMemoryCache<CacheModels> {
pub(crate) fn cache_soundboard_sounds(
&self,
sounds: impl IntoIterator<Item = SoundboardSound>,
) {
for sound in sounds {
self.cache_soundboard_sound(sound);
}
}

pub(crate) fn cache_soundboard_sound(&self, soundboard_sound: SoundboardSound) {
if let Some(guild_id) = soundboard_sound.guild_id {
self.guild_soundboard_sounds
.entry(guild_id)
.or_default()
.insert(soundboard_sound.sound_id);
}

self.soundboard_sound.insert(
soundboard_sound.sound_id,
CacheModels::SoundboardSound::from(soundboard_sound),
);
}

pub(crate) fn delete_soundboard_sound(&self, sound_id: Id<SoundboardSoundMarker>) {
let Some((_, sound)) = self.soundboard_sound.remove(&sound_id) else {
return;
};
let Some(guild_id) = sound.guild_id() else {
return;
};
let Some(mut sounds) = self.guild_soundboard_sounds.get_mut(&guild_id) else {
return;
};
sounds.remove(&sound_id);
}
}

impl<CacheModels: CacheableModels> UpdateCache<CacheModels> for GuildSoundboardSoundCreate {
fn update(&self, cache: &InMemoryCache<CacheModels>) {
if !cache.wants(ResourceType::SOUNDBOARD_SOUNDS) {
return;
}

cache.cache_soundboard_sound(self.0.clone());
}
}

impl<CacheModels: CacheableModels> UpdateCache<CacheModels> for GuildSoundboardSoundDelete {
fn update(&self, cache: &InMemoryCache<CacheModels>) {
cache.delete_soundboard_sound(self.sound_id);
}
}

impl<CacheModels: CacheableModels> UpdateCache<CacheModels> for GuildSoundboardSoundUpdate {
fn update(&self, cache: &InMemoryCache<CacheModels>) {
cache.cache_soundboard_sound(self.0.clone());
}
}

impl<CacheModels: CacheableModels> UpdateCache<CacheModels> for GuildSoundboardSoundsUpdate {
fn update(&self, cache: &InMemoryCache<CacheModels>) {
cache.cache_soundboard_sounds(self.soundboard_sounds.clone());
}
}
81 changes: 66 additions & 15 deletions twilight-cache-inmemory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ use std::{
use twilight_model::{
channel::{Channel, StageInstance},
gateway::event::Event,
guild::{scheduled_event::GuildScheduledEvent, GuildIntegration, Role},
guild::{scheduled_event::GuildScheduledEvent, GuildIntegration, Role, SoundboardSound},
id::{
marker::{
ChannelMarker, EmojiMarker, GuildMarker, IntegrationMarker, MessageMarker, RoleMarker,
ScheduledEventMarker, StageMarker, StickerMarker, UserMarker,
ScheduledEventMarker, SoundboardSoundMarker, StageMarker, StickerMarker, UserMarker,
},
Id,
},
Expand Down Expand Up @@ -205,6 +205,7 @@ pub struct InMemoryCache<CacheModels: CacheableModels = DefaultCacheModels> {
guild_presences: DashMap<Id<GuildMarker>, HashSet<Id<UserMarker>>>,
guild_roles: DashMap<Id<GuildMarker>, HashSet<Id<RoleMarker>>>,
guild_scheduled_events: DashMap<Id<GuildMarker>, HashSet<Id<ScheduledEventMarker>>>,
guild_soundboard_sounds: DashMap<Id<GuildMarker>, HashSet<Id<SoundboardSoundMarker>>>,
guild_stage_instances: DashMap<Id<GuildMarker>, HashSet<Id<StageMarker>>>,
guild_stickers: DashMap<Id<GuildMarker>, HashSet<Id<StickerMarker>>>,
integrations: DashMap<
Expand All @@ -217,6 +218,7 @@ pub struct InMemoryCache<CacheModels: CacheableModels = DefaultCacheModels> {
roles: DashMap<Id<RoleMarker>, GuildResource<CacheModels::Role>>,
scheduled_events:
DashMap<Id<ScheduledEventMarker>, GuildResource<CacheModels::GuildScheduledEvent>>,
soundboard_sound: DashMap<Id<SoundboardSoundMarker>, CacheModels::SoundboardSound>,
stage_instances: DashMap<Id<StageMarker>, GuildResource<CacheModels::StageInstance>>,
stickers: DashMap<Id<StickerMarker>, GuildResource<CacheModels::Sticker>>,
unavailable_guilds: DashSet<Id<GuildMarker>>,
Expand Down Expand Up @@ -245,6 +247,7 @@ impl CacheableModels for DefaultCacheModels {
type Message = model::CachedMessage;
type Presence = model::CachedPresence;
type Role = Role;
type SoundboardSound = SoundboardSound;
type StageInstance = StageInstance;
type Sticker = model::CachedSticker;
type User = User;
Expand Down Expand Up @@ -474,11 +477,11 @@ impl<CacheModels: CacheableModels> InMemoryCache<CacheModels> {

/// Gets the set of emojis in a guild.
///
/// This requires both the [`GUILDS`] and [`GUILD_EMOJIS_AND_STICKERS`]
/// This requires both the [`GUILDS`] and [`GUILD_EXPRESSIONS`]
/// intents.
///
/// [`GUILDS`]: ::twilight_model::gateway::Intents::GUILDS
/// [`GUILD_EMOJIS_AND_STICKERS`]: ::twilight_model::gateway::Intents::GUILD_EMOJIS_AND_STICKERS
/// [`GUILD_EXPRESSIONS`]: ::twilight_model::gateway::Intents::GUILD_EXPRESSIONS
pub fn guild_emojis(
&self,
guild_id: Id<GuildMarker>,
Expand Down Expand Up @@ -570,11 +573,11 @@ impl<CacheModels: CacheableModels> InMemoryCache<CacheModels> {
/// Gets the set of the stickers in a guild.
///
/// This is an O(m) operation, where m is the amount of stickers in the
/// guild. This requires the [`GUILDS`] and [`GUILD_EMOJIS_AND_STICKERS`]
/// guild. This requires the [`GUILDS`] and [`GUILD_EXPRESSIONS`]
/// intents and the [`STICKER`] resource type.
///
/// [`GUILDS`]: twilight_model::gateway::Intents::GUILDS
/// [`GUILD_EMOJIS_AND_STICKERS`]: ::twilight_model::gateway::Intents::GUILD_EMOJIS_AND_STICKERS
/// [`GUILD_EXPRESSIONS`]: ::twilight_model::gateway::Intents::GUILD_EXPRESSIONS
/// [`STICKER`]: crate::config::ResourceType::STICKER
pub fn guild_stickers(
&self,
Expand All @@ -583,6 +586,24 @@ impl<CacheModels: CacheableModels> InMemoryCache<CacheModels> {
self.guild_stickers.get(&guild_id).map(Reference::new)
}

/// Gets the set of the soundboard sounds in a guild.
///
/// This is an O(m) operation, where m is the amount of stickers in the
/// guild. This requires the [`GUILDS`] and [`GUILD_EXPRESSIONS`]
/// intents and the [`SOUNDBOARD_SOUND`] resource type.
///
/// [`GUILDS`]: twilight_model::gateway::Intents::GUILDS
/// [`GUILD_EXPRESSIONS`]: ::twilight_model::gateway::Intents::GUILD_EXPRESSIONS
/// [`SOUNDBOARD_SOUNDS`]: crate::config::ResourceType::SOUNDBOARD_SOUNDS
pub fn guild_soundboard_sounds(
&self,
guild_id: Id<GuildMarker>,
) -> Option<Reference<'_, Id<GuildMarker>, HashSet<Id<SoundboardSoundMarker>>>> {
self.guild_soundboard_sounds
.get(&guild_id)
.map(Reference::new)
}

/// Gets the set of voice states in a guild.
///
/// This requires both the [`GUILDS`] and [`GUILD_VOICE_STATES`] intents.
Expand Down Expand Up @@ -687,6 +708,21 @@ impl<CacheModels: CacheableModels> InMemoryCache<CacheModels> {
self.scheduled_events.get(&event_id).map(Reference::new)
}

/// Gets a soundboard sound by ID.
///
/// This requires the [`GUILD_EXPRESSIONS`] intent and the [`SOUNDBOARD_SOUNDS`] resource type.
///
/// [`GUILD_EXPRESSIONS`]: ::twilight_model::gateway::Intents::GUILD_EXPRESSIONS
/// [`SOUNDBOARD_SOUNDS`]: crate::config::ResourceType::SOUNDBOARD_SOUNDS
pub fn soundboard_sound(
&self,
soundboard_sound_id: Id<SoundboardSoundMarker>,
) -> Option<Reference<'_, Id<SoundboardSoundMarker>, CacheModels::SoundboardSound>> {
self.soundboard_sound
.get(&soundboard_sound_id)
.map(Reference::new)
}

/// Gets a stage instance by ID.
///
/// This requires the [`GUILDS`] intent.
Expand All @@ -702,10 +738,10 @@ impl<CacheModels: CacheableModels> InMemoryCache<CacheModels> {
/// Gets a sticker by ID.
///
/// This is the O(1) operation. This requires the [`GUILDS`] and the
/// [`GUILD_EMOJIS_AND_STICKERS`] intents and the [`STICKER`] resource type.
/// [`GUILD_EXPRESSIONS`] intents and the [`STICKER`] resource type.
///
/// [`GUILDS`]: twilight_model::gateway::Intents::GUILDS
/// [`GUILD_EMOJIS_AND_STICKERS`]: ::twilight_model::gateway::Intents::GUILD_EMOJIS_AND_STICKERS
/// [`GUILD_EXPRESSIONS`]: ::twilight_model::gateway::Intents::GUILD_EXPRESSIONS
/// [`STICKER`]: crate::config::ResourceType::STICKER
pub fn sticker(
&self,
Expand Down Expand Up @@ -842,6 +878,7 @@ impl<CacheModels: CacheableModels> Default for InMemoryCache<CacheModels> {
guild_presences: DashMap::new(),
guild_roles: DashMap::new(),
guild_scheduled_events: DashMap::new(),
guild_soundboard_sounds: DashMap::new(),
guild_stage_instances: DashMap::new(),
guild_stickers: DashMap::new(),
guilds: DashMap::new(),
Expand All @@ -851,6 +888,7 @@ impl<CacheModels: CacheableModels> Default for InMemoryCache<CacheModels> {
presences: DashMap::new(),
roles: DashMap::new(),
scheduled_events: DashMap::new(),
soundboard_sound: DashMap::new(),
stage_instances: DashMap::new(),
stickers: DashMap::new(),
unavailable_guilds: DashSet::new(),
Expand All @@ -870,13 +908,14 @@ mod private {
ChannelCreate, ChannelDelete, ChannelPinsUpdate, ChannelUpdate, GuildCreate,
GuildDelete, GuildEmojisUpdate, GuildScheduledEventCreate, GuildScheduledEventDelete,
GuildScheduledEventUpdate, GuildScheduledEventUserAdd, GuildScheduledEventUserRemove,
GuildStickersUpdate, GuildUpdate, IntegrationCreate, IntegrationDelete,
IntegrationUpdate, InteractionCreate, MemberAdd, MemberChunk, MemberRemove,
MemberUpdate, MessageCreate, MessageDelete, MessageDeleteBulk, MessageUpdate,
PresenceUpdate, ReactionAdd, ReactionRemove, ReactionRemoveAll, ReactionRemoveEmoji,
Ready, RoleCreate, RoleDelete, RoleUpdate, StageInstanceCreate, StageInstanceDelete,
StageInstanceUpdate, ThreadCreate, ThreadDelete, ThreadListSync, ThreadUpdate,
UnavailableGuild, UserUpdate, VoiceStateUpdate,
GuildSoundboardSoundCreate, GuildSoundboardSoundDelete, GuildSoundboardSoundUpdate,
GuildSoundboardSoundsUpdate, GuildStickersUpdate, GuildUpdate, IntegrationCreate,
IntegrationDelete, IntegrationUpdate, InteractionCreate, MemberAdd, MemberChunk,
MemberRemove, MemberUpdate, MessageCreate, MessageDelete, MessageDeleteBulk,
MessageUpdate, PresenceUpdate, ReactionAdd, ReactionRemove, ReactionRemoveAll,
ReactionRemoveEmoji, Ready, RoleCreate, RoleDelete, RoleUpdate, StageInstanceCreate,
StageInstanceDelete, StageInstanceUpdate, ThreadCreate, ThreadDelete, ThreadListSync,
ThreadUpdate, UnavailableGuild, UserUpdate, VoiceStateUpdate,
},
};

Expand Down Expand Up @@ -928,6 +967,10 @@ mod private {
impl Sealed for GuildScheduledEventUpdate {}
impl Sealed for GuildScheduledEventUserAdd {}
impl Sealed for GuildScheduledEventUserRemove {}
impl Sealed for GuildSoundboardSoundCreate {}
impl Sealed for GuildSoundboardSoundDelete {}
impl Sealed for GuildSoundboardSoundUpdate {}
impl Sealed for GuildSoundboardSoundsUpdate {}
}

/// Implemented for dispatch events.
Expand Down Expand Up @@ -1034,6 +1077,13 @@ impl<CacheModels: CacheableModels> UpdateCache<CacheModels> for Event {
| Event::GatewayReconnect
| Event::GuildAuditLogEntryCreate(_)
| Event::GuildIntegrationsUpdate(_)
// todo
| Event::GuildSoundboardSoundCreate(_)
| Event::GuildSoundboardSoundDelete(_)
| Event::GuildSoundboardSoundUpdate(_)
| Event::GuildSoundboardSoundsUpdate(_)
| Event::SoundboardSounds(_)
// todo
| Event::InviteCreate(_)
| Event::InviteDelete(_)
| Event::MessagePollVoteAdd(_)
Expand All @@ -1042,6 +1092,7 @@ impl<CacheModels: CacheableModels> UpdateCache<CacheModels> for Event {
| Event::ThreadMembersUpdate(_)
| Event::ThreadMemberUpdate(_)
| Event::TypingStart(_)
| Event::VoiceChannelEffectSend(_)
| Event::VoiceServerUpdate(_)
| Event::WebhooksUpdate(_) => {}
}
Expand Down
20 changes: 18 additions & 2 deletions twilight-cache-inmemory/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use twilight_model::{
},
guild::{
scheduled_event::GuildScheduledEvent, Emoji, Guild, GuildIntegration, Member,
PartialMember, Role,
PartialMember, Role, SoundboardSound,
},
id::{
marker::{
Expand All @@ -63,7 +63,7 @@ pub trait CacheableModels: Clone + Debug {
type Guild: CacheableGuild;
/// The cached [`GuildIntegration`] model representation.
type GuildIntegration: CacheableGuildIntegration;
/// The cached [`GuildScheduledEvent` model representation.
/// The cached [`GuildScheduledEvent`] model representation.
type GuildScheduledEvent: CacheableGuildScheduledEvent;
/// The cached [`Member`] model representation.
type Member: CacheableMember;
Expand All @@ -73,6 +73,8 @@ pub trait CacheableModels: Clone + Debug {
type Presence: CacheablePresence;
/// The cached [`Role`] model representation.
type Role: CacheableRole;
/// The cached [`SoundboardSound`] model representation/
type SoundboardSound: CacheableSoundboardSound;
/// The cached [`StageInstance`] model representation.
type StageInstance: CacheableStageInstance;
/// The cached [`Sticker`] model representation.
Expand Down Expand Up @@ -293,6 +295,20 @@ pub trait CacheablePresence:
{
}

/// Trait for a generic cached representation of a [`SoundboardSound`].
pub trait CacheableSoundboardSound:
From<SoundboardSound> + PartialEq<SoundboardSound> + Clone + Debug
{
/// Guild ID of the soundboard sound, if any.
fn guild_id(&self) -> Option<Id<GuildMarker>>;
}

impl CacheableSoundboardSound for SoundboardSound {
fn guild_id(&self) -> Option<Id<GuildMarker>> {
self.guild_id
}
}

/// Trait for a generic cached representation of a [`StageInstance`].
pub trait CacheableStageInstance:
From<StageInstance> + PartialEq<StageInstance> + PartialEq<Self> + Clone + Debug
Expand Down
Loading