From 141dc32819773a849ab39f6c4ba53fa5084227ea Mon Sep 17 00:00:00 2001 From: kozabrada123 <59031733+kozabrada123@users.noreply.github.com> Date: Tue, 29 Aug 2023 16:38:26 +0000 Subject: [PATCH] Error observer (also merge perpetual/gateway-dev) (#425) * Add Webrtc Identify & Ready * Test error observer * Minor updates * More derives * Even more derives * Small types update * e --- src/errors.rs | 7 ++++++- src/gateway.rs | 9 ++++++--- src/types/events/call.rs | 6 +++--- src/types/events/hello.rs | 4 ++-- src/types/events/identify.rs | 8 ++++---- src/types/events/mod.rs | 6 +++++- src/types/events/presence.rs | 2 +- src/types/events/user.rs | 6 +++--- src/types/events/voice.rs | 4 ++-- src/types/events/webrtc/identify.rs | 18 ++++++++++++++++++ src/types/events/webrtc/mod.rs | 5 +++++ src/types/events/webrtc/ready.rs | 29 +++++++++++++++++++++++++++++ src/types/interfaces/activity.rs | 12 ++++++------ src/types/interfaces/status.rs | 2 +- src/types/schema/user.rs | 4 ++-- 15 files changed, 93 insertions(+), 29 deletions(-) create mode 100644 src/types/events/webrtc/identify.rs create mode 100644 src/types/events/webrtc/mod.rs create mode 100644 src/types/events/webrtc/ready.rs diff --git a/src/errors.rs b/src/errors.rs index eebfae3..642a3ba 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -2,6 +2,8 @@ use custom_error::custom_error; use reqwest::Error; +use crate::types::WebSocketEvent; + custom_error! { #[derive(PartialEq, Eq)] pub RegistrationError @@ -54,9 +56,10 @@ custom_error! { /// Supposed to be sent as numbers, though they are sent as string most of the time? /// /// Also includes errors when initiating a connection and unexpected opcodes - #[derive(PartialEq, Eq)] + #[derive(PartialEq, Eq, Default, Clone)] pub GatewayError // Errors we have received from the gateway + #[default] Unknown = "We're not sure what went wrong. Try reconnecting?", UnknownOpcode = "You sent an invalid Gateway opcode or an invalid payload for an opcode", Decode = "Gateway server couldn't decode payload", @@ -79,3 +82,5 @@ custom_error! { // Other misc errors UnexpectedOpcodeReceived{opcode: u8} = "Received an opcode we weren't expecting to receive: {opcode}", } + +impl WebSocketEvent for GatewayError {} diff --git a/src/gateway.rs b/src/gateway.rs index ebe5ca2..e9c6053 100644 --- a/src/gateway.rs +++ b/src/gateway.rs @@ -479,13 +479,15 @@ impl Gateway { return; } - // Todo: handle errors in a good way, maybe observers like events? if msg.is_error() { - warn!("GW: Received error, connection will close.."); + let error = msg.error().unwrap(); - let _error = msg.error(); + warn!("GW: Received error {:?}, connection will close..", error); self.close().await; + + self.events.lock().await.error.notify(error).await; + return; } @@ -935,6 +937,7 @@ mod events { pub webhooks: Webhooks, pub gateway_identify_payload: GatewayEvent, pub gateway_resume: GatewayEvent, + pub error: GatewayEvent, } #[derive(Default, Debug)] diff --git a/src/types/events/call.rs b/src/types/events/call.rs index e37c19d..508aae2 100644 --- a/src/types/events/call.rs +++ b/src/types/events/call.rs @@ -21,7 +21,7 @@ pub struct CallCreate { impl WebSocketEvent for CallCreate {} -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq)] /// Officially Undocumented; /// Updates the client on which calls are ringing, along with a specific call?; /// @@ -38,7 +38,7 @@ pub struct CallUpdate { impl WebSocketEvent for CallUpdate {} -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq)] /// Officially Undocumented; /// Deletes a ringing call; /// Ex: {"t":"CALL_DELETE","s":8,"op":0,"d":{"channel_id":"837609115475771392"}} @@ -48,7 +48,7 @@ pub struct CallDelete { impl WebSocketEvent for CallDelete {} -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq)] /// Officially Undocumented; /// See ; /// diff --git a/src/types/events/hello.rs b/src/types/events/hello.rs index 44f1e4f..fef3e22 100644 --- a/src/types/events/hello.rs +++ b/src/types/events/hello.rs @@ -2,7 +2,7 @@ use crate::types::WebSocketEvent; use serde::{Deserialize, Serialize}; /// Received on gateway init, tells the client how often to send heartbeats; -#[derive(Debug, Default, Deserialize, Serialize)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] pub struct GatewayHello { pub op: i32, pub d: HelloData, @@ -10,7 +10,7 @@ pub struct GatewayHello { impl WebSocketEvent for GatewayHello {} -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq, Copy)] /// Contains info on how often the client should send heartbeats to the server; pub struct HelloData { /// How often a client should send heartbeats, in milliseconds diff --git a/src/types/events/identify.rs b/src/types/events/identify.rs index 35e1f78..12bc369 100644 --- a/src/types/events/identify.rs +++ b/src/types/events/identify.rs @@ -2,7 +2,7 @@ use crate::types::events::{PresenceUpdate, WebSocketEvent}; use serde::{Deserialize, Serialize}; use serde_with::serde_as; -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] pub struct GatewayIdentifyPayload { pub token: String, pub properties: GatewayIdentifyConnectionProps, @@ -68,7 +68,7 @@ impl GatewayIdentifyPayload { impl WebSocketEvent for GatewayIdentifyPayload {} -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] #[serde_as] pub struct GatewayIdentifyConnectionProps { /// Almost always sent @@ -144,7 +144,7 @@ impl GatewayIdentifyConnectionProps { referring_domain: None, referrer_current: None, release_channel: String::from("stable"), - client_build_number: 199933, + client_build_number: 0, } } @@ -159,7 +159,7 @@ impl GatewayIdentifyConnectionProps { system_locale: String::from("en-US"), os: String::from("Windows"), os_version: Some(String::from("10")), - client_build_number: 199933, + client_build_number: 222963, release_channel: String::from("stable"), ..Self::minimal() } diff --git a/src/types/events/mod.rs b/src/types/events/mod.rs index 4f287ce..e440c05 100644 --- a/src/types/events/mod.rs +++ b/src/types/events/mod.rs @@ -5,6 +5,8 @@ use std::collections::HashMap; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; +use serde_json::{from_str, from_value, to_value, Value}; + pub use application::*; pub use auto_moderation::*; pub use call::*; @@ -24,13 +26,13 @@ pub use ready::*; pub use relationship::*; pub use request_members::*; pub use resume::*; -use serde_json::{from_str, from_value, to_value, Value}; pub use session::*; pub use stage_instance::*; pub use thread::*; pub use user::*; pub use voice::*; pub use webhooks::*; +pub use webrtc::*; use crate::gateway::Updateable; @@ -62,6 +64,8 @@ mod user; mod voice; mod webhooks; +mod webrtc; + pub trait WebSocketEvent {} #[derive(Debug, Default, Serialize, Clone)] diff --git a/src/types/events/presence.rs b/src/types/events/presence.rs index c2d985e..e9a7dee 100644 --- a/src/types/events/presence.rs +++ b/src/types/events/presence.rs @@ -14,7 +14,7 @@ pub struct UpdatePresence { pub afk: bool, } -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq)] /// Received to tell the client that a user updated their presence / status /// See pub struct PresenceUpdate { diff --git a/src/types/events/user.rs b/src/types/events/user.rs index e3ce99a..7165812 100644 --- a/src/types/events/user.rs +++ b/src/types/events/user.rs @@ -4,7 +4,7 @@ use crate::types::entities::PublicUser; use crate::types::events::WebSocketEvent; use crate::types::utils::Snowflake; -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] /// See ; /// Sent to indicate updates to a user object; (name changes, discriminator changes, etc); pub struct UserUpdate { @@ -14,7 +14,7 @@ pub struct UserUpdate { impl WebSocketEvent for UserUpdate {} -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] /// Undocumented; /// /// Possibly an update for muted guild / channel settings for the current user; @@ -39,7 +39,7 @@ pub struct UserGuildSettingsUpdate { impl WebSocketEvent for UserGuildSettingsUpdate {} -#[derive(Debug, Default, Deserialize, Serialize, Clone)] +#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] /// Undocumented; /// /// Received in [UserGuildSettingsUpdate]; diff --git a/src/types/events/voice.rs b/src/types/events/voice.rs index ff13b73..2618ee1 100644 --- a/src/types/events/voice.rs +++ b/src/types/events/voice.rs @@ -1,7 +1,7 @@ use crate::types::{events::WebSocketEvent, Snowflake, VoiceState}; use serde::{Deserialize, Serialize}; -#[derive(Debug, Deserialize, Serialize, Default)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, Copy, PartialEq, Eq)] /// /// Sent to the server to indicate an update of the voice state (leave voice channel, join voice channel, mute, deafen); /// @@ -28,7 +28,7 @@ pub struct VoiceStateUpdate { impl WebSocketEvent for VoiceStateUpdate {} -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq)] /// See ; /// /// Received to indicate which voice endpoint, token and guild_id to use; diff --git a/src/types/events/webrtc/identify.rs b/src/types/events/webrtc/identify.rs new file mode 100644 index 0000000..45f1037 --- /dev/null +++ b/src/types/events/webrtc/identify.rs @@ -0,0 +1,18 @@ +use crate::types::{Snowflake, WebSocketEvent}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq)] +/// The identify payload for the webrtc stream; +/// Contains info to begin a webrtc connection; +/// See https://discord.com/developers/docs/topics/voice-connections#establishing-a-voice-websocket-connection-example-voice-identify-payload; +pub struct VoiceIdentify { + server_id: Snowflake, + user_id: Snowflake, + session_id: String, + token: String, + #[serde(skip_serializing_if = "Option::is_none")] + /// Undocumented field, but is also in discord client comms + video: Option, +} + +impl WebSocketEvent for VoiceIdentify {} diff --git a/src/types/events/webrtc/mod.rs b/src/types/events/webrtc/mod.rs new file mode 100644 index 0000000..ebaf7b2 --- /dev/null +++ b/src/types/events/webrtc/mod.rs @@ -0,0 +1,5 @@ +pub use identify::*; +pub use ready::*; + +mod identify; +mod ready; diff --git a/src/types/events/webrtc/ready.rs b/src/types/events/webrtc/ready.rs new file mode 100644 index 0000000..008e41e --- /dev/null +++ b/src/types/events/webrtc/ready.rs @@ -0,0 +1,29 @@ +use std::net::Ipv4Addr; + +use crate::types::WebSocketEvent; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// The ready event for the webrtc stream; +/// Used to give info after the identify event; +/// See https://discord.com/developers/docs/topics/voice-connections#establishing-a-voice-websocket-connection-example-voice-ready-payload; +pub struct VoiceReady { + ssrc: i32, + ip: Ipv4Addr, + port: u32, + modes: Vec, + // Heartbeat interval is also sent, but is "an erroneous field and should be ignored. The correct heartbeat_interval value comes from the Hello payload." +} + +impl Default for VoiceReady { + fn default() -> Self { + VoiceReady { + ssrc: 1, + ip: Ipv4Addr::UNSPECIFIED, + port: 0, + modes: Vec::new(), + } + } +} + +impl WebSocketEvent for VoiceReady {} diff --git a/src/types/interfaces/activity.rs b/src/types/interfaces/activity.rs index 1a48dfd..0da4747 100644 --- a/src/types/interfaces/activity.rs +++ b/src/types/interfaces/activity.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use crate::types::{entities::Emoji, Snowflake}; -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] pub struct Activity { name: String, #[serde(rename = "type")] @@ -22,19 +22,19 @@ pub struct Activity { buttons: Option>, } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq, Eq)] struct ActivityTimestamps { start: Option, end: Option, } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] struct ActivityParty { id: Option, size: Option>, } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] struct ActivityAssets { large_image: Option, large_text: Option, @@ -42,7 +42,7 @@ struct ActivityAssets { small_text: Option, } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] struct ActivitySecrets { join: Option, spectate: Option, @@ -50,7 +50,7 @@ struct ActivitySecrets { match_string: Option, } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] struct ActivityButton { label: String, url: String, diff --git a/src/types/interfaces/status.rs b/src/types/interfaces/status.rs index fadaf68..d5c07b6 100644 --- a/src/types/interfaces/status.rs +++ b/src/types/interfaces/status.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -#[derive(Debug, Deserialize, Serialize, Default, Clone)] +#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq, Eq)] /// See pub struct ClientStatusObject { pub desktop: Option, diff --git a/src/types/schema/user.rs b/src/types/schema/user.rs index 9946e73..5584cf4 100644 --- a/src/types/schema/user.rs +++ b/src/types/schema/user.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use crate::types::Snowflake; -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] #[serde(rename_all = "snake_case")] /// A schema used to modify a user. pub struct UserModifySchema { @@ -29,7 +29,7 @@ pub struct UserModifySchema { /// /// # Reference: /// Read: -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] pub struct PrivateChannelCreateSchema { pub recipients: Option>, pub access_tokens: Option>,