From 412f4a99d7a98e8d5995a99bbb1ad3f8b4b1f82c Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Sun, 14 Jul 2024 17:03:40 +0100 Subject: [PATCH] feat(core/events): add user settings / unreads to Ready payload refactor(core/events): make all Ready payload items optional --- crates/bonfire/src/config.rs | 12 ++++ crates/bonfire/src/events/impl.rs | 77 ++++++++++++++++++----- crates/bonfire/src/websocket.rs | 5 +- crates/core/database/src/events/client.rs | 41 +++++++++--- 4 files changed, 109 insertions(+), 26 deletions(-) diff --git a/crates/bonfire/src/config.rs b/crates/bonfire/src/config.rs index 71b8946a..5642d3ba 100644 --- a/crates/bonfire/src/config.rs +++ b/crates/bonfire/src/config.rs @@ -1,5 +1,6 @@ use async_tungstenite::tungstenite::{handshake, Message}; use futures::channel::oneshot::Sender; +use revolt_database::events::client::ReadyPayloadFields; use revolt_result::{create_error, Result}; use serde::{Deserialize, Serialize}; @@ -83,6 +84,17 @@ impl ProtocolConfiguration { pub fn get_protocol_format(&self) -> &ProtocolFormat { &self.format } + + /// Get ready payload fields + pub fn get_ready_payload_fields(&self) -> Vec { + vec![ + ReadyPayloadFields::Users, + ReadyPayloadFields::Servers, + ReadyPayloadFields::Channels, + ReadyPayloadFields::Members, + ReadyPayloadFields::Emoji, + ] + } } /// Object holding one side of a channel for receiving the parsed information diff --git a/crates/bonfire/src/events/impl.rs b/crates/bonfire/src/events/impl.rs index f574e578..426c7e58 100644 --- a/crates/bonfire/src/events/impl.rs +++ b/crates/bonfire/src/events/impl.rs @@ -1,8 +1,9 @@ use std::collections::HashSet; use revolt_database::{ - events::client::EventV1, util::permissions::DatabasePermissionQuery, Channel, Database, Member, - MemberCompositeKey, Presence, RelationshipStatus, + events::client::{EventV1, ReadyPayloadFields}, + util::permissions::DatabasePermissionQuery, + Channel, Database, Member, MemberCompositeKey, Presence, RelationshipStatus, }; use revolt_models::v0; use revolt_permissions::{calculate_channel_permissions, ChannelPermission}; @@ -90,7 +91,11 @@ impl Cache { /// State Manager impl State { /// Generate a Ready packet for the current user - pub async fn generate_ready_payload(&mut self, db: &Database) -> Result { + pub async fn generate_ready_payload( + &mut self, + db: &Database, + fields: Vec, + ) -> Result { let user = self.clone_user(); self.cache.is_bot = user.bot.is_some(); @@ -150,14 +155,36 @@ impl State { .await?; // Fetch customisations. - let emojis = db - .fetch_emoji_by_parent_ids( - &servers - .iter() - .map(|x| x.id.to_string()) - .collect::>(), + let emojis = if fields.contains(&ReadyPayloadFields::Emoji) { + Some( + db.fetch_emoji_by_parent_ids( + &servers + .iter() + .map(|x| x.id.to_string()) + .collect::>(), + ) + .await?, ) - .await?; + } else { + None + }; + + // 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?) + } else { + None + }; + + // Fetch channel unreads + let channel_unreads = if fields.contains(&ReadyPayloadFields::ChannelUnreads) { + Some(db.fetch_unreads(&user.id).await?) + } else { + None + }; // Copy data into local state cache. self.cache.users = users.iter().cloned().map(|x| (x.id.clone(), x)).collect(); @@ -201,13 +228,31 @@ impl State { for channel in &channels { self.insert_subscription(channel.id().to_string()).await; } - Ok(EventV1::Ready { - users, - servers: servers.into_iter().map(Into::into).collect(), - channels: channels.into_iter().map(Into::into).collect(), - members: members.into_iter().map(Into::into).collect(), - emojis: emojis.into_iter().map(Into::into).collect(), + users: if fields.contains(&ReadyPayloadFields::Users) { + Some(users) + } else { + None + }, + servers: if fields.contains(&ReadyPayloadFields::Servers) { + Some(servers.into_iter().map(Into::into).collect()) + } else { + None + }, + channels: if fields.contains(&ReadyPayloadFields::Channels) { + Some(channels.into_iter().map(Into::into).collect()) + } else { + None + }, + members: if fields.contains(&ReadyPayloadFields::Members) { + Some(members.into_iter().map(Into::into).collect()) + } else { + None + }, + emojis: emojis.map(|vec| vec.into_iter().map(Into::into).collect()), + + user_settings, + channel_unreads: channel_unreads.map(|vec| vec.into_iter().map(Into::into).collect()), }) } diff --git a/crates/bonfire/src/websocket.rs b/crates/bonfire/src/websocket.rs index d84824b8..db77f399 100644 --- a/crates/bonfire/src/websocket.rs +++ b/crates/bonfire/src/websocket.rs @@ -106,7 +106,10 @@ pub async fn client(db: &'static Database, stream: TcpStream, addr: SocketAddr) } // Download required data to local cache and send Ready payload. - let ready_payload = match state.generate_ready_payload(db).await { + let ready_payload = match state + .generate_ready_payload(db, config.get_ready_payload_fields()) + .await + { Ok(ready_payload) => ready_payload, Err(err) => { sentry::capture_error(&err); diff --git a/crates/core/database/src/events/client.rs b/crates/core/database/src/events/client.rs index 74338bfe..a0b3eef9 100644 --- a/crates/core/database/src/events/client.rs +++ b/crates/core/database/src/events/client.rs @@ -2,10 +2,10 @@ use authifier::AuthifierEvent; use serde::{Deserialize, Serialize}; use revolt_models::v0::{ - AppendMessage, Channel, Emoji, FieldsChannel, FieldsMember, FieldsRole, FieldsServer, - FieldsUser, FieldsWebhook, Member, MemberCompositeKey, Message, PartialChannel, PartialMember, - PartialMessage, PartialRole, PartialServer, PartialUser, PartialWebhook, RemovalIntention, - Report, Server, User, UserSettings, Webhook, + AppendMessage, Channel, ChannelUnread, Emoji, FieldsChannel, FieldsMember, FieldsRole, + FieldsServer, FieldsUser, FieldsWebhook, Member, MemberCompositeKey, Message, PartialChannel, + PartialMember, PartialMessage, PartialRole, PartialServer, PartialUser, PartialWebhook, + RemovalIntention, Report, Server, User, UserSettings, Webhook, }; use revolt_result::Error; @@ -39,6 +39,19 @@ pub enum ErrorEvent { APIError(Error), } +/// Fields provided in Ready payload +#[derive(PartialEq)] +pub enum ReadyPayloadFields { + Users, + Servers, + Channels, + Members, + Emoji, + + UserSettings(Vec), + ChannelUnreads, +} + /// Protocol Events #[derive(Serialize, Deserialize, Debug, Clone)] #[serde(tag = "type")] @@ -52,11 +65,21 @@ pub enum EventV1 { Logout, /// Basic data to cache Ready { - users: Vec, - servers: Vec, - channels: Vec, - members: Vec, - emojis: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + users: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + servers: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + channels: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + members: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + emojis: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + user_settings: Option, + #[serde(skip_serializing_if = "Option::is_none")] + channel_unreads: Option>, }, /// Ping response