diff --git a/src/api/client_server/sync.rs b/src/api/client_server/sync.rs index d7dc5a17..d9d8323f 100644 --- a/src/api/client_server/sync.rs +++ b/src/api/client_server/sync.rs @@ -170,6 +170,7 @@ pub(crate) async fn sync_events_route( lazy_load_enabled, lazy_load_send_redundant, full_state, + &compiled_filter, &mut device_list_updates, &mut left_encrypted_users, ) @@ -207,6 +208,7 @@ pub(crate) async fn sync_events_route( &next_batch_string, full_state, lazy_load_enabled, + &compiled_filter, ) .await?; } @@ -382,9 +384,11 @@ async fn load_joined_room( lazy_load_enabled: bool, lazy_load_send_redundant: bool, full_state: bool, + filter: &CompiledFilterDefinition<'_>, device_list_updates: &mut HashSet, left_encrypted_users: &mut HashSet, ) -> Result { + // TODO: can we skip this when the room is filtered out? { // Get and drop the lock to wait for remaining operations to finish // This will make sure the we have all events until next_batch @@ -402,7 +406,7 @@ async fn load_joined_room( } let (timeline_pdus, limited) = - load_timeline(sender_user, room_id, sincecount, 10)?; + load_timeline(sender_user, room_id, sincecount, 10, Some(filter))?; let send_notification_counts = !timeline_pdus.is_empty() || services() @@ -974,6 +978,7 @@ async fn load_joined_room( room_id = %room_id, ), )] +#[allow(clippy::too_many_arguments)] async fn handle_left_room( room_id: OwnedRoomId, sender_user: &UserId, @@ -982,6 +987,7 @@ async fn handle_left_room( next_batch_string: &str, full_state: bool, lazy_load_enabled: bool, + filter: &CompiledFilterDefinition<'_>, ) -> Result<()> { { // Get and drop the lock to wait for remaining operations to finish @@ -1006,6 +1012,20 @@ async fn handle_left_room( return Ok(()); } + let timeline = if filter.room.timeline.room_allowed(&room_id) { + Timeline { + limited: false, + prev_batch: Some(next_batch_string.to_owned()), + events: vec![], + } + } else { + Timeline { + limited: false, + prev_batch: None, + events: vec![], + } + }; + if !services().rooms.metadata.exists(&room_id)? { // This is just a rejected invite, not a room we know let event = PduEvent { @@ -1037,11 +1057,7 @@ async fn handle_left_room( account_data: RoomAccountData { events: Vec::new(), }, - timeline: Timeline { - limited: false, - prev_batch: Some(next_batch_string.to_owned()), - events: Vec::new(), - }, + timeline, state: State { events: vec![event.to_sync_state_event()], }, @@ -1126,11 +1142,7 @@ async fn handle_left_room( account_data: RoomAccountData { events: Vec::new(), }, - timeline: Timeline { - limited: false, - prev_batch: Some(next_batch_string.to_owned()), - events: Vec::new(), - }, + timeline, state: State { events: left_state_events, }, @@ -1145,9 +1157,17 @@ fn load_timeline( room_id: &RoomId, roomsincecount: PduCount, limit: u64, + filter: Option<&CompiledFilterDefinition<'_>>, ) -> Result<(Vec<(PduCount, PduEvent)>, bool), Error> { let timeline_pdus; let limited; + + if let Some(filter) = filter { + if !filter.room.timeline.room_allowed(room_id) { + return Ok((vec![], false)); + } + } + if services().rooms.timeline.last_timeline_count(sender_user, room_id)? > roomsincecount { @@ -1622,6 +1642,7 @@ pub(crate) async fn sync_events_v4_route( room_id, roomsincecount, *timeline_limit, + None, )?; if roomsince != &0 && timeline_pdus.is_empty() { diff --git a/src/utils/filter.rs b/src/utils/filter.rs index dded8f89..3258580b 100644 --- a/src/utils/filter.rs +++ b/src/utils/filter.rs @@ -12,7 +12,9 @@ //! In `/messages`, if the room is rejected by the filter, we can skip the //! entire request. The outer loop of our `/sync` implementation is over rooms, //! and so we are able to skip work for an entire room if it is rejected by the -//! top-level `filter.rooms.room`. +//! 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. use std::{collections::HashSet, hash::Hash}; @@ -156,6 +158,7 @@ pub(crate) struct CompiledFilterDefinition<'a> { pub(crate) struct CompiledRoomFilter<'a> { rooms: AllowDenyList<'a, RoomId>, + pub(crate) timeline: CompiledRoomEventFilter<'a>, } pub(crate) struct CompiledRoomEventFilter<'a> { @@ -193,6 +196,7 @@ impl<'a> TryFrom<&'a RoomFilter> for CompiledRoomFilter<'a> { source.rooms.as_deref(), &source.not_rooms, ), + timeline: (&source.timeline).try_into()?, }) } }