diff --git a/matrix_sdk_base/src/client.rs b/matrix_sdk_base/src/client.rs index c78090a2..cc181edb 100644 --- a/matrix_sdk_base/src/client.rs +++ b/matrix_sdk_base/src/client.rs @@ -29,7 +29,7 @@ use matrix_sdk_common::locks::Mutex; use matrix_sdk_common::{ api::r0 as api, events::{ - room::member::MemberEventContent, AnyStrippedStateEvent, AnySyncRoomEvent, + room::member::MemberEventContent, AnyBasicEvent, AnyStrippedStateEvent, AnySyncRoomEvent, AnySyncStateEvent, StateEvent, SyncStateEvent, }, identifiers::{RoomId, UserId}, @@ -54,7 +54,9 @@ use zeroize::Zeroizing; use crate::{ error::Result, - responses::{JoinedRoom, LeftRoom, Presence, Rooms, State, SyncResponse, Timeline}, + responses::{ + AccountData, JoinedRoom, LeftRoom, Presence, Rooms, State, SyncResponse, Timeline, + }, session::Session, store::{InnerSummary, Room, RoomType, StateChanges, Store}, }; @@ -529,6 +531,22 @@ impl BaseClient { state } + async fn handle_room_account_data( + &self, + room_id: &RoomId, + events: &[Raw], + changes: &mut StateChanges, + ) -> AccountData { + let events: Vec = + events.iter().filter_map(|e| e.deserialize().ok()).collect(); + + for event in &events { + changes.add_room_account_data(room_id, event.clone()); + } + + AccountData { events } + } + /// Receive a response from a sync call. /// /// # Arguments @@ -582,6 +600,10 @@ impl BaseClient { .handle_timeline(&room_id, &room_info.timeline, &mut summary, &mut changes) .await; + let account_data = self + .handle_room_account_data(&room_id, &room_info.account_data.events, &mut changes) + .await; + #[cfg(feature = "encryption")] if summary.is_encrypted() { // TODO if the room isn't encrypted but the new summary is, @@ -601,7 +623,9 @@ impl BaseClient { summary.mark_members_missing(); } - rooms.join.insert(room_id, JoinedRoom::new(timeline, state)); + rooms + .join + .insert(room_id, JoinedRoom::new(timeline, state, account_data)); changes.add_room(summary); } @@ -624,7 +648,13 @@ impl BaseClient { .handle_timeline(&room_id, &room_info.timeline, &mut summary, &mut changes) .await; - rooms.leave.insert(room_id, LeftRoom::new(timeline, state)); + let account_data = self + .handle_room_account_data(&room_id, &room_info.account_data.events, &mut changes) + .await; + + rooms + .leave + .insert(room_id, LeftRoom::new(timeline, state, account_data)); } for event in &response.presence.events { diff --git a/matrix_sdk_base/src/responses.rs b/matrix_sdk_base/src/responses.rs index dfb0b87b..ab363ebe 100644 --- a/matrix_sdk_base/src/responses.rs +++ b/matrix_sdk_base/src/responses.rs @@ -3,7 +3,10 @@ use std::collections::BTreeMap; use matrix_sdk_common::{ api::r0::sync::sync_events::DeviceLists, - events::{presence::PresenceEvent, AnySyncRoomEvent, AnySyncStateEvent, AnyToDeviceEvent}, + events::{ + presence::PresenceEvent, AnyBasicEvent, AnySyncRoomEvent, AnySyncStateEvent, + AnyToDeviceEvent, + }, identifiers::{DeviceKeyAlgorithm, RoomId}, }; @@ -44,6 +47,13 @@ pub struct Presence { pub events: Vec, } +/// Data that the user has attached to either the account or a specific room. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +pub struct AccountData { + /// The list of account data events. + pub events: Vec, +} + /// Messages sent dirrectly between devices. #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct ToDevice { @@ -72,16 +82,20 @@ pub struct JoinedRoom { /// of the `timeline` (or all state up to the start of the `timeline`, if `since` is not /// given, or `full_state` is true). pub state: State, - // /// The private data that this user has attached to this room. - // pub account_data: AccountData, + /// The private data that this user has attached to this room. + pub account_data: AccountData, // /// The ephemeral events in the room that aren't recorded in the timeline or state of the // /// room. e.g. typing. // pub ephemeral: Ephemeral, } impl JoinedRoom { - pub fn new(timeline: Timeline, state: State) -> Self { - Self { timeline, state } + pub fn new(timeline: Timeline, state: State, account_data: AccountData) -> Self { + Self { + timeline, + state, + account_data, + } } } @@ -94,11 +108,17 @@ pub struct LeftRoom { /// of the `timeline` (or all state up to the start of the `timeline`, if `since` is not /// given, or `full_state` is true). pub state: State, + /// The private data that this user has attached to this room. + pub account_data: AccountData, } impl LeftRoom { - pub fn new(timeline: Timeline, state: State) -> Self { - Self { timeline, state } + pub fn new(timeline: Timeline, state: State, account_data: AccountData) -> Self { + Self { + timeline, + state, + account_data, + } } } diff --git a/matrix_sdk_base/src/store.rs b/matrix_sdk_base/src/store.rs index a59666ae..18f06b08 100644 --- a/matrix_sdk_base/src/store.rs +++ b/matrix_sdk_base/src/store.rs @@ -17,10 +17,9 @@ use matrix_sdk_common::{ encryption::EncryptionEventContent, member::MemberEventContent, power_levels::PowerLevelsEventContent, }, - AnySyncStateEvent, EventContent, EventType, SyncStateEvent, + AnyBasicEvent, AnySyncStateEvent, EventContent, EventType, SyncStateEvent, }, identifiers::{RoomAliasId, RoomId, UserId}, - Raw, }; use serde::{Deserialize, Serialize}; @@ -34,18 +33,20 @@ pub struct Store { members: Tree, joined_user_ids: Tree, invited_user_ids: Tree, - room_state: Tree, room_summaries: Tree, + room_state: Tree, + room_account_data: Tree, presence: Tree, } -use crate::{client::hoist_and_deserialize_state_event, Session}; +use crate::Session; #[derive(Debug, Default)] pub struct StateChanges { pub session: Option, pub members: BTreeMap>>, pub state: BTreeMap>, + pub room_account_data: BTreeMap>, pub room_summaries: BTreeMap, // display_names: BTreeMap>>, pub joined_user_ids: BTreeMap>, @@ -96,6 +97,13 @@ impl StateChanges { .insert(room.room_id.as_ref().to_owned(), room); } + pub fn add_room_account_data(&mut self, room_id: &RoomId, event: AnyBasicEvent) { + self.room_account_data + .entry(room_id.to_owned()) + .or_insert_with(BTreeMap::new) + .insert(event.content().event_type().to_owned(), event); + } + pub fn add_state_event(&mut self, room_id: &RoomId, event: AnySyncStateEvent) { self.state .entry(room_id.to_owned()) @@ -402,18 +410,6 @@ pub struct InnerSummary { } impl InnerSummary { - pub fn handle_state_events(&mut self, state_events: &[Raw]) { - for e in state_events { - if let Ok(event) = hoist_and_deserialize_state_event(e) { - match event { - _ => { - self.handle_state_event(&event); - } - } - } - } - } - pub fn mark_as_joined(&mut self) { self.room_type = RoomType::Joined; } @@ -507,6 +503,7 @@ impl Store { let room_state = db.open_tree("room_state").unwrap(); let room_summaries = db.open_tree("room_summaries").unwrap(); let presence = db.open_tree("presence").unwrap(); + let room_account_data = db.open_tree("room_account_data").unwrap(); Self { inner: db, @@ -514,6 +511,7 @@ impl Store { members, joined_user_ids, invited_user_ids, + room_account_data, presence, room_state, room_summaries, @@ -552,12 +550,22 @@ impl Store { &self.members, &self.joined_user_ids, &self.invited_user_ids, - &self.room_state, &self.room_summaries, + &self.room_state, + &self.room_account_data, &self.presence, ) .transaction( - |(session, members, joined, invited, state, summaries, presence)| { + |( + session, + members, + joined, + invited, + summaries, + state, + room_account_data, + presence, + )| { if let Some(s) = &changes.session { session.insert("session", serde_json::to_vec(s).unwrap())?; } @@ -571,6 +579,15 @@ impl Store { } } + for (room, events) in &changes.room_account_data { + for (event_type, event) in events { + room_account_data.insert( + format!("{}{}", room.as_str(), event_type).as_str(), + serde_json::to_vec(&event).unwrap(), + )?; + } + } + for (room, users) in &changes.joined_user_ids { for user in users { let key = format!("{}{}", room.as_str(), user.as_str());