diff --git a/Cargo.toml b/Cargo.toml index f346a21..30dd107 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" tokio = {version = "1.27.0", features = ["rt", "macros", "rt-multi-thread"]} serde = {version = "1.0.159", features = ["derive"]} serde_json = "1.0.95" +serde-aux = "4.2.0" reqwest = {version = "0.11.16", features = ["multipart"]} url = "2.3.1" chrono = {version = "0.4.24", features = ["serde"]} diff --git a/src/api/types.rs b/src/api/types.rs index b3f7081..09d3ceb 100644 --- a/src/api/types.rs +++ b/src/api/types.rs @@ -7,6 +7,7 @@ I do not feel like re-documenting all of this, as everything is already perfectl use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_json::from_value; +use serde_aux::field_attributes::{deserialize_number_from_string}; use crate::{api::limits::Limits, instance::Instance}; @@ -293,14 +294,17 @@ pub struct UserObject { username: String, discriminator: String, avatar: Option, - bot: bool, + bot: Option, system: Option, mfa_enabled: Option, accent_color: Option, locale: Option, verified: Option, email: Option, - flags: String, + /// This field comes as either a string or a number as a string + /// So we need to account for that + #[serde(deserialize_with = "deserialize_number_from_string")] + flags: i32, premium_since: Option, premium_type: i8, pronouns: Option, @@ -311,8 +315,8 @@ pub struct UserObject { phone: Option, nsfw_allowed: bool, premium: bool, - purchased_flags: i32, - premium_usage_flags: i32, + purchased_flags: Option, + premium_usage_flags: Option, disabled: Option, } @@ -910,9 +914,13 @@ impl WebSocketEvent for TypingStartEvent {} pub struct GatewayIdentifyPayload { pub token: String, pub properties: GatewayIdentifyConnectionProps, + #[serde(skip_serializing_if = "Option::is_none")] pub compress: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub large_threshold: Option, //default: 50 + #[serde(skip_serializing_if = "Option::is_none")] pub shard: Option>, + #[serde(skip_serializing_if = "Option::is_none")] pub presence: Option, pub intents: i32, } @@ -1232,6 +1240,48 @@ impl Default for GuildCreateDataOption { } impl WebSocketEvent for GuildCreate {} +#[derive(Debug, Default, Deserialize, Serialize)] +/// See https://discord.com/developers/docs/topics/gateway-events#guild-update +/// Not directly serialized, as the inner payload is a guild object +pub struct GuildUpdate { + pub guild: Guild +} + +impl WebSocketEvent for GuildUpdate {} + +#[derive(Debug, Default, Deserialize, Serialize)] +/// See https://discord.com/developers/docs/topics/gateway-events#guild-delete +/// Not directly serialized, as the inner payload is an unavailable guild object +pub struct GuildDelete { + pub guild: UnavailableGuild +} + +impl WebSocketEvent for GuildDelete {} + +#[derive(Debug, Default, Deserialize, Serialize)] +/// See https://discord.com/developers/docs/topics/gateway-events#guild-emojis-update +pub struct GuildEmojisUpdate { + pub guild_id: String, + pub emojis: Vec +} + +impl WebSocketEvent for GuildEmojisUpdate {} + +#[derive(Debug, Deserialize, Serialize, Default)] +/// Undocumented +/// {"t":"CALL_CREATE","s":2,"op":0,"d":{"voice_states":[],"ringing":[],"region":"milan","message_id":"1107187514906775613","embedded_activities":[],"channel_id":"837609115475771392"}} +pub struct CallCreate { + pub voice_states: Vec, + /// What is this? + pub ringing: Vec, + pub region: String, // milan + pub message_id: String, + /// What is this? + pub embedded_activities: Vec, + pub channel_id: String, +} +impl WebSocketEvent for CallCreate {} + #[derive(Debug, Default, Deserialize, Serialize)] pub struct GatewayPayload { pub op: u8, diff --git a/src/gateway.rs b/src/gateway.rs index c79004f..4d12ceb 100644 --- a/src/gateway.rs +++ b/src/gateway.rs @@ -169,6 +169,8 @@ impl Gateway { let msg_string = msg.to_string(); + println!("{}", &msg_string); + let gateway_payload: GatewayPayload = serde_json::from_str(&msg_string).unwrap(); // See https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway-gateway-opcodes @@ -183,7 +185,8 @@ impl Gateway { // See https://discord.com/developers/docs/topics/gateway-events#receive-events match gateway_payload_t.as_str() { "READY" => { - let _data: GatewayReady = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); + let data: GatewayReady = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); + println!("{:?}", data); } "RESUMED" => {} "APPLICATION_COMMAND_PERMISSIONS_UPDATE" => {} @@ -210,6 +213,10 @@ impl Gateway { let new_data: ChannelPinsUpdate = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); self.events.lock().await.channel.pins_update.update_data(new_data).await; } + "CALL_CREATE" => { + let new_data: CallCreate = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); + self.events.lock().await.call.create.update_data(new_data).await; + } "THREAD_CREATE" => { let thread: Channel = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); let new_data = ThreadCreate {thread}; @@ -241,18 +248,29 @@ impl Gateway { let new_data: GuildCreate = serde_json::from_str(&msg_string).unwrap(); self.events.lock().await.guild.create.update_data(new_data).await; } - "GUILD_UPDATE" => {} + "GUILD_UPDATE" => { + let guild: Guild = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); + let new_data = GuildUpdate {guild}; + self.events.lock().await.guild.update.update_data(new_data).await; + } "GUILD_DELETE" => { - let _new_data: UnavailableGuild = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); + let guild: UnavailableGuild = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); + let new_data = GuildDelete {guild}; + self.events.lock().await.guild.delete.update_data(new_data).await; } "GUILD_AUDIT_LOG_ENTRY_CREATE" => {} "GUILD_BAN_ADD" => { - let _new_data: GuildBanAdd = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); + let new_data: GuildBanAdd = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); + self.events.lock().await.guild.ban_add.update_data(new_data).await; } "GUILD_BAN_REMOVE" => { - let _new_data: GuildBanRemove = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); + let new_data: GuildBanRemove = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); + self.events.lock().await.guild.ban_remove.update_data(new_data).await; + } + "GUILD_EMOJIS_UPDATE" => { + let new_data: GuildEmojisUpdate = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); + self.events.lock().await.guild.emojis_update.update_data(new_data).await; } - "GUILD_EMOJIS_UPDATE" => {} "GUILD_STICKERS_UPDATE" => {} "GUILD_INTEGRATIONS_UPDATE" => {} "GUILD_MEMBER_ADD" => {} @@ -517,6 +535,7 @@ mod events { pub channel: Channel, pub thread: Thread, pub guild: Guild, + pub call: Call, pub gateway_identify_payload: GatewayEvent, pub gateway_resume: GatewayEvent, } @@ -561,13 +580,13 @@ mod events { #[derive(Default, Debug)] pub struct Guild { pub create: GatewayEvent, - /*pub update: GatewayEvent, - pub delete: GatewayEvent, - pub audit_log_entry_create: GatewayEvent, - pub ban_add: GatewayEvent, - pub ban_remove: GatewayEvent, - pub emojis_update: GatewayEvent, - pub stickers_update: GatewayEvent, + pub update: GatewayEvent, + pub delete: GatewayEvent, + //pub audit_log_entry_create: GatewayEvent, + pub ban_add: GatewayEvent, + pub ban_remove: GatewayEvent, + pub emojis_update: GatewayEvent, + /*pub stickers_update: GatewayEvent, pub integrations_update: GatewayEvent, pub member_add: GatewayEvent, pub member_remove: GatewayEvent, @@ -582,6 +601,11 @@ mod events { pub role_scheduled_event_user_add: GatewayEvent, pub role_scheduled_event_user_remove: GatewayEvent,*/ } + + #[derive(Default, Debug)] + pub struct Call { + pub create: GatewayEvent + } } #[cfg(test)]