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 #[serde(rename = "username")]
248 pub name: Option<String>,
249 #[serde(default, skip_serializing_if = "Option::is_none", with = "discriminator")]
250 pub discriminator: Option<NonZeroU16>,
251 pub global_name: Option<String>,
252 pub avatar: Option<ImageHash>,
253 #[serde(default)]
254 pub bot: Option<bool>,
255 #[serde(default)]
256 pub system: Option<bool>,
257 #[serde(default)]
258 pub mfa_enabled: Option<bool>,
259 pub banner: Option<ImageHash>,
260 #[serde(rename = "accent_color")]
261 pub accent_colour: Option<Colour>,
262 pub locale: Option<String>,
263 pub verified: Option<bool>,
264 pub email: Option<String>,
265 #[serde(default)]
266 pub flags: Option<UserPublicFlags>,
267 #[serde(default)]
268 pub premium_type: Option<PremiumType>,
269 pub public_flags: Option<UserPublicFlags>,
270 pub member: Option<Box<PartialMember>>,
271 pub primary_guild: Option<PrimaryGuild>,
272 pub avatar_decoration_data: Option<AvatarDecorationData>,
273 pub collectibles: Option<Collectibles>,
274 // TODO: should really go over these fields at some point and check them.
275}
276
277impl PresenceUser {
278 /// Attempts to convert this [`PresenceUser`] instance into a [`User`].
279 ///
280 /// If one of [`User`]'s required fields is None in `self`, None is returned.
281 #[must_use]
282 pub fn into_user(self) -> Option<User> {
283 Some(User {
284 avatar: self.avatar,
285 bot: self.bot?,
286 discriminator: self.discriminator,
287 global_name: self.global_name,
288 id: self.id,
289 name: self.name?,
290 public_flags: self.public_flags,
291 banner: self.banner,
292 accent_colour: self.accent_colour,
293 member: self.member,
294 system: false,
295 mfa_enabled: self.mfa_enabled.unwrap_or_default(),
296 locale: self.locale,
297 verified: self.verified,
298 email: self.email,
299 flags: self.public_flags.unwrap_or_default(),
300 premium_type: self.premium_type.unwrap_or_default(),
301 primary_guild: self.primary_guild,
302 avatar_decoration_data: self.avatar_decoration_data,
303 collectibles: self.collectibles,
304 })
305 }
306
307 /// Attempts to convert this [`PresenceUser`] instance into a [`User`].
308 ///
309 /// Will clone individual fields if needed.
310 ///
311 /// If one of [`User`]'s required fields is None in `self`, None is returned.
312 #[must_use]
313 pub fn to_user(&self) -> Option<User> {
314 self.clone().into_user()
315 }
316
317 #[cfg(feature = "cache")] // method is only used with the cache feature enabled
318 pub(crate) fn update_with_user(&mut self, user: &User) {
319 self.id = user.id;
320 if let Some(avatar) = user.avatar {
321 self.avatar = Some(avatar);
322 }
323 self.bot = Some(user.bot);
324 self.discriminator = user.discriminator;
325 self.name = Some(user.name.clone());
326 if let Some(public_flags) = user.public_flags {
327 self.public_flags = Some(public_flags);
328 }
329 }
330}
331
332/// Information detailing the current online status of a [`User`].
333///
334/// [Discord docs](https://discord.com/developers/docs/topics/gateway#presence-update-presence-update-event-fields).
335#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
336#[derive(Clone, Debug, Deserialize, Serialize)]
337#[non_exhaustive]
338pub struct Presence {
339 /// Data about the associated user.
340 pub user: PresenceUser,
341 /// The `GuildId` the presence update is coming from.
342 pub guild_id: Option<GuildId>,
343 /// The user's online status.
344 pub status: OnlineStatus,
345 /// [`User`]'s current activities.
346 #[serde(default)]
347 pub activities: Vec<Activity>,
348 /// The devices a user are currently active on, if available.
349 pub client_status: Option<ClientStatus>,
350}
351
352/// An initial set of information given after IDENTIFYing to the gateway.
353///
354/// [Discord docs](https://discord.com/developers/docs/topics/gateway#ready-ready-event-fields).
355#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
356#[derive(Clone, Debug, Deserialize, Serialize)]
357#[non_exhaustive]
358pub struct Ready {
359 /// API version
360 #[serde(rename = "v")]
361 pub version: u8,
362 /// Information about the user including email
363 pub user: CurrentUser,
364 /// Guilds the user is in
365 pub guilds: Vec<UnavailableGuild>,
366 /// Used for resuming connections
367 pub session_id: String,
368 /// Gateway URL for resuming connections
369 pub resume_gateway_url: String,
370 /// Shard information associated with this session, if sent when identifying
371 pub shard: Option<ShardInfo>,
372 /// Contains id and flags
373 pub application: PartialCurrentApplicationInfo,
374}
375
376/// Information describing how many gateway sessions you can initiate within a ratelimit period.
377///
378/// [Discord docs](https://discord.com/developers/docs/topics/gateway#session-start-limit-object-session-start-limit-structure).
379#[derive(Clone, Debug, Deserialize, Serialize)]
380#[non_exhaustive]
381pub struct SessionStartLimit {
382 /// The number of sessions that you can still initiate within the current ratelimit period.
383 pub remaining: u64,
384 /// The number of milliseconds until the ratelimit period resets.
385 pub reset_after: u64,
386 /// The total number of session starts within the ratelimit period allowed.
387 pub total: u64,
388 /// The number of identify requests allowed per 5 seconds.
389 pub max_concurrency: u64,
390}
391
392#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
393#[derive(Clone, Copy, Debug)]
394pub struct ShardInfo {
395 pub id: ShardId,
396 pub total: u32,
397}
398
399impl ShardInfo {
400 #[must_use]
401 pub(crate) fn new(id: ShardId, total: u32) -> Self {
402 Self {
403 id,
404 total,
405 }
406 }
407}
408
409impl<'de> serde::Deserialize<'de> for ShardInfo {
410 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
411 <(u32, u32)>::deserialize(deserializer).map(|(id, total)| ShardInfo {
412 id: ShardId(id),
413 total,
414 })
415 }
416}
417
418impl serde::Serialize for ShardInfo {
419 fn serialize<S: serde::Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
420 let mut seq = serializer.serialize_seq(Some(2))?;
421 seq.serialize_element(&self.id.0)?;
422 seq.serialize_element(&self.total)?;
423 seq.end()
424 }
425}
426
427/// Timestamps of when a user started and/or is ending their activity.
428///
429/// [Discord docs](https://discord.com/developers/docs/game-sdk/activities#data-models-activitytimestamps-struct).
430#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
431#[derive(Clone, Debug, Deserialize, Serialize)]
432#[non_exhaustive]
433pub struct ActivityTimestamps {
434 pub end: Option<u64>,
435 pub start: Option<u64>,
436}
437
438bitflags! {
439 /// [Gateway Intents] will limit the events your bot will receive via the gateway. By default,
440 /// all intents except [Privileged Intents] are selected.
441 ///
442 /// # What are Intents
443 ///
444 /// A [gateway intent] sets the types of gateway events (e.g. member joins, guild integrations,
445 /// guild emoji updates, ...) the bot shall receive. Carefully picking the needed intents
446 /// greatly helps the bot to scale, as less intents will result in less events to be received
447 /// via the network from Discord and less processing needed for handling the data.
448 ///
449 /// # Privileged Intents
450 ///
451 /// The intents [`GatewayIntents::GUILD_PRESENCES`], [`GatewayIntents::GUILD_MEMBERS`] and
452 /// [`GatewayIntents::MESSAGE_CONTENT`] are [Privileged Intents]. They need to be enabled in
453 /// the *developer portal*.
454 ///
455 /// **Note**: Once the bot is in 100 guilds or more, [the bot must be verified] in order to use
456 /// privileged intents.
457 ///
458 /// [Discord docs](https://discord.com/developers/docs/topics/gateway#list-of-intents).
459 ///
460 /// [Gateway Intents]: https://discord.com/developers/docs/topics/gateway#gateway-intents
461 /// [Privileged Intents]: https://discord.com/developers/docs/topics/gateway#privileged-intents
462 /// [the bot must be verified]: https://support.discord.com/hc/en-us/articles/360040720412-Bot-Verification-and-Data-Whitelisting
463 #[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
464 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
465 pub struct GatewayIntents: u64 {
466 /// Enables the following gateway events:
467 /// - GUILD_CREATE
468 /// - GUILD_UPDATE
469 /// - GUILD_DELETE
470 /// - GUILD_ROLE_CREATE
471 /// - GUILD_ROLE_UPDATE
472 /// - GUILD_ROLE_DELETE
473 /// - CHANNEL_CREATE
474 /// - CHANNEL_UPDATE
475 /// - CHANNEL_DELETE
476 /// - CHANNEL_PINS_UPDATE
477 /// - THREAD_CREATE
478 /// - THREAD_UPDATE
479 /// - THREAD_DELETE
480 /// - THREAD_LIST_SYNC
481 /// - THREAD_MEMBER_UPDATE
482 /// - THREAD_MEMBERS_UPDATE
483 /// - STAGE_INSTANCE_CREATE
484 /// - STAGE_INSTANCE_UPDATE
485 /// - STAGE_INSTANCE_DELETE
486 ///
487 /// **Info:** The THREAD_MEMBERS_UPDATE event contains different data depending on which
488 /// intents are used. See [Discord's Docs](https://discord.com/developers/docs/topics/gateway-events#thread-members-update)
489 /// for more information.
490 const GUILDS = 1;
491 /// Enables the following gateway events:
492 /// - GUILD_MEMBER_ADD
493 /// - GUILD_MEMBER_UPDATE
494 /// - GUILD_MEMBER_REMOVE
495 /// - THREAD_MEMBERS_UPDATE
496 ///
497 /// **Info**: This intent is *privileged*. In order to use it, you must head to your
498 /// application in the Developer Portal and enable the toggle for *Privileged Intents*, as
499 /// well as enabling it in your code.
500 ///
501 /// **Info:** The THREAD_MEMBERS_UPDATE event contains different data depending on which
502 /// intents are used. See [Discord's Docs](https://discord.com/developers/docs/topics/gateway-events#thread-members-update)
503 /// for more information.
504 const GUILD_MEMBERS = 1 << 1;
505
506 /// Enables the following gateway events:
507 /// - GUILD_AUDIT_LOG_ENTRY_CREATE
508 /// - GUILD_BAN_ADD
509 /// - GUILD_BAN_REMOVE
510 const GUILD_MODERATION = 1 << 2;
511 /// Backwards compatibility with old gateway event name. Same as GUILD_MODERATION
512 #[deprecated = "Use [`Self::GUILD_MODERATION`] instead"]
513 const GUILD_BANS = 1 << 2;
514
515 /// Enables the following gateway events:
516 /// - GUILD_EMOJIS_UPDATE
517 /// - GUILD_STICKERS_UPDATE
518 const GUILD_EMOJIS_AND_STICKERS = 1 << 3;
519 /// Enables the following gateway events:
520 /// - GUILD_INTEGRATIONS_UPDATE
521 /// - INTEGRATION_CREATE
522 /// - INTEGRATION_UPDATE
523 /// - INTEGRATION_DELETE
524 const GUILD_INTEGRATIONS = 1 << 4;
525 /// Enables the following gateway event:
526 /// - WEBHOOKS_UPDATE
527 const GUILD_WEBHOOKS = 1 << 5;
528 /// Enables the following gateway events:
529 /// - INVITE_CREATE
530 /// - INVITE_DELETE
531 const GUILD_INVITES = 1 << 6;
532 /// Enables the following gateway event:
533 /// - VOICE_STATE_UPDATE
534 ///
535 /// **Note**: this intent is mandatory for `songbird` to function properly.
536 const GUILD_VOICE_STATES = 1 << 7;
537 /// Enables the following gateway event:
538 /// - PRESENCE_UPDATE
539 ///
540 /// **Info**: This intent is *privileged*. In order to use it, you must head to your
541 /// application in the Developer Portal and enable the toggle for *Privileged Intents*,
542 /// as well as enabling it in your code.
543 const GUILD_PRESENCES = 1 << 8;
544 /// Enables the following gateway events in guilds:
545 /// - MESSAGE_CREATE
546 /// - MESSAGE_UPDATE
547 /// - MESSAGE_DELETE
548 /// - MESSAGE_DELETE_BULK
549 const GUILD_MESSAGES = 1 << 9;
550 /// Enables the following gateway events in guilds:
551 /// - MESSAGE_REACTION_ADD
552 /// - MESSAGE_REACTION_REMOVE
553 /// - MESSAGE_REACTION_REMOVE_ALL
554 /// - MESSAGE_REACTION_REMOVE_EMOJI
555 const GUILD_MESSAGE_REACTIONS = 1 << 10;
556 /// Enable following gateway event:
557 /// - TYPING_START
558 const GUILD_MESSAGE_TYPING = 1 << 11;
559
560 /// Enables the following gateway events for direct messages:
561 /// - MESSAGE_CREATE
562 /// - MESSAGE_UPDATE
563 /// - MESSAGE_DELETE
564 /// - CHANNEL_PINS_UPDATE
565 const DIRECT_MESSAGES = 1 << 12;
566 /// Enable following gateway events for direct messages:
567 /// - MESSAGE_REACTION_ADD
568 /// - MESSAGE_REACTION_REMOVE
569 /// - MESSAGE_REACTION_REMOVE_ALL
570 /// - MESSAGE_REACTION_REMOVE_EMOJI
571 const DIRECT_MESSAGE_REACTIONS = 1 << 13;
572 /// Enables the following gateway events for direct messages:
573 /// - TYPING_START
574 const DIRECT_MESSAGE_TYPING = 1 << 14;
575
576 /// Enables receiving message content in gateway events
577 ///
578 /// See [Discord's Docs](https://discord.com/developers/docs/topics/gateway#message-content-intent) for more information
579 ///
580 /// **Info**: This intent is *privileged*. In order to use it, you must head to your
581 /// application in the Developer Portal and enable the toggle for *Privileged Intents*,
582 /// as well as enabling it in your code.
583 const MESSAGE_CONTENT = 1 << 15;
584
585 /// Enables the following gateway events:
586 /// - GUILD_SCHEDULED_EVENT_CREATE
587 /// - GUILD_SCHEDULED_EVENT_UPDATE
588 /// - GUILD_SCHEDULED_EVENT_DELETE
589 /// - GUILD_SCHEDULED_EVENT_USER_ADD
590 /// - GUILD_SCHEDULED_EVENT_USER_REMOVE
591 const GUILD_SCHEDULED_EVENTS = 1 << 16;
592 /// Enables the following gateway events:
593 /// - AUTO_MODERATION_RULE_CREATE
594 /// - AUTO_MODERATION_RULE_UPDATE
595 /// - AUTO_MODERATION_RULE_DELETE
596 const AUTO_MODERATION_CONFIGURATION = 1 << 20;
597 /// Enables the following gateway events:
598 /// - AUTO_MODERATION_ACTION_EXECUTION
599 const AUTO_MODERATION_EXECUTION = 1 << 21;
600
601 /// Enables the following gateway events for guilds:
602 /// - MESSAGE_POLL_VOTE_ADD
603 /// - MESSAGE_POLL_VOTE_REMOVE
604 const GUILD_MESSAGE_POLLS = 1 << 24;
605 /// Enables the following gateway events for direct messages:
606 /// - MESSAGE_POLL_VOTE_ADD
607 /// - MESSAGE_POLL_VOTE_REMOVE
608 const DIRECT_MESSAGE_POLLS = 1 << 25;
609 }
610}
611
612impl GatewayIntents {
613 /// Gets all of the intents that aren't considered privileged by Discord.
614 #[must_use]
615 pub const fn non_privileged() -> GatewayIntents {
616 // bitflags don't support const evaluation. Workaround.
617 // See: https://github.com/bitflags/bitflags/issues/180
618 Self::privileged().complement()
619 }
620
621 /// Gets all of the intents that are considered privileged by Discord.
622 /// Use of these intents will require explicitly whitelisting the bot.
623 #[must_use]
624 pub const fn privileged() -> GatewayIntents {
625 // bitflags don't support const evaluation. Workaround.
626 // See: https://github.com/bitflags/bitflags/issues/180
627 Self::GUILD_MEMBERS.union(Self::GUILD_PRESENCES).union(Self::MESSAGE_CONTENT)
628 }
629}
630
631#[cfg(feature = "model")]
632impl GatewayIntents {
633 /// Checks if any of the included intents are privileged.
634 #[must_use]
635 pub const fn is_privileged(self) -> bool {
636 self.intersects(Self::privileged())
637 }
638
639 /// Shorthand for checking that the set of intents contains the [GUILDS] intent.
640 ///
641 /// [GUILDS]: Self::GUILDS
642 #[must_use]
643 pub const fn guilds(self) -> bool {
644 self.contains(Self::GUILDS)
645 }
646
647 /// Shorthand for checking that the set of intents contains the [GUILD_MEMBERS] intent.
648 ///
649 /// [GUILD_MEMBERS]: Self::GUILD_MEMBERS
650 #[must_use]
651 pub const fn guild_members(self) -> bool {
652 self.contains(Self::GUILD_MEMBERS)
653 }
654
655 /// Shorthand for checking that the set of intents contains the [GUILD_BANS] intent.
656 ///
657 /// [GUILD_BANS]: Self::GUILD_BANS
658 ///
659 /// This is the same as calling guild_moderation since Discord changed the name
660 #[must_use]
661 #[deprecated = "Use [`Self::guild_moderation`] instead"]
662 pub const fn guild_bans(self) -> bool {
663 #[allow(deprecated)] // this is a deprecated method itself
664 self.contains(Self::GUILD_BANS)
665 }
666
667 /// Shorthand for checking that the set of intents contains the [GUILD_MODERATION] intent.
668 ///
669 /// [GUILD_MODERATION]: Self::GUILD_MODERATION
670 #[must_use]
671 pub const fn guild_moderation(self) -> bool {
672 self.contains(Self::GUILD_MODERATION)
673 }
674
675 /// Shorthand for checking that the set of intents contains the [GUILD_EMOJIS_AND_STICKERS]
676 /// intent.
677 ///
678 /// [GUILD_EMOJIS_AND_STICKERS]: Self::GUILD_EMOJIS_AND_STICKERS
679 #[must_use]
680 pub const fn guild_emojis_and_stickers(self) -> bool {
681 self.contains(Self::GUILD_EMOJIS_AND_STICKERS)
682 }
683
684 /// Shorthand for checking that the set of intents contains the [GUILD_INTEGRATIONS] intent.
685 ///
686 /// [GUILD_INTEGRATIONS]: Self::GUILD_INTEGRATIONS
687 #[must_use]
688 pub const fn guild_integrations(self) -> bool {
689 self.contains(Self::GUILD_INTEGRATIONS)
690 }
691
692 /// Shorthand for checking that the set of intents contains the [GUILD_WEBHOOKS] intent.
693 ///
694 /// [GUILD_WEBHOOKS]: Self::GUILD_WEBHOOKS
695 #[must_use]
696 pub const fn guild_webhooks(self) -> bool {
697 self.contains(Self::GUILD_WEBHOOKS)
698 }
699
700 /// Shorthand for checking that the set of intents contains the [GUILD_INVITES] intent.
701 ///
702 /// [GUILD_INVITES]: Self::GUILD_INVITES
703 #[must_use]
704 pub const fn guild_invites(self) -> bool {
705 self.contains(Self::GUILD_INVITES)
706 }
707
708 /// Shorthand for checking that the set of intents contains the [GUILD_VOICE_STATES] intent.
709 ///
710 /// [GUILD_VOICE_STATES]: Self::GUILD_VOICE_STATES
711 #[must_use]
712 pub const fn guild_voice_states(self) -> bool {
713 self.contains(Self::GUILD_VOICE_STATES)
714 }
715
716 /// Shorthand for checking that the set of intents contains the [GUILD_PRESENCES] intent.
717 ///
718 /// [GUILD_PRESENCES]: Self::GUILD_PRESENCES
719 #[must_use]
720 pub const fn guild_presences(self) -> bool {
721 self.contains(Self::GUILD_PRESENCES)
722 }
723
724 /// Shorthand for checking that the set of intents contains the [GUILD_MESSAGE_REACTIONS]
725 /// intent.
726 ///
727 /// [GUILD_MESSAGE_REACTIONS]: Self::GUILD_MESSAGE_REACTIONS
728 #[must_use]
729 pub const fn guild_message_reactions(self) -> bool {
730 self.contains(Self::GUILD_MESSAGE_REACTIONS)
731 }
732
733 /// Shorthand for checking that the set of intents contains the [GUILD_MESSAGE_TYPING] intent.
734 ///
735 /// [GUILD_MESSAGE_TYPING]: Self::GUILD_MESSAGE_TYPING
736 #[must_use]
737 pub const fn guild_message_typing(self) -> bool {
738 self.contains(Self::GUILD_MESSAGE_TYPING)
739 }
740
741 /// Shorthand for checking that the set of intents contains the [DIRECT_MESSAGES] intent.
742 ///
743 /// [DIRECT_MESSAGES]: Self::DIRECT_MESSAGES
744 #[must_use]
745 pub const fn direct_messages(self) -> bool {
746 self.contains(Self::DIRECT_MESSAGES)
747 }
748
749 /// Shorthand for checking that the set of intents contains the [DIRECT_MESSAGE_REACTIONS]
750 /// intent.
751 ///
752 /// [DIRECT_MESSAGE_REACTIONS]: Self::DIRECT_MESSAGE_REACTIONS
753 #[must_use]
754 pub const fn direct_message_reactions(self) -> bool {
755 self.contains(Self::DIRECT_MESSAGE_REACTIONS)
756 }
757
758 /// Shorthand for checking that the set of intents contains the [DIRECT_MESSAGE_TYPING] intent.
759 ///
760 /// [DIRECT_MESSAGE_TYPING]: Self::DIRECT_MESSAGE_TYPING
761 #[must_use]
762 pub const fn direct_message_typing(self) -> bool {
763 self.contains(Self::DIRECT_MESSAGE_TYPING)
764 }
765
766 /// Shorthand for checking that the set of intents contains the [MESSAGE_CONTENT] intent.
767 ///
768 /// [MESSAGE_CONTENT]: Self::MESSAGE_CONTENT
769 #[must_use]
770 pub const fn message_content(self) -> bool {
771 self.contains(Self::MESSAGE_CONTENT)
772 }
773
774 /// Shorthand for checking that the set of intents contains the [GUILD_SCHEDULED_EVENTS]
775 /// intent.
776 ///
777 /// [GUILD_SCHEDULED_EVENTS]: Self::GUILD_SCHEDULED_EVENTS
778 #[must_use]
779 pub const fn guild_scheduled_events(self) -> bool {
780 self.contains(Self::GUILD_SCHEDULED_EVENTS)
781 }
782
783 /// Shorthand for checking that the set of intents contains the [AUTO_MODERATION_CONFIGURATION]
784 /// intent.
785 ///
786 /// [AUTO_MODERATION_CONFIGURATION]: Self::AUTO_MODERATION_CONFIGURATION
787 #[must_use]
788 pub const fn auto_moderation_configuration(self) -> bool {
789 self.contains(Self::AUTO_MODERATION_CONFIGURATION)
790 }
791
792 /// Shorthand for checking that the set of intents contains the [AUTO_MODERATION_EXECUTION]
793 /// intent.
794 ///
795 /// [AUTO_MODERATION_EXECUTION]: Self::AUTO_MODERATION_EXECUTION
796 #[must_use]
797 pub const fn auto_moderation_execution(self) -> bool {
798 self.contains(Self::AUTO_MODERATION_EXECUTION)
799 }
800}
801
802impl Default for GatewayIntents {
803 fn default() -> Self {
804 Self::non_privileged()
805 }
806}