From 63cfebdf5a4c94bf8b99597ae710793e9297a4b0 Mon Sep 17 00:00:00 2001 From: kozabrada123 <“kozabrada123@users.noreply.github.com”> Date: Sun, 28 May 2023 08:18:50 +0200 Subject: [PATCH 01/34] Stability, new event --- src/gateway.rs | 5 ++++ src/types/entities/channel.rs | 2 +- src/types/entities/guild.rs | 2 +- src/types/entities/guild_member.rs | 4 +-- src/types/entities/message.rs | 4 +-- src/types/entities/user.rs | 18 ++++++------ src/types/events/guild.rs | 10 +++---- src/types/events/message.rs | 4 ++- src/types/events/thread.rs | 2 +- src/types/events/user.rs | 46 ++++++++++++++++++++++++++++-- 10 files changed, 73 insertions(+), 24 deletions(-) diff --git a/src/gateway.rs b/src/gateway.rs index 90bcff5..c11b5ee 100644 --- a/src/gateway.rs +++ b/src/gateway.rs @@ -492,6 +492,10 @@ impl Gateway { "USER_UPDATE" => { let new_data: types::UserUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); self.events.lock().await.user.update.update_data(new_data).await; + }, + "USER_GUILD_SETTINGS_UPDATE" => { + let new_data: types::UserGuildSettingsUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + self.events.lock().await.user.guild_settings_update.update_data(new_data).await; } "VOICE_STATE_UPDATE" => { let new_data: types::VoiceStateUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); @@ -781,6 +785,7 @@ mod events { #[derive(Default, Debug)] pub struct User { pub update: GatewayEvent, + pub guild_settings_update: GatewayEvent, pub presence_update: GatewayEvent, pub typing_start_event: GatewayEvent, } diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index a0c2bcb..377ef93 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -12,7 +12,7 @@ use crate::types::{ #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Channel { pub id: Snowflake, - pub created_at: chrono::DateTime, + pub created_at: Option>, #[serde(rename = "type")] pub channel_type: ChannelType, pub guild_id: Option, diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index c79ee1d..9960fe6 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -19,7 +19,7 @@ pub struct Guild { pub splash: Option, pub discovery_splash: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub owner: bool, // True if requesting user is owner + pub owner: Option, // True if requesting user is owner pub owner_id: Option, pub permissions: Option, pub afk_channel_id: Option, diff --git a/src/types/entities/guild_member.rs b/src/types/entities/guild_member.rs index 5e1ebfa..6123199 100644 --- a/src/types/entities/guild_member.rs +++ b/src/types/entities/guild_member.rs @@ -1,10 +1,10 @@ use serde::{Deserialize, Serialize}; -use crate::types::entities::User; +use crate::types::entities::PublicUser; #[derive(Debug, Deserialize, Default, Serialize, Clone, PartialEq, Eq)] pub struct GuildMember { - pub user: Option, + pub user: Option, pub nick: Option, pub avatar: Option, pub roles: Vec, diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index 484a575..c6ff6e5 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::types::{ entities::{ Application, Attachment, Channel, Emoji, GuildMember, RoleSubscriptionData, Sticker, - StickerItem, User, + StickerItem, User, PublicUser }, utils::Snowflake, }; @@ -14,7 +14,7 @@ pub struct Message { pub id: Snowflake, pub channel_id: Snowflake, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub author: User, + pub author: PublicUser, pub content: String, pub timestamp: String, pub edited_timestamp: Option, diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index f6bf5c0..bb3b0eb 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -42,11 +42,11 @@ pub struct User { #[serde(deserialize_with = "deserialize_option_number_from_string")] flags: Option, pub premium_since: Option>, - pub premium_type: u8, + pub premium_type: Option, pub pronouns: Option, pub public_flags: Option, pub banner: Option, - pub bio: String, + pub bio: Option, pub theme_colors: Option>, pub phone: Option, pub nsfw_allowed: bool, @@ -56,19 +56,19 @@ pub struct User { pub disabled: Option, } -#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct PublicUser { pub id: Snowflake, - pub username: String, - pub discriminator: String, + pub username: Option, + pub discriminator: Option, pub avatar: Option, pub accent_color: Option, pub banner: Option, pub theme_colors: Option>, pub pronouns: Option, pub bot: Option, - pub bio: String, - pub premium_type: u8, + pub bio: Option, + pub premium_type: Option, pub premium_since: Option>, pub public_flags: Option, } @@ -77,8 +77,8 @@ impl From for PublicUser { fn from(value: User) -> Self { Self { id: value.id, - username: value.username, - discriminator: value.discriminator, + username: Some(value.username), + discriminator: Some(value.discriminator), avatar: value.avatar, accent_color: value.accent_color, banner: value.banner, diff --git a/src/types/events/guild.rs b/src/types/events/guild.rs index 6ddd95d..3bd81fd 100644 --- a/src/types/events/guild.rs +++ b/src/types/events/guild.rs @@ -1,4 +1,4 @@ -use crate::types::entities::{Guild, UnavailableGuild, User}; +use crate::types::entities::{Guild, UnavailableGuild, PublicUser}; use crate::types::events::WebSocketEvent; use crate::types::{AuditLogEntry, Emoji, GuildMember, GuildScheduledEvent, RoleObject, Sticker}; use chrono::{DateTime, Utc}; @@ -32,7 +32,7 @@ impl WebSocketEvent for GuildCreate {} /// See https://discord.com/developers/docs/topics/gateway-events#guild-ban-add-guild-ban-add-event-fields pub struct GuildBanAdd { pub guild_id: String, - pub user: User, + pub user: PublicUser, } impl WebSocketEvent for GuildBanAdd {} @@ -41,7 +41,7 @@ impl WebSocketEvent for GuildBanAdd {} /// See https://discord.com/developers/docs/topics/gateway-events#guild-ban-remove pub struct GuildBanRemove { pub guild_id: String, - pub user: User, + pub user: PublicUser, } impl WebSocketEvent for GuildBanRemove {} @@ -113,7 +113,7 @@ impl WebSocketEvent for GuildMemberAdd {} /// See https://discord.com/developers/docs/topics/gateway-events#guild-member-remove pub struct GuildMemberRemove { pub guild_id: String, - pub user: User, + pub user: PublicUser, } impl WebSocketEvent for GuildMemberRemove {} @@ -123,7 +123,7 @@ impl WebSocketEvent for GuildMemberRemove {} pub struct GuildMemberUpdate { pub guild_id: String, pub roles: Vec, - pub user: User, + pub user: PublicUser, pub nick: Option, pub avatar: Option, pub joined_at: Option>, diff --git a/src/types/events/message.rs b/src/types/events/message.rs index 758deff..24eb0fa 100644 --- a/src/types/events/message.rs +++ b/src/types/events/message.rs @@ -145,7 +145,9 @@ pub struct MessageACK { /// ? pub version: u16, pub message_id: String, - pub last_viewed: Option>, + /// This is an integer??? + /// Not even unix, see '3070'??? + pub last_viewed: Option, /// What flags? pub flags: Option, pub channel_id: String, diff --git a/src/types/events/thread.rs b/src/types/events/thread.rs index a02a148..102a754 100644 --- a/src/types/events/thread.rs +++ b/src/types/events/thread.rs @@ -35,7 +35,7 @@ pub struct ThreadListSync { pub guild_id: String, pub channel_ids: Option>, pub threads: Vec, - pub members: Vec, + pub members: Option>, } impl WebSocketEvent for ThreadListSync {} diff --git a/src/types/events/user.rs b/src/types/events/user.rs index bd90771..6a0ddce 100644 --- a/src/types/events/user.rs +++ b/src/types/events/user.rs @@ -1,12 +1,54 @@ -use crate::types::entities::User; +use crate::types::entities::PublicUser; use crate::types::events::WebSocketEvent; +use crate::types::utils::Snowflake; use serde::{Deserialize, Serialize}; #[derive(Debug, Default, Deserialize, Serialize)] /// See https://discord.com/developers/docs/topics/gateway-events#user-update pub struct UserUpdate { #[serde(flatten)] - pub user: User, + pub user: PublicUser, } impl WebSocketEvent for UserUpdate {} + +#[derive(Debug, Default, Deserialize, Serialize)] +/// Undocumented +/// +/// Possibly an update for muted guild / channel settings for the current user +/// +/// {"version":2,"suppress_roles":false,"suppress_everyone":false,"notify_highlights":0,"muted":false,"mute_scheduled_events":false,"mute_config":null,"mobile_push":true,"message_notifications":1,"hide_muted_channels":false,"guild_id":"848582562217590824","flags":0,"channel_overrides":[{"muted":false,"mute_config":null,"message_notifications":3,"flags":4096,"collapsed":false,"channel_id":"1042689182893604885"}]} +pub struct UserGuildSettingsUpdate { + pub version: u8, + pub suppress_roles: bool, + pub suppress_everyone: bool, + pub notify_highlights: u8, + pub muted: bool, + pub mute_scheduled_events: bool, + /// ?? + pub mute_config: Option, + pub mobile_push: bool, + pub message_notifications: u8, + pub hide_muted_channels: bool, + pub guild_id: Snowflake, + pub flags: i32, + pub channel_overrides: Vec +} + +impl WebSocketEvent for UserGuildSettingsUpdate {} + +#[derive(Debug, Default, Deserialize, Serialize)] +/// Undocumented +/// +/// Received in [UserGuildSettingsUpdate] +/// +/// {"muted":false,"mute_config":null,"message_notifications":3,"flags":4096,"collapsed":false,"channel_id":"1042689182893604885"} +pub struct UserGuildSettingsChannelOverride { + pub muted: bool, + /// ?? + pub mute_config: Option, + pub message_notifications: u8, + pub flags: i32, + pub collapsed: bool, + pub channel_id: Snowflake, +} \ No newline at end of file From d233b82243d0790bede857f54510e98a2c0919e6 Mon Sep 17 00:00:00 2001 From: kozabrada123 <“kozabrada123@users.noreply.github.com”> Date: Sun, 28 May 2023 08:43:22 +0200 Subject: [PATCH 02/34] More stability --- src/types/entities/voice_state.rs | 2 +- src/types/events/message.rs | 32 +++++-------------------------- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/src/types/entities/voice_state.rs b/src/types/entities/voice_state.rs index dd0ab15..b4d4ae5 100644 --- a/src/types/entities/voice_state.rs +++ b/src/types/entities/voice_state.rs @@ -12,7 +12,7 @@ use crate::types::{ pub struct VoiceState { pub guild_id: Option, pub guild: Option, - pub channel_id: Snowflake, + pub channel_id: Option, pub user_id: Snowflake, pub member: Option, pub session_id: Snowflake, diff --git a/src/types/events/message.rs b/src/types/events/message.rs index 24eb0fa..94d9336 100644 --- a/src/types/events/message.rs +++ b/src/types/events/message.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::types::{ entities::{Emoji, GuildMember, Message, User}, - utils::Snowflake, + utils::Snowflake, PublicUser, }; use super::WebSocketEvent; @@ -32,31 +32,9 @@ pub struct MessageCreate { #[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 + #[serde(flatten)] + user: PublicUser, + member: Option } impl WebSocketEvent for MessageCreate {} @@ -67,7 +45,7 @@ pub struct MessageUpdate { message: Message, guild_id: Option, member: Option, - mentions: Option>, // Not sure if this is correct: https://discord.com/developers/docs/topics/gateway-events#message-create + mentions: Option>, } impl WebSocketEvent for MessageUpdate {} From ebe80914d2937696128d6715edd6adc465abce3f Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 28 May 2023 11:43:03 +0200 Subject: [PATCH 03/34] Change rusty-hook to be pre-commit --- .rusty-hook.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.rusty-hook.toml b/.rusty-hook.toml index b1bd0ab..033f863 100644 --- a/.rusty-hook.toml +++ b/.rusty-hook.toml @@ -1,5 +1,5 @@ [hooks] -pre-push = "cargo fmt --all -- --check --color always" +pre-commit = "cargo fmt -p chorus && exit 0" [logging] verbose = true From da27692b537783106d9e4eec5195fd4f3c8e07de Mon Sep 17 00:00:00 2001 From: kozabrada123 <“kozabrada123@users.noreply.github.com”> Date: Sun, 28 May 2023 14:39:41 +0200 Subject: [PATCH 04/34] Gateway opcode constants and small refactor --- src/gateway.rs | 338 +++++++++++++++++++++++----------------- src/types/events/mod.rs | 26 +++- 2 files changed, 214 insertions(+), 150 deletions(-) diff --git a/src/gateway.rs b/src/gateway.rs index c11b5ee..aadd587 100644 --- a/src/gateway.rs +++ b/src/gateway.rs @@ -5,6 +5,7 @@ use futures_util::stream::SplitSink; use futures_util::SinkExt; use futures_util::StreamExt; use native_tls::TlsConnector; +use tokio::task::JoinHandle; use std::sync::Arc; use tokio::net::TcpStream; use tokio::sync::mpsc; @@ -17,6 +18,54 @@ use tokio::time::Instant; use tokio_tungstenite::MaybeTlsStream; use tokio_tungstenite::{connect_async_tls_with_config, Connector, WebSocketStream}; +// Gateway opcodes +/// Opcode received when the server dispatches a [crate::types::WebSocketEvent] +const GATEWAY_DISPATCH: u8 = 0; +/// Opcode sent when sending a heartbeat +const GATEWAY_HEARTBEAT: u8 = 1; +/// Opcode sent to initiate a session +/// +/// See [types::GatewayIdentifyPayload] +const GATEWAY_IDENTIFY: u8 = 2; +/// Opcode sent to update our presence +/// +/// See [types::GatewayUpdatePresence] +const GATEWAY_UPDATE_PRESENCE: u8 = 3; +/// Opcode sent to update our state in vc +/// +/// Like muting, deafening, leaving, joining.. +/// +/// See [types::UpdateVoiceState] +const GATEWAY_UPDATE_VOICE_STATE: u8 = 4; +/// Opcode sent to resume a session +/// +/// See [types::GatewayResume] +const GATEWAY_RESUME: u8 = 6; +/// Opcode received to tell the client to reconnect +const GATEWAY_RECONNECT: u8 = 7; +/// Opcode sent to request guild member data +/// +/// See [types::GatewayRequestGuildMembers] +const GATEWAY_REQUEST_GUILD_MEMBERS: u8 = 8; +/// Opcode received to tell the client their token / session is invalid +const GATEWAY_INVALID_SESSION: u8 = 9; +/// Opcode received when initially connecting to the gateway, starts our heartbeat +/// +/// See [types::HelloData] +const GATEWAY_HELLO: u8 = 10; +/// Opcode received to acknowledge a heartbeat +const GATEWAY_HEARTBEAT_ACK: u8 = 11; +/// Opcode sent to get the voice state of users in a given DM/group channel +/// +/// See [types::CallSync] +const GATEWAY_CALL_SYNC: u8 = 13; +/// Opcode sent to get data for a server (Lazy Loading request) +/// +/// Sent by the official client when switching to a server +/// +/// See [types::LazyRequest] +const GATEWAY_LAZY_REQUEST: u8 = 14; + #[derive(Debug)] /** Represents a handle to a Gateway connection. A Gateway connection will create observable @@ -27,7 +76,7 @@ Using this handle you can also send Gateway Events directly. pub struct GatewayHandle { pub url: String, pub events: Arc>, - pub websocket_tx: Arc< + pub websocket_send: Arc< Mutex< SplitSink< WebSocketStream>, @@ -35,23 +84,24 @@ pub struct GatewayHandle { >, >, >, + pub handle: JoinHandle<()> } impl GatewayHandle { /// Sends json to the gateway with an opcode - async fn send_json_event(&self, op: u8, to_send: serde_json::Value) { + async fn send_json_event(&self, op_code: u8, to_send: serde_json::Value) { let gateway_payload = types::GatewaySendPayload { - op, - d: Some(to_send), - s: None + op_code, + event_data: Some(to_send), + sequence_number: None }; let payload_json = serde_json::to_string(&gateway_payload).unwrap(); let message = tokio_tungstenite::tungstenite::Message::text(payload_json); - self.websocket_tx.lock().await.send(message).await.unwrap(); + self.websocket_send.lock().await.send(message).await.unwrap(); } /// Sends an identify event to the gateway @@ -60,7 +110,7 @@ impl GatewayHandle { println!("GW: Sending Identify.."); - self.send_json_event(2, to_send_value).await; + self.send_json_event(GATEWAY_IDENTIFY, to_send_value).await; } /// Sends a resume event to the gateway @@ -69,7 +119,7 @@ impl GatewayHandle { println!("GW: Sending Resume.."); - self.send_json_event(6, to_send_value).await; + self.send_json_event(GATEWAY_RESUME, to_send_value).await; } /// Sends an update presence event to the gateway @@ -78,7 +128,7 @@ impl GatewayHandle { println!("GW: Sending Presence Update.."); - self.send_json_event(3, to_send_value).await; + self.send_json_event(GATEWAY_UPDATE_PRESENCE, to_send_value).await; } /// Sends a request guild members to the server @@ -87,7 +137,7 @@ impl GatewayHandle { println!("GW: Sending Request Guild Members.."); - self.send_json_event(8, to_send_value).await; + self.send_json_event(GATEWAY_REQUEST_GUILD_MEMBERS, to_send_value).await; } /// Sends an update voice state to the server @@ -97,7 +147,7 @@ impl GatewayHandle { println!("GW: Sending Update Voice State.."); - self.send_json_event(4, to_send_value).await; + self.send_json_event(GATEWAY_UPDATE_VOICE_STATE, to_send_value).await; } /// Sends a call sync to the server @@ -107,7 +157,7 @@ impl GatewayHandle { println!("GW: Sending Call Sync.."); - self.send_json_event(13, to_send_value).await; + self.send_json_event(GATEWAY_CALL_SYNC, to_send_value).await; } /// Sends a Lazy Request @@ -117,14 +167,14 @@ impl GatewayHandle { println!("GW: Sending Lazy Request.."); - self.send_json_event(14, to_send_value).await; + self.send_json_event(GATEWAY_LAZY_REQUEST, to_send_value).await; } } pub struct Gateway { pub events: Arc>, heartbeat_handler: Option, - pub websocket_tx: Arc< + pub websocket_send: Arc< Mutex< SplitSink< WebSocketStream>, @@ -138,7 +188,7 @@ impl Gateway { pub async fn new( websocket_url: String, ) -> Result { - let (ws_stream, _) = match connect_async_tls_with_config( + let (websocket_stream, _) = match connect_async_tls_with_config( &websocket_url, None, false, @@ -148,45 +198,45 @@ impl Gateway { ) .await { - Ok(ws_stream) => ws_stream, + Ok(websocket_stream) => websocket_stream, Err(e) => return Err(e), }; - let (ws_tx, mut ws_rx) = ws_stream.split(); + let (gateway_send, mut gateway_receive) = websocket_stream.split(); - let shared_tx = Arc::new(Mutex::new(ws_tx)); + let shared_gateway_send = Arc::new(Mutex::new(gateway_send)); let mut gateway = Gateway { events: Arc::new(Mutex::new(Events::default())), heartbeat_handler: None, - websocket_tx: shared_tx.clone(), + websocket_send: shared_gateway_send.clone(), }; let shared_events = gateway.events.clone(); // Wait for the first hello and then spawn both tasks so we avoid nested tasks // This automatically spawns the heartbeat task, but from the main thread - let msg = ws_rx.next().await.unwrap().unwrap(); + let msg = gateway_receive.next().await.unwrap().unwrap(); let gateway_payload: types::GatewayReceivePayload = serde_json::from_str(msg.to_text().unwrap()).unwrap(); - if gateway_payload.op != 10 { - println!("Recieved non hello on gateway init, what is happening?"); + if gateway_payload.op_code != GATEWAY_HELLO { + println!("Received non hello on gateway init, what is happening?"); return Err(tokio_tungstenite::tungstenite::Error::Protocol( tokio_tungstenite::tungstenite::error::ProtocolError::InvalidOpcode( - gateway_payload.op, + gateway_payload.op_code, ), )); } println!("GW: Received Hello"); - let gateway_hello: types::HelloData = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); - gateway.heartbeat_handler = Some(HeartbeatHandler::new(gateway_hello.heartbeat_interval, shared_tx.clone())); + let gateway_hello: types::HelloData = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + gateway.heartbeat_handler = Some(HeartbeatHandler::new(gateway_hello.heartbeat_interval, shared_gateway_send.clone())); - // Now we can continously check for messages in a different task, since we aren't going to receive another hello - task::spawn(async move { + // Now we can continuously check for messages in a different task, since we aren't going to receive another hello + let handle: JoinHandle<()> = task::spawn(async move { loop { - let msg = ws_rx.next().await; + let msg = gateway_receive.next().await; if msg.as_ref().is_some() { let msg_unwrapped = msg.unwrap().unwrap(); gateway.handle_event(msg_unwrapped).await; @@ -197,7 +247,8 @@ impl Gateway { return Ok(GatewayHandle { url: websocket_url.clone(), events: shared_events, - websocket_tx: shared_tx.clone(), + websocket_send: shared_gateway_send.clone(), + handle, }); } @@ -210,347 +261,341 @@ impl Gateway { let gateway_payload: types::GatewayReceivePayload = 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 { - // Dispatch + match gateway_payload.op_code { // An event was dispatched, we need to look at the gateway event name t - 0 => { - let gateway_payload_t = gateway_payload.clone().t.unwrap(); + GATEWAY_DISPATCH => { + let gateway_payload_t = gateway_payload.clone().event_name.unwrap(); println!("GW: Received {}..", gateway_payload_t); //println!("Event data dump: {}", gateway_payload.d.clone().unwrap().get()); // See https://discord.com/developers/docs/topics/gateway-events#receive-events - // "Some" of these are uncodumented + // "Some" of these are undocumented match gateway_payload_t.as_str() { "READY" => { - let new_data: types::GatewayReady = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GatewayReady = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.session.ready.update_data(new_data).await; }, "READY_SUPPLEMENTAL" => { - let new_data: types::GatewayReadySupplemental = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); - self.events.lock().await.session.ready_supplimental.update_data(new_data).await; + let new_data: types::GatewayReadySupplemental = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + self.events.lock().await.session.ready_supplemental.update_data(new_data).await; } "RESUMED" => {} "APPLICATION_COMMAND_PERMISSIONS_UPDATE" => { - let new_data: types::ApplicationCommandPermissionsUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::ApplicationCommandPermissionsUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.application.command_permissions_update.update_data(new_data).await; } "AUTO_MODERATION_RULE_CREATE" => { - let new_data: types::AutoModerationRuleCreate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::AutoModerationRuleCreate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.auto_moderation.rule_create.update_data(new_data).await; } "AUTO_MODERATION_RULE_UPDATE" => { - let new_data: types::AutoModerationRuleUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::AutoModerationRuleUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.auto_moderation.rule_update.update_data(new_data).await; } "AUTO_MODERATION_RULE_DELETE" => { - let new_data: types::AutoModerationRuleDelete = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::AutoModerationRuleDelete = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.auto_moderation.rule_delete.update_data(new_data).await; } "AUTO_MODERATION_ACTION_EXECUTION" => { - let new_data: types::AutoModerationActionExecution = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::AutoModerationActionExecution = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.auto_moderation.action_execution.update_data(new_data).await; } "CHANNEL_CREATE" => { - let new_data: types::ChannelCreate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::ChannelCreate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.channel.create.update_data(new_data).await; } "CHANNEL_UPDATE" => { - let new_data: types::ChannelUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::ChannelUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.channel.update.update_data(new_data).await; } "CHANNEL_UNREAD_UPDATE" => { - let new_data: types::ChannelUnreadUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::ChannelUnreadUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.channel.unread_update.update_data(new_data).await; } "CHANNEL_DELETE" => { - let new_data: types::ChannelDelete = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::ChannelDelete = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.channel.delete.update_data(new_data).await; } "CHANNEL_PINS_UPDATE" => { - let new_data: types::ChannelPinsUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::ChannelPinsUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.channel.pins_update.update_data(new_data).await; } "CALL_CREATE" => { - let new_data: types::CallCreate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::CallCreate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.call.create.update_data(new_data).await; }, "CALL_UPDATE" => { - let new_data: types::CallUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::CallUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.call.update.update_data(new_data).await; } "CALL_DELETE" => { - let new_data: types::CallDelete = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::CallDelete = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.call.delete.update_data(new_data).await; } "THREAD_CREATE" => { - let new_data: types::ThreadCreate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::ThreadCreate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.thread.create.update_data(new_data).await; } "THREAD_UPDATE" => { - let new_data: types::ThreadUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::ThreadUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.thread.update.update_data(new_data).await; } "THREAD_DELETE" => { - let new_data: types::ThreadDelete = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::ThreadDelete = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.thread.delete.update_data(new_data).await; } "THREAD_LIST_SYNC" => { - let new_data: types::ThreadListSync = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::ThreadListSync = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.thread.list_sync.update_data(new_data).await; } "THREAD_MEMBER_UPDATE" => { - let new_data: types::ThreadMemberUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::ThreadMemberUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.thread.member_update.update_data(new_data).await; } "THREAD_MEMBERS_UPDATE" => { - let new_data: types::ThreadMembersUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::ThreadMembersUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.thread.members_update.update_data(new_data).await; } "GUILD_CREATE" => { - let new_data: types::GuildCreate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildCreate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.create.update_data(new_data).await; } "GUILD_UPDATE" => { - let new_data: types::GuildUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.update.update_data(new_data).await; } "GUILD_DELETE" => { - let new_data: types::GuildDelete = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildDelete = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.delete.update_data(new_data).await; } "GUILD_AUDIT_LOG_ENTRY_CREATE" => { - let new_data: types::GuildAuditLogEntryCreate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildAuditLogEntryCreate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.audit_log_entry_create.update_data(new_data).await; } "GUILD_BAN_ADD" => { - let new_data: types::GuildBanAdd = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildBanAdd = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.ban_add.update_data(new_data).await; } "GUILD_BAN_REMOVE" => { - let new_data: types::GuildBanRemove = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildBanRemove = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.ban_remove.update_data(new_data).await; } "GUILD_EMOJIS_UPDATE" => { - let new_data: types::GuildEmojisUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildEmojisUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.emojis_update.update_data(new_data).await; } "GUILD_STICKERS_UPDATE" => { - let new_data: types::GuildStickersUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildStickersUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.stickers_update.update_data(new_data).await; } "GUILD_INTEGRATIONS_UPDATE" => { - let new_data: types::GuildIntegrationsUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildIntegrationsUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.integrations_update.update_data(new_data).await; } "GUILD_MEMBER_ADD" => { - let new_data: types::GuildMemberAdd = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildMemberAdd = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.member_add.update_data(new_data).await; } "GUILD_MEMBER_REMOVE" => { - let new_data: types::GuildMemberRemove = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildMemberRemove = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.member_remove.update_data(new_data).await; } "GUILD_MEMBER_UPDATE" => { - let new_data: types::GuildMemberUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildMemberUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.member_update.update_data(new_data).await; } "GUILD_MEMBERS_CHUNK" => { - let new_data: types::GuildMembersChunk = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildMembersChunk = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.members_chunk.update_data(new_data).await; } "GUILD_ROLE_CREATE" => { - let new_data: types::GuildRoleCreate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildRoleCreate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.role_create.update_data(new_data).await; } "GUILD_ROLE_UPDATE" => { - let new_data: types::GuildRoleUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildRoleUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.role_update.update_data(new_data).await; } "GUILD_ROLE_DELETE" => { - let new_data: types::GuildRoleDelete = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildRoleDelete = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.role_delete.update_data(new_data).await; } "GUILD_SCHEDULED_EVENT_CREATE" => { - let new_data: types::GuildScheduledEventCreate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildScheduledEventCreate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.role_scheduled_event_create.update_data(new_data).await; } "GUILD_SCHEDULED_EVENT_UPDATE" => { - let new_data: types::GuildScheduledEventUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildScheduledEventUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.role_scheduled_event_update.update_data(new_data).await; } "GUILD_SCHEDULED_EVENT_DELETE" => { - let new_data: types::GuildScheduledEventDelete = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildScheduledEventDelete = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.role_scheduled_event_delete.update_data(new_data).await; } "GUILD_SCHEDULED_EVENT_USER_ADD" => { - let new_data: types::GuildScheduledEventUserAdd = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildScheduledEventUserAdd = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.role_scheduled_event_user_add.update_data(new_data).await; } "GUILD_SCHEDULED_EVENT_USER_REMOVE" => { - let new_data: types::GuildScheduledEventUserRemove = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::GuildScheduledEventUserRemove = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.role_scheduled_event_user_remove.update_data(new_data).await; } "PASSIVE_UPDATE_V1" => { - let new_data: types::PassiveUpdateV1 = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::PassiveUpdateV1 = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.guild.passive_update_v1.update_data(new_data).await; } "INTEGRATION_CREATE" => { - let new_data: types::IntegrationCreate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::IntegrationCreate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.integration.create.update_data(new_data).await; } "INTEGRATION_UPDATE" => { - let new_data: types::IntegrationUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::IntegrationUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.integration.update.update_data(new_data).await; } "INTEGRATION_DELETE" => { - let new_data: types::IntegrationDelete = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::IntegrationDelete = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.integration.delete.update_data(new_data).await; } "INTERACTION_CREATE" => { - let new_data: types::InteractionCreate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::InteractionCreate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.interaction.create.update_data(new_data).await; } "INVITE_CREATE" => { - let new_data: types::InviteCreate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::InviteCreate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.invite.create.update_data(new_data).await; } "INVITE_DELETE" => { - let new_data: types::InviteDelete = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::InviteDelete = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.invite.delete.update_data(new_data).await; } "MESSAGE_CREATE" => { - let new_data: types::MessageCreate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::MessageCreate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.message.create.update_data(new_data).await; } "MESSAGE_UPDATE" => { - let new_data: types::MessageUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::MessageUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.message.update.update_data(new_data).await; } "MESSAGE_DELETE" => { - let new_data: types::MessageDelete = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::MessageDelete = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.message.delete.update_data(new_data).await; } "MESSAGE_DELETE_BULK" => { - let new_data: types::MessageDeleteBulk = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::MessageDeleteBulk = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.message.delete_bulk.update_data(new_data).await; } "MESSAGE_REACTION_ADD" => { - let new_data: types::MessageReactionAdd = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::MessageReactionAdd = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.message.reaction_add.update_data(new_data).await; } "MESSAGE_REACTION_REMOVE" => { - let new_data: types::MessageReactionRemove = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::MessageReactionRemove = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.message.reaction_remove.update_data(new_data).await; } "MESSAGE_REACTION_REMOVE_ALL" => { - let new_data: types::MessageReactionRemoveAll = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::MessageReactionRemoveAll = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.message.reaction_remove_all.update_data(new_data).await; } "MESSAGE_REACTION_REMOVE_EMOJI" => { - let new_data: types::MessageReactionRemoveEmoji= serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::MessageReactionRemoveEmoji= serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.message.reaction_remove_emoji.update_data(new_data).await; }, "MESSAGE_ACK" => { - let new_data: types::MessageACK = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::MessageACK = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.message.ack.update_data(new_data).await; } "PRESENCE_UPDATE" => { - let new_data: types::PresenceUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::PresenceUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.user.presence_update.update_data(new_data).await; } "RELATIONSHIP_ADD" => { - let new_data: types::RelationshipAdd = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::RelationshipAdd = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.relationship.add.update_data(new_data).await; } "RELATIONSHIP_REMOVE" => { - let new_data: types::RelationshipRemove = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::RelationshipRemove = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.relationship.remove.update_data(new_data).await; } "STAGE_INSTANCE_CREATE" => { - let new_data: types::StageInstanceCreate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::StageInstanceCreate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.stage_instance.create.update_data(new_data).await; } "STAGE_INSTANCE_UPDATE" => { - let new_data: types::StageInstanceUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::StageInstanceUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.stage_instance.update.update_data(new_data).await; } "STAGE_INSTANCE_DELETE" => { - let new_data: types::StageInstanceDelete = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::StageInstanceDelete = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.stage_instance.delete.update_data(new_data).await; } "SESSIONS_REPLACE" => { - let sessions: Vec = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let sessions: Vec = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); let new_data = types::SessionsReplace {sessions}; self.events.lock().await.session.replace.update_data(new_data).await; } "TYPING_START" => { - let new_data: types::TypingStartEvent = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::TypingStartEvent = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.user.typing_start_event.update_data(new_data).await; } "USER_UPDATE" => { - let new_data: types::UserUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::UserUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.user.update.update_data(new_data).await; }, "USER_GUILD_SETTINGS_UPDATE" => { - let new_data: types::UserGuildSettingsUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::UserGuildSettingsUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.user.guild_settings_update.update_data(new_data).await; } "VOICE_STATE_UPDATE" => { - let new_data: types::VoiceStateUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::VoiceStateUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.voice.state_update.update_data(new_data).await; } "VOICE_SERVER_UPDATE" => { - let new_data: types::VoiceServerUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::VoiceServerUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.voice.server_update.update_data(new_data).await; } "WEBHOOKS_UPDATE" => { - let new_data: types::WebhooksUpdate = serde_json::from_str(gateway_payload.d.unwrap().get()).unwrap(); + let new_data: types::WebhooksUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); self.events.lock().await.webhooks.update.update_data(new_data).await; } _ => { - println!("Received unrecognised gateway event ({})! Please open an issue on the chorus github so we can implement it", &gateway_payload_t); + println!("Received unrecognized gateway event ({})! Please open an issue on the chorus github so we can implement it", &gateway_payload_t); } } } - // Heartbeat // We received a heartbeat from the server - 1 => {} - // Reconnect - 7 => { + GATEWAY_HEARTBEAT => {} + GATEWAY_RECONNECT => { todo!() } - // Invalid Session - 9 => { + GATEWAY_INVALID_SESSION => { todo!() } - // Hello // Starts our heartbeat // We should have already handled this in gateway init - 10 => { - panic!("Recieved hello when it was unexpected"); + GATEWAY_HELLO => { + panic!("Received hello when it was unexpected"); } - // Heartbeat ACK - 11 => { + GATEWAY_HEARTBEAT_ACK => { println!("GW: Received Heartbeat ACK"); } - 2 | 3 | 4 | 6 | 8 => {panic!("Received gateway op code that's meant to be sent, not received ({})", gateway_payload.op)} - _ => {println!("Received unrecognised gateway op code ({})! Please open an issue on the chorus github so we can implement it", gateway_payload.op);} + GATEWAY_IDENTIFY | GATEWAY_UPDATE_PRESENCE | GATEWAY_UPDATE_VOICE_STATE | GATEWAY_RESUME | GATEWAY_REQUEST_GUILD_MEMBERS | GATEWAY_CALL_SYNC | GATEWAY_LAZY_REQUEST => {panic!("Received gateway op code that's meant to be sent, not received ({})", gateway_payload.op_code)} + _ => {println!("Received unrecognized gateway op code ({})! Please open an issue on the chorus github so we can implement it", gateway_payload.op_code);} } // If we have an active heartbeat thread and we received a seq number we should let it know - if gateway_payload.s.is_some() { + if gateway_payload.sequence_number.is_some() { if self.heartbeat_handler.is_some() { let heartbeat_communication = HeartbeatThreadCommunication { - op: gateway_payload.op, - d: gateway_payload.s.unwrap(), + op_code: gateway_payload.op_code, + sequence_number: gateway_payload.sequence_number.unwrap(), }; self.heartbeat_handler .as_mut() .unwrap() - .tx + .send .send(heartbeat_communication) .await .unwrap(); @@ -564,8 +609,11 @@ Handles sending heartbeats to the gateway in another thread */ struct HeartbeatHandler { /// The heartbeat interval in milliseconds - heartbeat_interval: u128, - tx: Sender, + pub heartbeat_interval: u128, + /// The send channel for the heartbeat thread + pub send: Sender, + /// The handle of the thread + handle: JoinHandle<()> } impl HeartbeatHandler { @@ -580,25 +628,28 @@ impl HeartbeatHandler { >, >, ) -> HeartbeatHandler { - let (tx, mut rx) = mpsc::channel(32); + let (send, mut receive) = mpsc::channel(32); - task::spawn(async move { - let mut last_heartbeat: Instant = time::Instant::now(); + let handle: JoinHandle<()> = task::spawn(async move { + + let mut last_heartbeat_timestamp: Instant = time::Instant::now(); let mut last_seq_number: Option = None; loop { // If we received a seq number update, use that as the last seq number - let hb_communication: Result = - rx.try_recv(); - if hb_communication.is_ok() { - last_seq_number = Some(hb_communication.unwrap().d); + let received_communication: Result = + receive.try_recv(); + if received_communication.is_ok() { + last_seq_number = Some(received_communication.unwrap().sequence_number); } - if last_heartbeat.elapsed().as_millis() > heartbeat_interval { + let should_send = last_heartbeat_timestamp.elapsed().as_millis() >= heartbeat_interval; + + if should_send { println!("GW: Sending Heartbeat.."); let heartbeat = types::GatewayHeartbeat { - op: 1, + op: GATEWAY_HEARTBEAT, d: last_seq_number, }; @@ -608,14 +659,15 @@ impl HeartbeatHandler { websocket_tx.lock().await.send(msg).await.unwrap(); - last_heartbeat = time::Instant::now(); + last_heartbeat_timestamp = time::Instant::now(); } } }); Self { heartbeat_interval, - tx, + send, + handle, } } } @@ -626,14 +678,14 @@ Either signifies a sequence number update or a received heartbeat ack */ #[derive(Clone, Copy, Debug)] struct HeartbeatThreadCommunication { - /// An opcode for the communication we received - op: u8, + /// The opcode for the communication we received + op_code: u8, /// The sequence number we got from discord - d: u64, + sequence_number: u64, } /** -Trait which defines the behaviour of an Observer. An Observer is an object which is subscribed to +Trait which defines the behavior of an Observer. An Observer is an object which is subscribed to an Observable. The Observer is notified when the Observable's data changes. In this case, the Observable is a [`GatewayEvent`], which is a wrapper around a WebSocketEvent. */ @@ -758,7 +810,7 @@ mod events { #[derive(Default, Debug)] pub struct Session { pub ready: GatewayEvent, - pub ready_supplimental: GatewayEvent, + pub ready_supplemental: GatewayEvent, pub replace: GatewayEvent } @@ -891,7 +943,7 @@ mod example { } #[tokio::test] - async fn test_observer_behaviour() { + async fn test_observer_behavior() { let mut event = GatewayEvent::new(types::GatewayResume { token: "start".to_string(), session_id: "start".to_string(), diff --git a/src/types/events/mod.rs b/src/types/events/mod.rs index 3dbf5a6..61cdf6d 100644 --- a/src/types/events/mod.rs +++ b/src/types/events/mod.rs @@ -60,11 +60,16 @@ pub trait WebSocketEvent {} /// Similar to [GatewayReceivePayload], except we send a [Value] for d whilst we receive a [serde_json::value::RawValue] /// Also, we never need to send the event name pub struct GatewaySendPayload { - pub op: u8, + #[serde(rename = "op")] + pub op_code: u8, + + #[serde(rename = "d")] #[serde(skip_serializing_if = "Option::is_none")] - pub d: Option, + pub event_data: Option, + + #[serde(rename = "s")] #[serde(skip_serializing_if = "Option::is_none")] - pub s: Option, + pub sequence_number: Option, } impl WebSocketEvent for GatewaySendPayload {} @@ -76,11 +81,18 @@ impl WebSocketEvent for GatewaySendPayload {} /// Also, we never need to sent the event name pub struct GatewayReceivePayload<'a> { - pub op: u8, + #[serde(rename = "op")] + pub op_code: u8, + #[serde(borrow)] - pub d: Option<&'a serde_json::value::RawValue>, - pub s: Option, - pub t: Option, + #[serde(rename = "d")] + pub event_data: Option<&'a serde_json::value::RawValue>, + + #[serde(rename = "s")] + pub sequence_number: Option, + + #[serde(rename = "t")] + pub event_name: Option, } impl<'a> WebSocketEvent for GatewayReceivePayload<'a> {} From 0fd7b304ad59c228f922d24d1514452bda7cf2ec Mon Sep 17 00:00:00 2001 From: kozabrada123 <“kozabrada123@users.noreply.github.com”> Date: Sun, 28 May 2023 14:52:48 +0200 Subject: [PATCH 05/34] agjbg??! --- src/gateway.rs | 281 ++++++++++++++++++++++------------ src/types/entities/message.rs | 4 +- src/types/events/guild.rs | 2 +- src/types/events/user.rs | 12 +- 4 files changed, 196 insertions(+), 103 deletions(-) diff --git a/src/gateway.rs b/src/gateway.rs index 9cf7b0a..7906b01 100644 --- a/src/gateway.rs +++ b/src/gateway.rs @@ -5,7 +5,6 @@ use futures_util::stream::SplitSink; use futures_util::SinkExt; use futures_util::StreamExt; use native_tls::TlsConnector; -use tokio::task::JoinHandle; use std::sync::Arc; use tokio::net::TcpStream; use tokio::sync::mpsc; @@ -13,6 +12,7 @@ use tokio::sync::mpsc::error::TryRecvError; use tokio::sync::mpsc::Sender; use tokio::sync::Mutex; use tokio::task; +use tokio::task::JoinHandle; use tokio::time; use tokio::time::Instant; use tokio_tungstenite::MaybeTlsStream; @@ -24,45 +24,45 @@ const GATEWAY_DISPATCH: u8 = 0; /// Opcode sent when sending a heartbeat const GATEWAY_HEARTBEAT: u8 = 1; /// Opcode sent to initiate a session -/// +/// /// See [types::GatewayIdentifyPayload] const GATEWAY_IDENTIFY: u8 = 2; /// Opcode sent to update our presence -/// +/// /// See [types::GatewayUpdatePresence] const GATEWAY_UPDATE_PRESENCE: u8 = 3; /// Opcode sent to update our state in vc -/// +/// /// Like muting, deafening, leaving, joining.. -/// +/// /// See [types::UpdateVoiceState] const GATEWAY_UPDATE_VOICE_STATE: u8 = 4; /// Opcode sent to resume a session -/// +/// /// See [types::GatewayResume] const GATEWAY_RESUME: u8 = 6; /// Opcode received to tell the client to reconnect const GATEWAY_RECONNECT: u8 = 7; /// Opcode sent to request guild member data -/// +/// /// See [types::GatewayRequestGuildMembers] const GATEWAY_REQUEST_GUILD_MEMBERS: u8 = 8; /// Opcode received to tell the client their token / session is invalid const GATEWAY_INVALID_SESSION: u8 = 9; /// Opcode received when initially connecting to the gateway, starts our heartbeat -/// +/// /// See [types::HelloData] const GATEWAY_HELLO: u8 = 10; /// Opcode received to acknowledge a heartbeat const GATEWAY_HEARTBEAT_ACK: u8 = 11; /// Opcode sent to get the voice state of users in a given DM/group channel -/// +/// /// See [types::CallSync] const GATEWAY_CALL_SYNC: u8 = 13; /// Opcode sent to get data for a server (Lazy Loading request) -/// +/// /// Sent by the official client when switching to a server -/// +/// /// See [types::LazyRequest] const GATEWAY_LAZY_REQUEST: u8 = 14; @@ -84,7 +84,7 @@ pub struct GatewayHandle { >, >, >, - pub handle: JoinHandle<()> + pub handle: JoinHandle<()>, } impl GatewayHandle { @@ -100,7 +100,12 @@ impl GatewayHandle { let message = tokio_tungstenite::tungstenite::Message::text(payload_json); - self.websocket_send.lock().await.send(message).await.unwrap(); + self.websocket_send + .lock() + .await + .send(message) + .await + .unwrap(); } /// Sends an identify event to the gateway @@ -127,7 +132,8 @@ impl GatewayHandle { println!("GW: Sending Presence Update.."); - self.send_json_event(GATEWAY_UPDATE_PRESENCE, to_send_value).await; + self.send_json_event(GATEWAY_UPDATE_PRESENCE, to_send_value) + .await; } /// Sends a request guild members to the server @@ -136,7 +142,8 @@ impl GatewayHandle { println!("GW: Sending Request Guild Members.."); - self.send_json_event(GATEWAY_REQUEST_GUILD_MEMBERS, to_send_value).await; + self.send_json_event(GATEWAY_REQUEST_GUILD_MEMBERS, to_send_value) + .await; } /// Sends an update voice state to the server @@ -145,7 +152,8 @@ impl GatewayHandle { println!("GW: Sending Update Voice State.."); - self.send_json_event(GATEWAY_UPDATE_VOICE_STATE, to_send_value).await; + self.send_json_event(GATEWAY_UPDATE_VOICE_STATE, to_send_value) + .await; } /// Sends a call sync to the server @@ -163,7 +171,8 @@ impl GatewayHandle { println!("GW: Sending Lazy Request.."); - self.send_json_event(GATEWAY_LAZY_REQUEST, to_send_value).await; + self.send_json_event(GATEWAY_LAZY_REQUEST, to_send_value) + .await; } } @@ -277,7 +286,8 @@ impl Gateway { match gateway_payload_t.as_str() { "READY" => { let new_data: types::GatewayReady = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -288,7 +298,8 @@ impl Gateway { } "READY_SUPPLEMENTAL" => { let new_data: types::GatewayReadySupplemental = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -300,7 +311,8 @@ impl Gateway { "RESUMED" => {} "APPLICATION_COMMAND_PERMISSIONS_UPDATE" => { let new_data: types::ApplicationCommandPermissionsUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -311,7 +323,8 @@ impl Gateway { } "AUTO_MODERATION_RULE_CREATE" => { let new_data: types::AutoModerationRuleCreate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -322,7 +335,8 @@ impl Gateway { } "AUTO_MODERATION_RULE_UPDATE" => { let new_data: types::AutoModerationRuleUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -333,7 +347,8 @@ impl Gateway { } "AUTO_MODERATION_RULE_DELETE" => { let new_data: types::AutoModerationRuleDelete = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -344,7 +359,8 @@ impl Gateway { } "AUTO_MODERATION_ACTION_EXECUTION" => { let new_data: types::AutoModerationActionExecution = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -355,7 +371,8 @@ impl Gateway { } "CHANNEL_CREATE" => { let new_data: types::ChannelCreate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -366,7 +383,8 @@ impl Gateway { } "CHANNEL_UPDATE" => { let new_data: types::ChannelUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -377,7 +395,8 @@ impl Gateway { } "CHANNEL_UNREAD_UPDATE" => { let new_data: types::ChannelUnreadUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -388,7 +407,8 @@ impl Gateway { } "CHANNEL_DELETE" => { let new_data: types::ChannelDelete = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -399,7 +419,8 @@ impl Gateway { } "CHANNEL_PINS_UPDATE" => { let new_data: types::ChannelPinsUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -410,7 +431,8 @@ impl Gateway { } "CALL_CREATE" => { let new_data: types::CallCreate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -421,7 +443,8 @@ impl Gateway { } "CALL_UPDATE" => { let new_data: types::CallUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -432,7 +455,8 @@ impl Gateway { } "CALL_DELETE" => { let new_data: types::CallDelete = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -443,7 +467,8 @@ impl Gateway { } "THREAD_CREATE" => { let new_data: types::ThreadCreate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -454,7 +479,8 @@ impl Gateway { } "THREAD_UPDATE" => { let new_data: types::ThreadUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -465,7 +491,8 @@ impl Gateway { } "THREAD_DELETE" => { let new_data: types::ThreadDelete = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -476,7 +503,8 @@ impl Gateway { } "THREAD_LIST_SYNC" => { let new_data: types::ThreadListSync = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -487,7 +515,8 @@ impl Gateway { } "THREAD_MEMBER_UPDATE" => { let new_data: types::ThreadMemberUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -498,7 +527,8 @@ impl Gateway { } "THREAD_MEMBERS_UPDATE" => { let new_data: types::ThreadMembersUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -509,7 +539,8 @@ impl Gateway { } "GUILD_CREATE" => { let new_data: types::GuildCreate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -520,7 +551,8 @@ impl Gateway { } "GUILD_UPDATE" => { let new_data: types::GuildUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -531,7 +563,8 @@ impl Gateway { } "GUILD_DELETE" => { let new_data: types::GuildDelete = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -542,7 +575,8 @@ impl Gateway { } "GUILD_AUDIT_LOG_ENTRY_CREATE" => { let new_data: types::GuildAuditLogEntryCreate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -553,7 +587,8 @@ impl Gateway { } "GUILD_BAN_ADD" => { let new_data: types::GuildBanAdd = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -564,7 +599,8 @@ impl Gateway { } "GUILD_BAN_REMOVE" => { let new_data: types::GuildBanRemove = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -575,7 +611,8 @@ impl Gateway { } "GUILD_EMOJIS_UPDATE" => { let new_data: types::GuildEmojisUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -586,7 +623,8 @@ impl Gateway { } "GUILD_STICKERS_UPDATE" => { let new_data: types::GuildStickersUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -597,7 +635,8 @@ impl Gateway { } "GUILD_INTEGRATIONS_UPDATE" => { let new_data: types::GuildIntegrationsUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -608,7 +647,8 @@ impl Gateway { } "GUILD_MEMBER_ADD" => { let new_data: types::GuildMemberAdd = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -619,7 +659,8 @@ impl Gateway { } "GUILD_MEMBER_REMOVE" => { let new_data: types::GuildMemberRemove = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -630,7 +671,8 @@ impl Gateway { } "GUILD_MEMBER_UPDATE" => { let new_data: types::GuildMemberUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -641,7 +683,8 @@ impl Gateway { } "GUILD_MEMBERS_CHUNK" => { let new_data: types::GuildMembersChunk = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -652,7 +695,8 @@ impl Gateway { } "GUILD_ROLE_CREATE" => { let new_data: types::GuildRoleCreate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -663,7 +707,8 @@ impl Gateway { } "GUILD_ROLE_UPDATE" => { let new_data: types::GuildRoleUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -674,7 +719,8 @@ impl Gateway { } "GUILD_ROLE_DELETE" => { let new_data: types::GuildRoleDelete = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -685,7 +731,8 @@ impl Gateway { } "GUILD_SCHEDULED_EVENT_CREATE" => { let new_data: types::GuildScheduledEventCreate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -696,7 +743,8 @@ impl Gateway { } "GUILD_SCHEDULED_EVENT_UPDATE" => { let new_data: types::GuildScheduledEventUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -707,7 +755,8 @@ impl Gateway { } "GUILD_SCHEDULED_EVENT_DELETE" => { let new_data: types::GuildScheduledEventDelete = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -718,7 +767,8 @@ impl Gateway { } "GUILD_SCHEDULED_EVENT_USER_ADD" => { let new_data: types::GuildScheduledEventUserAdd = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -729,7 +779,8 @@ impl Gateway { } "GUILD_SCHEDULED_EVENT_USER_REMOVE" => { let new_data: types::GuildScheduledEventUserRemove = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -740,7 +791,8 @@ impl Gateway { } "PASSIVE_UPDATE_V1" => { let new_data: types::PassiveUpdateV1 = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -751,7 +803,8 @@ impl Gateway { } "INTEGRATION_CREATE" => { let new_data: types::IntegrationCreate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -762,7 +815,8 @@ impl Gateway { } "INTEGRATION_UPDATE" => { let new_data: types::IntegrationUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -773,7 +827,8 @@ impl Gateway { } "INTEGRATION_DELETE" => { let new_data: types::IntegrationDelete = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -784,7 +839,8 @@ impl Gateway { } "INTERACTION_CREATE" => { let new_data: types::InteractionCreate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -795,7 +851,8 @@ impl Gateway { } "INVITE_CREATE" => { let new_data: types::InviteCreate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -806,7 +863,8 @@ impl Gateway { } "INVITE_DELETE" => { let new_data: types::InviteDelete = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -817,7 +875,8 @@ impl Gateway { } "MESSAGE_CREATE" => { let new_data: types::MessageCreate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -828,7 +887,8 @@ impl Gateway { } "MESSAGE_UPDATE" => { let new_data: types::MessageUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -839,7 +899,8 @@ impl Gateway { } "MESSAGE_DELETE" => { let new_data: types::MessageDelete = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -850,7 +911,8 @@ impl Gateway { } "MESSAGE_DELETE_BULK" => { let new_data: types::MessageDeleteBulk = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -861,7 +923,8 @@ impl Gateway { } "MESSAGE_REACTION_ADD" => { let new_data: types::MessageReactionAdd = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -872,7 +935,8 @@ impl Gateway { } "MESSAGE_REACTION_REMOVE" => { let new_data: types::MessageReactionRemove = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -883,7 +947,8 @@ impl Gateway { } "MESSAGE_REACTION_REMOVE_ALL" => { let new_data: types::MessageReactionRemoveAll = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -894,7 +959,8 @@ impl Gateway { } "MESSAGE_REACTION_REMOVE_EMOJI" => { let new_data: types::MessageReactionRemoveEmoji = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -905,7 +971,8 @@ impl Gateway { } "MESSAGE_ACK" => { let new_data: types::MessageACK = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -916,7 +983,8 @@ impl Gateway { } "PRESENCE_UPDATE" => { let new_data: types::PresenceUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -927,7 +995,8 @@ impl Gateway { } "RELATIONSHIP_ADD" => { let new_data: types::RelationshipAdd = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -938,7 +1007,8 @@ impl Gateway { } "RELATIONSHIP_REMOVE" => { let new_data: types::RelationshipRemove = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -949,7 +1019,8 @@ impl Gateway { } "STAGE_INSTANCE_CREATE" => { let new_data: types::StageInstanceCreate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -960,7 +1031,8 @@ impl Gateway { } "STAGE_INSTANCE_UPDATE" => { let new_data: types::StageInstanceUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -971,7 +1043,8 @@ impl Gateway { } "STAGE_INSTANCE_DELETE" => { let new_data: types::StageInstanceDelete = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -982,7 +1055,8 @@ impl Gateway { } "SESSIONS_REPLACE" => { let sessions: Vec = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); let new_data = types::SessionsReplace { sessions }; self.events .lock() @@ -994,7 +1068,8 @@ impl Gateway { } "TYPING_START" => { let new_data: types::TypingStartEvent = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -1005,7 +1080,8 @@ impl Gateway { } "USER_UPDATE" => { let new_data: types::UserUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -1013,14 +1089,23 @@ impl Gateway { .update .update_data(new_data) .await; - }, + } "USER_GUILD_SETTINGS_UPDATE" => { - let new_data: types::UserGuildSettingsUpdate = serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); - self.events.lock().await.user.guild_settings_update.update_data(new_data).await; + let new_data: types::UserGuildSettingsUpdate = + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); + self.events + .lock() + .await + .user + .guild_settings_update + .update_data(new_data) + .await; } "VOICE_STATE_UPDATE" => { let new_data: types::VoiceStateUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -1031,7 +1116,8 @@ impl Gateway { } "VOICE_SERVER_UPDATE" => { let new_data: types::VoiceServerUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -1042,7 +1128,8 @@ impl Gateway { } "WEBHOOKS_UPDATE" => { let new_data: types::WebhooksUpdate = - serde_json::from_str(gateway_payload.event_data.unwrap().get()).unwrap(); + serde_json::from_str(gateway_payload.event_data.unwrap().get()) + .unwrap(); self.events .lock() .await @@ -1072,7 +1159,13 @@ impl Gateway { GATEWAY_HEARTBEAT_ACK => { println!("GW: Received Heartbeat ACK"); } - GATEWAY_IDENTIFY | GATEWAY_UPDATE_PRESENCE | GATEWAY_UPDATE_VOICE_STATE | GATEWAY_RESUME | GATEWAY_REQUEST_GUILD_MEMBERS | GATEWAY_CALL_SYNC | GATEWAY_LAZY_REQUEST => { + GATEWAY_IDENTIFY + | GATEWAY_UPDATE_PRESENCE + | GATEWAY_UPDATE_VOICE_STATE + | GATEWAY_RESUME + | GATEWAY_REQUEST_GUILD_MEMBERS + | GATEWAY_CALL_SYNC + | GATEWAY_LAZY_REQUEST => { panic!( "Received gateway op code that's meant to be sent, not received ({})", gateway_payload.op_code @@ -1112,7 +1205,7 @@ struct HeartbeatHandler { /// The send channel for the heartbeat thread pub send: Sender, /// The handle of the thread - handle: JoinHandle<()> + handle: JoinHandle<()>, } impl HeartbeatHandler { @@ -1130,7 +1223,6 @@ impl HeartbeatHandler { let (send, mut receive) = mpsc::channel(32); let handle: JoinHandle<()> = task::spawn(async move { - let mut last_heartbeat_timestamp: Instant = time::Instant::now(); let mut last_seq_number: Option = None; @@ -1142,7 +1234,8 @@ impl HeartbeatHandler { last_seq_number = Some(received_communication.unwrap().sequence_number); } - let should_send = last_heartbeat_timestamp.elapsed().as_millis() >= heartbeat_interval; + let should_send = + last_heartbeat_timestamp.elapsed().as_millis() >= heartbeat_interval; if should_send { println!("GW: Sending Heartbeat.."); diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index c6ff6e5..f864014 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -2,8 +2,8 @@ use serde::{Deserialize, Serialize}; use crate::types::{ entities::{ - Application, Attachment, Channel, Emoji, GuildMember, RoleSubscriptionData, Sticker, - StickerItem, User, PublicUser + Application, Attachment, Channel, Emoji, GuildMember, PublicUser, RoleSubscriptionData, + Sticker, StickerItem, User, }, utils::Snowflake, }; diff --git a/src/types/events/guild.rs b/src/types/events/guild.rs index 3bd81fd..d1c8fe4 100644 --- a/src/types/events/guild.rs +++ b/src/types/events/guild.rs @@ -1,4 +1,4 @@ -use crate::types::entities::{Guild, UnavailableGuild, PublicUser}; +use crate::types::entities::{Guild, PublicUser, UnavailableGuild}; use crate::types::events::WebSocketEvent; use crate::types::{AuditLogEntry, Emoji, GuildMember, GuildScheduledEvent, RoleObject, Sticker}; use chrono::{DateTime, Utc}; diff --git a/src/types/events/user.rs b/src/types/events/user.rs index 6a0ddce..cfdae5c 100644 --- a/src/types/events/user.rs +++ b/src/types/events/user.rs @@ -14,9 +14,9 @@ impl WebSocketEvent for UserUpdate {} #[derive(Debug, Default, Deserialize, Serialize)] /// Undocumented -/// +/// /// Possibly an update for muted guild / channel settings for the current user -/// +/// /// {"version":2,"suppress_roles":false,"suppress_everyone":false,"notify_highlights":0,"muted":false,"mute_scheduled_events":false,"mute_config":null,"mobile_push":true,"message_notifications":1,"hide_muted_channels":false,"guild_id":"848582562217590824","flags":0,"channel_overrides":[{"muted":false,"mute_config":null,"message_notifications":3,"flags":4096,"collapsed":false,"channel_id":"1042689182893604885"}]} pub struct UserGuildSettingsUpdate { pub version: u8, @@ -32,16 +32,16 @@ pub struct UserGuildSettingsUpdate { pub hide_muted_channels: bool, pub guild_id: Snowflake, pub flags: i32, - pub channel_overrides: Vec + pub channel_overrides: Vec, } impl WebSocketEvent for UserGuildSettingsUpdate {} #[derive(Debug, Default, Deserialize, Serialize)] /// Undocumented -/// +/// /// Received in [UserGuildSettingsUpdate] -/// +/// /// {"muted":false,"mute_config":null,"message_notifications":3,"flags":4096,"collapsed":false,"channel_id":"1042689182893604885"} pub struct UserGuildSettingsChannelOverride { pub muted: bool, @@ -51,4 +51,4 @@ pub struct UserGuildSettingsChannelOverride { pub flags: i32, pub collapsed: bool, pub channel_id: Snowflake, -} \ No newline at end of file +} From 6d90980bf48caa4ee6835c9593ccd724ce160f5b Mon Sep 17 00:00:00 2001 From: kozabrada123 <“kozabrada123@users.noreply.github.com”> Date: Sun, 28 May 2023 17:36:12 +0200 Subject: [PATCH 06/34] Members is optional --- src/types/events/passive_update.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/events/passive_update.rs b/src/types/events/passive_update.rs index 65a7272..7417467 100644 --- a/src/types/events/passive_update.rs +++ b/src/types/events/passive_update.rs @@ -9,7 +9,7 @@ use crate::types::{GuildMember, VoiceState}; /// Seems to be passively set to update the client on guild details (though, why not just send the update events?) pub struct PassiveUpdateV1 { pub voice_states: Vec, - pub members: Vec, + pub members: Option>, pub guild_id: String, pub channels: Vec, } From 6c2e29228fc4a8bd49514a9abea6109cc91d2234 Mon Sep 17 00:00:00 2001 From: kozabrada123 <“kozabrada123@users.noreply.github.com”> Date: Sun, 28 May 2023 17:36:30 +0200 Subject: [PATCH 07/34] u16 is too small for flags apparently --- src/types/entities/user.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index a591ae0..ee611a0 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -40,7 +40,7 @@ pub struct User { pub premium_since: Option>, pub premium_type: Option, pub pronouns: Option, - pub public_flags: Option, + pub public_flags: Option, pub banner: Option, pub bio: Option, pub theme_colors: Option>, @@ -66,7 +66,7 @@ pub struct PublicUser { pub bio: Option, pub premium_type: Option, pub premium_since: Option>, - pub public_flags: Option, + pub public_flags: Option, } impl From for PublicUser { From 7e37d2df42a6444e85511ceda9b5e00fdf995b72 Mon Sep 17 00:00:00 2001 From: kozabrada123 <“kozabrada123@users.noreply.github.com”> Date: Sun, 28 May 2023 17:37:05 +0200 Subject: [PATCH 08/34] Fix weird observer subscribe return --- src/gateway.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gateway.rs b/src/gateway.rs index 7906b01..01bc8bd 100644 --- a/src/gateway.rs +++ b/src/gateway.rs @@ -1322,13 +1322,13 @@ impl GatewayEvent { pub fn subscribe( &mut self, observable: Arc + Sync + Send>>, - ) -> Option { + ) -> Result<(), ObserverError> { if self.is_observed { - return Some(ObserverError::AlreadySubscribedError); + return Err(ObserverError::AlreadySubscribedError); } self.is_observed = true; self.observers.push(observable); - None + Ok(()) } /** From d9b1c382b70e0226da22402697b070048775f623 Mon Sep 17 00:00:00 2001 From: kozabrada123 <“kozabrada123@users.noreply.github.com”> Date: Sun, 28 May 2023 17:41:50 +0200 Subject: [PATCH 09/34] Add simple gateway examples --- examples/gateway_observers.rs | 58 +++++++++++++++++++++++++++++++++++ examples/gateway_simple.rs | 31 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 examples/gateway_observers.rs create mode 100644 examples/gateway_simple.rs diff --git a/examples/gateway_observers.rs b/examples/gateway_observers.rs new file mode 100644 index 0000000..e4c78e1 --- /dev/null +++ b/examples/gateway_observers.rs @@ -0,0 +1,58 @@ +use chorus::{ + self, + gateway::{Gateway, Observer}, + types::{GatewayIdentifyPayload, GatewayReady}, +}; +use std::sync::Arc; +use tokio::{self, sync::Mutex}; + +// This example creates a simple gateway connection and a basic observer struct + +// Due to certain limitations all observers must impl debug +#[derive(Debug)] +pub struct ExampleObserver {} + +// This struct can observe GatewayReady events when subscribed, because it implements the trait Observer. +// The Observer trait can be implemented for a struct for a given websocketevent to handle observing it +// One struct can be an observer of multiple websocketevents, if needed +impl Observer for ExampleObserver { + // After we subscribe to an event this function is called every time we receive it + fn update(&self, data: &GatewayReady) { + println!("Observed Ready!"); + } +} + +#[tokio::main] +async fn main() { + // Find the gateway websocket url of the server we want to connect to + let websocket_url_spacebar = "wss://gateway.old.server.spacebar.chat/".to_string(); + + // Initiate the gateway connection + let gateway = Gateway::new(websocket_url_spacebar).await.unwrap(); + + // Create an instance of our observer + let observer = ExampleObserver {}; + + // Because observers have to reside in between the main and gateway thread, (they have to be shared between both) we need to put them in an Arc + let shared_observer = Arc::new(Mutex::new(observer)); + + // Subscribe our observer to the Ready event on this gateway + // From now on observer.update(data) will be called every time we receive the Ready event + gateway + .events + .lock() + .await + .session + .ready + .subscribe(shared_observer) + .unwrap(); + + // Authenticate so we will receive any events + let token = "SecretToken".to_string(); + let mut identify = GatewayIdentifyPayload::common(); + identify.token = token; + gateway.send_identify(identify).await; + + // Do something on the main thread so we don't quit + loop {} +} diff --git a/examples/gateway_simple.rs b/examples/gateway_simple.rs new file mode 100644 index 0000000..19de9bb --- /dev/null +++ b/examples/gateway_simple.rs @@ -0,0 +1,31 @@ +use chorus::{self, gateway::Gateway, types::GatewayIdentifyPayload}; +use tokio; + +/// This example creates a simple gateway connection and a session with an Identify event +#[tokio::main] +async fn main() { + // Find the gateway websocket url of the server we want to connect to + let websocket_url_spacebar = "wss://gateway.old.server.spacebar.chat/".to_string(); + + // Initiate the gateway connection, starting a listener in one thread and a heartbeat handler in another + let gateway = Gateway::new(websocket_url_spacebar).await.unwrap(); + + // At this point, we are connected to the server and are sending heartbeats, however we still haven't authenticated + + // Get a token for an account on the server + let token = "SecretToken".to_string(); + + // Create an identify event + // An Identify event is how the server authenticates us and gets info about our os and browser, along with our intents / capabilities + // (Chorus never sends real telemetry data about your system to servers, always just using the most common option or a custom set one) + // By default the capabilities requests all the data of a regular client + let mut identify = GatewayIdentifyPayload::common(); + + identify.token = token; + + // Send off the event + gateway.send_identify(identify).await; + + // Do something on the main thread so we don't quit + loop {} +} From 2e81f5c4e1ee94cedd522dab03e60e3206dc2a5c Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Sun, 28 May 2023 22:29:24 +0200 Subject: [PATCH 10/34] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 37dc52e..23acd09 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ - [ ] [Events (Message, User, Channel, etc.)](https://github.com/polyphony-chat/chorus/issues/51) - [x] Channel creation - [x] Channel deletion -- [ ] Channel management (name, description, icon, etc.) +- [ ] [Channel management (name, description, icon, etc.)](https://github.com/polyphony-chat/chorus/issues/48) - [ ] Deleting messages - [ ] Message threads - [ ] Reactions From ed330859bdd6b9a6ecd0444bee80c7aa7f07a9fd Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 28 May 2023 22:39:25 +0200 Subject: [PATCH 11/34] Add channel delete method --- src/api/channels/channels.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/api/channels/channels.rs b/src/api/channels/channels.rs index aba4725..12df44e 100644 --- a/src/api/channels/channels.rs +++ b/src/api/channels/channels.rs @@ -38,4 +38,29 @@ impl Channel { }), } } + + pub async fn delete( + token: &str, + url_api: &str, + channel_id: &str, + limits_user: &mut Limits, + limits_instance: &mut Limits, + ) -> Option { + let request = Client::new() + .delete(format!("{}/channels/{}/", url_api, channel_id)) + .bearer_auth(token); + match LimitedRequester::new() + .await + .send_request( + request, + crate::api::limits::LimitType::Channel, + limits_instance, + limits_user, + ) + .await + { + Ok(_) => None, + Err(e) => return Some(e), + } + } } From a189d2baaa2debeec3ea0c3883f3d5d876d54a72 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 28 May 2023 22:39:38 +0200 Subject: [PATCH 12/34] Make channel delete take ownership of a Channel --- src/api/channels/channels.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/channels/channels.rs b/src/api/channels/channels.rs index 12df44e..2e0a3ff 100644 --- a/src/api/channels/channels.rs +++ b/src/api/channels/channels.rs @@ -42,12 +42,12 @@ impl Channel { pub async fn delete( token: &str, url_api: &str, - channel_id: &str, + channel: Channel, limits_user: &mut Limits, limits_instance: &mut Limits, ) -> Option { let request = Client::new() - .delete(format!("{}/channels/{}/", url_api, channel_id)) + .delete(format!("{}/channels/{}/", url_api, channel.id.to_string())) .bearer_auth(token); match LimitedRequester::new() .await From f2824f3a810f7fcfbaef9c3318a4bb97a3bcf118 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 28 May 2023 22:40:37 +0200 Subject: [PATCH 13/34] Add documentation --- src/api/channels/channels.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/api/channels/channels.rs b/src/api/channels/channels.rs index 2e0a3ff..6a23578 100644 --- a/src/api/channels/channels.rs +++ b/src/api/channels/channels.rs @@ -39,6 +39,19 @@ impl Channel { } } + /// Deletes a channel. + /// + /// # Arguments + /// + /// * `token` - A string slice that holds the authorization token. + /// * `url_api` - A string slice that holds the URL of the API. + /// * `channel` - A `Channel` object that represents the channel to be deleted. + /// * `limits_user` - A mutable reference to a `Limits` object that represents the user's rate limits. + /// * `limits_instance` - A mutable reference to a `Limits` object that represents the instance's rate limits. + /// + /// # Returns + /// + /// An `Option` that contains an `InstanceServerError` if an error occurred during the request, or `None` if the request was successful. pub async fn delete( token: &str, url_api: &str, From 8e8556ee538e38f99e5080738193507e43776bc1 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 28 May 2023 23:04:02 +0200 Subject: [PATCH 14/34] Add InvalidResponseError --- src/errors.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/errors.rs b/src/errors.rs index f76b029..749c8f7 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -23,6 +23,7 @@ custom_error! { NoPermission = "You do not have the permissions needed to perform this action.", NotFound{error: String} = "The provided resource hasn't been found: {}", PasswordRequiredError = "You need to provide your current password to authenticate for this action.", + InvalidResponseError{error: String} = "The response is malformed and cannot be processed. Error: {}", } custom_error! { From 84505829c4a071e3936ceb2eb8d69a7f9e94e1dc Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 28 May 2023 23:04:13 +0200 Subject: [PATCH 15/34] Make delete use self --- src/api/channels/channels.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/channels/channels.rs b/src/api/channels/channels.rs index 6a23578..4fd217d 100644 --- a/src/api/channels/channels.rs +++ b/src/api/channels/channels.rs @@ -53,14 +53,14 @@ impl Channel { /// /// An `Option` that contains an `InstanceServerError` if an error occurred during the request, or `None` if the request was successful. pub async fn delete( + self, token: &str, url_api: &str, - channel: Channel, limits_user: &mut Limits, limits_instance: &mut Limits, ) -> Option { let request = Client::new() - .delete(format!("{}/channels/{}/", url_api, channel.id.to_string())) + .delete(format!("{}/channels/{}/", url_api, self.id.to_string())) .bearer_auth(token); match LimitedRequester::new() .await From 1fb3ef6766552a8cd8b26505adc18e05e66560a7 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 28 May 2023 23:04:35 +0200 Subject: [PATCH 16/34] Create channels() for Guild This method retrieves all channels from a guild --- src/api/guilds/guilds.rs | 54 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/api/guilds/guilds.rs b/src/api/guilds/guilds.rs index d1f03f0..6a5092f 100644 --- a/src/api/guilds/guilds.rs +++ b/src/api/guilds/guilds.rs @@ -148,6 +148,60 @@ impl Guild { ) .await } + + /// Returns a `Result` containing a vector of `Channel` structs if the request was successful, or an `InstanceServerError` if there was an error. + /// + /// # Arguments + /// + /// * `url_api` - A string slice that holds the URL of the API. + /// * `token` - A string slice that holds the authorization token. + /// * `limits_user` - A mutable reference to a `Limits` struct containing the user's rate limits. + /// * `limits_instance` - A mutable reference to a `Limits` struct containing the instance's rate limits. + /// + pub async fn channels( + &self, + url_api: &str, + token: &str, + limits_user: &mut Limits, + limits_instance: &mut Limits, + ) -> Result, InstanceServerError> { + let request = Client::new() + .get(format!( + "{}/guilds/{}/channels/", + url_api, + self.id.to_string() + )) + .bearer_auth(token); + let result = match LimitedRequester::new() + .await + .send_request( + request, + crate::api::limits::LimitType::Guild, + limits_instance, + limits_user, + ) + .await + { + Ok(result) => result, + Err(e) => return Err(e), + }; + let stringed_response = match result.text().await { + Ok(value) => value, + Err(e) => { + return Err(InstanceServerError::InvalidResponseError { + error: e.to_string(), + }) + } + }; + let _: Vec = match from_str(&stringed_response) { + Ok(result) => return Ok(result), + Err(e) => { + return Err(InstanceServerError::InvalidResponseError { + error: e.to_string(), + }) + } + }; + } } impl Channel { From 7a1c9b1f90088727f0bef03f11cdae9b65b42b83 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 28 May 2023 23:04:56 +0200 Subject: [PATCH 17/34] Add delete_channel test. --- tests/channel.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/channel.rs b/tests/channel.rs index 4e0db28..a162d41 100644 --- a/tests/channel.rs +++ b/tests/channel.rs @@ -21,3 +21,18 @@ async fn get_channel() { ); common::teardown(bundle).await } + +#[tokio::test] +async fn delete_channel() { + let mut bundle = common::setup().await; + let result = bundle + .channel + .delete( + &bundle.user.token, + bundle.instance.urls.get_api(), + &mut bundle.user.limits, + &mut bundle.instance.limits, + ) + .await; + assert!(result.is_none()); +} From fdc1da9af7f4475a319e7123f20928e4947a36f7 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 28 May 2023 23:08:05 +0200 Subject: [PATCH 18/34] Remove print statement --- src/api/auth/register.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/api/auth/register.rs b/src/api/auth/register.rs index d318916..2c8f3f9 100644 --- a/src/api/auth/register.rs +++ b/src/api/auth/register.rs @@ -48,7 +48,6 @@ pub mod register { let response_unwrap = response.unwrap(); let status = response_unwrap.status(); let response_unwrap_text = response_unwrap.text().await.unwrap(); - println!("{}", response_unwrap_text); let token = from_str::(&response_unwrap_text).unwrap(); let token = token.token; if status.is_client_error() { From 3fe3e2a461db1efd8ec82ad4542a2e26a9a71446 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sun, 28 May 2023 23:08:13 +0200 Subject: [PATCH 19/34] Remove print statement --- src/api/channels/messages.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/api/channels/messages.rs b/src/api/channels/messages.rs index 91e148a..7b43eef 100644 --- a/src/api/channels/messages.rs +++ b/src/api/channels/messages.rs @@ -78,8 +78,6 @@ pub mod messages { .bearer_auth(token) .multipart(form); - println!("[Request Headers: ] {:?}", message_request); - requester .send_request( message_request, From aa28fbe1cde7e2cafe2dda9b2c2d0bb86e4ba32c Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 29 May 2023 16:49:36 +0200 Subject: [PATCH 20/34] Changed some apparently incorrect attributes Some attributes are not necessarily returned by the GET route for a guild. Also, some integers were too small. One example is max_video_channel_users, which was a u8, but could theoretically be a value much higher than u8::MAX. --- src/types/entities/guild.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index 3a6b11a..9ce09ac 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -19,25 +19,25 @@ pub struct Guild { pub splash: Option, pub discovery_splash: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub owner: bool, // True if requesting user is owner + pub owner: Option, // True if requesting user is owner pub owner_id: Option, pub permissions: Option, pub afk_channel_id: Option, - pub afk_timeout: Option, + pub afk_timeout: Option, pub widget_enabled: Option, pub widget_channel_id: Option, pub verification_level: Option, pub default_message_notifications: Option, pub explicit_content_filter: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub roles: Vec, + pub roles: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub emojis: Vec, + pub emojis: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub features: Option>, pub application_id: Option, pub system_channel_id: Option, - pub system_channel_flags: Option, + pub system_channel_flags: Option, pub rules_channel_id: Option, pub rules_channel: Option, pub max_presences: Option, @@ -49,8 +49,8 @@ pub struct Guild { pub premium_subscription_count: Option, pub preferred_locale: Option, pub public_updates_channel_id: Option, - pub max_video_channel_users: Option, - pub max_stage_video_channel_users: Option, + pub max_video_channel_users: Option, + pub max_stage_video_channel_users: Option, pub approximate_member_count: Option, pub approximate_presence_count: Option, #[cfg(feature = "sqlx")] @@ -62,7 +62,7 @@ pub struct Guild { pub stickers: Option>, pub premium_progress_bar_enabled: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub joined_at: String, + pub joined_at: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub bans: Option>, pub primary_category_id: Option, From 1f739ebfb71e8bd42cbb56db6052813f2762ff9d Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 29 May 2023 16:50:10 +0200 Subject: [PATCH 21/34] Made Guild::create return Guild instead of String. This makes way more sense, I think. --- src/api/guilds/guilds.rs | 70 +++++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/src/api/guilds/guilds.rs b/src/api/guilds/guilds.rs index 6a5092f..45482b3 100644 --- a/src/api/guilds/guilds.rs +++ b/src/api/guilds/guilds.rs @@ -19,32 +19,20 @@ impl Guild { /// /// # Returns /// - /// A `Result` containing the ID of the newly created guild, or an error if the request fails. + /// A `Result` containing the object of the newly created guild, or an error if the request fails. /// /// # Errors /// /// Returns an `InstanceServerError` if the request fails. /// - /// # Examples - /// - /// ```rs - /// let guild_create_schema = chorus::api::schemas::GuildCreateSchema::new(insert args here); - /// - /// let result = Guild::create(&mut user, &mut instance, &guild_create_schema).await; - /// - /// match result { - /// Ok(guild_id) => println!("Created guild with ID {}", guild_id), - /// Err(e) => println!("Failed to create guild: {}", e), - /// } - /// ``` pub async fn create( user: &mut UserMeta, url_api: &str, guild_create_schema: GuildCreateSchema, - ) -> Result { + ) -> Result { let url = format!("{}/guilds/", url_api); - let limits_user = user.limits.get_as_mut(); - let limits_instance = &mut user.belongs_to.borrow_mut().limits; + let mut limits_user = user.limits.get_as_mut(); + let mut limits_instance = &mut user.belongs_to.borrow_mut().limits; let request = reqwest::Client::new() .post(url.clone()) .bearer_auth(user.token.clone()) @@ -63,7 +51,16 @@ impl Guild { Err(e) => return Err(e), }; let id: GuildCreateResponse = from_str(&result.text().await.unwrap()).unwrap(); - Ok(id.id) + let guild = Guild::get( + url_api, + &id.id, + &user.token, + &mut limits_user, + &mut limits_instance, + ) + .await + .unwrap(); + Ok(guild) } /// Deletes a guild. @@ -93,7 +90,7 @@ impl Guild { pub async fn delete( user: &mut UserMeta, url_api: &str, - guild_id: String, + guild_id: &str, ) -> Option { let url = format!("{}/guilds/{}/delete/", url_api, guild_id); let limits_user = user.limits.get_as_mut(); @@ -202,6 +199,43 @@ impl Guild { } }; } + + /// Returns a `Result` containing a `Guild` struct if the request was successful, or an `InstanceServerError` if there was an error. + /// + /// # Arguments + /// + /// * `url_api` - A string slice that holds the URL of the API. + /// * `guild_id` - A string slice that holds the ID of the guild. + /// * `token` - A string slice that holds the authorization token. + /// * `limits_user` - A mutable reference to a `Limits` struct containing the user's rate limits. + /// * `limits_instance` - A mutable reference to a `Limits` struct containing the instance's rate limits. + /// + pub async fn get( + url_api: &str, + guild_id: &str, + token: &str, + limits_user: &mut Limits, + limits_instance: &mut Limits, + ) -> Result { + let request = Client::new() + .get(format!("{}/guilds/{}/", url_api, guild_id)) + .bearer_auth(token); + let response = match LimitedRequester::new() + .await + .send_request( + request, + crate::api::limits::LimitType::Guild, + limits_instance, + limits_user, + ) + .await + { + Ok(response) => response, + Err(e) => return Err(e), + }; + let guild: Guild = from_str(&response.text().await.unwrap()).unwrap(); + Ok(guild) + } } impl Channel { From 229a612df2ae15a05b2ba170cf8dc678e928a42c Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 29 May 2023 16:51:28 +0200 Subject: [PATCH 22/34] Change test delete, add test get_channels() --- tests/guild.rs | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/tests/guild.rs b/tests/guild.rs index 6b50a94..48794d8 100644 --- a/tests/guild.rs +++ b/tests/guild.rs @@ -19,11 +19,34 @@ async fn guild_creation_deletion() { .await .unwrap(); - println!("{}", guild); - - match Guild::delete(&mut bundle.user, bundle.urls.get_api(), guild).await { + match Guild::delete( + &mut bundle.user, + bundle.urls.get_api(), + &guild.id.to_string(), + ) + .await + { None => assert!(true), Some(_) => assert!(false), } common::teardown(bundle).await } + +#[tokio::test] +async fn get_channels() { + let mut bundle = common::setup().await; + println!( + "{:?}", + bundle + .guild + .channels( + bundle.instance.urls.get_api(), + &bundle.user.token, + &mut bundle.user.limits, + &mut bundle.instance.limits, + ) + .await + .unwrap() + ); + common::teardown(bundle).await; +} From f97f53c873f3394d91ae49fe0d6558b0801e8895 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 29 May 2023 16:51:41 +0200 Subject: [PATCH 23/34] Replace guild_id with guild object --- tests/common/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 3fdb42b..61fb2fc 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -9,7 +9,7 @@ pub struct TestBundle { pub urls: URLBundle, pub user: UserMeta, pub instance: Instance, - pub guild_id: String, + pub guild: Guild, pub channel: Channel, } @@ -65,13 +65,13 @@ pub async fn setup() -> TestBundle { video_quality_mode: None, }; let mut user = instance.register_account(®).await.unwrap(); - let guild_id = Guild::create(&mut user, urls.get_api(), guild_create_schema) + let guild = Guild::create(&mut user, urls.get_api(), guild_create_schema) .await .unwrap(); let channel = Channel::create( &user.token, urls.get_api(), - guild_id.as_str(), + &guild.id.to_string(), channel_create_schema, &mut user.limits, &mut instance.limits, @@ -83,7 +83,7 @@ pub async fn setup() -> TestBundle { urls, user, instance, - guild_id, + guild, channel, } } @@ -93,7 +93,7 @@ pub async fn teardown(mut bundle: TestBundle) { Guild::delete( &mut bundle.user, bundle.instance.urls.get_api(), - bundle.guild_id, + &bundle.guild.id.to_string(), ) .await; bundle.user.delete().await; From 9d546ef2a5bea8129e03e06bd8730bfc857f2d7b Mon Sep 17 00:00:00 2001 From: kozabrada123 <“kozabrada123@users.noreply.github.com”> Date: Mon, 29 May 2023 17:11:08 +0200 Subject: [PATCH 24/34] Fix some errors caused by the observer return fix --- src/gateway.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/gateway.rs b/src/gateway.rs index 01bc8bd..85c3515 100644 --- a/src/gateway.rs +++ b/src/gateway.rs @@ -1560,17 +1560,14 @@ mod example { let second_consumer = Consumer; let arc_mut_second_consumer = Arc::new(Mutex::new(second_consumer)); - match event.subscribe(arc_mut_second_consumer.clone()) { + match event.subscribe(arc_mut_second_consumer.clone()).err() { None => assert!(false), Some(err) => println!("You cannot subscribe twice: {}", err), } event.unsubscribe(arc_mut_consumer.clone()); - match event.subscribe(arc_mut_second_consumer.clone()) { - None => assert!(true), - Some(_) => assert!(false), - } + event.subscribe(arc_mut_second_consumer.clone()).unwrap(); } #[tokio::test] From 24a79b18e22d6786e07c1196097f4522483fe2e6 Mon Sep 17 00:00:00 2001 From: kozabrada123 <“kozabrada123@users.noreply.github.com”> Date: Mon, 29 May 2023 17:18:52 +0200 Subject: [PATCH 25/34] Fix typo --- src/types/events/ready.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/events/ready.rs b/src/types/events/ready.rs index 78d2010..c559f0b 100644 --- a/src/types/events/ready.rs +++ b/src/types/events/ready.rs @@ -36,7 +36,7 @@ pub struct GatewayReadySupplemental { pub merged_members: Vec>, // ? pub lazy_private_channels: Vec, - pub guilds: Vec, + pub guilds: Vec, // ? pomelo pub disclose: Vec, } @@ -70,7 +70,7 @@ pub struct MergedPresenceGuild { } #[derive(Debug, Deserialize, Serialize, Default)] -pub struct SupplimentalGuild { +pub struct SupplementalGuild { pub voice_states: Option>, pub id: String, pub embedded_activities: Vec, From 4bac730e141d423b96fe8b9256d1b96cf5ed0665 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 29 May 2023 17:25:34 +0200 Subject: [PATCH 26/34] Implement User methods on User instead of UserMeta --- src/api/users/users.rs | 101 ++++++++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 41 deletions(-) diff --git a/src/api/users/users.rs b/src/api/users/users.rs index 098a92f..dacff1f 100644 --- a/src/api/users/users.rs +++ b/src/api/users/users.rs @@ -26,30 +26,7 @@ impl UserMeta { id: Option<&String>, instance_limits: &mut Limits, ) -> Result { - let url: String; - if id.is_none() { - url = format!("{}/users/@me/", url_api); - } else { - url = format!("{}/users/{}", url_api, id.unwrap()); - } - let request = reqwest::Client::new().get(url).bearer_auth(token); - let mut requester = crate::limit::LimitedRequester::new().await; - let mut cloned_limits = instance_limits.clone(); - match requester - .send_request( - request, - crate::api::limits::LimitType::Ip, - instance_limits, - &mut cloned_limits, - ) - .await - { - Ok(result) => { - let result_text = result.text().await.unwrap(); - Ok(serde_json::from_str::(&result_text).unwrap()) - } - Err(e) => Err(e), - } + User::get(token, url_api, id, instance_limits).await } pub async fn get_settings( @@ -57,23 +34,7 @@ impl UserMeta { url_api: &String, instance_limits: &mut Limits, ) -> Result { - let request: reqwest::RequestBuilder = Client::new() - .get(format!("{}/users/@me/settings/", url_api)) - .bearer_auth(token); - let mut cloned_limits = instance_limits.clone(); - let mut requester = crate::limit::LimitedRequester::new().await; - match requester - .send_request( - request, - crate::api::limits::LimitType::Ip, - instance_limits, - &mut cloned_limits, - ) - .await - { - Ok(result) => Ok(serde_json::from_str(&result.text().await.unwrap()).unwrap()), - Err(e) => Err(e), - } + User::get_settings(token, url_api, instance_limits).await } /// Modify the current user's `UserObject`. @@ -153,6 +114,64 @@ impl UserMeta { } } +impl User { + pub async fn get( + token: &String, + url_api: &String, + id: Option<&String>, + instance_limits: &mut Limits, + ) -> Result { + let url: String; + if id.is_none() { + url = format!("{}/users/@me/", url_api); + } else { + url = format!("{}/users/{}", url_api, id.unwrap()); + } + let request = reqwest::Client::new().get(url).bearer_auth(token); + let mut requester = crate::limit::LimitedRequester::new().await; + let mut cloned_limits = instance_limits.clone(); + match requester + .send_request( + request, + crate::api::limits::LimitType::Ip, + instance_limits, + &mut cloned_limits, + ) + .await + { + Ok(result) => { + let result_text = result.text().await.unwrap(); + Ok(serde_json::from_str::(&result_text).unwrap()) + } + Err(e) => Err(e), + } + } + + pub async fn get_settings( + token: &String, + url_api: &String, + instance_limits: &mut Limits, + ) -> Result { + let request: reqwest::RequestBuilder = Client::new() + .get(format!("{}/users/@me/settings/", url_api)) + .bearer_auth(token); + let mut cloned_limits = instance_limits.clone(); + let mut requester = crate::limit::LimitedRequester::new().await; + match requester + .send_request( + request, + crate::api::limits::LimitType::Ip, + instance_limits, + &mut cloned_limits, + ) + .await + { + Ok(result) => Ok(serde_json::from_str(&result.text().await.unwrap()).unwrap()), + Err(e) => Err(e), + } + } +} + impl Instance { /** Get a user object by id, or get the current user. From 572ff07b93ba90daef6249dd48bf4d0ea3e939af Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 29 May 2023 18:27:15 +0200 Subject: [PATCH 27/34] Add ChannelModifySchema --- src/types/schema/channel.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index 458c33c..6cc16ab 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -25,3 +25,26 @@ pub struct ChannelCreateSchema { pub default_thread_rate_limit_per_user: Option, pub video_quality_mode: Option, } + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "snake_case")] +pub struct ChannelModifySchema { + name: Option, + channel_type: Option, + topic: Option, + icon: Option, + bitrate: Option, + user_limit: Option, + rate_limit_per_user: Option, + position: Option, + permission_overwrites: Option>, + parent_id: Option, + id: Option, + nsfw: Option, + rtc_region: Option, + default_auto_archive_duration: Option, + default_reaction_emoji: Option, + flags: Option, + default_thread_rate_limit_per_user: Option, + video_quality_mode: Option, +} From 6cb400b3d0f7d0298993a2a40c1250ad4acf11c0 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 29 May 2023 18:27:30 +0200 Subject: [PATCH 28/34] Add modify() --- src/api/channels/channels.rs | 49 ++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/src/api/channels/channels.rs b/src/api/channels/channels.rs index 4fd217d..bfe9959 100644 --- a/src/api/channels/channels.rs +++ b/src/api/channels/channels.rs @@ -1,8 +1,11 @@ use reqwest::Client; -use serde_json::from_str; +use serde_json::{from_str, to_string}; use crate::{ - api::limits::Limits, errors::InstanceServerError, limit::LimitedRequester, types::Channel, + api::limits::Limits, + errors::InstanceServerError, + limit::LimitedRequester, + types::{Channel, ChannelModifySchema}, }; impl Channel { @@ -76,4 +79,46 @@ impl Channel { Err(e) => return Some(e), } } + + /// Modifies a channel. + /// + /// # Arguments + /// + /// * `modify_data` - A `ChannelModifySchema` object that represents the modifications to be made to the channel. + /// * `token` - A string slice that holds the authorization token. + /// * `url_api` - A string slice that holds the URL of the API. + /// * `channel_id` - A string slice that holds the ID of the channel to be modified. + /// * `limits_user` - A mutable reference to a `Limits` object that represents the user's rate limits. + /// * `limits_instance` - A mutable reference to a `Limits` object that represents the instance's rate limits. + /// + /// # Returns + /// + /// A `Result` that contains a `Channel` object if the request was successful, or an `InstanceServerError` if an error occurred during the request. + pub async fn modify( + modify_data: ChannelModifySchema, + token: &str, + url_api: &str, + channel_id: &str, + limits_user: &mut Limits, + limits_instance: &mut Limits, + ) -> Result { + let request = Client::new() + .patch(format!("{}/channels/{}/", url_api, channel_id)) + .bearer_auth(token) + .body(to_string(&modify_data).unwrap()); + let channel = match LimitedRequester::new() + .await + .send_request( + request, + crate::api::limits::LimitType::Channel, + limits_instance, + limits_user, + ) + .await + { + Ok(channel) => from_str::(&channel.text().await.unwrap()).unwrap(), + Err(e) => return Err(e), + }; + Ok(channel) + } } From b4cac5a65c360adcc6982e051ccf775e42804cfa Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 29 May 2023 18:29:08 +0200 Subject: [PATCH 29/34] Teardown after delete_channel --- tests/channel.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/channel.rs b/tests/channel.rs index a162d41..03e570f 100644 --- a/tests/channel.rs +++ b/tests/channel.rs @@ -27,6 +27,7 @@ async fn delete_channel() { let mut bundle = common::setup().await; let result = bundle .channel + .clone() .delete( &bundle.user.token, bundle.instance.urls.get_api(), @@ -35,4 +36,5 @@ async fn delete_channel() { ) .await; assert!(result.is_none()); + common::teardown(bundle).await } From f8655c22bc3df749194f54ad5146a31c8959c472 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 29 May 2023 18:34:08 +0200 Subject: [PATCH 30/34] Make all attributes pub --- src/types/schema/channel.rs | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index 6cc16ab..67d9823 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -29,22 +29,21 @@ pub struct ChannelCreateSchema { #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] pub struct ChannelModifySchema { - name: Option, - channel_type: Option, - topic: Option, - icon: Option, - bitrate: Option, - user_limit: Option, - rate_limit_per_user: Option, - position: Option, - permission_overwrites: Option>, - parent_id: Option, - id: Option, - nsfw: Option, - rtc_region: Option, - default_auto_archive_duration: Option, - default_reaction_emoji: Option, - flags: Option, - default_thread_rate_limit_per_user: Option, - video_quality_mode: Option, + pub name: Option, + pub channel_type: Option, + pub topic: Option, + pub icon: Option, + pub bitrate: Option, + pub user_limit: Option, + pub rate_limit_per_user: Option, + pub position: Option, + pub permission_overwrites: Option>, + pub parent_id: Option, + pub nsfw: Option, + pub rtc_region: Option, + pub default_auto_archive_duration: Option, + pub default_reaction_emoji: Option, + pub flags: Option, + pub default_thread_rate_limit_per_user: Option, + pub video_quality_mode: Option, } From b9c3f0279997c5e30a5f5edaefd4e9e1cb433169 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 29 May 2023 18:50:09 +0200 Subject: [PATCH 31/34] ADd test for modify_channel() --- tests/channel.rs | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/tests/channel.rs b/tests/channel.rs index 03e570f..56f1ce5 100644 --- a/tests/channel.rs +++ b/tests/channel.rs @@ -1,5 +1,5 @@ mod common; -use chorus::types::Channel; +use chorus::types::{self, Channel}; #[tokio::test] async fn get_channel() { @@ -38,3 +38,39 @@ async fn delete_channel() { assert!(result.is_none()); common::teardown(bundle).await } + +#[tokio::test] +async fn modify_channel() { + let mut bundle = common::setup().await; + let modify_data: types::ChannelModifySchema = types::ChannelModifySchema { + name: Some("beepboop".to_string()), + channel_type: None, + topic: None, + icon: None, + bitrate: None, + user_limit: None, + rate_limit_per_user: None, + position: None, + permission_overwrites: None, + parent_id: None, + nsfw: None, + rtc_region: None, + default_auto_archive_duration: None, + default_reaction_emoji: None, + flags: None, + default_thread_rate_limit_per_user: None, + video_quality_mode: None, + }; + let result = Channel::modify( + modify_data, + &bundle.user.token, + bundle.instance.urls.get_api(), + &bundle.channel.id.to_string(), + &mut bundle.user.limits, + &mut bundle.instance.limits, + ) + .await + .unwrap(); + assert_eq!(result.name, Some("beepboop".to_string())); + common::teardown(bundle).await +} From 84b3b72928d4753fe98acc0364583e2c17813862 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Mon, 29 May 2023 18:50:19 +0200 Subject: [PATCH 32/34] Add clone, default derives --- src/types/schema/channel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/schema/channel.rs b/src/types/schema/channel.rs index 67d9823..fb626bb 100644 --- a/src/types/schema/channel.rs +++ b/src/types/schema/channel.rs @@ -26,7 +26,7 @@ pub struct ChannelCreateSchema { pub video_quality_mode: Option, } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone, Default)] #[serde(rename_all = "snake_case")] pub struct ChannelModifySchema { pub name: Option, From 2a61a4db7ece72d2b5edbacca0302c820d1087b3 Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Mon, 29 May 2023 19:05:26 +0200 Subject: [PATCH 33/34] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 23acd09..0cb8f0f 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ - [ ] [Events (Message, User, Channel, etc.)](https://github.com/polyphony-chat/chorus/issues/51) - [x] Channel creation - [x] Channel deletion -- [ ] [Channel management (name, description, icon, etc.)](https://github.com/polyphony-chat/chorus/issues/48) +- [x] [Channel management (name, description, icon, etc.)](https://github.com/polyphony-chat/chorus/issues/48) - [ ] Deleting messages - [ ] Message threads - [ ] Reactions From 3a6d1c56201b557842ff5a4b94e7946cfda32eea Mon Sep 17 00:00:00 2001 From: Flori <39242991+bitfl0wer@users.noreply.github.com> Date: Mon, 29 May 2023 19:20:41 +0200 Subject: [PATCH 34/34] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0cb8f0f..bc696a1 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ ### Messaging - [x] [Sending messages](https://github.com/polyphony-chat/chorus/issues/23) -- [ ] [Events (Message, User, Channel, etc.)](https://github.com/polyphony-chat/chorus/issues/51) +- [x] [Events (Message, User, Channel, etc.)](https://github.com/polyphony-chat/chorus/issues/51) - [x] Channel creation - [x] Channel deletion - [x] [Channel management (name, description, icon, etc.)](https://github.com/polyphony-chat/chorus/issues/48)