Compare commits

..

2 Commits

Author SHA1 Message Date
kozabrada123 69222548bd
Merge 743f106ec6 into cb3551dcd4 2024-06-28 12:06:02 +00:00
kozabrada123 743f106ec6
Miscellaneous fixes (#514)
- fix `PATCH /users/@me` - It incorrectly returned a required password error, even if the current password was set
- fix `GET /users/@me/guilds` - It incorrectly sent body parameters instead of query ones
- don't log debug! for every successful ratelimited request - use trace! so it's less spamy
- update the max expected compression ratio (several times) from 20 to 200. let's hope that will be enough
- fix deserialization errors relating to guild folders in user settings
- fix a panic in `SqlxBitFlags` if there are extra flags. It now truncates them
- update `chorus_macros` to 0.4.1 (due to the above fix)
- log (trace!) event data if we fail to parse it or it's unrecognised, for debugging purposes
- fix a deserialization error in the `MessageACK` event
- fix `public_flags` in user objects not being `PublicFlags` bitflags
2024-06-28 14:05:59 +02:00
15 changed files with 98 additions and 36 deletions

2
Cargo.lock generated
View File

@ -266,7 +266,7 @@ dependencies = [
[[package]]
name = "chorus-macros"
version = "0.4.0"
version = "0.4.1"
dependencies = [
"async-trait",
"quote",

View File

@ -15,7 +15,7 @@ dependencies = [
[[package]]
name = "chorus-macros"
version = "0.4.0"
version = "0.4.1"
dependencies = [
"async-trait",
"quote",

View File

@ -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."

View File

@ -214,9 +214,11 @@ pub fn serde_bitflag_derive(input: TokenStream) -> TokenStream {
// let s = String::deserialize(deserializer)?.parse::<u64>().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()
}
}

View File

@ -44,6 +44,16 @@ impl ChorusUser {
&mut self,
query: Option<GetUserGuildSchema>,
) -> ChorusResult<Vec<Guild>> {
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,
};

View File

@ -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<Vec<types::Session>, serde_json::Error> =
serde_json::from_str(gateway_payload.event_data.unwrap().get());
let json = gateway_payload.event_data.unwrap().get();
let result: Result<Vec<types::Session>, 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());
}
}
};

View File

@ -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();

View File

@ -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<T> {
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) => {

View File

@ -162,6 +162,8 @@ pub struct PermissionOverwrite {
#[derive(Debug, Serialize_repr, Clone, PartialEq, Eq, PartialOrd)]
#[repr(u8)]
/// # Reference
///
/// See <https://docs.discord.sex/resources/channel#permission-overwrite-type>
pub enum PermissionOverwriteType {
Role = 0,
Member = 1,

View File

@ -45,7 +45,7 @@ pub struct User {
pub bot: Option<bool>,
pub system: Option<bool>,
pub mfa_enabled: Option<bool>,
pub accent_color: Option<u8>,
pub accent_color: Option<u32>,
#[cfg_attr(feature = "sqlx", sqlx(default))]
pub locale: Option<String>,
pub verified: Option<bool>,
@ -58,10 +58,10 @@ pub struct User {
pub premium_since: Option<DateTime<Utc>>,
pub premium_type: Option<u8>,
pub pronouns: Option<String>,
pub public_flags: Option<u32>,
pub public_flags: Option<UserFlags>,
pub banner: Option<String>,
pub bio: Option<String>,
pub theme_colors: Option<Vec<u8>>,
pub theme_colors: Option<Vec<u32>>,
pub phone: Option<String>,
pub nsfw_allowed: Option<bool>,
pub premium: Option<bool>,
@ -76,15 +76,15 @@ pub struct PublicUser {
pub username: Option<String>,
pub discriminator: Option<String>,
pub avatar: Option<String>,
pub accent_color: Option<u8>,
pub accent_color: Option<u32>,
pub banner: Option<String>,
pub theme_colors: Option<Vec<u8>>,
pub theme_colors: Option<Vec<u32>>,
pub pronouns: Option<String>,
pub bot: Option<bool>,
pub bio: Option<String>,
pub premium_type: Option<u8>,
pub premium_since: Option<DateTime<Utc>>,
pub public_flags: Option<u32>,
pub public_flags: Option<UserFlags>,
}
impl From<User> for PublicUser {

View File

@ -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<u16>,
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<u32>,
pub guild_ids: Vec<String>,
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<i64>,
pub name: Option<String>,
}
#[derive(Debug, Serialize, Deserialize)]

View File

@ -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'???

View File

@ -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<VoiceState>,
pub members: Option<Vec<GuildMember>>,
#[serde(default)]
pub members: Vec<GuildMember>,
pub guild_id: Snowflake,
#[serde(default)]
pub channels: Vec<ChannelUnreadUpdateObject>,
}

View File

@ -28,6 +28,7 @@ pub struct PresenceUpdate {
#[serde(default)]
pub guild_id: Option<Snowflake>,
pub status: UserStatus,
#[serde(default)]
pub activities: Vec<Activity>,
pub client_status: ClientStatusObject,
}

View File

@ -85,6 +85,31 @@ pub struct GetUserGuildSchema {
pub with_counts: Option<bool>,
}
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<String>
}
}