From 262cd0e780066b29fdc6711f460f16a679a52430 Mon Sep 17 00:00:00 2001 From: kozabrada123 <“kozabrada123@users.noreply.github.com”> Date: Sun, 14 May 2023 08:20:25 +0200 Subject: [PATCH 1/4] Add more events, fix deserialization errors --- Cargo.toml | 1 + src/api/types.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++---- src/gateway.rs | 50 ++++++++++++++++++++++++++++++----------- 3 files changed, 92 insertions(+), 17 deletions(-) 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)] From 40b459b9742773156bac16bf6b044af043fe6909 Mon Sep 17 00:00:00 2001 From: kozabrada123 <“kozabrada123@users.noreply.github.com”> Date: Sun, 14 May 2023 08:39:23 +0200 Subject: [PATCH 2/4] Add call update and delete --- src/api/types.rs | 25 +++++++++++++++++++++++-- src/gateway.rs | 12 +++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/api/types.rs b/src/api/types.rs index 09d3ceb..1abc237 100644 --- a/src/api/types.rs +++ b/src/api/types.rs @@ -1272,8 +1272,8 @@ impl WebSocketEvent for GuildEmojisUpdate {} /// {"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, + /// Seems like a vec of channel ids + pub ringing: Vec, pub region: String, // milan pub message_id: String, /// What is this? @@ -1282,6 +1282,27 @@ pub struct CallCreate { } impl WebSocketEvent for CallCreate {} +#[derive(Debug, Deserialize, Serialize, Default)] +/// Undocumented +/// {"t":"CALL_UPDATE","s":5,"op":0,"d":{"ringing":["837606544539254834"],"region":"milan","message_id":"1107191540234846308","guild_id":null,"channel_id":"837609115475771392"}} +pub struct CallUpdate { + /// Seems like a vec of channel ids + pub ringing: Vec, + pub region: String, // milan + pub message_id: String, + pub guild_id: Option, + pub channel_id: String, +} +impl WebSocketEvent for CallUpdate {} + +#[derive(Debug, Deserialize, Serialize, Default)] +/// Undocumented +/// {"t":"CALL_DELETE","s":8,"op":0,"d":{"channel_id":"837609115475771392"}} +pub struct CallDelete { + pub channel_id: String, +} +impl WebSocketEvent for CallDelete {} + #[derive(Debug, Default, Deserialize, Serialize)] pub struct GatewayPayload { pub op: u8, diff --git a/src/gateway.rs b/src/gateway.rs index 4d12ceb..27c3c80 100644 --- a/src/gateway.rs +++ b/src/gateway.rs @@ -216,6 +216,14 @@ impl Gateway { "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; + }, + "CALL_UPDATE" => { + let new_data: CallUpdate = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); + self.events.lock().await.call.update.update_data(new_data).await; + } + "CALL_DELETE" => { + let new_data: CallDelete = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); + self.events.lock().await.call.delete.update_data(new_data).await; } "THREAD_CREATE" => { let thread: Channel = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); @@ -604,7 +612,9 @@ mod events { #[derive(Default, Debug)] pub struct Call { - pub create: GatewayEvent + pub create: GatewayEvent, + pub update: GatewayEvent, + pub delete: GatewayEvent } } From 2209d967cdb9a2377f04a140d934e7f29abb439b Mon Sep 17 00:00:00 2001 From: kozabrada123 <“kozabrada123@users.noreply.github.com”> Date: Sun, 14 May 2023 11:43:17 +0200 Subject: [PATCH 3/4] Flatten, new events --- src/api/types.rs | 90 +++++++++++++++++++++++++++++++++--------------- src/gateway.rs | 49 +++++++++++++++++--------- 2 files changed, 95 insertions(+), 44 deletions(-) diff --git a/src/api/types.rs b/src/api/types.rs index 1abc237..ae6d8ba 100644 --- a/src/api/types.rs +++ b/src/api/types.rs @@ -4,6 +4,8 @@ https://discord.com/developers/docs . I do not feel like re-documenting all of this, as everything is already perfectly explained there. */ +use std::collections::HashMap; + use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_json::from_value; @@ -138,7 +140,7 @@ pub struct Error { #[derive(Serialize, Deserialize, Debug, Default)] pub struct UnavailableGuild { id: String, - unavailable: bool + unavailable: Option } /// See https://discord.com/developers/docs/resources/guild @@ -834,7 +836,7 @@ pub struct VoiceStateObject { pub self_stream: Option, pub self_video: bool, pub suppress: bool, - pub request_to_speak_timestamp: DateTime + pub request_to_speak_timestamp: Option> } #[derive(Default, Debug, Deserialize, Serialize, Clone)] @@ -1035,7 +1037,7 @@ pub struct GatewayRequestGuildMembers { pub guild_id: String, pub query: Option, pub limit: u64, - pub presence: Option, + pub presences: Option, pub user_ids: Option, pub nonce: Option, } @@ -1113,8 +1115,8 @@ impl WebSocketEvent for GuildBanRemove {} #[derive(Debug, Default, Deserialize, Serialize)] /// See https://discord.com/developers/docs/topics/gateway-events#user-update -/// Not directly serialized, as the inner payload is the user object pub struct UserUpdate { + #[serde(flatten)] pub user: UserObject, } @@ -1122,8 +1124,8 @@ impl WebSocketEvent for UserUpdate {} #[derive(Debug, Default, Deserialize, Serialize)] /// See https://discord.com/developers/docs/topics/gateway-events#channel-create -/// Not directly serialized, as the inner payload is a channel object pub struct ChannelCreate { + #[serde(flatten)] pub channel: Channel, } @@ -1131,8 +1133,8 @@ impl WebSocketEvent for ChannelCreate {} #[derive(Debug, Default, Deserialize, Serialize)] /// See https://discord.com/developers/docs/topics/gateway-events#channel-update -/// Not directly serialized, as the inner payload is a channel object pub struct ChannelUpdate { + #[serde(flatten)] pub channel: Channel, } @@ -1140,8 +1142,8 @@ impl WebSocketEvent for ChannelUpdate {} #[derive(Debug, Default, Deserialize, Serialize)] /// See https://discord.com/developers/docs/topics/gateway-events#channel-delete -/// Not directly serialized, as the inner payload is a channel object pub struct ChannelDelete { + #[serde(flatten)] pub channel: Channel, } @@ -1149,8 +1151,8 @@ impl WebSocketEvent for ChannelDelete {} #[derive(Debug, Default, Deserialize, Serialize)] /// See https://discord.com/developers/docs/topics/gateway-events#thread-create -/// Not directly serialized, as the inner payload is a channel object pub struct ThreadCreate { + #[serde(flatten)] pub thread: Channel, } @@ -1158,8 +1160,8 @@ impl WebSocketEvent for ThreadCreate {} #[derive(Debug, Default, Deserialize, Serialize)] /// See https://discord.com/developers/docs/topics/gateway-events#thread-update -/// Not directly serialized, as the inner payload is a channel object pub struct ThreadUpdate { + #[serde(flatten)] pub thread: Channel, } @@ -1167,8 +1169,8 @@ impl WebSocketEvent for ThreadUpdate {} #[derive(Debug, Default, Deserialize, Serialize)] /// See https://discord.com/developers/docs/topics/gateway-events#thread-delete -/// Not directly serialized, as the inner payload is a channel object pub struct ThreadDelete { + #[serde(flatten)] pub thread: Channel, } @@ -1188,23 +1190,12 @@ impl WebSocketEvent for ThreadListSync {} #[derive(Debug, Default, Deserialize, Serialize)] /// See https://discord.com/developers/docs/topics/gateway-events#thread-member-update /// The inner payload is a thread member object with an extra field. -/// The extra field is a bit painful, because we can't just serialize a thread member object pub struct ThreadMemberUpdate { - pub id: Option, - pub user_id: Option, - pub join_timestamp: Option, - pub flags: Option, - pub member: Option, + #[serde(flatten)] + pub member: ThreadMember, pub guild_id: String, } -impl ThreadMemberUpdate { - /// Convert self to a thread member, losing the added guild_id field - pub fn to_thread_member(&self) -> ThreadMember { - ThreadMember { id: self.id, user_id: self.user_id, join_timestamp: self.join_timestamp.clone(), flags: self.flags, member: self.member.clone() } - } -} - impl WebSocketEvent for ThreadMemberUpdate {} #[derive(Debug, Default, Deserialize, Serialize)] @@ -1224,6 +1215,7 @@ impl WebSocketEvent for ThreadMembersUpdate {} /// See https://discord.com/developers/docs/topics/gateway-events#guild-create /// This one is particularly painful, it can be a Guild object with extra field or an unavailbile guild object pub struct GuildCreate { + #[serde(flatten)] pub d: GuildCreateDataOption } @@ -1242,8 +1234,8 @@ 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 { + #[serde(flatten)] pub guild: Guild } @@ -1251,8 +1243,8 @@ 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 { + #[serde(flatten)] pub guild: UnavailableGuild } @@ -1268,7 +1260,7 @@ pub struct GuildEmojisUpdate { impl WebSocketEvent for GuildEmojisUpdate {} #[derive(Debug, Deserialize, Serialize, Default)] -/// Undocumented +/// Officially 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, @@ -1283,7 +1275,7 @@ pub struct CallCreate { impl WebSocketEvent for CallCreate {} #[derive(Debug, Deserialize, Serialize, Default)] -/// Undocumented +/// Officially Undocumented /// {"t":"CALL_UPDATE","s":5,"op":0,"d":{"ringing":["837606544539254834"],"region":"milan","message_id":"1107191540234846308","guild_id":null,"channel_id":"837609115475771392"}} pub struct CallUpdate { /// Seems like a vec of channel ids @@ -1296,13 +1288,55 @@ pub struct CallUpdate { impl WebSocketEvent for CallUpdate {} #[derive(Debug, Deserialize, Serialize, Default)] -/// Undocumented +/// Officially Undocumented /// {"t":"CALL_DELETE","s":8,"op":0,"d":{"channel_id":"837609115475771392"}} pub struct CallDelete { pub channel_id: String, } impl WebSocketEvent for CallDelete {} +#[derive(Debug, Deserialize, Serialize, Default)] +/// Officially Undocumented +/// See https://unofficial-discord-docs.vercel.app/gateway/op13 +/// {"op":13,"d":{"channel_id":"837609115475771392"}} +pub struct CallSync { + pub channel_id: String, +} +impl WebSocketEvent for CallSync {} + +#[derive(Debug, Deserialize, Serialize, Default)] +/// Officially Undocumented +/// See https://luna.gitlab.io/discord-unofficial-docs/lazy_guilds.html#op-14-lazy-request +/// {"op":14,"d":{"guild_id":"848582562217590824","typing":true,"activities":true,"threads":true}} +pub struct LazyRequest { + pub guild_id: String, + pub typing: bool, + pub activities: bool, + pub threads: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub members: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub channels: Option>>> +} +impl WebSocketEvent for LazyRequest {} + +#[derive(Debug, Deserialize, Serialize, Default)] +/// Officially Undocumented +/// Not documented anywhere unofficially +/// Apparently "Message ACK refers to marking a message as read for Discord's API." (https://github.com/Rapptz/discord.py/issues/1851) +/// I suspect this is sent and recieved from the gateway to let clients on other devices know the user has read a message +/// {"t":"MESSAGE_ACK","s":3,"op":0,"d":{"version":52,"message_id":"1107236673638633472","last_viewed":null,"flags":null,"channel_id":"967363950217936897"}} +pub struct MessageACK { + /// ? + pub version: u16, + pub message_id: String, + pub last_viewed: Option>, + /// What flags? + pub flags: Option, + pub channel_id: String, +} +impl WebSocketEvent for MessageACK {} + #[derive(Debug, Default, Deserialize, Serialize)] pub struct GatewayPayload { pub op: u8, diff --git a/src/gateway.rs b/src/gateway.rs index 27c3c80..6edf86f 100644 --- a/src/gateway.rs +++ b/src/gateway.rs @@ -93,6 +93,26 @@ impl GatewayHandle { self.send_json_event(4, to_send_value).await; } + + /// Sends a Call Sync + pub async fn send_call_sync(&self, to_send: CallSync) { + + let to_send_value = serde_json::to_value(&to_send).unwrap(); + + println!("GW: Sending Call Sync.."); + + self.send_json_event(13, to_send_value).await; + } + + /// Sends a Lazy Request + pub async fn send_lazy_request(&self, to_send: LazyRequest) { + + let to_send_value = serde_json::to_value(&to_send).unwrap(); + + println!("GW: Sending Lazy Request.."); + + self.send_json_event(14, to_send_value).await; + } } pub struct Gateway { @@ -195,18 +215,15 @@ impl Gateway { "AUTO_MODERATION_RULE_DELETE" => {} "AUTO_MODERATION_ACTION_EXECUTION" => {} "CHANNEL_CREATE" => { - let channel: Channel = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); - let new_data = ChannelCreate {channel}; + let new_data: ChannelCreate = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); self.events.lock().await.channel.create.update_data(new_data).await; } "CHANNEL_UPDATE" => { - let channel: Channel = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); - let new_data = ChannelUpdate {channel}; + let new_data: ChannelUpdate = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); self.events.lock().await.channel.update.update_data(new_data).await; } "CHANNEL_DELETE" => { - let channel: Channel = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); - let new_data = ChannelDelete {channel}; + let new_data: ChannelDelete = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); self.events.lock().await.channel.delete.update_data(new_data).await; } "CHANNEL_PINS_UPDATE" => { @@ -226,18 +243,15 @@ impl Gateway { self.events.lock().await.call.delete.update_data(new_data).await; } "THREAD_CREATE" => { - let thread: Channel = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); - let new_data = ThreadCreate {thread}; + let new_data: ThreadCreate = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); self.events.lock().await.thread.create.update_data(new_data).await; } "THREAD_UPDATE" => { - let thread: Channel = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); - let new_data = ThreadUpdate {thread}; + let new_data: ThreadUpdate = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); self.events.lock().await.thread.update.update_data(new_data).await; } "THREAD_DELETE" => { - let thread: Channel = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); - let new_data = ThreadDelete {thread}; + let new_data: ThreadDelete = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); self.events.lock().await.thread.delete.update_data(new_data).await; } "THREAD_LIST_SYNC" => { @@ -257,13 +271,11 @@ impl Gateway { self.events.lock().await.guild.create.update_data(new_data).await; } "GUILD_UPDATE" => { - let guild: Guild = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); - let new_data = GuildUpdate {guild}; + let new_data: GuildUpdate = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); self.events.lock().await.guild.update.update_data(new_data).await; } "GUILD_DELETE" => { - let guild: UnavailableGuild = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); - let new_data = GuildDelete {guild}; + let new_data: GuildDelete = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); self.events.lock().await.guild.delete.update_data(new_data).await; } "GUILD_AUDIT_LOG_ENTRY_CREATE" => {} @@ -330,6 +342,10 @@ impl Gateway { "MESSAGE_REACTION_REMOVE_EMOJI" => { let new_data: MessageReactionRemoveEmoji= serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); self.events.lock().await.message.reaction_remove_emoji.update_data(new_data).await; + }, + "MESSAGE_ACK" => { + let new_data: MessageACK = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); + self.events.lock().await.message.ack.update_data(new_data).await; } "PRESENCE_UPDATE" => { let new_data: PresenceUpdate = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); @@ -558,6 +574,7 @@ mod events { pub reaction_remove: GatewayEvent, pub reaction_remove_all: GatewayEvent, pub reaction_remove_emoji: GatewayEvent, + pub ack: GatewayEvent } #[derive(Default, Debug)] From 2ff5e4fd9d50d10e1a0b77fb62863214e03e055a Mon Sep 17 00:00:00 2001 From: kozabrada123 <“kozabrada123@users.noreply.github.com”> Date: Sun, 14 May 2023 14:03:18 +0200 Subject: [PATCH 4/4] Add Readies to Events, try to fix msg_create error --- src/api/types.rs | 116 +++++++++++++++++++++++++++++++++++++++++------ src/gateway.rs | 26 +++++++---- 2 files changed, 118 insertions(+), 24 deletions(-) diff --git a/src/api/types.rs b/src/api/types.rs index ae6d8ba..3ca9f9d 100644 --- a/src/api/types.rs +++ b/src/api/types.rs @@ -9,7 +9,7 @@ use std::collections::HashMap; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_json::from_value; -use serde_aux::field_attributes::{deserialize_number_from_string}; +use serde_aux::field_attributes::deserialize_option_number_from_string; use crate::{api::limits::Limits, instance::Instance}; @@ -290,7 +290,7 @@ pub struct RoleObject { //pub tags: Option } -#[derive(Serialize, Deserialize, Debug, Default, Clone)] +#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash)] pub struct UserObject { pub id: String, username: String, @@ -305,18 +305,18 @@ pub struct UserObject { email: Option, /// 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, + #[serde(deserialize_with = "deserialize_option_number_from_string")] + flags: Option, premium_since: Option, - premium_type: i8, + premium_type: Option, pronouns: Option, - public_flags: Option, + public_flags: Option, banner: Option, - bio: String, + bio: Option, theme_colors: Option>, phone: Option, - nsfw_allowed: bool, - premium: bool, + nsfw_allowed: Option, + premium: Option, purchased_flags: Option, premium_usage_flags: Option, disabled: Option, @@ -398,12 +398,43 @@ pub struct Message { } #[derive(Debug, Serialize, Deserialize, Default)] +/// See https://discord.com/developers/docs/topics/gateway-events#message-create pub struct MessageCreate { #[serde(flatten)] message: Message, guild_id: Option, member: Option, - mentions: Vec<(UserObject, GuildMember)>, // Not sure if this is correct: https://discord.com/developers/docs/topics/gateway-events#message-create + mentions: Vec, +} + +#[derive(Debug, Serialize, Deserialize, Default)] +/// See https://discord.com/developers/docs/topics/gateway-events#message-create-message-create-extra-fields +pub struct MessageCreateUser { + pub id: String, + username: String, + discriminator: String, + avatar: Option, + bot: Option, + system: Option, + mfa_enabled: Option, + accent_color: Option, + locale: Option, + verified: Option, + email: Option, + premium_since: Option, + premium_type: Option, + pronouns: Option, + public_flags: Option, + banner: Option, + bio: Option, + theme_colors: Option>, + phone: Option, + nsfw_allowed: Option, + premium: Option, + purchased_flags: Option, + premium_usage_flags: Option, + disabled: Option, + member: GuildMember } impl WebSocketEvent for MessageCreate {} @@ -700,17 +731,17 @@ pub struct MessageInteraction { pub member: Option, } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone, Default)] pub struct GuildMember { pub user: Option, pub nick: Option, pub avatar: Option, - pub roles: Vec, + pub roles: Vec, pub joined_at: String, pub premium_since: Option, pub deaf: bool, pub mute: bool, - pub flags: i32, + pub flags: Option, pub pending: Option, pub permissions: Option, pub communication_disabled_until: Option, @@ -924,7 +955,15 @@ pub struct GatewayIdentifyPayload { pub shard: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub presence: Option, - pub intents: i32, + pub capabilities: i32, +} + +impl GatewayIdentifyPayload { + pub fn default_w_client_capabilities() -> Self { + let mut def = Self::default(); + def.capabilities = 8189; // Default capabilities for a client + def + } } impl WebSocketEvent for GatewayIdentifyPayload {} @@ -1031,6 +1070,55 @@ pub struct GatewayReady { impl WebSocketEvent for GatewayReady {} +#[derive(Debug, Deserialize, Serialize, Default)] +/// Officially Undocumented +/// Sent after the READY event when a client has capabilities +/// {"t":"READY_SUPPLEMENTAL","s":2,"op":0,"d":{"merged_presences":{"guilds":[[{"user_id":"463640391196082177","status":"online","game":null,"client_status":{"web":"online"},"activities":[]}]],"friends":[{"user_id":"463640391196082177","status":"online","last_modified":1684053508443,"client_status":{"web":"online"},"activities":[]}]},"merged_members":[[{"user_id":"463640391196082177","roles":[],"premium_since":null,"pending":false,"nick":"pog","mute":false,"joined_at":"2021-05-30T15:24:08.763000+00:00","flags":0,"deaf":false,"communication_disabled_until":null,"avatar":null}]],"lazy_private_channels":[],"guilds":[{"voice_states":[],"id":"848582562217590824","embedded_activities":[]}],"disclose":["pomelo"]}} +pub struct GatewayReadySupplemental { + pub merged_presences: MergedPresences, + pub merged_members: Vec>, + // ? + pub lazy_private_channels: Vec, + pub guilds: Vec, + // ? pomelo + pub disclose: Vec, +} + +impl WebSocketEvent for GatewayReadySupplemental {} + +#[derive(Debug, Deserialize, Serialize, Default)] +pub struct MergedPresences { + pub guilds: Vec>, + pub friends: Vec +} + +#[derive(Debug, Deserialize, Serialize, Default)] +pub struct MergedPresenceFriend { + pub user_id: String, + pub status: String, + /// Looks like ms?? + pub last_modified: u128, + pub client_status: ClientStatusObject, + pub activities: Vec +} + +#[derive(Debug, Deserialize, Serialize, Default)] +pub struct MergedPresenceGuild { + pub user_id: String, + pub status: String, + // ? + pub game: Option, + pub client_status: ClientStatusObject, + pub activities: Vec +} + +#[derive(Debug, Deserialize, Serialize, Default)] +pub struct SupplimentalGuild { + pub voice_states: Vec, + pub id: String, + pub embedded_activities: Vec +} + #[derive(Debug, Deserialize, Serialize, Default)] /// See https://discord.com/developers/docs/topics/gateway-events#request-guild-members-request-guild-members-structure pub struct GatewayRequestGuildMembers { diff --git a/src/gateway.rs b/src/gateway.rs index 6edf86f..a75a77d 100644 --- a/src/gateway.rs +++ b/src/gateway.rs @@ -187,11 +187,7 @@ impl Gateway { return; } - let msg_string = msg.to_string(); - - println!("{}", &msg_string); - - let gateway_payload: GatewayPayload = serde_json::from_str(&msg_string).unwrap(); + let gateway_payload: GatewayPayload = serde_json::from_str(msg.to_text().unwrap()).unwrap(); // See https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway-gateway-opcodes match gateway_payload.op { @@ -205,8 +201,12 @@ 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(); - println!("{:?}", data); + let new_data: GatewayReady = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); + self.events.lock().await.ready.ready.update_data(new_data).await; + }, + "READY_SUPPLEMENTAL" => { + let new_data: GatewayReadySupplemental = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); + self.events.lock().await.ready.ready_supplimental.update_data(new_data).await; } "RESUMED" => {} "APPLICATION_COMMAND_PERMISSIONS_UPDATE" => {} @@ -267,7 +267,7 @@ impl Gateway { self.events.lock().await.thread.members_update.update_data(new_data).await; } "GUILD_CREATE" => { - let new_data: GuildCreate = serde_json::from_str(&msg_string).unwrap(); + let new_data: GuildCreate = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); self.events.lock().await.guild.create.update_data(new_data).await; } "GUILD_UPDATE" => { @@ -361,8 +361,7 @@ impl Gateway { self.events.lock().await.user.typing_start_event.update_data(new_data).await; } "USER_UPDATE" => { - let user: UserObject = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); - let new_data = UserUpdate {user}; + let new_data: UserUpdate = serde_json::from_value(gateway_payload.d.unwrap()).unwrap(); self.events.lock().await.user.update.update_data(new_data).await; } "VOICE_STATE_UPDATE" => {} @@ -554,6 +553,7 @@ mod events { use super::*; #[derive(Default, Debug)] pub struct Events { + pub ready: Ready, pub message: Message, pub user: User, pub channel: Channel, @@ -564,6 +564,12 @@ mod events { pub gateway_resume: GatewayEvent, } + #[derive(Default, Debug)] + pub struct Ready { + pub ready: GatewayEvent, + pub ready_supplimental: GatewayEvent + } + #[derive(Default, Debug)] pub struct Message { pub create: GatewayEvent,