diff --git a/Cargo.lock b/Cargo.lock index f967a21..4a7d6ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -266,7 +266,7 @@ dependencies = [ [[package]] name = "chorus-macros" -version = "0.4.0" +version = "0.4.1" dependencies = [ "async-trait", "quote", diff --git a/chorus-macros/Cargo.lock b/chorus-macros/Cargo.lock index a3eedd4..e74f64c 100644 --- a/chorus-macros/Cargo.lock +++ b/chorus-macros/Cargo.lock @@ -15,7 +15,7 @@ dependencies = [ [[package]] name = "chorus-macros" -version = "0.4.0" +version = "0.4.1" dependencies = [ "async-trait", "quote", diff --git a/chorus-macros/Cargo.toml b/chorus-macros/Cargo.toml index c81cc90..6aa416a 100644 --- a/chorus-macros/Cargo.toml +++ b/chorus-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "chorus-macros" -version = "0.4.0" +version = "0.4.1" edition = "2021" license = "MPL-2.0" description = "Macros for the chorus crate." diff --git a/chorus-macros/src/lib.rs b/chorus-macros/src/lib.rs index 4102039..aa4f1bc 100644 --- a/chorus-macros/src/lib.rs +++ b/chorus-macros/src/lib.rs @@ -214,9 +214,11 @@ pub fn serde_bitflag_derive(input: TokenStream) -> TokenStream { // let s = String::deserialize(deserializer)?.parse::().map_err(serde::de::Error::custom)?; let s = crate::types::serde::string_or_u64(deserializer)?; - Ok(Self::from_bits(s).unwrap()) + // Note: while truncating may not be ideal, it's better than a panic if there are + // extra flags + Ok(Self::from_bits_truncate(s)) } } } .into() -} \ No newline at end of file +} diff --git a/src/api/users/guilds.rs b/src/api/users/guilds.rs index aac2f7a..46a25fb 100644 --- a/src/api/users/guilds.rs +++ b/src/api/users/guilds.rs @@ -44,6 +44,16 @@ impl ChorusUser { &mut self, query: Option, ) -> ChorusResult> { + + let query_parameters = { + if let Some(query_some) = query { + query_some.to_query() + } + else { + Vec::new() + } + }; + let url = format!( "{}/users/@me/guilds", self.belongs_to.read().unwrap().urls.api, @@ -53,7 +63,7 @@ impl ChorusUser { .get(url) .header("Authorization", self.token()) .header("Content-Type", "application/json") - .body(to_string(&query).unwrap()), + .query(&query_parameters), limit_type: LimitType::Global, }; diff --git a/src/gateway/gateway.rs b/src/gateway/gateway.rs index ec42b30..1312137 100644 --- a/src/gateway/gateway.rs +++ b/src/gateway/gateway.rs @@ -90,13 +90,15 @@ impl Gateway { zlib_buffer = Some(Vec::new()); let mut inflate = Decompress::new(true); - message = GatewayMessage::from_zlib_stream_json_message(received, &mut inflate).unwrap(); + message = + GatewayMessage::from_zlib_stream_json_message(received, &mut inflate).unwrap(); zlib_inflate = Some(inflate); } } - let gateway_payload: types::GatewayReceivePayload = serde_json::from_str(&message.0).unwrap(); + let gateway_payload: types::GatewayReceivePayload = + serde_json::from_str(&message.0).unwrap(); if gateway_payload.op_code != GATEWAY_HELLO { return Err(GatewayError::NonHelloOnInitiate { @@ -232,7 +234,8 @@ impl Gateway { let zlib_buffer = self.zlib_buffer.as_ref().unwrap(); let inflate = self.zlib_inflate.as_mut().unwrap(); - message = GatewayMessage::from_zlib_stream_json_bytes(zlib_buffer, inflate).unwrap(); + message = + GatewayMessage::from_zlib_stream_json_bytes(zlib_buffer, inflate).unwrap(); self.zlib_buffer = Some(Vec::new()); } }; @@ -278,7 +281,10 @@ impl Gateway { let event = &mut self.events.lock().await.$($path).+; let json = gateway_payload.event_data.unwrap().get(); match serde_json::from_str(json) { - Err(err) => warn!("Failed to parse gateway event {event_name} ({err})"), + Err(err) => { + warn!("Failed to parse gateway event {event_name} ({err})"); + trace!("Event data: {json}"); + }, Ok(message) => { $( let mut message: $message_type = message; @@ -314,15 +320,12 @@ impl Gateway { },)* "RESUMED" => (), "SESSIONS_REPLACE" => { - let result: Result, serde_json::Error> = - serde_json::from_str(gateway_payload.event_data.unwrap().get()); + let json = gateway_payload.event_data.unwrap().get(); + let result: Result, serde_json::Error> = serde_json::from_str(json); match result { Err(err) => { - warn!( - "Failed to parse gateway event {} ({})", - event_name, - err - ); + warn!("Failed to parse gateway event {event_name} ({err})"); + trace!("Event data: {json}"); return; } Ok(sessions) => { @@ -334,6 +337,7 @@ impl Gateway { }, _ => { warn!("Received unrecognized gateway event ({event_name})! Please open an issue on the chorus github so we can implement it"); + trace!("Event data: {}", gateway_payload.event_data.unwrap().get()); } } }; diff --git a/src/gateway/message.rs b/src/gateway/message.rs index 7f581e5..7d44af6 100644 --- a/src/gateway/message.rs +++ b/src/gateway/message.rs @@ -94,7 +94,14 @@ impl GatewayMessage { // Note: is there a better way to handle the size of this output buffer? // // This used to be 10, I measured it at 11.5, so a safe bet feels like 20 - let mut output = Vec::with_capacity(bytes.len() * 20); + // + // ^ - This dude is naive. apparently not even 20x is okay. Measured at 47.9x!!!! + // If it is >100x ever, I will literally explode + // + // About an hour later, you ^ will literally explode. + // 133 vs 13994 -- 105.21805x ratio + // Let's hope it doesn't go above 200?? + let mut output = Vec::with_capacity(bytes.len() * 200); let _status = inflate.decompress_vec(bytes, &mut output, flate2::FlushDecompress::Sync)?; output.shrink_to_fit(); diff --git a/src/ratelimiter.rs b/src/ratelimiter.rs index 5e69d95..2b08082 100644 --- a/src/ratelimiter.rs +++ b/src/ratelimiter.rs @@ -88,7 +88,7 @@ impl ChorusRequest { let client = user.belongs_to.read().unwrap().client.clone(); let result = match client.execute(self.request.build().unwrap()).await { Ok(result) => { - debug!("Request successful: {:?}", result); + log::trace!("Request successful: {:?}", result); result } Err(error) => { @@ -494,7 +494,7 @@ impl ChorusRequest { user: &mut ChorusUser, ) -> ChorusResult { let response = self.send_request(user).await?; - debug!("Got response: {:?}", response); + log::trace!("Got response: {:?}", response); let response_text = match response.text().await { Ok(string) => string, Err(e) => { diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index a42dadf..19bdcef 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -162,6 +162,8 @@ pub struct PermissionOverwrite { #[derive(Debug, Serialize_repr, Clone, PartialEq, Eq, PartialOrd)] #[repr(u8)] /// # Reference +/// +/// See pub enum PermissionOverwriteType { Role = 0, Member = 1, diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index c7e60b3..81978b0 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -45,7 +45,7 @@ pub struct User { pub bot: Option, pub system: Option, pub mfa_enabled: Option, - pub accent_color: Option, + pub accent_color: Option, #[cfg_attr(feature = "sqlx", sqlx(default))] pub locale: Option, pub verified: Option, @@ -58,10 +58,10 @@ 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>, + pub theme_colors: Option>, pub phone: Option, pub nsfw_allowed: Option, pub premium: Option, @@ -76,15 +76,15 @@ pub struct PublicUser { pub username: Option, pub discriminator: Option, pub avatar: Option, - pub accent_color: Option, + pub accent_color: Option, pub banner: Option, - pub theme_colors: Option>, + pub theme_colors: Option>, pub pronouns: Option, pub bot: Option, pub bio: Option, pub premium_type: Option, pub premium_since: Option>, - pub public_flags: Option, + pub public_flags: Option, } impl From for PublicUser { diff --git a/src/types/entities/user_settings.rs b/src/types/entities/user_settings.rs index 0dbce3e..fa3433a 100644 --- a/src/types/entities/user_settings.rs +++ b/src/types/entities/user_settings.rs @@ -6,6 +6,7 @@ use chrono::{serde::ts_milliseconds_option, Utc}; use serde::{Deserialize, Serialize}; use crate::types::Shared; +use serde_aux::field_attributes::deserialize_option_number_from_string; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] @@ -37,7 +38,7 @@ pub enum UserTheme { #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct UserSettings { - pub afk_timeout: u16, + pub afk_timeout: Option, pub allow_accessibility_detection: bool, pub animate_emoji: bool, pub animate_stickers: u8, @@ -90,7 +91,7 @@ pub struct UserSettings { impl Default for UserSettings { fn default() -> Self { Self { - afk_timeout: 3600, + afk_timeout: Some(3600), allow_accessibility_detection: true, animate_emoji: true, animate_stickers: 0, @@ -148,10 +149,17 @@ impl Default for FriendSourceFlags { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct GuildFolder { - pub color: u32, + pub color: Option, pub guild_ids: Vec, - pub id: u16, - pub name: String, + // FIXME: What is this thing? + // It's not a snowflake, and it's sometimes a string and sometimes an integer. + // + // Ex: 1249181105 + // + // It can also be negative somehow? Ex: -1176643795 + #[serde(deserialize_with = "deserialize_option_number_from_string")] + pub id: Option, + pub name: Option, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/types/events/message.rs b/src/types/events/message.rs index 8f982e5..62a9d9d 100644 --- a/src/types/events/message.rs +++ b/src/types/events/message.rs @@ -121,8 +121,8 @@ pub struct MessageReactionRemoveEmoji { /// /// {"t":"MESSAGE_ACK","s":3,"op":0,"d":{"version":52,"message_id":"1107236673638633472","last_viewed":null,"flags":null,"channel_id":"967363950217936897"}} pub struct MessageACK { - /// ? - pub version: u16, + // No ideas. See 206933 + pub version: u32, pub message_id: Snowflake, /// This is an integer??? /// Not even unix, see '3070'??? diff --git a/src/types/events/passive_update.rs b/src/types/events/passive_update.rs index a0f9909..088fb22 100644 --- a/src/types/events/passive_update.rs +++ b/src/types/events/passive_update.rs @@ -12,9 +12,12 @@ use crate::types::{GuildMember, Snowflake, VoiceState}; /// /// Seems to be passively set to update the client on guild details (though, why not just send the update events?) pub struct PassiveUpdateV1 { + #[serde(default)] pub voice_states: Vec, - pub members: Option>, + #[serde(default)] + pub members: Vec, pub guild_id: Snowflake, + #[serde(default)] pub channels: Vec, } diff --git a/src/types/events/presence.rs b/src/types/events/presence.rs index 09d0739..d96d984 100644 --- a/src/types/events/presence.rs +++ b/src/types/events/presence.rs @@ -28,6 +28,7 @@ pub struct PresenceUpdate { #[serde(default)] pub guild_id: Option, pub status: UserStatus, + #[serde(default)] pub activities: Vec, pub client_status: ClientStatusObject, } diff --git a/src/types/schema/guild.rs b/src/types/schema/guild.rs index 17c9d61..6405d94 100644 --- a/src/types/schema/guild.rs +++ b/src/types/schema/guild.rs @@ -85,6 +85,31 @@ pub struct GetUserGuildSchema { pub with_counts: Option, } +impl GetUserGuildSchema { + /// Converts self to query string parameters + pub fn to_query(self) -> Vec<(&'static str, String)> { + let mut query = Vec::with_capacity(4); + + if let Some(before) = self.before { + query.push(("before", before.to_string())); + } + + if let Some(after) = self.after { + query.push(("after", after.to_string())); + } + + if let Some(limit) = self.limit { + query.push(("limit", limit.to_string())); + } + + if let Some(with_counts) = self.with_counts { + query.push(("with_counts", with_counts.to_string())); + } + + query + } +} + impl std::default::Default for GetUserGuildSchema { fn default() -> Self { Self { @@ -145,7 +170,7 @@ pub struct ModifyGuildMemberSchema { } bitflags! { - #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)] + #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, chorus_macros::SerdeBitFlags)] #[cfg_attr(feature = "sqlx", derive(chorus_macros::SqlxBitFlags))] /// Represents the flags of a Guild Member. /// @@ -384,4 +409,4 @@ pub struct GuildTemplateCreateSchema { pub name: String, /// Description of the template (max 120 characters) pub description: Option -} \ No newline at end of file +}