serenity/model/gateway.rs
1//! Models pertaining to the gateway.
2
3use std::num::NonZeroU16;
4
5use serde::ser::SerializeSeq;
6use url::Url;
7
8use super::prelude::*;
9use super::utils::*;
10
11/// A representation of the data retrieved from the bot gateway endpoint.
12///
13/// This is different from the [`Gateway`], as this includes the number of shards that Discord
14/// recommends to use for a bot user.
15///
16/// This is only applicable to bot users.
17///
18/// [Discord docs](https://discord.com/developers/docs/topics/gateway#get-gateway-bot-json-response).
19#[derive(Clone, Debug, Deserialize, Serialize)]
20#[non_exhaustive]
21pub struct BotGateway {
22 /// The gateway to connect to.
23 pub url: String,
24 /// The number of shards that is recommended to be used by the current bot user.
25 pub shards: u32,
26 /// Information describing how many gateway sessions you can initiate within a ratelimit
27 /// period.
28 pub session_start_limit: SessionStartLimit,
29}
30
31/// Representation of an activity that a [`User`] is performing.
32///
33/// [Discord docs](https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-structure).
34#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
35#[derive(Clone, Debug, Deserialize, Serialize)]
36#[non_exhaustive]
37pub struct Activity {
38 /// The ID of the application for the activity.
39 #[serde(deserialize_with = "deserialize_buggy_id")]
40 #[serde(default)]
41 pub application_id: Option<ApplicationId>,
42 /// Images for the presence and their texts.
43 pub assets: Option<ActivityAssets>,
44 /// What the user is doing.
45 pub details: Option<String>,
46 /// Activity flags describing what the payload includes.
47 pub flags: Option<ActivityFlags>,
48 /// Whether or not the activity is an instanced game session.
49 pub instance: Option<bool>,
50 /// The type of activity being performed
51 #[serde(rename = "type")]
52 pub kind: ActivityType,
53 /// The name of the activity.
54 pub name: String,
55 /// Information about the user's current party.
56 pub party: Option<ActivityParty>,
57 /// Secrets for Rich Presence joining and spectating.
58 pub secrets: Option<ActivitySecrets>,
59 /// The user's current party status.
60 pub state: Option<String>,
61 /// Emoji currently used in custom status
62 pub emoji: Option<ActivityEmoji>,
63 /// Unix timestamps for the start and/or end times of the activity.
64 pub timestamps: Option<ActivityTimestamps>,
65 /// The sync ID of the activity. Mainly used by the Spotify activity type which uses this
66 /// parameter to store the track ID.
67 #[cfg(feature = "unstable_discord_api")]
68 pub sync_id: Option<String>,
69 /// The session ID of the activity. Reserved for specific activity types, such as the Activity
70 /// that is transmitted when a user is listening to Spotify.
71 #[cfg(feature = "unstable_discord_api")]
72 pub session_id: Option<String>,
73 /// The Stream URL if [`Self::kind`] is [`ActivityType::Streaming`].
74 pub url: Option<Url>,
75 /// The buttons of this activity.
76 ///
77 /// **Note**: There can only be up to 2 buttons.
78 #[serde(default, deserialize_with = "deserialize_buttons")]
79 pub buttons: Vec<ActivityButton>,
80 /// Unix timestamp (in milliseconds) of when the activity was added to the user's session
81 pub created_at: u64,
82}
83
84/// [Discord docs](https://discord.com/developers/docs/topics/gateway#activity-object-activity-buttons).
85#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
86#[derive(Clone, Debug, Serialize, Deserialize)]
87#[non_exhaustive]
88pub struct ActivityButton {
89 /// The text shown on the button.
90 pub label: String,
91 /// The url opened when clicking the button.
92 ///
93 /// **Note**: Bots cannot access activity button URL.
94 #[serde(default)]
95 pub url: String,
96}
97
98/// The assets for an activity.
99///
100/// [Discord docs](https://discord.com/developers/docs/topics/gateway#activity-object-activity-assets).
101#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
102#[derive(Clone, Debug, Deserialize, Serialize)]
103#[non_exhaustive]
104pub struct ActivityAssets {
105 /// The ID for a large asset of the activity, usually a snowflake.
106 pub large_image: Option<String>,
107 /// Text displayed when hovering over the large image of the activity.
108 pub large_text: Option<String>,
109 /// The ID for a small asset of the activity, usually a snowflake.
110 pub small_image: Option<String>,
111 /// Text displayed when hovering over the small image of the activity.
112 pub small_text: Option<String>,
113}
114
115bitflags! {
116 /// A set of flags defining what is in an activity's payload.
117 ///
118 /// [Discord docs](https://discord.com/developers/docs/topics/gateway#activity-object-activity-flags).
119 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
120 #[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq)]
121 pub struct ActivityFlags: u64 {
122 /// Whether the activity is an instance activity.
123 const INSTANCE = 1 << 0;
124 /// Whether the activity is joinable.
125 const JOIN = 1 << 1;
126 /// Whether the activity can be spectated.
127 const SPECTATE = 1 << 2;
128 /// Whether a request can be sent to join the user's party.
129 const JOIN_REQUEST = 1 << 3;
130 /// Whether the activity can be synced.
131 const SYNC = 1 << 4;
132 /// Whether the activity can be played.
133 const PLAY = 1 << 5;
134 /// Whether the activity party is friend only.
135 const PARTY_PRIVACY_FRIENDS = 1 << 6;
136 /// Whether the activity party is in a voice channel.
137 const PARTY_PRIVACY_VOICE_CHANNEL = 1 << 7;
138 /// Whether the activity can be embedded.
139 const EMBEDDED = 1 << 8;
140 }
141}
142
143/// Information about an activity's party.
144///
145/// [Discord docs](https://discord.com/developers/docs/game-sdk/activities#data-models-activityparty-struct).
146#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
147#[derive(Clone, Debug, Deserialize, Serialize)]
148#[non_exhaustive]
149pub struct ActivityParty {
150 /// The ID of the party.
151 pub id: Option<String>,
152 /// Used to show the party's current and maximum size.
153 pub size: Option<[u32; 2]>,
154}
155
156/// Secrets for an activity.
157///
158/// [Discord docs](https://discord.com/developers/docs/topics/gateway#activity-object-activity-secrets).
159#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
160#[derive(Clone, Debug, Deserialize, Serialize)]
161#[non_exhaustive]
162pub struct ActivitySecrets {
163 /// The secret for joining a party.
164 pub join: Option<String>,
165 /// The secret for a specific instanced match.
166 #[serde(rename = "match")]
167 pub match_: Option<String>,
168 /// The secret for spectating an activity.
169 pub spectate: Option<String>,
170}
171
172/// Representation of an emoji used in a custom status
173///
174/// [Discord docs](https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-emoji).
175#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
176#[derive(Clone, Debug, Deserialize, Serialize)]
177#[non_exhaustive]
178pub struct ActivityEmoji {
179 /// The name of the emoji.
180 pub name: String,
181 /// The id of the emoji.
182 pub id: Option<EmojiId>,
183 /// Whether this emoji is animated.
184 pub animated: Option<bool>,
185}
186
187enum_number! {
188 /// [Discord docs](https://discord.com/developers/docs/topics/gateway-events#activity-object-activity-types).
189 #[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
190 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
191 #[serde(from = "u8", into = "u8")]
192 #[non_exhaustive]
193 pub enum ActivityType {
194 /// An indicator that the user is playing a game.
195 #[default]
196 Playing = 0,
197 /// An indicator that the user is streaming to a service.
198 Streaming = 1,
199 /// An indicator that the user is listening to something.
200 Listening = 2,
201 /// An indicator that the user is watching something.
202 Watching = 3,
203 /// An indicator that the user uses custom statuses
204 Custom = 4,
205 /// An indicator that the user is competing somewhere.
206 Competing = 5,
207 _ => Unknown(u8),
208 }
209}
210
211/// A representation of the data retrieved from the gateway endpoint.
212///
213/// For the bot-specific gateway, refer to [`BotGateway`].
214///
215/// [Discord docs](https://discord.com/developers/docs/topics/gateway#get-gateway-example-response).
216#[derive(Clone, Debug, Deserialize, Serialize)]
217#[non_exhaustive]
218pub struct Gateway {
219 /// The gateway to connect to.
220 pub url: String,
221}
222
223/// Information detailing the current active status of a [`User`].
224///
225/// [Discord docs](https://discord.com/developers/docs/topics/gateway#client-status-object).
226#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
227#[derive(Clone, Debug, Deserialize, Serialize)]
228#[non_exhaustive]
229pub struct ClientStatus {
230 pub desktop: Option<OnlineStatus>,
231 pub mobile: Option<OnlineStatus>,
232 pub web: Option<OnlineStatus>,
233}
234
235/// Information about the user of a [`Presence`] event.
236///
237/// Fields should be identical to those of [`User`], except that every field but `id` is
238/// optional. This is currently not implemented fully.
239///
240/// [Discord docs](https://discord.com/developers/docs/resources/user#user-object),
241/// [modification description](https://discord.com/developers/docs/topics/gateway-events#presence-update).
242#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
243#[derive(Clone, Debug, Default, Deserialize, Serialize)]
244#[non_exhaustive]
245pub struct PresenceUser {
246 pub id: UserId,
247 pub avatar: Option<ImageHash>,
248 pub bot: Option<bool>,
249 #[serde(default, skip_serializing_if = "Option::is_none", with = "discriminator")]
250 pub discriminator: Option<NonZeroU16>,
251 pub email: Option<String>,
252 pub mfa_enabled: Option<bool>,
253 #[serde(rename = "username")]
254 pub name: Option<String>,
255 pub verified: Option<bool>,
256 pub public_flags: Option<UserPublicFlags>,
257}
258
259impl PresenceUser {
260 /// Attempts to convert this [`PresenceUser`] instance into a [`User`].
261 ///
262 /// If one of [`User`]'s required fields is None in `self`, None is returned.
263 #[must_use]
264 pub fn into_user(self) -> Option<User> {
265 Some(User {
266 avatar: self.avatar,
267 bot: self.bot?,
268 discriminator: self.discriminator,
269 global_name: None,
270 id: self.id,
271 name: self.name?,
272 public_flags: self.public_flags,
273 banner: None,
274 accent_colour: None,
275 member: None,
276 system: false,
277 mfa_enabled: self.mfa_enabled.unwrap_or_default(),
278 locale: None,
279 verified: self.verified,
280 email: self.email,
281 flags: self.public_flags.unwrap_or_default(),
282 premium_type: PremiumType::None,
283 })
284 }
285
286 /// Attempts to convert this [`PresenceUser`] instance into a [`User`].
287 ///
288 /// Will clone individual fields if needed.
289 ///
290 /// If one of [`User`]'s required fields is None in `self`, None is returned.
291 #[must_use]
292 pub fn to_user(&self) -> Option<User> {
293 self.clone().into_user()
294 }
295
296 #[cfg(feature = "cache")] // method is only used with the cache feature enabled
297 pub(crate) fn update_with_user(&mut self, user: &User) {
298 self.id = user.id;
299 if let Some(avatar) = user.avatar {
300 self.avatar = Some(avatar);
301 }
302 self.bot = Some(user.bot);
303 self.discriminator = user.discriminator;
304 self.name = Some(user.name.clone());
305 if let Some(public_flags) = user.public_flags {
306 self.public_flags = Some(public_flags);
307 }
308 }
309}
310
311/// Information detailing the current online status of a [`User`].
312///
313/// [Discord docs](https://discord.com/developers/docs/topics/gateway#presence-update-presence-update-event-fields).
314#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
315#[derive(Clone, Debug, Deserialize, Serialize)]
316#[non_exhaustive]
317pub struct Presence {
318 /// Data about the associated user.
319 pub user: PresenceUser,
320 /// The `GuildId` the presence update is coming from.
321 pub guild_id: Option<GuildId>,
322 /// The user's online status.
323 pub status: OnlineStatus,
324 /// [`User`]'s current activities.
325 #[serde(default)]
326 pub activities: Vec<Activity>,
327 /// The devices a user are currently active on, if available.
328 pub client_status: Option<ClientStatus>,
329}
330
331/// An initial set of information given after IDENTIFYing to the gateway.
332///
333/// [Discord docs](https://discord.com/developers/docs/topics/gateway#ready-ready-event-fields).
334#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
335#[derive(Clone, Debug, Deserialize, Serialize)]
336#[non_exhaustive]
337pub struct Ready {
338 /// API version
339 #[serde(rename = "v")]
340 pub version: u8,
341 /// Information about the user including email
342 pub user: CurrentUser,
343 /// Guilds the user is in
344 pub guilds: Vec<UnavailableGuild>,
345 /// Used for resuming connections
346 pub session_id: String,
347 /// Gateway URL for resuming connections
348 pub resume_gateway_url: String,
349 /// Shard information associated with this session, if sent when identifying
350 pub shard: Option<ShardInfo>,
351 /// Contains id and flags
352 pub application: PartialCurrentApplicationInfo,
353}
354
355/// Information describing how many gateway sessions you can initiate within a ratelimit period.
356///
357/// [Discord docs](https://discord.com/developers/docs/topics/gateway#session-start-limit-object-session-start-limit-structure).
358#[derive(Clone, Debug, Deserialize, Serialize)]
359#[non_exhaustive]
360pub struct SessionStartLimit {
361 /// The number of sessions that you can still initiate within the current ratelimit period.
362 pub remaining: u64,
363 /// The number of milliseconds until the ratelimit period resets.
364 pub reset_after: u64,
365 /// The total number of session starts within the ratelimit period allowed.
366 pub total: u64,
367 /// The number of identify requests allowed per 5 seconds.
368 pub max_concurrency: u64,
369}
370
371#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
372#[derive(Clone, Copy, Debug)]
373pub struct ShardInfo {
374 pub id: ShardId,
375 pub total: u32,
376}
377
378impl ShardInfo {
379 #[must_use]
380 pub(crate) fn new(id: ShardId, total: u32) -> Self {
381 Self {
382 id,
383 total,
384 }
385 }
386}
387
388impl<'de> serde::Deserialize<'de> for ShardInfo {
389 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
390 <(u32, u32)>::deserialize(deserializer).map(|(id, total)| ShardInfo {
391 id: ShardId(id),
392 total,
393 })
394 }
395}
396
397impl serde::Serialize for ShardInfo {
398 fn serialize<S: serde::Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
399 let mut seq = serializer.serialize_seq(Some(2))?;
400 seq.serialize_element(&self.id.0)?;
401 seq.serialize_element(&self.total)?;
402 seq.end()
403 }
404}
405
406/// Timestamps of when a user started and/or is ending their activity.
407///
408/// [Discord docs](https://discord.com/developers/docs/game-sdk/activities#data-models-activitytimestamps-struct).
409#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
410#[derive(Clone, Debug, Deserialize, Serialize)]
411#[non_exhaustive]
412pub struct ActivityTimestamps {
413 pub end: Option<u64>,
414 pub start: Option<u64>,
415}
416
417bitflags! {
418 /// [Gateway Intents] will limit the events your bot will receive via the gateway. By default,
419 /// all intents except [Privileged Intents] are selected.
420 ///
421 /// # What are Intents
422 ///
423 /// A [gateway intent] sets the types of gateway events (e.g. member joins, guild integrations,
424 /// guild emoji updates, ...) the bot shall receive. Carefully picking the needed intents
425 /// greatly helps the bot to scale, as less intents will result in less events to be received
426 /// via the network from Discord and less processing needed for handling the data.
427 ///
428 /// # Privileged Intents
429 ///
430 /// The intents [`GatewayIntents::GUILD_PRESENCES`], [`GatewayIntents::GUILD_MEMBERS`] and
431 /// [`GatewayIntents::MESSAGE_CONTENT`] are [Privileged Intents]. They need to be enabled in
432 /// the *developer portal*.
433 ///
434 /// **Note**: Once the bot is in 100 guilds or more, [the bot must be verified] in order to use
435 /// privileged intents.
436 ///
437 /// [Discord docs](https://discord.com/developers/docs/topics/gateway#list-of-intents).
438 ///
439 /// [Gateway Intents]: https://discord.com/developers/docs/topics/gateway#gateway-intents
440 /// [Privileged Intents]: https://discord.com/developers/docs/topics/gateway#privileged-intents
441 /// [the bot must be verified]: https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting
442 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
443 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
444 pub struct GatewayIntents: u64 {
445 /// Enables the following gateway events:
446 /// - GUILD_CREATE
447 /// - GUILD_UPDATE
448 /// - GUILD_DELETE
449 /// - GUILD_ROLE_CREATE
450 /// - GUILD_ROLE_UPDATE
451 /// - GUILD_ROLE_DELETE
452 /// - CHANNEL_CREATE
453 /// - CHANNEL_UPDATE
454 /// - CHANNEL_DELETE
455 /// - CHANNEL_PINS_UPDATE
456 /// - THREAD_CREATE
457 /// - THREAD_UPDATE
458 /// - THREAD_DELETE
459 /// - THREAD_LIST_SYNC
460 /// - THREAD_MEMBER_UPDATE
461 /// - THREAD_MEMBERS_UPDATE
462 /// - STAGE_INSTANCE_CREATE
463 /// - STAGE_INSTANCE_UPDATE
464 /// - STAGE_INSTANCE_DELETE
465 ///
466 /// **Info:** The THREAD_MEMBERS_UPDATE event contains different data depending on which
467 /// intents are used. See [Discord's Docs](https://discord.com/developers/docs/topics/gateway-events#thread-members-update)
468 /// for more information.
469 const GUILDS = 1;
470 /// Enables the following gateway events:
471 /// - GUILD_MEMBER_ADD
472 /// - GUILD_MEMBER_UPDATE
473 /// - GUILD_MEMBER_REMOVE
474 /// - THREAD_MEMBERS_UPDATE
475 ///
476 /// **Info**: This intent is *privileged*. In order to use it, you must head to your
477 /// application in the Developer Portal and enable the toggle for *Privileged Intents*, as
478 /// well as enabling it in your code.
479 ///
480 /// **Info:** The THREAD_MEMBERS_UPDATE event contains different data depending on which
481 /// intents are used. See [Discord's Docs](https://discord.com/developers/docs/topics/gateway-events#thread-members-update)
482 /// for more information.
483 const GUILD_MEMBERS = 1 << 1;
484
485 /// Enables the following gateway events:
486 /// - GUILD_AUDIT_LOG_ENTRY_CREATE
487 /// - GUILD_BAN_ADD
488 /// - GUILD_BAN_REMOVE
489 const GUILD_MODERATION = 1 << 2;
490 /// Backwards compatibility with old gateway event name. Same as GUILD_MODERATION
491 #[deprecated = "Use [`Self::GUILD_MODERATION`] instead"]
492 const GUILD_BANS = 1 << 2;
493
494 /// Enables the following gateway events:
495 /// - GUILD_EMOJIS_UPDATE
496 /// - GUILD_STICKERS_UPDATE
497 const GUILD_EMOJIS_AND_STICKERS = 1 << 3;
498 /// Enables the following gateway events:
499 /// - GUILD_INTEGRATIONS_UPDATE
500 /// - INTEGRATION_CREATE
501 /// - INTEGRATION_UPDATE
502 /// - INTEGRATION_DELETE
503 const GUILD_INTEGRATIONS = 1 << 4;
504 /// Enables the following gateway event:
505 /// - WEBHOOKS_UPDATE
506 const GUILD_WEBHOOKS = 1 << 5;
507 /// Enables the following gateway events:
508 /// - INVITE_CREATE
509 /// - INVITE_DELETE
510 const GUILD_INVITES = 1 << 6;
511 /// Enables the following gateway event:
512 /// - VOICE_STATE_UPDATE
513 ///
514 /// **Note**: this intent is mandatory for `songbird` to function properly.
515 const GUILD_VOICE_STATES = 1 << 7;
516 /// Enables the following gateway event:
517 /// - PRESENCE_UPDATE
518 ///
519 /// **Info**: This intent is *privileged*. In order to use it, you must head to your
520 /// application in the Developer Portal and enable the toggle for *Privileged Intents*,
521 /// as well as enabling it in your code.
522 const GUILD_PRESENCES = 1 << 8;
523 /// Enables the following gateway events in guilds:
524 /// - MESSAGE_CREATE
525 /// - MESSAGE_UPDATE
526 /// - MESSAGE_DELETE
527 /// - MESSAGE_DELETE_BULK
528 const GUILD_MESSAGES = 1 << 9;
529 /// Enables the following gateway events in guilds:
530 /// - MESSAGE_REACTION_ADD
531 /// - MESSAGE_REACTION_REMOVE
532 /// - MESSAGE_REACTION_REMOVE_ALL
533 /// - MESSAGE_REACTION_REMOVE_EMOJI
534 const GUILD_MESSAGE_REACTIONS = 1 << 10;
535 /// Enable following gateway event:
536 /// - TYPING_START
537 const GUILD_MESSAGE_TYPING = 1 << 11;
538
539 /// Enables the following gateway events for direct messages:
540 /// - MESSAGE_CREATE
541 /// - MESSAGE_UPDATE
542 /// - MESSAGE_DELETE
543 /// - CHANNEL_PINS_UPDATE
544 const DIRECT_MESSAGES = 1 << 12;
545 /// Enable following gateway events for direct messages:
546 /// - MESSAGE_REACTION_ADD
547 /// - MESSAGE_REACTION_REMOVE
548 /// - MESSAGE_REACTION_REMOVE_ALL
549 /// - MESSAGE_REACTION_REMOVE_EMOJI
550 const DIRECT_MESSAGE_REACTIONS = 1 << 13;
551 /// Enables the following gateway events for direct messages:
552 /// - TYPING_START
553 const DIRECT_MESSAGE_TYPING = 1 << 14;
554
555 /// Enables receiving message content in gateway events
556 ///
557 /// See [Discord's Docs](https://discord.com/developers/docs/topics/gateway#message-content-intent) for more information
558 ///
559 /// **Info**: This intent is *privileged*. In order to use it, you must head to your
560 /// application in the Developer Portal and enable the toggle for *Privileged Intents*,
561 /// as well as enabling it in your code.
562 const MESSAGE_CONTENT = 1 << 15;
563
564 /// Enables the following gateway events:
565 /// - GUILD_SCHEDULED_EVENT_CREATE
566 /// - GUILD_SCHEDULED_EVENT_UPDATE
567 /// - GUILD_SCHEDULED_EVENT_DELETE
568 /// - GUILD_SCHEDULED_EVENT_USER_ADD
569 /// - GUILD_SCHEDULED_EVENT_USER_REMOVE
570 const GUILD_SCHEDULED_EVENTS = 1 << 16;
571 /// Enables the following gateway events:
572 /// - AUTO_MODERATION_RULE_CREATE
573 /// - AUTO_MODERATION_RULE_UPDATE
574 /// - AUTO_MODERATION_RULE_DELETE
575 const AUTO_MODERATION_CONFIGURATION = 1 << 20;
576 /// Enables the following gateway events:
577 /// - AUTO_MODERATION_ACTION_EXECUTION
578 const AUTO_MODERATION_EXECUTION = 1 << 21;
579
580 /// Enables the following gateway events for guilds:
581 /// - MESSAGE_POLL_VOTE_ADD
582 /// - MESSAGE_POLL_VOTE_REMOVE
583 const GUILD_MESSAGE_POLLS = 1 << 24;
584 /// Enables the following gateway events for direct messages:
585 /// - MESSAGE_POLL_VOTE_ADD
586 /// - MESSAGE_POLL_VOTE_REMOVE
587 const DIRECT_MESSAGE_POLLS = 1 << 25;
588 }
589}
590
591impl GatewayIntents {
592 /// Gets all of the intents that aren't considered privileged by Discord.
593 #[must_use]
594 pub const fn non_privileged() -> GatewayIntents {
595 // bitflags don't support const evaluation. Workaround.
596 // See: https://github.com/bitflags/bitflags/issues/180
597 Self::privileged().complement()
598 }
599
600 /// Gets all of the intents that are considered privileged by Discord.
601 /// Use of these intents will require explicitly whitelisting the bot.
602 #[must_use]
603 pub const fn privileged() -> GatewayIntents {
604 // bitflags don't support const evaluation. Workaround.
605 // See: https://github.com/bitflags/bitflags/issues/180
606 Self::GUILD_MEMBERS.union(Self::GUILD_PRESENCES).union(Self::MESSAGE_CONTENT)
607 }
608}
609
610#[cfg(feature = "model")]
611impl GatewayIntents {
612 /// Checks if any of the included intents are privileged.
613 #[must_use]
614 pub const fn is_privileged(self) -> bool {
615 self.intersects(Self::privileged())
616 }
617
618 /// Shorthand for checking that the set of intents contains the [GUILDS] intent.
619 ///
620 /// [GUILDS]: Self::GUILDS
621 #[must_use]
622 pub const fn guilds(self) -> bool {
623 self.contains(Self::GUILDS)
624 }
625
626 /// Shorthand for checking that the set of intents contains the [GUILD_MEMBERS] intent.
627 ///
628 /// [GUILD_MEMBERS]: Self::GUILD_MEMBERS
629 #[must_use]
630 pub const fn guild_members(self) -> bool {
631 self.contains(Self::GUILD_MEMBERS)
632 }
633
634 /// Shorthand for checking that the set of intents contains the [GUILD_BANS] intent.
635 ///
636 /// [GUILD_BANS]: Self::GUILD_BANS
637 ///
638 /// This is the same as calling guild_moderation since Discord changed the name
639 #[must_use]
640 #[deprecated = "Use [`Self::guild_moderation`] instead"]
641 pub const fn guild_bans(self) -> bool {
642 #[allow(deprecated)] // this is a deprecated method itself
643 self.contains(Self::GUILD_BANS)
644 }
645
646 /// Shorthand for checking that the set of intents contains the [GUILD_MODERATION] intent.
647 ///
648 /// [GUILD_MODERATION]: Self::GUILD_MODERATION
649 #[must_use]
650 pub const fn guild_moderation(self) -> bool {
651 self.contains(Self::GUILD_MODERATION)
652 }
653
654 /// Shorthand for checking that the set of intents contains the [GUILD_EMOJIS_AND_STICKERS]
655 /// intent.
656 ///
657 /// [GUILD_EMOJIS_AND_STICKERS]: Self::GUILD_EMOJIS_AND_STICKERS
658 #[must_use]
659 pub const fn guild_emojis_and_stickers(self) -> bool {
660 self.contains(Self::GUILD_EMOJIS_AND_STICKERS)
661 }
662
663 /// Shorthand for checking that the set of intents contains the [GUILD_INTEGRATIONS] intent.
664 ///
665 /// [GUILD_INTEGRATIONS]: Self::GUILD_INTEGRATIONS
666 #[must_use]
667 pub const fn guild_integrations(self) -> bool {
668 self.contains(Self::GUILD_INTEGRATIONS)
669 }
670
671 /// Shorthand for checking that the set of intents contains the [GUILD_WEBHOOKS] intent.
672 ///
673 /// [GUILD_WEBHOOKS]: Self::GUILD_WEBHOOKS
674 #[must_use]
675 pub const fn guild_webhooks(self) -> bool {
676 self.contains(Self::GUILD_WEBHOOKS)
677 }
678
679 /// Shorthand for checking that the set of intents contains the [GUILD_INVITES] intent.
680 ///
681 /// [GUILD_INVITES]: Self::GUILD_INVITES
682 #[must_use]
683 pub const fn guild_invites(self) -> bool {
684 self.contains(Self::GUILD_INVITES)
685 }
686
687 /// Shorthand for checking that the set of intents contains the [GUILD_VOICE_STATES] intent.
688 ///
689 /// [GUILD_VOICE_STATES]: Self::GUILD_VOICE_STATES
690 #[must_use]
691 pub const fn guild_voice_states(self) -> bool {
692 self.contains(Self::GUILD_VOICE_STATES)
693 }
694
695 /// Shorthand for checking that the set of intents contains the [GUILD_PRESENCES] intent.
696 ///
697 /// [GUILD_PRESENCES]: Self::GUILD_PRESENCES
698 #[must_use]
699 pub const fn guild_presences(self) -> bool {
700 self.contains(Self::GUILD_PRESENCES)
701 }
702
703 /// Shorthand for checking that the set of intents contains the [GUILD_MESSAGE_REACTIONS]
704 /// intent.
705 ///
706 /// [GUILD_MESSAGE_REACTIONS]: Self::GUILD_MESSAGE_REACTIONS
707 #[must_use]
708 pub const fn guild_message_reactions(self) -> bool {
709 self.contains(Self::GUILD_MESSAGE_REACTIONS)
710 }
711
712 /// Shorthand for checking that the set of intents contains the [GUILD_MESSAGE_TYPING] intent.
713 ///
714 /// [GUILD_MESSAGE_TYPING]: Self::GUILD_MESSAGE_TYPING
715 #[must_use]
716 pub const fn guild_message_typing(self) -> bool {
717 self.contains(Self::GUILD_MESSAGE_TYPING)
718 }
719
720 /// Shorthand for checking that the set of intents contains the [DIRECT_MESSAGES] intent.
721 ///
722 /// [DIRECT_MESSAGES]: Self::DIRECT_MESSAGES
723 #[must_use]
724 pub const fn direct_messages(self) -> bool {
725 self.contains(Self::DIRECT_MESSAGES)
726 }
727
728 /// Shorthand for checking that the set of intents contains the [DIRECT_MESSAGE_REACTIONS]
729 /// intent.
730 ///
731 /// [DIRECT_MESSAGE_REACTIONS]: Self::DIRECT_MESSAGE_REACTIONS
732 #[must_use]
733 pub const fn direct_message_reactions(self) -> bool {
734 self.contains(Self::DIRECT_MESSAGE_REACTIONS)
735 }
736
737 /// Shorthand for checking that the set of intents contains the [DIRECT_MESSAGE_TYPING] intent.
738 ///
739 /// [DIRECT_MESSAGE_TYPING]: Self::DIRECT_MESSAGE_TYPING
740 #[must_use]
741 pub const fn direct_message_typing(self) -> bool {
742 self.contains(Self::DIRECT_MESSAGE_TYPING)
743 }
744
745 /// Shorthand for checking that the set of intents contains the [MESSAGE_CONTENT] intent.
746 ///
747 /// [MESSAGE_CONTENT]: Self::MESSAGE_CONTENT
748 #[must_use]
749 pub const fn message_content(self) -> bool {
750 self.contains(Self::MESSAGE_CONTENT)
751 }
752
753 /// Shorthand for checking that the set of intents contains the [GUILD_SCHEDULED_EVENTS]
754 /// intent.
755 ///
756 /// [GUILD_SCHEDULED_EVENTS]: Self::GUILD_SCHEDULED_EVENTS
757 #[must_use]
758 pub const fn guild_scheduled_events(self) -> bool {
759 self.contains(Self::GUILD_SCHEDULED_EVENTS)
760 }
761
762 /// Shorthand for checking that the set of intents contains the [AUTO_MODERATION_CONFIGURATION]
763 /// intent.
764 ///
765 /// [AUTO_MODERATION_CONFIGURATION]: Self::AUTO_MODERATION_CONFIGURATION
766 #[must_use]
767 pub const fn auto_moderation_configuration(self) -> bool {
768 self.contains(Self::AUTO_MODERATION_CONFIGURATION)
769 }
770
771 /// Shorthand for checking that the set of intents contains the [AUTO_MODERATION_EXECUTION]
772 /// intent.
773 ///
774 /// [AUTO_MODERATION_EXECUTION]: Self::AUTO_MODERATION_EXECUTION
775 #[must_use]
776 pub const fn auto_moderation_execution(self) -> bool {
777 self.contains(Self::AUTO_MODERATION_EXECUTION)
778 }
779}
780
781impl Default for GatewayIntents {
782 fn default() -> Self {
783 Self::non_privileged()
784 }
785}