chore: add policy changes

This commit is contained in:
Zomatree
2025-09-16 20:46:05 +01:00
committed by Angelo Kontaxis
parent db57706794
commit 964884a5de
3 changed files with 63 additions and 31 deletions

View File

@@ -1,13 +1,14 @@
use async_tungstenite::tungstenite::{handshake, Message}; use async_tungstenite::tungstenite::{handshake, Message};
use futures::channel::oneshot::Sender; use futures::channel::oneshot::Sender;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex;
use revolt_database::events::client::ReadyPayloadFields; use revolt_database::events::client::ReadyPayloadFields;
use revolt_result::{create_error, Result}; use revolt_result::{create_error, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use regex::Regex;
/// matches either a single word ie "users" or a key and value ie "settings[notifications]" /// 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()); static READY_PAYLOAD_FIELD_REGEX: Lazy<Regex> =
Lazy::new(|| Regex::new(r#"^(\w+)(?:\[(\w+)\])?$"#).unwrap());
/// Enumeration of supported protocol formats /// Enumeration of supported protocol formats
#[derive(Debug)] #[derive(Debug)]
@@ -22,7 +23,7 @@ pub struct ProtocolConfiguration {
protocol_version: i32, protocol_version: i32,
format: ProtocolFormat, format: ProtocolFormat,
session_token: Option<String>, session_token: Option<String>,
ready_payload_fields: ReadyPayloadFields ready_payload_fields: ReadyPayloadFields,
} }
impl ProtocolConfiguration { impl ProtocolConfiguration {
@@ -31,13 +32,13 @@ impl ProtocolConfiguration {
protocol_version: i32, protocol_version: i32,
format: ProtocolFormat, format: ProtocolFormat,
session_token: Option<String>, session_token: Option<String>,
ready_payload_fields: ReadyPayloadFields ready_payload_fields: ReadyPayloadFields,
) -> Self { ) -> Self {
Self { Self {
protocol_version, protocol_version,
format, format,
session_token, 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 protocol_version = 1;
let mut format = ProtocolFormat::Json; let mut format = ProtocolFormat::Json;
let mut session_token = None; 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. // Parse and map parameters from key-value to known variables.
for (key, value) in params { for (key, value) in params {
@@ -143,6 +159,7 @@ impl handshake::server::Callback for WebsocketHandshakeCallback {
}, },
"token" => session_token = Some(value.into()), "token" => session_token = Some(value.into()),
"ready" => { "ready" => {
// Re-enable all the fields the client specifies
if let Some(captures) = READY_PAYLOAD_FIELD_REGEX.captures(value) { if let Some(captures) = READY_PAYLOAD_FIELD_REGEX.captures(value) {
if let Some(field) = captures.get(0) { if let Some(field) = captures.get(0) {
match field.as_str() { match field.as_str() {
@@ -154,9 +171,12 @@ impl handshake::server::Callback for WebsocketHandshakeCallback {
"channel_unreads" => ready_payload_fields.channel_unreads = true, "channel_unreads" => ready_payload_fields.channel_unreads = true,
"user_settings" => { "user_settings" => {
if let Some(subkey) = captures.get(1) { 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, protocol_version,
format, format,
session_token, session_token,
ready_payload_fields ready_payload_fields,
}) })
.is_ok() .is_ok()
{ {

View File

@@ -101,15 +101,17 @@ impl State {
self.cache.is_bot = user.bot.is_some(); self.cache.is_bot = user.bot.is_some();
// Fetch pending policy changes. // Fetch pending policy changes.
let policy_changes = if user.bot.is_some() { let policy_changes = if user.bot.is_some() || !fields.policy_changes {
vec![] None
} else { } else {
db.fetch_policy_changes() Some(
.await? db.fetch_policy_changes()
.into_iter() .await?
.filter(|policy| policy.created_time > user.last_acknowledged_policy_change) .into_iter()
.map(Into::into) .filter(|policy| policy.created_time > user.last_acknowledged_policy_change)
.collect() .map(Into::into)
.collect(),
)
}; };
// Find all relationships to the user. // Find all relationships to the user.
@@ -176,7 +178,10 @@ impl State {
.map(|x| x.id.to_string()) .map(|x| x.id.to_string())
.collect::<Vec<String>>(), .collect::<Vec<String>>(),
) )
.await?, .await?
.into_iter()
.map(|emoji| emoji.into())
.collect(),
) )
} else { } else {
None None
@@ -184,14 +189,23 @@ impl State {
// Fetch user settings // Fetch user settings
let user_settings = if !fields.user_settings.is_empty() { 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 { } else {
None None
}; };
// Fetch channel unreads // Fetch channel unreads
let channel_unreads = if fields.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 { } else {
None None
}; };
@@ -238,11 +252,7 @@ impl State {
} }
Ok(EventV1::Ready { Ok(EventV1::Ready {
users: if fields.users { users: if fields.users { Some(users) } else { None },
Some(users)
} else {
None
},
servers: if fields.servers { servers: if fields.servers {
Some(servers.into_iter().map(Into::into).collect()) Some(servers.into_iter().map(Into::into).collect())
} else { } else {
@@ -258,10 +268,9 @@ impl State {
} else { } else {
None None
}, },
emojis: emojis.map(|vec| vec.into_iter().map(Into::into).collect()), emojis,
user_settings, user_settings,
channel_unreads: channel_unreads.map(|vec| vec.into_iter().map(Into::into).collect()), channel_unreads,
policy_changes, policy_changes,
}) })

View File

@@ -28,7 +28,8 @@ pub struct ReadyPayloadFields {
pub members: bool, pub members: bool,
pub emojis: bool, pub emojis: bool,
pub user_settings: Vec<String>, pub user_settings: Vec<String>,
pub channel_unreads: bool pub channel_unreads: bool,
pub policy_changes: bool,
} }
impl Default for ReadyPayloadFields { impl Default for ReadyPayloadFields {
@@ -40,7 +41,8 @@ impl Default for ReadyPayloadFields {
members: true, members: true,
emojis: true, emojis: true,
user_settings: Vec::new(), 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")] #[serde(skip_serializing_if = "Option::is_none")]
channel_unreads: Option<Vec<ChannelUnread>>, channel_unreads: Option<Vec<ChannelUnread>>,
policy_changes: Vec<PolicyChange>, #[serde(skip_serializing_if = "Option::is_none")]
policy_changes: Option<Vec<PolicyChange>>,
}, },
/// Ping response /// Ping response