diff --git a/crates/matrix-sdk-base/src/client.rs b/crates/matrix-sdk-base/src/client.rs index 586192b397c..1693f029606 100644 --- a/crates/matrix-sdk-base/src/client.rs +++ b/crates/matrix-sdk-base/src/client.rs @@ -688,13 +688,18 @@ impl BaseClient { } } + /// Parses and stores any raw global account data events into the + /// [`StateChanges`]. + /// + /// Returns a list with the parsed account data events. #[instrument(skip_all)] pub(crate) async fn handle_account_data( &self, events: &[Raw], changes: &mut StateChanges, - ) { + ) -> Vec { let mut account_data = BTreeMap::new(); + let mut parsed_events = Vec::new(); for raw_event in events { let event = match raw_event.deserialize() { @@ -705,64 +710,78 @@ impl BaseClient { continue; } }; + account_data.insert(event.event_type(), raw_event.clone()); + parsed_events.push(event); + } - if let AnyGlobalAccountDataEvent::Direct(e) = &event { - let mut new_dms = HashMap::<&RoomId, HashSet>::new(); - for (user_id, rooms) in e.content.iter() { - for room_id in rooms { - new_dms.entry(room_id).or_default().insert(user_id.clone()); - } + changes.account_data = account_data; + parsed_events + } + + /// Processes the direct rooms in a sync response: + /// + /// Given a [`StateChanges`] instance, processes any direct room info + /// from the global account data and adds it to the room infos to + /// save. + #[instrument(skip_all)] + pub(crate) async fn process_direct_rooms( + &self, + events: &[AnyGlobalAccountDataEvent], + changes: &mut StateChanges, + ) { + for event in events { + let AnyGlobalAccountDataEvent::Direct(direct_event) = event else { continue }; + let mut new_dms = HashMap::<&RoomId, HashSet>::new(); + for (user_id, rooms) in direct_event.content.iter() { + for room_id in rooms { + new_dms.entry(room_id).or_default().insert(user_id.clone()); } + } - let rooms = self.store.rooms(); - let mut old_dms = rooms - .iter() - .filter_map(|r| { - let direct_targets = r.direct_targets(); - (!direct_targets.is_empty()).then(|| (r.room_id(), direct_targets)) - }) - .collect::>(); - - // Update the direct targets of rooms if they changed. - for (room_id, new_direct_targets) in new_dms { - if let Some(old_direct_targets) = old_dms.remove(&room_id) { - if old_direct_targets == new_direct_targets { - continue; - } + let rooms = self.store.rooms(); + let mut old_dms = rooms + .iter() + .filter_map(|r| { + let direct_targets = r.direct_targets(); + (!direct_targets.is_empty()).then(|| (r.room_id(), direct_targets)) + }) + .collect::>(); + + // Update the direct targets of rooms if they changed. + for (room_id, new_direct_targets) in new_dms { + if let Some(old_direct_targets) = old_dms.remove(&room_id) { + if old_direct_targets == new_direct_targets { + continue; } + } - trace!( - ?room_id, targets = ?new_direct_targets, - "Marking room as direct room" - ); + trace!( + ?room_id, targets = ?new_direct_targets, + "Marking room as direct room" + ); - if let Some(info) = changes.room_infos.get_mut(room_id) { - info.base_info.dm_targets = new_direct_targets; - } else if let Some(room) = self.store.room(room_id) { - let mut info = room.clone_info(); - info.base_info.dm_targets = new_direct_targets; - changes.add_room(info); - } + if let Some(info) = changes.room_infos.get_mut(room_id) { + info.base_info.dm_targets = new_direct_targets; + } else if let Some(room) = self.store.room(room_id) { + let mut info = room.clone_info(); + info.base_info.dm_targets = new_direct_targets; + changes.add_room(info); } + } - // Remove the targets of old direct chats. - for room_id in old_dms.keys() { - trace!(?room_id, "Unmarking room as direct room"); + // Remove the targets of old direct chats. + for room_id in old_dms.keys() { + trace!(?room_id, "Unmarking room as direct room"); - if let Some(info) = changes.room_infos.get_mut(*room_id) { - info.base_info.dm_targets.clear(); - } else if let Some(room) = self.store.room(room_id) { - let mut info = room.clone_info(); - info.base_info.dm_targets.clear(); - changes.add_room(info); - } + if let Some(info) = changes.room_infos.get_mut(*room_id) { + info.base_info.dm_targets.clear(); + } else if let Some(room) = self.store.room(room_id) { + let mut info = room.clone_info(); + info.base_info.dm_targets.clear(); + changes.add_room(info); } } - - account_data.insert(event.event_type(), raw_event.clone()); } - - changes.account_data = account_data; } #[cfg(feature = "e2e-encryption")] @@ -971,7 +990,8 @@ impl BaseClient { let mut ambiguity_cache = AmbiguityCache::new(self.store.inner.clone()); - self.handle_account_data(&response.account_data.events, &mut changes).await; + let global_account_data_events = + self.handle_account_data(&response.account_data.events, &mut changes).await; let push_rules = self.get_push_rules(&changes).await?; @@ -1186,23 +1206,24 @@ impl BaseClient { new_rooms.invite.insert(room_id, new_info); } - // TODO remove this, we're processing account data events here again + // We're processing direct state events here separately // because we want to have the push rules in place before we process // rooms and their events, but we want to create the rooms before we // process the `m.direct` account data event. - let has_new_direct_room_data = response.account_data.events.iter().any(|raw_event| { - raw_event - .deserialize() - .map(|event| event.event_type() == GlobalAccountDataEventType::Direct) - .unwrap_or_default() - }); + let has_new_direct_room_data = global_account_data_events + .iter() + .any(|event| event.event_type() == GlobalAccountDataEventType::Direct); if has_new_direct_room_data { - self.handle_account_data(&response.account_data.events, &mut changes).await; + self.process_direct_rooms(&global_account_data_events, &mut changes).await; } else if let Ok(Some(direct_account_data)) = self.store.get_account_data_event(GlobalAccountDataEventType::Direct).await { debug!("Found direct room data in the Store, applying it"); - self.handle_account_data(&[direct_account_data], &mut changes).await; + if let Ok(direct_account_data) = direct_account_data.deserialize() { + self.process_direct_rooms(&[direct_account_data], &mut changes).await; + } else { + warn!("Failed to deserialize direct room account data"); + } } changes.presence = response diff --git a/crates/matrix-sdk-base/src/sliding_sync/mod.rs b/crates/matrix-sdk-base/src/sliding_sync/mod.rs index 825247b579e..5aa0993b09d 100644 --- a/crates/matrix-sdk-base/src/sliding_sync/mod.rs +++ b/crates/matrix-sdk-base/src/sliding_sync/mod.rs @@ -164,9 +164,11 @@ impl BaseClient { let mut ambiguity_cache = AmbiguityCache::new(store.inner.clone()); let account_data = &extensions.account_data; - if !account_data.is_empty() { - self.handle_account_data(&account_data.global, &mut changes).await; - } + let global_account_data_events = if !account_data.is_empty() { + self.handle_account_data(&account_data.global, &mut changes).await + } else { + Vec::new() + }; let mut new_rooms = RoomUpdates::default(); let mut notifications = Default::default(); @@ -302,23 +304,24 @@ impl BaseClient { } } - // TODO remove this, we're processing account data events here again + // We're processing direct state events here separately // because we want to have the push rules in place before we process // rooms and their events, but we want to create the rooms before we // process the `m.direct` account data event. - let has_new_direct_room_data = account_data.global.iter().any(|raw_event| { - raw_event - .deserialize() - .map(|event| event.event_type() == GlobalAccountDataEventType::Direct) - .unwrap_or_default() - }); + let has_new_direct_room_data = global_account_data_events + .iter() + .any(|event| event.event_type() == GlobalAccountDataEventType::Direct); if has_new_direct_room_data { - self.handle_account_data(&account_data.global, &mut changes).await; + self.process_direct_rooms(&global_account_data_events, &mut changes).await; } else if let Ok(Some(direct_account_data)) = self.store.get_account_data_event(GlobalAccountDataEventType::Direct).await { debug!("Found direct room data in the Store, applying it"); - self.handle_account_data(&[direct_account_data], &mut changes).await; + if let Ok(direct_account_data) = direct_account_data.deserialize() { + self.process_direct_rooms(&[direct_account_data], &mut changes).await; + } else { + warn!("Failed to deserialize direct room account data"); + } } // FIXME not yet supported by sliding sync.