feat: ready payload field customisation

This commit is contained in:
Zomatree
2025-05-05 22:14:10 +01:00
committed by Angelo Kontaxis
parent a186732ca5
commit db57706794
5 changed files with 65 additions and 29 deletions

1
Cargo.lock generated
View File

@@ -6294,6 +6294,7 @@ dependencies = [
"once_cell",
"querystring",
"redis-kiss",
"regex",
"revolt-config",
"revolt-database",
"revolt-models",

View File

@@ -19,6 +19,7 @@ async-channel = "2.3.1"
# parsing
querystring = "1.1.0"
regex = "1.11.1"
# serde
bincode = "1.3.3"

View File

@@ -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<Regex> = 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<String>,
ready_payload_fields: ReadyPayloadFields
}
impl ProtocolConfiguration {
@@ -25,11 +31,13 @@ impl ProtocolConfiguration {
protocol_version: i32,
format: ProtocolFormat,
session_token: Option<String>,
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<ReadyPayloadFields> {
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()
{

View File

@@ -95,7 +95,7 @@ impl State {
pub async fn generate_ready_payload(
&mut self,
db: &Database,
fields: Vec<ReadyPayloadFields>,
fields: &ReadyPayloadFields,
) -> Result<EventV1> {
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

View File

@@ -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<String>,
pub channel_unreads: bool
}
UserSettings(Vec<String>),
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