tulpje_cache/models/
voice_state.rs1use serde::{Deserialize, Serialize};
2use twilight_model::{
3 id::{
4 Id,
5 marker::{ChannelMarker, GuildMarker, UserMarker},
6 },
7 util::Timestamp,
8 voice::VoiceState,
9};
10
11use crate::{Cache, Error};
12
13#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
14pub struct CachedVoiceState {
15 channel_id: Id<ChannelMarker>,
16 deaf: bool,
17 guild_id: Id<GuildMarker>,
18 mute: bool,
19 request_to_speak_timestamp: Option<Timestamp>,
20 self_deaf: bool,
21 self_mute: bool,
22 self_stream: bool,
23 self_video: bool,
24 session_id: String,
25 suppress: bool,
26 user_id: Id<UserMarker>,
27}
28
29impl From<(Id<ChannelMarker>, Id<GuildMarker>, VoiceState)> for CachedVoiceState {
30 fn from(
31 (channel_id, guild_id, voice_state): (Id<ChannelMarker>, Id<GuildMarker>, VoiceState),
32 ) -> Self {
33 #[expect(
39 clippy::unneeded_field_pattern,
40 reason = "clearer that we're explicitly skipping those fields"
41 )]
42 let VoiceState {
43 channel_id: _,
44 deaf,
45 guild_id: _,
46 member: _,
47 mute,
48 self_deaf,
49 self_mute,
50 self_stream,
51 self_video,
52 session_id,
53 suppress,
54 user_id,
55 request_to_speak_timestamp,
56 } = voice_state;
57
58 Self {
59 channel_id,
60 deaf,
61 guild_id,
62 mute,
63 request_to_speak_timestamp,
64 self_deaf,
65 self_mute,
66 self_stream,
67 self_video,
68 session_id,
69 suppress,
70 user_id,
71 }
72 }
73}
74
75impl PartialEq<VoiceState> for CachedVoiceState {
76 fn eq(&self, other: &VoiceState) -> bool {
77 Some(self.channel_id) == other.channel_id
78 && self.deaf == other.deaf
79 && Some(self.guild_id) == other.guild_id
80 && self.mute == other.mute
81 && self.request_to_speak_timestamp == other.request_to_speak_timestamp
82 && self.self_deaf == other.self_deaf
83 && self.self_mute == other.self_mute
84 && self.self_stream == other.self_stream
85 && self.self_video == other.self_video
86 && self.session_id == other.session_id
87 && self.suppress == other.suppress
88 && self.user_id == other.user_id
89 }
90}
91
92impl Cache {
93 pub(crate) async fn cache_voice_states(
94 &self,
95 voice_states: impl IntoIterator<Item = VoiceState>,
96 ) -> Result<(), Error> {
97 for voice_state in voice_states {
98 self.cache_voice_state(voice_state).await?;
99 }
100
101 Ok(())
102 }
103
104 pub(crate) async fn cache_voice_state(&self, voice_state: VoiceState) -> Result<(), Error> {
105 let Some(guild_id) = voice_state.guild_id else {
107 return Ok(());
108 };
109
110 let user_id = voice_state.user_id;
111
112 if let Some(voice_state) = self.voice_states.get(&(guild_id, user_id)).await? {
114 self.voice_state_channels
115 .remove(&voice_state.channel_id, &(guild_id, user_id))
116 .await?;
117 }
118
119 if let Some(channel_id) = voice_state.channel_id {
120 let cached_voice_state = CachedVoiceState::from((channel_id, guild_id, voice_state));
121
122 self.voice_states
123 .insert(&(guild_id, user_id), &cached_voice_state)
124 .await?;
125 self.voice_state_guilds.insert(&guild_id, &user_id).await?;
126 self.voice_state_channels
127 .insert(&channel_id, &(guild_id, user_id))
128 .await?;
129 } else {
130 self.voice_state_guilds.remove(&guild_id, &user_id).await?;
133 self.voice_states.remove(&(guild_id, user_id)).await?;
134 }
135
136 Ok(())
137 }
138}