From db577067948f13e830b5fb773034e9713a1abaff Mon Sep 17 00:00:00 2001 From: Zomatree Date: Mon, 5 May 2025 22:14:10 +0100 Subject: [PATCH] feat: ready payload field customisation --- Cargo.lock | 1 + crates/bonfire/Cargo.toml | 1 + crates/bonfire/src/config.rs | 40 ++++++++++++++++++----- crates/bonfire/src/events/impl.rs | 21 +++++------- crates/core/database/src/events/client.rs | 31 +++++++++++++----- 5 files changed, 65 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d310e03..a3c3b024 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6294,6 +6294,7 @@ dependencies = [ "once_cell", "querystring", "redis-kiss", + "regex", "revolt-config", "revolt-database", "revolt-models", diff --git a/crates/bonfire/Cargo.toml b/crates/bonfire/Cargo.toml index e447825d..c0160270 100644 --- a/crates/bonfire/Cargo.toml +++ b/crates/bonfire/Cargo.toml @@ -19,6 +19,7 @@ async-channel = "2.3.1" # parsing querystring = "1.1.0" +regex = "1.11.1" # serde bincode = "1.3.3" diff --git a/crates/bonfire/src/config.rs b/crates/bonfire/src/config.rs index 5642d3ba..ea02092e 100644 --- a/crates/bonfire/src/config.rs +++ b/crates/bonfire/src/config.rs @@ -1,8 +1,13 @@ use async_tungstenite::tungstenite::{handshake, Message}; use futures::channel::oneshot::Sender; +use once_cell::sync::Lazy; 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()); /// Enumeration of supported protocol formats #[derive(Debug)] @@ -17,6 +22,7 @@ pub struct ProtocolConfiguration { protocol_version: i32, format: ProtocolFormat, session_token: Option, + ready_payload_fields: ReadyPayloadFields } impl ProtocolConfiguration { @@ -25,11 +31,13 @@ impl ProtocolConfiguration { protocol_version: i32, format: ProtocolFormat, session_token: Option, + ready_payload_fields: ReadyPayloadFields ) -> Self { Self { protocol_version, format, session_token, + ready_payload_fields } } @@ -86,14 +94,8 @@ impl ProtocolConfiguration { } /// Get ready payload fields - pub fn get_ready_payload_fields(&self) -> Vec { - vec![ - ReadyPayloadFields::Users, - ReadyPayloadFields::Servers, - ReadyPayloadFields::Channels, - ReadyPayloadFields::Members, - ReadyPayloadFields::Emoji, - ] + pub fn get_ready_payload_fields(&self) -> &ReadyPayloadFields { + &self.ready_payload_fields } } @@ -124,6 +126,7 @@ 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(); // Parse and map parameters from key-value to known variables. for (key, value) in params { @@ -139,6 +142,26 @@ impl handshake::server::Callback for WebsocketHandshakeCallback { _ => {} }, "token" => session_token = Some(value.into()), + "ready" => { + if let Some(captures) = READY_PAYLOAD_FIELD_REGEX.captures(value) { + if let Some(field) = captures.get(0) { + match field.as_str() { + "users" => ready_payload_fields.users = true, + "servers" => ready_payload_fields.servers = true, + "channels" => ready_payload_fields.channels = true, + "members" => ready_payload_fields.members = true, + "emojis" => ready_payload_fields.emojis = true, + "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()); + } + }, + _ => {} + } + } + } + } _ => {} } } @@ -151,6 +174,7 @@ impl handshake::server::Callback for WebsocketHandshakeCallback { protocol_version, format, session_token, + ready_payload_fields }) .is_ok() { diff --git a/crates/bonfire/src/events/impl.rs b/crates/bonfire/src/events/impl.rs index 160e7c6c..49b30d51 100644 --- a/crates/bonfire/src/events/impl.rs +++ b/crates/bonfire/src/events/impl.rs @@ -95,7 +95,7 @@ impl State { pub async fn generate_ready_payload( &mut self, db: &Database, - fields: Vec, + fields: &ReadyPayloadFields, ) -> Result { let user = self.clone_user(); self.cache.is_bot = user.bot.is_some(); @@ -168,7 +168,7 @@ impl State { .await?; // Fetch customisations. - let emojis = if fields.contains(&ReadyPayloadFields::Emoji) { + let emojis = if fields.emojis { Some( db.fetch_emoji_by_parent_ids( &servers @@ -183,17 +183,14 @@ impl State { }; // Fetch user settings - let user_settings = if let Some(ReadyPayloadFields::UserSettings(keys)) = fields - .iter() - .find(|e| matches!(e, ReadyPayloadFields::UserSettings(_))) - { - Some(db.fetch_user_settings(&user.id, keys).await?) + let user_settings = if !fields.user_settings.is_empty() { + Some(db.fetch_user_settings(&user.id, &fields.user_settings).await?) } else { None }; // Fetch channel unreads - let channel_unreads = if fields.contains(&ReadyPayloadFields::ChannelUnreads) { + let channel_unreads = if fields.channel_unreads { Some(db.fetch_unreads(&user.id).await?) } else { None @@ -241,22 +238,22 @@ impl State { } Ok(EventV1::Ready { - users: if fields.contains(&ReadyPayloadFields::Users) { + users: if fields.users { Some(users) } else { None }, - servers: if fields.contains(&ReadyPayloadFields::Servers) { + servers: if fields.servers { Some(servers.into_iter().map(Into::into).collect()) } else { None }, - channels: if fields.contains(&ReadyPayloadFields::Channels) { + channels: if fields.channels { Some(channels.into_iter().map(Into::into).collect()) } else { None }, - members: if fields.contains(&ReadyPayloadFields::Members) { + members: if fields.members { Some(members.into_iter().map(Into::into).collect()) } else { None diff --git a/crates/core/database/src/events/client.rs b/crates/core/database/src/events/client.rs index aa9fb0b9..b64a02ad 100644 --- a/crates/core/database/src/events/client.rs +++ b/crates/core/database/src/events/client.rs @@ -20,16 +20,29 @@ pub enum Ping { } /// Fields provided in Ready payload -#[derive(PartialEq)] -pub enum ReadyPayloadFields { - Users, - Servers, - Channels, - Members, - Emoji, +#[derive(PartialEq, Debug, Clone, Deserialize)] +pub struct ReadyPayloadFields { + pub users: bool, + pub servers: bool, + pub channels: bool, + pub members: bool, + pub emojis: bool, + pub user_settings: Vec, + pub channel_unreads: bool +} - UserSettings(Vec), - ChannelUnreads, +impl Default for ReadyPayloadFields { + fn default() -> Self { + Self { + users: true, + servers: true, + channels: true, + members: true, + emojis: true, + user_settings: Vec::new(), + channel_unreads: false + } + } } /// Protocol Events