twilight_model/voice/
voice_state.rs

1use crate::{
2    guild::Member,
3    id::{
4        Id,
5        marker::{ChannelMarker, GuildMarker, UserMarker},
6    },
7    util::Timestamp,
8};
9use serde::{Deserialize, Serialize};
10
11/// User's voice connection status.
12#[allow(clippy::struct_excessive_bools)]
13#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
14pub struct VoiceState {
15    /// Channel this user is connected to.
16    ///
17    /// [`None`] corresponds to being disconnected.
18    pub channel_id: Option<Id<ChannelMarker>>,
19    /// Whether this user is server deafened.
20    pub deaf: bool,
21    /// Guild this voice state is for.
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub guild_id: Option<Id<GuildMarker>>,
24    /// Member this voice state is for.
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub member: Option<Member>,
27    /// Whether this user is server muted.
28    pub mute: bool,
29    /// Whether this user is locally deafened.
30    pub self_deaf: bool,
31    /// Whether this user is locally muted.
32    pub self_mute: bool,
33    /// Whether this user is streaming using "Go Live".
34    #[serde(default)]
35    pub self_stream: bool,
36    /// Whether this user's camera is enabled.
37    pub self_video: bool,
38    /// Session ID for this voice state.
39    ///
40    /// Used to establish a voice websocket connection.
41    pub session_id: String,
42    /// Whether the user's permission to speak is denied.
43    ///
44    /// Only applies to stage channels.
45    pub suppress: bool,
46    /// User this voice state is for.
47    pub user_id: Id<UserMarker>,
48    /// When the user requested to speak.
49    ///
50    /// # serde
51    ///
52    /// This is serialized as an ISO 8601 timestamp in the format of
53    /// "2021-01-01T01-01-01.010000+00:00".
54    pub request_to_speak_timestamp: Option<Timestamp>,
55}
56
57#[cfg(test)]
58mod tests {
59    use super::VoiceState;
60    use crate::{
61        guild::{Member, MemberFlags},
62        id::Id,
63        user::User,
64        util::datetime::{Timestamp, TimestampParseError},
65    };
66    use serde_test::Token;
67    use std::str::FromStr;
68
69    #[test]
70    fn voice_state() {
71        let value = VoiceState {
72            channel_id: Some(Id::new(1)),
73            deaf: false,
74            guild_id: Some(Id::new(2)),
75            member: None,
76            mute: true,
77            self_deaf: false,
78            self_mute: true,
79            self_stream: false,
80            self_video: false,
81            session_id: "a".to_owned(),
82            suppress: true,
83            user_id: Id::new(3),
84            request_to_speak_timestamp: None,
85        };
86
87        serde_test::assert_tokens(
88            &value,
89            &[
90                Token::Struct {
91                    name: "VoiceState",
92                    len: 12,
93                },
94                Token::Str("channel_id"),
95                Token::Some,
96                Token::NewtypeStruct { name: "Id" },
97                Token::Str("1"),
98                Token::Str("deaf"),
99                Token::Bool(false),
100                Token::Str("guild_id"),
101                Token::Some,
102                Token::NewtypeStruct { name: "Id" },
103                Token::Str("2"),
104                Token::Str("mute"),
105                Token::Bool(true),
106                Token::Str("self_deaf"),
107                Token::Bool(false),
108                Token::Str("self_mute"),
109                Token::Bool(true),
110                Token::Str("self_stream"),
111                Token::Bool(false),
112                Token::Str("self_video"),
113                Token::Bool(false),
114                Token::Str("session_id"),
115                Token::Str("a"),
116                Token::Str("suppress"),
117                Token::Bool(true),
118                Token::Str("user_id"),
119                Token::NewtypeStruct { name: "Id" },
120                Token::Str("3"),
121                Token::Str("request_to_speak_timestamp"),
122                Token::None,
123                Token::StructEnd,
124            ],
125        );
126    }
127
128    #[allow(clippy::too_many_lines)]
129    #[test]
130    fn voice_state_complete() -> Result<(), TimestampParseError> {
131        let joined_at = Some(Timestamp::from_str("2015-04-26T06:26:56.936000+00:00")?);
132        let premium_since = Timestamp::from_str("2021-03-16T14:29:19.046000+00:00")?;
133        let request_to_speak_timestamp = Timestamp::from_str("2021-04-21T22:16:50.000000+00:00")?;
134        let flags = MemberFlags::BYPASSES_VERIFICATION | MemberFlags::DID_REJOIN;
135
136        let value = VoiceState {
137            channel_id: Some(Id::new(1)),
138            deaf: false,
139            guild_id: Some(Id::new(2)),
140            member: Some(Member {
141                avatar: None,
142                avatar_decoration_data: None,
143                banner: None,
144                communication_disabled_until: None,
145                deaf: false,
146                flags,
147                joined_at,
148                mute: true,
149                nick: Some("twilight".to_owned()),
150                pending: false,
151                premium_since: Some(premium_since),
152                roles: Vec::new(),
153                user: User {
154                    accent_color: None,
155                    avatar: None,
156                    avatar_decoration: None,
157                    avatar_decoration_data: None,
158                    banner: None,
159                    bot: false,
160                    discriminator: 1,
161                    email: None,
162                    flags: None,
163                    global_name: Some("test".to_owned()),
164                    id: Id::new(3),
165                    locale: None,
166                    mfa_enabled: None,
167                    name: "twilight".to_owned(),
168                    premium_type: None,
169                    primary_guild: None,
170                    public_flags: None,
171                    system: None,
172                    verified: None,
173                },
174            }),
175            mute: true,
176            self_deaf: false,
177            self_mute: true,
178            self_stream: false,
179            self_video: false,
180            session_id: "a".to_owned(),
181            suppress: true,
182            user_id: Id::new(3),
183            request_to_speak_timestamp: Some(request_to_speak_timestamp),
184        };
185
186        serde_test::assert_tokens(
187            &value,
188            &[
189                Token::Struct {
190                    name: "VoiceState",
191                    len: 13,
192                },
193                Token::Str("channel_id"),
194                Token::Some,
195                Token::NewtypeStruct { name: "Id" },
196                Token::Str("1"),
197                Token::Str("deaf"),
198                Token::Bool(false),
199                Token::Str("guild_id"),
200                Token::Some,
201                Token::NewtypeStruct { name: "Id" },
202                Token::Str("2"),
203                Token::Str("member"),
204                Token::Some,
205                Token::Struct {
206                    name: "Member",
207                    len: 10,
208                },
209                Token::Str("communication_disabled_until"),
210                Token::None,
211                Token::Str("deaf"),
212                Token::Bool(false),
213                Token::Str("flags"),
214                Token::U64(flags.bits()),
215                Token::Str("joined_at"),
216                Token::Some,
217                Token::Str("2015-04-26T06:26:56.936000+00:00"),
218                Token::Str("mute"),
219                Token::Bool(true),
220                Token::Str("nick"),
221                Token::Some,
222                Token::Str("twilight"),
223                Token::Str("pending"),
224                Token::Bool(false),
225                Token::Str("premium_since"),
226                Token::Some,
227                Token::Str("2021-03-16T14:29:19.046000+00:00"),
228                Token::Str("roles"),
229                Token::Seq { len: Some(0) },
230                Token::SeqEnd,
231                Token::Str("user"),
232                Token::Struct {
233                    name: "User",
234                    len: 10,
235                },
236                Token::Str("accent_color"),
237                Token::None,
238                Token::Str("avatar"),
239                Token::None,
240                Token::Str("avatar_decoration"),
241                Token::None,
242                Token::Str("avatar_decoration_data"),
243                Token::None,
244                Token::Str("banner"),
245                Token::None,
246                Token::Str("bot"),
247                Token::Bool(false),
248                Token::Str("discriminator"),
249                Token::Str("0001"),
250                Token::Str("global_name"),
251                Token::Some,
252                Token::Str("test"),
253                Token::Str("id"),
254                Token::NewtypeStruct { name: "Id" },
255                Token::Str("3"),
256                Token::Str("username"),
257                Token::Str("twilight"),
258                Token::StructEnd,
259                Token::StructEnd,
260                Token::Str("mute"),
261                Token::Bool(true),
262                Token::Str("self_deaf"),
263                Token::Bool(false),
264                Token::Str("self_mute"),
265                Token::Bool(true),
266                Token::Str("self_stream"),
267                Token::Bool(false),
268                Token::Str("self_video"),
269                Token::Bool(false),
270                Token::Str("session_id"),
271                Token::Str("a"),
272                Token::Str("suppress"),
273                Token::Bool(true),
274                Token::Str("user_id"),
275                Token::NewtypeStruct { name: "Id" },
276                Token::Str("3"),
277                Token::Str("request_to_speak_timestamp"),
278                Token::Some,
279                Token::Str("2021-04-21T22:16:50.000000+00:00"),
280                Token::StructEnd,
281            ],
282        );
283
284        Ok(())
285    }
286}