use url::Url;
use super::prelude::*;
use super::utils::*;
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct BotGateway {
pub session_start_limit: SessionStartLimit,
pub shards: u64,
pub url: String,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct Activity {
pub application_id: Option<ApplicationId>,
pub assets: Option<ActivityAssets>,
pub details: Option<String>,
pub flags: Option<ActivityFlags>,
pub instance: Option<bool>,
#[serde(default, 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>,
}
#[cfg(feature = "model")]
impl Activity {
fn new(name: String, kind: ActivityType) -> Self {
Self {
application_id: None,
assets: None,
details: None,
flags: None,
instance: None,
kind,
name,
party: None,
secrets: None,
state: None,
emoji: None,
timestamps: None,
#[cfg(feature = "unstable_discord_api")]
sync_id: None,
#[cfg(feature = "unstable_discord_api")]
session_id: None,
url: None,
buttons: vec![],
}
}
pub fn playing<N>(name: N) -> Activity
where
N: ToString,
{
Activity::new(name.to_string(), ActivityType::Playing)
}
pub fn streaming<N, U>(name: N, url: U) -> Activity
where
N: ToString,
U: AsRef<str>,
{
Activity {
url: Some(Url::parse(url.as_ref()).expect("Failed to parse url")),
..Activity::new(name.to_string(), ActivityType::Streaming)
}
}
pub fn listening<N>(name: N) -> Activity
where
N: ToString,
{
Activity::new(name.to_string(), ActivityType::Listening)
}
pub fn watching<N>(name: N) -> Activity
where
N: ToString,
{
Activity::new(name.to_string(), ActivityType::Watching)
}
pub fn competing<N>(name: N) -> Activity
where
N: ToString,
{
Activity::new(name.to_string(), ActivityType::Competing)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub struct ActivityButton {
pub label: String,
#[serde(default)]
pub url: String,
}
#[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! {
#[derive(Default)]
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;
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct ActivityParty {
pub id: Option<String>,
pub size: Option<[u64; 2]>,
}
#[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>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ActivityEmoji {
pub name: String,
pub id: Option<EmojiId>,
pub animated: Option<bool>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum ActivityType {
Playing = 0,
Streaming = 1,
Listening = 2,
Watching = 3,
Custom = 4,
Competing = 5,
Unknown = !0,
}
enum_number!(ActivityType {
Playing,
Streaming,
Listening,
Watching,
Custom,
Competing
});
impl Default for ActivityType {
fn default() -> Self {
ActivityType::Playing
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct Gateway {
pub url: String,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ClientStatus {
pub desktop: Option<OnlineStatus>,
pub mobile: Option<OnlineStatus>,
pub web: Option<OnlineStatus>,
}
#[derive(Clone, Default, Debug, Deserialize, Serialize)]
#[non_exhaustive]
#[serde(default)]
pub struct PresenceUser {
pub id: UserId,
pub avatar: Option<String>,
pub bot: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none", with = "discriminator::option")]
pub discriminator: Option<u16>,
pub email: Option<String>,
pub mfa_enabled: Option<bool>,
#[serde(rename = "username")]
pub name: Option<String>,
pub verified: Option<bool>,
pub public_flags: Option<UserPublicFlags>,
}
impl PresenceUser {
#[must_use]
pub fn into_user(self) -> Option<User> {
Some(User {
avatar: self.avatar,
bot: self.bot?,
discriminator: self.discriminator?,
id: self.id,
name: self.name?,
public_flags: self.public_flags,
banner: None,
accent_colour: None,
member: None,
})
}
#[must_use]
pub fn to_user(&self) -> Option<User> {
Some(User {
avatar: self.avatar.clone(),
bot: self.bot?,
discriminator: self.discriminator?,
id: self.id,
name: self.name.clone()?,
public_flags: self.public_flags,
banner: None,
accent_colour: None,
member: None,
})
}
#[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 = Some(user.discriminator);
self.name = Some(user.name);
if let Some(public_flags) = user.public_flags {
self.public_flags = Some(public_flags);
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct Presence {
#[serde(default)]
pub activities: Vec<Activity>,
#[serde(default)]
pub client_status: Option<ClientStatus>,
pub guild_id: Option<GuildId>,
pub status: OnlineStatus,
pub user: PresenceUser,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct Ready {
pub application: PartialCurrentApplicationInfo,
pub guilds: Vec<UnavailableGuild>,
#[serde(default, with = "presences")]
pub presences: HashMap<UserId, Presence>,
#[serde(default, with = "private_channels")]
pub private_channels: HashMap<ChannelId, Channel>,
pub session_id: String,
pub shard: Option<[u64; 2]>,
#[serde(default, rename = "_trace")]
pub trace: Vec<String>,
pub user: CurrentUser,
#[serde(rename = "v")]
pub version: u64,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct SessionStartLimit {
pub remaining: u64,
pub reset_after: u64,
pub total: u64,
pub max_concurrency: u64,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[non_exhaustive]
pub struct ActivityTimestamps {
pub end: Option<u64>,
pub start: Option<u64>,
}
bitflags! {
pub struct GatewayIntents: u64 {
const GUILDS = 1;
const GUILD_MEMBERS = 1 << 1;
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;
}
}
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 fn is_privileged(self) -> bool {
self.intersects(Self::privileged())
}
#[must_use]
pub fn guilds(self) -> bool {
self.contains(Self::GUILDS)
}
#[must_use]
pub fn guild_members(self) -> bool {
self.contains(Self::GUILD_MEMBERS)
}
#[must_use]
pub fn guild_bans(self) -> bool {
self.contains(Self::GUILD_BANS)
}
#[must_use]
pub fn guild_emojis_and_stickers(self) -> bool {
self.contains(Self::GUILD_EMOJIS_AND_STICKERS)
}
#[must_use]
pub fn guild_integrations(self) -> bool {
self.contains(Self::GUILD_INTEGRATIONS)
}
#[must_use]
pub fn guild_webhooks(self) -> bool {
self.contains(Self::GUILD_WEBHOOKS)
}
#[must_use]
pub fn guild_invites(self) -> bool {
self.contains(Self::GUILD_INVITES)
}
#[must_use]
pub fn guild_voice_states(self) -> bool {
self.contains(Self::GUILD_VOICE_STATES)
}
#[must_use]
pub fn guild_presences(self) -> bool {
self.contains(Self::GUILD_PRESENCES)
}
#[must_use]
pub fn guild_message_reactions(self) -> bool {
self.contains(Self::GUILD_MESSAGE_REACTIONS)
}
#[must_use]
pub fn guild_message_typing(self) -> bool {
self.contains(Self::GUILD_MESSAGE_TYPING)
}
#[must_use]
pub fn direct_messages(self) -> bool {
self.contains(Self::DIRECT_MESSAGES)
}
#[must_use]
pub fn direct_message_reactions(self) -> bool {
self.contains(Self::DIRECT_MESSAGE_REACTIONS)
}
#[must_use]
pub fn direct_message_typing(self) -> bool {
self.contains(Self::DIRECT_MESSAGE_TYPING)
}
#[must_use]
pub fn message_content(self) -> bool {
self.contains(Self::MESSAGE_CONTENT)
}
#[must_use]
pub fn guild_scheduled_events(self) -> bool {
self.contains(Self::GUILD_SCHEDULED_EVENTS)
}
#[must_use]
pub fn auto_moderation_configuration(self) -> bool {
self.contains(Self::AUTO_MODERATION_CONFIGURATION)
}
#[must_use]
pub fn auto_moderation_execution(self) -> bool {
self.contains(Self::AUTO_MODERATION_EXECUTION)
}
}
impl Default for GatewayIntents {
fn default() -> Self {
Self::non_privileged()
}
}