use std::num::NonZeroU16;
use serde::ser::SerializeSeq;
use url::Url;
use super::prelude::*;
use super::utils::*;
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct BotGateway {
pub url: String,
pub shards: u32,
pub session_start_limit: SessionStartLimit,
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct Activity {
#[serde(deserialize_with = "deserialize_buggy_id")]
#[serde(default)]
pub application_id: Option<ApplicationId>,
pub assets: Option<ActivityAssets>,
pub details: Option<String>,
pub flags: Option<ActivityFlags>,
pub instance: Option<bool>,
#[serde(rename = "type")]
pub kind: ActivityType,
pub name: String,
pub party: Option<ActivityParty>,
pub secrets: Option<ActivitySecrets>,
pub state: Option<String>,
pub emoji: Option<ActivityEmoji>,
pub timestamps: Option<ActivityTimestamps>,
#[cfg(feature = "unstable_discord_api")]
pub sync_id: Option<String>,
#[cfg(feature = "unstable_discord_api")]
pub session_id: Option<String>,
pub url: Option<Url>,
#[serde(default, deserialize_with = "deserialize_buttons")]
pub buttons: Vec<ActivityButton>,
pub created_at: u64,
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub struct ActivityButton {
pub label: String,
#[serde(default)]
pub url: String,
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct ActivityAssets {
pub large_image: Option<String>,
pub large_text: Option<String>,
pub small_image: Option<String>,
pub small_text: Option<String>,
}
bitflags! {
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Copy, Clone, Default, Debug, Eq, Hash, PartialEq)]
pub struct ActivityFlags: u64 {
const INSTANCE = 1 << 0;
const JOIN = 1 << 1;
const SPECTATE = 1 << 2;
const JOIN_REQUEST = 1 << 3;
const SYNC = 1 << 4;
const PLAY = 1 << 5;
const PARTY_PRIVACY_FRIENDS = 1 << 6;
const PARTY_PRIVACY_VOICE_CHANNEL = 1 << 7;
const EMBEDDED = 1 << 8;
}
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct ActivityParty {
pub id: Option<String>,
pub size: Option<[u32; 2]>,
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct ActivitySecrets {
pub join: Option<String>,
#[serde(rename = "match")]
pub match_: Option<String>,
pub spectate: Option<String>,
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct ActivityEmoji {
pub name: String,
pub id: Option<EmojiId>,
pub animated: Option<bool>,
}
enum_number! {
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Deserialize, Serialize)]
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[serde(from = "u8", into = "u8")]
#[non_exhaustive]
pub enum ActivityType {
#[default]
Playing = 0,
Streaming = 1,
Listening = 2,
Watching = 3,
Custom = 4,
Competing = 5,
_ => Unknown(u8),
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct Gateway {
pub url: String,
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct ClientStatus {
pub desktop: Option<OnlineStatus>,
pub mobile: Option<OnlineStatus>,
pub web: Option<OnlineStatus>,
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[non_exhaustive]
pub struct PresenceUser {
pub id: UserId,
#[serde(rename = "username")]
pub name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "discriminator")]
pub discriminator: Option<NonZeroU16>,
pub global_name: Option<String>,
pub avatar: Option<ImageHash>,
#[serde(default)]
pub bot: Option<bool>,
#[serde(default)]
pub system: Option<bool>,
#[serde(default)]
pub mfa_enabled: Option<bool>,
pub banner: Option<ImageHash>,
#[serde(rename = "accent_color")]
pub accent_colour: Option<Colour>,
pub locale: Option<String>,
pub verified: Option<bool>,
pub email: Option<String>,
#[serde(default)]
pub flags: Option<UserPublicFlags>,
#[serde(default)]
pub premium_type: Option<PremiumType>,
pub public_flags: Option<UserPublicFlags>,
pub member: Option<Box<PartialMember>>,
pub primary_guild: Option<PrimaryGuild>,
pub avatar_decoration_data: Option<AvatarDecorationData>,
pub collectibles: Option<Collectibles>,
}
impl PresenceUser {
#[must_use]
pub fn into_user(self) -> Option<User> {
Some(User {
avatar: self.avatar,
bot: self.bot?,
discriminator: self.discriminator,
global_name: self.global_name,
id: self.id,
name: self.name?,
public_flags: self.public_flags,
banner: self.banner,
accent_colour: self.accent_colour,
member: self.member,
system: false,
mfa_enabled: self.mfa_enabled.unwrap_or_default(),
locale: self.locale,
verified: self.verified,
email: self.email,
flags: self.public_flags.unwrap_or_default(),
premium_type: self.premium_type.unwrap_or_default(),
primary_guild: self.primary_guild,
avatar_decoration_data: self.avatar_decoration_data,
collectibles: self.collectibles,
})
}
#[must_use]
pub fn to_user(&self) -> Option<User> {
self.clone().into_user()
}
#[cfg(feature = "cache")] pub(crate) fn update_with_user(&mut self, user: &User) {
self.id = user.id;
if let Some(avatar) = user.avatar {
self.avatar = Some(avatar);
}
self.bot = Some(user.bot);
self.discriminator = user.discriminator;
self.name = Some(user.name.clone());
if let Some(public_flags) = user.public_flags {
self.public_flags = Some(public_flags);
}
}
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct Presence {
pub user: PresenceUser,
pub guild_id: Option<GuildId>,
pub status: OnlineStatus,
#[serde(default)]
pub activities: Vec<Activity>,
pub client_status: Option<ClientStatus>,
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct Ready {
#[serde(rename = "v")]
pub version: u8,
pub user: CurrentUser,
pub guilds: Vec<UnavailableGuild>,
pub session_id: String,
pub resume_gateway_url: String,
pub shard: Option<ShardInfo>,
pub application: PartialCurrentApplicationInfo,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct SessionStartLimit {
pub remaining: u64,
pub reset_after: u64,
pub total: u64,
pub max_concurrency: u64,
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Copy, Debug)]
pub struct ShardInfo {
pub id: ShardId,
pub total: u32,
}
impl ShardInfo {
#[must_use]
pub(crate) fn new(id: ShardId, total: u32) -> Self {
Self {
id,
total,
}
}
}
impl<'de> serde::Deserialize<'de> for ShardInfo {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
<(u32, u32)>::deserialize(deserializer).map(|(id, total)| ShardInfo {
id: ShardId(id),
total,
})
}
}
impl serde::Serialize for ShardInfo {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
let mut seq = serializer.serialize_seq(Some(2))?;
seq.serialize_element(&self.id.0)?;
seq.serialize_element(&self.total)?;
seq.end()
}
}
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct ActivityTimestamps {
pub end: Option<u64>,
pub start: Option<u64>,
}
bitflags! {
#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct GatewayIntents: u64 {
const GUILDS = 1;
const GUILD_MEMBERS = 1 << 1;
const GUILD_MODERATION = 1 << 2;
#[deprecated = "Use [`Self::GUILD_MODERATION`] instead"]
const GUILD_BANS = 1 << 2;
const GUILD_EMOJIS_AND_STICKERS = 1 << 3;
const GUILD_INTEGRATIONS = 1 << 4;
const GUILD_WEBHOOKS = 1 << 5;
const GUILD_INVITES = 1 << 6;
const GUILD_VOICE_STATES = 1 << 7;
const GUILD_PRESENCES = 1 << 8;
const GUILD_MESSAGES = 1 << 9;
const GUILD_MESSAGE_REACTIONS = 1 << 10;
const GUILD_MESSAGE_TYPING = 1 << 11;
const DIRECT_MESSAGES = 1 << 12;
const DIRECT_MESSAGE_REACTIONS = 1 << 13;
const DIRECT_MESSAGE_TYPING = 1 << 14;
const MESSAGE_CONTENT = 1 << 15;
const GUILD_SCHEDULED_EVENTS = 1 << 16;
const AUTO_MODERATION_CONFIGURATION = 1 << 20;
const AUTO_MODERATION_EXECUTION = 1 << 21;
const GUILD_MESSAGE_POLLS = 1 << 24;
const DIRECT_MESSAGE_POLLS = 1 << 25;
}
}
impl GatewayIntents {
#[must_use]
pub const fn non_privileged() -> GatewayIntents {
Self::privileged().complement()
}
#[must_use]
pub const fn privileged() -> GatewayIntents {
Self::GUILD_MEMBERS.union(Self::GUILD_PRESENCES).union(Self::MESSAGE_CONTENT)
}
}
#[cfg(feature = "model")]
impl GatewayIntents {
#[must_use]
pub const fn is_privileged(self) -> bool {
self.intersects(Self::privileged())
}
#[must_use]
pub const fn guilds(self) -> bool {
self.contains(Self::GUILDS)
}
#[must_use]
pub const fn guild_members(self) -> bool {
self.contains(Self::GUILD_MEMBERS)
}
#[must_use]
#[deprecated = "Use [`Self::guild_moderation`] instead"]
pub const fn guild_bans(self) -> bool {
#[allow(deprecated)] self.contains(Self::GUILD_BANS)
}
#[must_use]
pub const fn guild_moderation(self) -> bool {
self.contains(Self::GUILD_MODERATION)
}
#[must_use]
pub const fn guild_emojis_and_stickers(self) -> bool {
self.contains(Self::GUILD_EMOJIS_AND_STICKERS)
}
#[must_use]
pub const fn guild_integrations(self) -> bool {
self.contains(Self::GUILD_INTEGRATIONS)
}
#[must_use]
pub const fn guild_webhooks(self) -> bool {
self.contains(Self::GUILD_WEBHOOKS)
}
#[must_use]
pub const fn guild_invites(self) -> bool {
self.contains(Self::GUILD_INVITES)
}
#[must_use]
pub const fn guild_voice_states(self) -> bool {
self.contains(Self::GUILD_VOICE_STATES)
}
#[must_use]
pub const fn guild_presences(self) -> bool {
self.contains(Self::GUILD_PRESENCES)
}
#[must_use]
pub const fn guild_message_reactions(self) -> bool {
self.contains(Self::GUILD_MESSAGE_REACTIONS)
}
#[must_use]
pub const fn guild_message_typing(self) -> bool {
self.contains(Self::GUILD_MESSAGE_TYPING)
}
#[must_use]
pub const fn direct_messages(self) -> bool {
self.contains(Self::DIRECT_MESSAGES)
}
#[must_use]
pub const fn direct_message_reactions(self) -> bool {
self.contains(Self::DIRECT_MESSAGE_REACTIONS)
}
#[must_use]
pub const fn direct_message_typing(self) -> bool {
self.contains(Self::DIRECT_MESSAGE_TYPING)
}
#[must_use]
pub const fn message_content(self) -> bool {
self.contains(Self::MESSAGE_CONTENT)
}
#[must_use]
pub const fn guild_scheduled_events(self) -> bool {
self.contains(Self::GUILD_SCHEDULED_EVENTS)
}
#[must_use]
pub const fn auto_moderation_configuration(self) -> bool {
self.contains(Self::AUTO_MODERATION_CONFIGURATION)
}
#[must_use]
pub const fn auto_moderation_execution(self) -> bool {
self.contains(Self::AUTO_MODERATION_EXECUTION)
}
}
impl Default for GatewayIntents {
fn default() -> Self {
Self::non_privileged()
}
}