diff --git a/crates/bonfire/src/config.rs b/crates/bonfire/src/config.rs index ea02092e..5cd87b8b 100644 --- a/crates/bonfire/src/config.rs +++ b/crates/bonfire/src/config.rs @@ -1,13 +1,14 @@ use async_tungstenite::tungstenite::{handshake, Message}; use futures::channel::oneshot::Sender; use once_cell::sync::Lazy; +use regex::Regex; use revolt_database::events::client::ReadyPayloadFields; use revolt_result::{create_error, Result}; use serde::{Deserialize, Serialize}; -use regex::Regex; /// matches either a single word ie "users" or a key and value ie "settings[notifications]" -static READY_PAYLOAD_FIELD_REGEX: Lazy = Lazy::new(|| Regex::new(r#"^(\w+)(?:\[(\w+)\])?$"#).unwrap()); +static READY_PAYLOAD_FIELD_REGEX: Lazy = + Lazy::new(|| Regex::new(r#"^(\w+)(?:\[(\w+)\])?$"#).unwrap()); /// Enumeration of supported protocol formats #[derive(Debug)] @@ -22,7 +23,7 @@ pub struct ProtocolConfiguration { protocol_version: i32, format: ProtocolFormat, session_token: Option, - ready_payload_fields: ReadyPayloadFields + ready_payload_fields: ReadyPayloadFields, } impl ProtocolConfiguration { @@ -31,13 +32,13 @@ impl ProtocolConfiguration { protocol_version: i32, format: ProtocolFormat, session_token: Option, - ready_payload_fields: ReadyPayloadFields + ready_payload_fields: ReadyPayloadFields, ) -> Self { Self { protocol_version, format, session_token, - ready_payload_fields + ready_payload_fields, } } @@ -126,7 +127,22 @@ impl handshake::server::Callback for WebsocketHandshakeCallback { let mut protocol_version = 1; let mut format = ProtocolFormat::Json; let mut session_token = None; - let mut ready_payload_fields = ReadyPayloadFields::default(); + let mut ready_payload_fields = if params.iter().any(|(k, _)| *k == "ready") { + // If they pass the ready field, set all fields to false + + ReadyPayloadFields { + users: false, + servers: false, + channels: false, + members: false, + emojis: false, + user_settings: Vec::new(), + channel_unreads: false, + policy_changes: false, + } + } else { + ReadyPayloadFields::default() + }; // Parse and map parameters from key-value to known variables. for (key, value) in params { @@ -143,6 +159,7 @@ impl handshake::server::Callback for WebsocketHandshakeCallback { }, "token" => session_token = Some(value.into()), "ready" => { + // Re-enable all the fields the client specifies if let Some(captures) = READY_PAYLOAD_FIELD_REGEX.captures(value) { if let Some(field) = captures.get(0) { match field.as_str() { @@ -154,9 +171,12 @@ impl handshake::server::Callback for WebsocketHandshakeCallback { "channel_unreads" => ready_payload_fields.channel_unreads = true, "user_settings" => { if let Some(subkey) = captures.get(1) { - ready_payload_fields.user_settings.push(subkey.as_str().to_string()); + ready_payload_fields + .user_settings + .push(subkey.as_str().to_string()); } - }, + } + "policy_changes" => ready_payload_fields.policy_changes = true, _ => {} } } @@ -174,7 +194,7 @@ impl handshake::server::Callback for WebsocketHandshakeCallback { protocol_version, format, session_token, - ready_payload_fields + ready_payload_fields, }) .is_ok() { diff --git a/crates/bonfire/src/events/impl.rs b/crates/bonfire/src/events/impl.rs index 49b30d51..83b0d4c6 100644 --- a/crates/bonfire/src/events/impl.rs +++ b/crates/bonfire/src/events/impl.rs @@ -101,15 +101,17 @@ impl State { self.cache.is_bot = user.bot.is_some(); // Fetch pending policy changes. - let policy_changes = if user.bot.is_some() { - vec![] + let policy_changes = if user.bot.is_some() || !fields.policy_changes { + None } else { - db.fetch_policy_changes() - .await? - .into_iter() - .filter(|policy| policy.created_time > user.last_acknowledged_policy_change) - .map(Into::into) - .collect() + Some( + db.fetch_policy_changes() + .await? + .into_iter() + .filter(|policy| policy.created_time > user.last_acknowledged_policy_change) + .map(Into::into) + .collect(), + ) }; // Find all relationships to the user. @@ -176,7 +178,10 @@ impl State { .map(|x| x.id.to_string()) .collect::>(), ) - .await?, + .await? + .into_iter() + .map(|emoji| emoji.into()) + .collect(), ) } else { None @@ -184,14 +189,23 @@ impl State { // Fetch user settings let user_settings = if !fields.user_settings.is_empty() { - Some(db.fetch_user_settings(&user.id, &fields.user_settings).await?) + Some( + db.fetch_user_settings(&user.id, &fields.user_settings) + .await?, + ) } else { None }; // Fetch channel unreads let channel_unreads = if fields.channel_unreads { - Some(db.fetch_unreads(&user.id).await?) + Some( + db.fetch_unreads(&user.id) + .await? + .into_iter() + .map(|unread| unread.into()) + .collect(), + ) } else { None }; @@ -238,11 +252,7 @@ impl State { } Ok(EventV1::Ready { - users: if fields.users { - Some(users) - } else { - None - }, + users: if fields.users { Some(users) } else { None }, servers: if fields.servers { Some(servers.into_iter().map(Into::into).collect()) } else { @@ -258,10 +268,9 @@ impl State { } else { None }, - emojis: emojis.map(|vec| vec.into_iter().map(Into::into).collect()), - + emojis, user_settings, - channel_unreads: channel_unreads.map(|vec| vec.into_iter().map(Into::into).collect()), + channel_unreads, policy_changes, }) diff --git a/crates/core/database/src/events/client.rs b/crates/core/database/src/events/client.rs index b64a02ad..996347ca 100644 --- a/crates/core/database/src/events/client.rs +++ b/crates/core/database/src/events/client.rs @@ -28,7 +28,8 @@ pub struct ReadyPayloadFields { pub members: bool, pub emojis: bool, pub user_settings: Vec, - pub channel_unreads: bool + pub channel_unreads: bool, + pub policy_changes: bool, } impl Default for ReadyPayloadFields { @@ -40,7 +41,8 @@ impl Default for ReadyPayloadFields { members: true, emojis: true, user_settings: Vec::new(), - channel_unreads: false + channel_unreads: false, + policy_changes: true, } } } @@ -76,7 +78,8 @@ pub enum EventV1 { #[serde(skip_serializing_if = "Option::is_none")] channel_unreads: Option>, - policy_changes: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + policy_changes: Option>, }, /// Ping response