From d69b88566ad48dc17c1b27c1f3c6f2a7442595b4 Mon Sep 17 00:00:00 2001 From: Benjamin Lee Date: Thu, 16 May 2024 15:51:30 -0700 Subject: [PATCH] implement per-event filtering for ephemeral events in /sync I've asked a few times for clarification on whether the `senders` field in the filter applies to userids mentioned in the typing/receipt ephemeral events, and never got a response. Synapse does not filter these userids by sender, so we're gonna go with that. --- src/api/client_server/sync.rs | 64 ++++++++++++++++++----------------- src/utils/filter.rs | 17 ++++++++-- 2 files changed, 48 insertions(+), 33 deletions(-) diff --git a/src/api/client_server/sync.rs b/src/api/client_server/sync.rs index 7e23294f..f991ac98 100644 --- a/src/api/client_server/sync.rs +++ b/src/api/client_server/sync.rs @@ -22,9 +22,12 @@ use ruma::{ uiaa::UiaaResponse, }, events::{ + receipt::ReceiptEventContent, room::member::{MembershipState, RoomMemberEventContent}, - StateEventType, TimelineEventType, + typing::TypingEventContent, + StateEventType, StaticEventContent, TimelineEventType, }, + serde::Raw, uint, DeviceId, EventId, JsOption, OwnedRoomId, OwnedUserId, RoomId, UInt, UserId, }; @@ -933,39 +936,38 @@ async fn load_joined_room( let room_events: Vec<_> = timeline_pdus.iter().map(|(_, pdu)| pdu.to_sync_room_event()).collect(); - let edus = if filter.room.ephemeral.room_allowed(room_id) { - let mut edus: Vec<_> = services() - .rooms - .edus - .read_receipt - .readreceipts_since(room_id, since) - .filter_map(Result::ok) - .map(|(_, _, v)| v) - .collect(); - - if services().rooms.edus.typing.last_typing_update(room_id).await? - > since - { - edus.push( - serde_json::from_str( - &serde_json::to_string( - &services() - .rooms - .edus - .typing - .typings_all(room_id) - .await?, - ) - .expect("event is valid, we just created it"), - ) - .expect("event is valid, we just created it"), + let mut edus = vec![]; + if filter.room.ephemeral.room_allowed(room_id) { + // We only filter on event type for ephemeral events because none of the + // other filter parameters apply to the specific ephemeral + // events we're generating (m.room.receipt and m.room.typing). + // If we add fields to either of these events, or start + // generating other event types in the future, we need to + // reevaluate this. + if filter.room.ephemeral.type_allowed(ReceiptEventContent::TYPE) { + edus.extend( + services() + .rooms + .edus + .read_receipt + .readreceipts_since(room_id, since) + .filter_map(Result::ok) + .map(|(_, _, v)| v), ); } - edus - } else { - vec![] - }; + if filter.room.ephemeral.type_allowed(TypingEventContent::TYPE) + && services().rooms.edus.typing.last_typing_update(room_id).await? + > since + { + let edu = services().rooms.edus.typing.typings_all(room_id).await?; + edus.push( + Raw::new(&edu) + .expect("event is valid, we just created it") + .cast(), + ); + } + } let account_data_events = if filter.room.account_data.room_allowed(room_id) { diff --git a/src/utils/filter.rs b/src/utils/filter.rs index 47afaba7..aeb460d7 100644 --- a/src/utils/filter.rs +++ b/src/utils/filter.rs @@ -15,6 +15,10 @@ //! top-level `filter.rooms.room`. Similarly, when a room is rejected for all //! events in a particular category, we can skip work generating events in that //! category for the rejected room. +//! +//! The second exception is ephemeral event types (`type`/`not_type` in +//! `filter.room.ephemeral`). For these, we can skip work generating events of a +//! particular type in `/sync` if it is rejected. use std::{borrow::Cow, collections::HashSet, hash::Hash}; @@ -258,6 +262,15 @@ impl CompiledRoomEventFilter<'_> { self.rooms.allowed(room_id) } + /// Returns `true` if an event type is allowed by the `types` and + /// `not_types` fields. + /// + /// This is mainly useful to skip work generating events for a particular + /// type, if that event type is always rejected by the filter. + pub(crate) fn type_allowed(&self, kind: &str) -> bool { + self.types.allowed(kind) + } + /// Returns `true` if a PDU event is allowed by the filter. /// /// This tests against the `senders`, `not_senders`, `types`, `not_types`, @@ -269,7 +282,7 @@ impl CompiledRoomEventFilter<'_> { /// [`CompiledRoomFilter::rooms`]. pub(crate) fn pdu_event_allowed(&self, pdu: &PduEvent) -> bool { self.senders.allowed(&pdu.sender) - && self.types.allowed(&pdu.kind.to_string()) + && self.type_allowed(&pdu.kind.to_string()) && self.allowed_by_url_filter(pdu) } @@ -305,7 +318,7 @@ impl CompiledRoomEventFilter<'_> { allowed_by_url_filter && self.senders.allowed(&event.sender) - && self.types.allowed(&event.kind) + && self.type_allowed(&event.kind) } // TODO: refactor this as well?