From f7039d9a8dc867f6a0433ac9771a937bc5b41b79 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Wed, 7 Oct 2020 14:23:15 +0200 Subject: [PATCH 1/7] matrix_sdk_base: expose RoomMember --- matrix_sdk_base/src/lib.rs | 2 +- matrix_sdk_base/src/models/room_member.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/matrix_sdk_base/src/lib.rs b/matrix_sdk_base/src/lib.rs index 1934faf5..6f4377b4 100644 --- a/matrix_sdk_base/src/lib.rs +++ b/matrix_sdk_base/src/lib.rs @@ -53,7 +53,7 @@ mod state; pub use client::{BaseClient, BaseClientConfig, RoomState, RoomStateType}; pub use event_emitter::{CustomEvent, EventEmitter, SyncRoom}; -pub use models::Room; +pub use models::{Room, RoomMember}; pub use state::{AllRooms, ClientState}; #[cfg(feature = "encryption")] diff --git a/matrix_sdk_base/src/models/room_member.rs b/matrix_sdk_base/src/models/room_member.rs index efe31aba..393d54ac 100644 --- a/matrix_sdk_base/src/models/room_member.rs +++ b/matrix_sdk_base/src/models/room_member.rs @@ -83,6 +83,14 @@ impl PartialEq for RoomMember { } impl RoomMember { + /// Create a new room member. + /// + /// # Arguments + /// + /// * `event` - event associated with a member joining, leaving or getting + /// invited to a room. + /// + /// * `room_id` - The unique id of the room this member is part of. pub fn new(event: &SyncStateEvent, room_id: &RoomId) -> Self { Self { name: event.state_key.clone(), From a4eae1053c7c29ddc09215e512acac7725a3a28e Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Wed, 7 Oct 2020 14:23:37 +0200 Subject: [PATCH 2/7] matrix_sdk: expose RoomMember --- matrix_sdk/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/matrix_sdk/src/lib.rs b/matrix_sdk/src/lib.rs index 078de2e1..0b97e007 100644 --- a/matrix_sdk/src/lib.rs +++ b/matrix_sdk/src/lib.rs @@ -52,7 +52,8 @@ pub use matrix_sdk_base::crypto::LocalTrust; #[cfg(not(target_arch = "wasm32"))] pub use matrix_sdk_base::JsonStore; pub use matrix_sdk_base::{ - CustomEvent, Error as BaseError, EventEmitter, Room, RoomState, Session, StateStore, SyncRoom, + CustomEvent, Error as BaseError, EventEmitter, Room, RoomMember, RoomState, Session, + StateStore, SyncRoom, }; #[cfg(feature = "messages")] From 7d023ebdb908790c946edcf6457c04b4e7d27e24 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Thu, 8 Oct 2020 15:25:32 +0200 Subject: [PATCH 3/7] matrix_sdk examples: set `#![type_length_limit = "1075569"]` Some examples no longer build after the following commits, set a bigger-than-default type_length_limit to let tests pass. The exceptions are not necessary on nightly and can be removed again after https://github.com/rust-lang/rust/issues/54540 is fixed. --- matrix_sdk/examples/command_bot.rs | 4 ++++ matrix_sdk/examples/image_bot.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/matrix_sdk/examples/command_bot.rs b/matrix_sdk/examples/command_bot.rs index 4f2d9fea..ffd39f76 100644 --- a/matrix_sdk/examples/command_bot.rs +++ b/matrix_sdk/examples/command_bot.rs @@ -1,3 +1,7 @@ +// allow biggr types until rustc fix, consider removing after new rust +// stable release. see https://github.com/rust-lang/rust/issues/54540 +#![type_length_limit = "1075569"] + use std::{env, process::exit}; use matrix_sdk::{ diff --git a/matrix_sdk/examples/image_bot.rs b/matrix_sdk/examples/image_bot.rs index 68099d89..5f48e6e0 100644 --- a/matrix_sdk/examples/image_bot.rs +++ b/matrix_sdk/examples/image_bot.rs @@ -1,3 +1,7 @@ +// allow biggr types until rustc fix, consider removing after new rust +// stable release. see https://github.com/rust-lang/rust/issues/54540 +#![type_length_limit = "1075569"] + use std::{ env, fs::File, From 883183324f7c8a0a0afc92b8c906ab51be9a12b7 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Wed, 7 Oct 2020 19:02:13 +0200 Subject: [PATCH 4/7] matrix_sdk_base: room: add direct_target field Rooms marked as "direct" are associated a user_id in "m.direct" events. Clients could want to handle these separately --- matrix_sdk_base/src/client.rs | 21 ++++++++++++++++++++- matrix_sdk_base/src/models/message.rs | 2 ++ matrix_sdk_base/src/models/room.rs | 17 +++++++++++++++++ matrix_sdk_base/src/state/mod.rs | 2 ++ 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/matrix_sdk_base/src/client.rs b/matrix_sdk_base/src/client.rs index ff91cfcd..f28b8ec2 100644 --- a/matrix_sdk_base/src/client.rs +++ b/matrix_sdk_base/src/client.rs @@ -27,7 +27,7 @@ use matrix_sdk_common::locks::Mutex; use matrix_sdk_common::{ api::r0 as api, events::{ - ignored_user_list::IgnoredUserListEvent, push_rules::PushRulesEvent, + direct::DirectEvent, ignored_user_list::IgnoredUserListEvent, push_rules::PushRulesEvent, room::member::MemberEventContent, AnyBasicEvent, AnyStrippedStateEvent, AnySyncEphemeralRoomEvent, AnySyncMessageEvent, AnySyncRoomEvent, AnySyncStateEvent, }, @@ -695,6 +695,24 @@ impl BaseClient { // } } + /// Handle a m.direct event, updating rooms states if necessary. + /// + /// Returns true if any room changed, false otherwise. + pub(crate) async fn handle_direct(&self, event: &DirectEvent) -> bool { + let mut update = false; + for (user_id, rooms) in event.content.iter() { + for room_id in rooms.iter() { + if let Some(room) = self.get_joined_room(room_id).await { + let mut room = room.write().await; + if room.handle_direct(user_id) { + update = true; + } + } + } + } + update + } + /// Receive a timeline event for a joined room and update the client state. /// /// Returns a bool, true when the `Room` state has been updated. @@ -888,6 +906,7 @@ impl BaseClient { match event { AnyBasicEvent::IgnoredUserList(event) => self.handle_ignored_users(event).await, AnyBasicEvent::PushRules(event) => self.handle_push_rules(event).await, + AnyBasicEvent::Direct(event) => self.handle_direct(event).await, _ => false, } } diff --git a/matrix_sdk_base/src/models/message.rs b/matrix_sdk_base/src/models/message.rs index 9cac09c9..9403c6c0 100644 --- a/matrix_sdk_base/src/models/message.rs +++ b/matrix_sdk_base/src/models/message.rs @@ -206,6 +206,7 @@ mod test { }, "own_user_id": "@example:example.com", "creator": null, + "direct_target": null, "joined_members": {}, "invited_members": {}, "messages": [ msg ], @@ -253,6 +254,7 @@ mod test { }, "own_user_id": "@example:example.com", "creator": null, + "direct_target": null, "joined_members": {}, "invited_members": {}, "messages": [ msg ], diff --git a/matrix_sdk_base/src/models/room.rs b/matrix_sdk_base/src/models/room.rs index 33150622..aa333c57 100644 --- a/matrix_sdk_base/src/models/room.rs +++ b/matrix_sdk_base/src/models/room.rs @@ -190,6 +190,8 @@ pub struct Room { pub own_user_id: UserId, /// The mxid of the room creator. pub creator: Option, + /// The mxid of the "direct" target if any + pub direct_target: Option, // TODO: Track banned members, e.g. for /unban support? /// The map of invited room members. pub invited_members: HashMap, @@ -312,6 +314,7 @@ impl Room { room_name: RoomName::default(), own_user_id: own_user_id.clone(), creator: None, + direct_target: None, invited_members: HashMap::new(), joined_members: HashMap::new(), #[cfg(feature = "messages")] @@ -799,6 +802,20 @@ impl Room { true } + /// Handle setting direct attribute as part of a m.direct event, + /// updating the room if necessary + /// + /// Returns true if the direct_target changed, false otherwise. + pub fn handle_direct(&mut self, user_id: &UserId) -> bool { + if let Some(old_target) = &self.direct_target { + if old_target == user_id { + return false; + } + } + self.direct_target = Some(user_id.clone()); + true + } + fn handle_encryption_event(&mut self, event: &SyncStateEvent) -> bool { self.encrypted = Some(event.into()); true diff --git a/matrix_sdk_base/src/state/mod.rs b/matrix_sdk_base/src/state/mod.rs index 4d18a47c..ffd53d58 100644 --- a/matrix_sdk_base/src/state/mod.rs +++ b/matrix_sdk_base/src/state/mod.rs @@ -160,6 +160,7 @@ mod test { }, "own_user_id": "@example:example.com", "creator": null, + "direct_target": null, "joined_members": {}, "invited_members": {}, "typing_users": [], @@ -188,6 +189,7 @@ mod test { }, "own_user_id": "@example:example.com", "creator": null, + "direct_target": null, "joined_members": {}, "invited_members": {}, "messages": [], From d8589403426e9e693af38c4514f02a0adb5b8760 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Wed, 7 Oct 2020 19:03:42 +0200 Subject: [PATCH 5/7] matrix_sdk_base: handle response.account_data events "m.direct" events are not in room account data events but in main one --- matrix_sdk_base/src/client.rs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/matrix_sdk_base/src/client.rs b/matrix_sdk_base/src/client.rs index f28b8ec2..17b11e82 100644 --- a/matrix_sdk_base/src/client.rs +++ b/matrix_sdk_base/src/client.rs @@ -902,7 +902,11 @@ impl BaseClient { /// * `room_id` - The unique id of the room the event belongs to. /// /// * `event` - The presence event for a specified room member. - pub async fn receive_account_data_event(&self, _: &RoomId, event: &AnyBasicEvent) -> bool { + pub async fn receive_account_data_event( + &self, + _: Option<&RoomId>, + event: &AnyBasicEvent, + ) -> bool { match event { AnyBasicEvent::IgnoredUserList(event) => self.handle_ignored_users(event).await, AnyBasicEvent::PushRules(event) => self.handle_push_rules(event).await, @@ -971,6 +975,7 @@ impl BaseClient { self.iter_joined_rooms(response).await?; self.iter_invited_rooms(response).await?; self.iter_left_rooms(response).await?; + self.iter_account_data(response).await?; let store = self.state_store.read().await; @@ -1071,7 +1076,7 @@ impl BaseClient { // FIXME: receive_* and emit_* methods shouldn't be called in parallel. We // should only pass events to receive_* methods and then let *them* emit. if let Ok(e) = account_data.deserialize() { - if self.receive_account_data_event(&room_id, &e).await { + if self.receive_account_data_event(Some(&room_id), &e).await { updated = true; } self.emit_account_data_event(room_id, &e, RoomStateType::Joined) @@ -1187,6 +1192,25 @@ impl BaseClient { Ok(updated) } + async fn iter_account_data( + &self, + response: &mut api::sync::sync_events::Response, + ) -> Result { + let mut updated = false; + for account_data in &response.account_data.events { + { + // FIXME: emit_account_data_event assumes a room is given + if let Ok(e) = account_data.deserialize() { + if self.receive_account_data_event(None, &e).await { + updated = true; + } + } + } + } + // FIXME store all rooms if updated? + Ok(updated) + } + async fn iter_invited_rooms( &self, response: &api::sync::sync_events::Response, From 2602c36ad032f6adcf57fd1eaba8e6fcf57501ad Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Thu, 8 Oct 2020 09:06:27 +0200 Subject: [PATCH 6/7] matrix_sdk_base: save room states after successfully parsed account events --- matrix_sdk_base/src/client.rs | 54 ++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/matrix_sdk_base/src/client.rs b/matrix_sdk_base/src/client.rs index 17b11e82..8da690f4 100644 --- a/matrix_sdk_base/src/client.rs +++ b/matrix_sdk_base/src/client.rs @@ -698,19 +698,20 @@ impl BaseClient { /// Handle a m.direct event, updating rooms states if necessary. /// /// Returns true if any room changed, false otherwise. - pub(crate) async fn handle_direct(&self, event: &DirectEvent) -> bool { - let mut update = false; + pub(crate) async fn handle_direct(&self, event: &DirectEvent) -> Vec>> { + let mut updated_rooms = vec![]; + for (user_id, rooms) in event.content.iter() { for room_id in rooms.iter() { - if let Some(room) = self.get_joined_room(room_id).await { - let mut room = room.write().await; - if room.handle_direct(user_id) { - update = true; + if let Some(room) = &self.get_joined_room(room_id).await { + let mut room_locked = room.write().await; + if room_locked.handle_direct(user_id) { + updated_rooms.push(room.to_owned()); } } } } - update + updated_rooms } /// Receive a timeline event for a joined room and update the client state. @@ -893,7 +894,8 @@ impl BaseClient { } } - /// Receive an account data event from a sync response and updates the client state. + /// Receive an account data event associated to a room from a sync + /// response and updates the client state. /// /// Returns true if the state of the `Room` has changed, false otherwise. /// @@ -902,19 +904,32 @@ impl BaseClient { /// * `room_id` - The unique id of the room the event belongs to. /// /// * `event` - The presence event for a specified room member. - pub async fn receive_account_data_event( - &self, - _: Option<&RoomId>, - event: &AnyBasicEvent, - ) -> bool { + pub async fn receive_room_account_data_event(&self, _: &RoomId, event: &AnyBasicEvent) -> bool { match event { AnyBasicEvent::IgnoredUserList(event) => self.handle_ignored_users(event).await, AnyBasicEvent::PushRules(event) => self.handle_push_rules(event).await, - AnyBasicEvent::Direct(event) => self.handle_direct(event).await, _ => false, } } + /// Receive an account data event from a sync response and updates + /// the client state. + /// + /// Returns true if the state of any room has changed, false otherwise. + /// + /// # Arguments + /// + /// * `event` - The presence event for a specified room member. + pub async fn receive_account_data_event( + &self, + event: &AnyBasicEvent, + ) -> Vec>> { + match event { + AnyBasicEvent::Direct(event) => self.handle_direct(event).await, + _ => vec![], + } + } + /// Receive an ephemeral event from a sync response and updates the client state. /// /// Returns true if the state of the `Room` has changed, false otherwise. @@ -1076,7 +1091,7 @@ impl BaseClient { // FIXME: receive_* and emit_* methods shouldn't be called in parallel. We // should only pass events to receive_* methods and then let *them* emit. if let Ok(e) = account_data.deserialize() { - if self.receive_account_data_event(Some(&room_id), &e).await { + if self.receive_room_account_data_event(&room_id, &e).await { updated = true; } self.emit_account_data_event(room_id, &e, RoomStateType::Joined) @@ -1201,13 +1216,18 @@ impl BaseClient { { // FIXME: emit_account_data_event assumes a room is given if let Ok(e) = account_data.deserialize() { - if self.receive_account_data_event(None, &e).await { + for room in self.receive_account_data_event(&e).await { + if let Some(store) = self.state_store.read().await.as_ref() { + // FIXME: currently only operate on Joined rooms + store + .store_room_state(RoomState::Joined(room.read().await.deref())) + .await?; + } updated = true; } } } } - // FIXME store all rooms if updated? Ok(updated) } From 9ea4835e3e5c0015421fd6400ca1f9d86e073b51 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Thu, 8 Oct 2020 17:48:57 +0200 Subject: [PATCH 7/7] Revert "matrix_sdk examples: set `#![type_length_limit = "1075569"]`" This reverts commit 7d023ebdb908790c946edcf6457c04b4e7d27e24. Rust 1.47.0 got released and the tuning is no longer necessary. --- matrix_sdk/examples/command_bot.rs | 4 ---- matrix_sdk/examples/image_bot.rs | 4 ---- 2 files changed, 8 deletions(-) diff --git a/matrix_sdk/examples/command_bot.rs b/matrix_sdk/examples/command_bot.rs index ffd39f76..4f2d9fea 100644 --- a/matrix_sdk/examples/command_bot.rs +++ b/matrix_sdk/examples/command_bot.rs @@ -1,7 +1,3 @@ -// allow biggr types until rustc fix, consider removing after new rust -// stable release. see https://github.com/rust-lang/rust/issues/54540 -#![type_length_limit = "1075569"] - use std::{env, process::exit}; use matrix_sdk::{ diff --git a/matrix_sdk/examples/image_bot.rs b/matrix_sdk/examples/image_bot.rs index 5f48e6e0..68099d89 100644 --- a/matrix_sdk/examples/image_bot.rs +++ b/matrix_sdk/examples/image_bot.rs @@ -1,7 +1,3 @@ -// allow biggr types until rustc fix, consider removing after new rust -// stable release. see https://github.com/rust-lang/rust/issues/54540 -#![type_length_limit = "1075569"] - use std::{ env, fs::File,