From b420d7022a4535feafbfaea6d037871220992e9e Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Fri, 22 Apr 2022 15:35:38 +0200 Subject: [PATCH 01/28] typed display name for i18n --- crates/matrix-sdk-base/src/rooms/mod.rs | 62 +++++++++++++++------- crates/matrix-sdk-base/src/rooms/normal.rs | 38 +++++++++++-- 2 files changed, 77 insertions(+), 23 deletions(-) diff --git a/crates/matrix-sdk-base/src/rooms/mod.rs b/crates/matrix-sdk-base/src/rooms/mod.rs index f1924096e..783182742 100644 --- a/crates/matrix-sdk-base/src/rooms/mod.rs +++ b/crates/matrix-sdk-base/src/rooms/mod.rs @@ -18,6 +18,34 @@ use ruma::{ }; use serde::{Deserialize, Serialize}; +/// The name of the room, either from the metadata or calculaetd +/// according to [matrix specification][spec] +/// [spec]: +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub enum DisplayName { + /// The room has been named explicitly as + Named(String), + /// The room has not given an explicit name but a name could be + /// calculated + Calculated(String), + /// The room doesn't have a name right now, but used to have one + /// e.g. because it was a DM and everyone has left the room + EmptyWas(String), + /// No useful name could be calculated or ever found + Empty, +} + +impl DisplayName { + /// Generate the caninocal String of the DisplayName in english + pub fn to_string(&self) -> String { + match self { + DisplayName::Named(s) | DisplayName::Calculated(s) => s.clone(), + DisplayName::EmptyWas(s) => format!("Empty (was {})", s), + DisplayName::Empty => "Empty".to_string(), + } + } +} + /// A base room info struct that is the backbone of normal as well as stripped /// rooms. Holds all the state events that are important to present a room to /// users. @@ -61,7 +89,7 @@ impl BaseRoomInfo { joined_member_count: u64, invited_member_count: u64, heroes: Vec, - ) -> String { + ) -> DisplayName { calculate_room_name( joined_member_count, invited_member_count, @@ -196,14 +224,12 @@ impl Default for BaseRoomInfo { } } -/// Calculate room name according to step 3 of the [naming algorithm.][spec] -/// -/// [spec]: +/// Calculate room name according to step 3 of the [naming algorithm.] fn calculate_room_name( joined_member_count: u64, invited_member_count: u64, heroes: Vec<&str>, -) -> String { +) -> DisplayName { let heroes_count = heroes.len() as u64; let invited_joined = invited_member_count + joined_member_count; let invited_joined_minus_one = invited_joined.saturating_sub(1); @@ -227,12 +253,12 @@ fn calculate_room_name( // User is alone. if invited_joined <= 1 { if names.is_empty() { - "Empty room".to_owned() + DisplayName::Empty } else { - format!("Empty room (was {})", names) + DisplayName::EmptyWas(names) } } else { - names + DisplayName::Calculated(names) } } @@ -243,33 +269,33 @@ mod tests { fn test_calculate_room_name() { let mut actual = calculate_room_name(2, 0, vec!["a"]); - assert_eq!("a", actual); + assert_eq!(DisplayName::Calculated("a".to_string()), actual); actual = calculate_room_name(3, 0, vec!["a", "b"]); - assert_eq!("a, b", actual); + assert_eq!(DisplayName::Calculated("a, b".to_string()), actual); actual = calculate_room_name(4, 0, vec!["a", "b", "c"]); - assert_eq!("a, b, c", actual); + assert_eq!(DisplayName::Calculated("a, b, c".to_string()), actual); actual = calculate_room_name(5, 0, vec!["a", "b", "c"]); - assert_eq!("a, b, c, and 2 others", actual); + assert_eq!(DisplayName::Calculated("a, b, c, and 2 others".to_string()), actual); actual = calculate_room_name(0, 0, vec![]); - assert_eq!("Empty room", actual); + assert_eq!(DisplayName::Empty, actual); actual = calculate_room_name(1, 0, vec![]); - assert_eq!("Empty room", actual); + assert_eq!(DisplayName::Empty, actual); actual = calculate_room_name(0, 1, vec![]); - assert_eq!("Empty room", actual); + assert_eq!(DisplayName::Empty, actual); actual = calculate_room_name(1, 0, vec!["a"]); - assert_eq!("Empty room (was a)", actual); + assert_eq!(DisplayName::EmptyWas("a".to_string()), actual); actual = calculate_room_name(1, 0, vec!["a", "b"]); - assert_eq!("Empty room (was a, b)", actual); + assert_eq!(DisplayName::EmptyWas("a, b".to_string()), actual); actual = calculate_room_name(1, 0, vec!["a", "b", "c"]); - assert_eq!("Empty room (was a, b, c)", actual); + assert_eq!(DisplayName::EmptyWas("a, b, c".to_string()), actual); } } diff --git a/crates/matrix-sdk-base/src/rooms/normal.rs b/crates/matrix-sdk-base/src/rooms/normal.rs index 04b4bd391..a6d5622b4 100644 --- a/crates/matrix-sdk-base/src/rooms/normal.rs +++ b/crates/matrix-sdk-base/src/rooms/normal.rs @@ -39,7 +39,7 @@ use ruma::{ use serde::{Deserialize, Serialize}; use tracing::{debug, warn}; -use super::{BaseRoomInfo, RoomMember}; +use super::{BaseRoomInfo, RoomMember, DisplayName}; use crate::{ deserialized_responses::{SyncRoomEvent, TimelineSlice, UnreadNotificationsCount}, store::{Result as StoreResult, StateStore}, @@ -261,7 +261,7 @@ impl Room { /// The display name is calculated according to [this algorithm][spec]. /// /// [spec]: - pub async fn display_name(&self) -> StoreResult { + pub async fn display_name(&self) -> StoreResult { self.calculate_name().await } @@ -323,16 +323,16 @@ impl Room { Ok(members) } - async fn calculate_name(&self) -> StoreResult { + async fn calculate_name(&self) -> StoreResult { let summary = { let inner = self.inner.read().unwrap(); if let Some(name) = &inner.base_info.name { let name = name.trim(); - return Ok(name.to_owned()); + return Ok(DisplayName::Named(name.to_owned())); } else if let Some(alias) = &inner.base_info.canonical_alias { let alias = alias.alias().trim(); - return Ok(alias.to_owned()); + return Ok(DisplayName::Named(alias.to_owned())); } inner.summary.clone() }; @@ -716,3 +716,31 @@ impl RoomInfo { self.base_info.create.as_ref().map(|c| &c.room_version) } } + +#[cfg(test)] +mod test { + use crate::store::MemoryStore; + use std::sync::Arc; + use ruma::{user_id, room_id}; + use super::*; + + fn make_room(room_type: RoomType) -> Room { + let store = Arc::new(MemoryStore::new()); + let user_id = user_id!("@something:example.org"); + let room_id = room_id!("!test:localhost"); + + Room::new( + &user_id, + store, + room_id, + room_type + ) + } + + #[tokio::test] + async fn test_display_name() { + let mut room = make_room(RoomType::Joined); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Empty); + + } +} \ No newline at end of file From 48fc26a35bce5ba6fe0ab1e252cfa6a9fda9f15b Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Fri, 22 Apr 2022 17:45:27 +0200 Subject: [PATCH 02/28] tests for broken room name --- crates/matrix-sdk-base/Cargo.toml | 1 + crates/matrix-sdk-base/src/rooms/mod.rs | 10 +- crates/matrix-sdk-base/src/rooms/normal.rs | 127 +++++++++++++++++++-- 3 files changed, 126 insertions(+), 12 deletions(-) diff --git a/crates/matrix-sdk-base/Cargo.toml b/crates/matrix-sdk-base/Cargo.toml index 8bb2f8194..81c742bf2 100644 --- a/crates/matrix-sdk-base/Cargo.toml +++ b/crates/matrix-sdk-base/Cargo.toml @@ -49,6 +49,7 @@ http = { version = "0.2.4", optional = true } [dev-dependencies] futures = { version = "0.3.15", default-features = false, features = ["executor"] } http = "0.2.4" +assign = "1.1.1" matrix-sdk-test = { version = "0.4.0", path = "../matrix-sdk-test" } tokio = { version = "1.7.1", default-features = false, features = [ "rt-multi-thread", diff --git a/crates/matrix-sdk-base/src/rooms/mod.rs b/crates/matrix-sdk-base/src/rooms/mod.rs index 783182742..c2dd49ada 100644 --- a/crates/matrix-sdk-base/src/rooms/mod.rs +++ b/crates/matrix-sdk-base/src/rooms/mod.rs @@ -25,6 +25,8 @@ use serde::{Deserialize, Serialize}; pub enum DisplayName { /// The room has been named explicitly as Named(String), + /// The room has a canonical alias that should be used + Aliased(String), /// The room has not given an explicit name but a name could be /// calculated Calculated(String), @@ -39,9 +41,11 @@ impl DisplayName { /// Generate the caninocal String of the DisplayName in english pub fn to_string(&self) -> String { match self { - DisplayName::Named(s) | DisplayName::Calculated(s) => s.clone(), - DisplayName::EmptyWas(s) => format!("Empty (was {})", s), - DisplayName::Empty => "Empty".to_string(), + DisplayName::Named(s) + | DisplayName::Calculated(s) + | DisplayName::Aliased(s) => s.clone(), + DisplayName::EmptyWas(s) => format!("Empty Room (was {})", s), + DisplayName::Empty => "Empty Room".to_string(), } } } diff --git a/crates/matrix-sdk-base/src/rooms/normal.rs b/crates/matrix-sdk-base/src/rooms/normal.rs index a6d5622b4..8180c79b0 100644 --- a/crates/matrix-sdk-base/src/rooms/normal.rs +++ b/crates/matrix-sdk-base/src/rooms/normal.rs @@ -332,7 +332,7 @@ impl Room { return Ok(DisplayName::Named(name.to_owned())); } else if let Some(alias) = &inner.base_info.canonical_alias { let alias = alias.alias().trim(); - return Ok(DisplayName::Named(alias.to_owned())); + return Ok(DisplayName::Aliased(alias.to_owned())); } inner.summary.clone() }; @@ -719,28 +719,137 @@ impl RoomInfo { #[cfg(test)] mod test { - use crate::store::MemoryStore; + use crate::{ + store::{MemoryStore, StateChanges}, + deserialized_responses::{ + StrippedMemberEvent, + MemberEvent, + } + }; use std::sync::Arc; - use ruma::{user_id, room_id}; + use ruma::{ + user_id, room_id, event_id, RoomAliasId, + MilliSecondsSinceUnixEpoch, + events::{ + room::member::{ + RoomMemberEventContent, MembershipState + }, + StateUnsigned, + }, + }; use super::*; + use assign::assign; - fn make_room(room_type: RoomType) -> Room { + fn make_room(room_type: RoomType) -> (Arc, Room) { let store = Arc::new(MemoryStore::new()); - let user_id = user_id!("@something:example.org"); + let user_id = user_id!("@me:example.org"); let room_id = room_id!("!test:localhost"); - Room::new( + (store.clone(), Room::new( &user_id, store, room_id, room_type - ) + )) + } + + fn make_stripped_member_event(user_id: &UserId, name: &str) -> StrippedMemberEvent { + StrippedMemberEvent { + content: assign!(RoomMemberEventContent::new(MembershipState::Join), { + displayname: Some(name.to_string()) + }), + sender: user_id.to_owned(), + state_key: user_id.to_owned(), + } + } + + fn make_member_event(user_id: &UserId, name: &str) -> MemberEvent { + MemberEvent { + content: assign!(RoomMemberEventContent::new(MembershipState::Join), { + displayname: Some(name.to_string()) + }), + sender: user_id.to_owned(), + state_key: user_id.to_owned(), + event_id: event_id!("$h29iv0s1:example.com").to_owned(), + origin_server_ts: MilliSecondsSinceUnixEpoch(208u32.into()), + unsigned: StateUnsigned::default(), + + } } #[tokio::test] - async fn test_display_name() { - let mut room = make_room(RoomType::Joined); + async fn test_display_name_default() { + let (_, room) = make_room(RoomType::Joined); assert_eq!(room.display_name().await.unwrap(), DisplayName::Empty); + // has precedence + room.inner.write().unwrap().base_info.canonical_alias = Some(RoomAliasId::parse("#test:example.com").unwrap()); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Aliased("test".to_string())); + + // has precedence + room.inner.write().unwrap().base_info.name = Some("Test Room".to_string()); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Named("Test Room".to_string())); + + let (_, room) = make_room(RoomType::Invited); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Empty); + + // has precedence + room.inner.write().unwrap().base_info.canonical_alias = Some(RoomAliasId::parse("#test:example.com").unwrap()); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Aliased("test".to_string())); + + // has precedence + room.inner.write().unwrap().base_info.name = Some("Test Room".to_string()); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Named("Test Room".to_string())); + + } + + #[tokio::test] + async fn test_display_name_dm_invited() { + let (store, room) = make_room(RoomType::Invited); + let room_id = room_id!("!test:localhost"); + let matthew = user_id!("@matthew:example.org"); + let me = user_id!("@me:example.org"); + let mut changes = StateChanges::new("".to_string()); + let summary = assign!(RumaSummary::new(), { + heroes: vec![me.to_string(), matthew.to_string()], + }); + + changes.add_stripped_member( + &room_id, + make_stripped_member_event(matthew, "Matthew") + ); + changes.add_stripped_member( + &room_id, + make_stripped_member_event(me, "Me") + ); + store.save_changes(&changes).await.unwrap(); + + room.inner.write().unwrap().update_summary(&summary); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Calculated("Matthew".to_string())); + } + + #[tokio::test] + async fn test_display_name_dm_joined() { + let (store, room) = make_room(RoomType::Joined); + let room_id = room_id!("!test:localhost"); + let matthew = user_id!("@matthew:example.org"); + let me = user_id!("@me:example.org"); + let mut changes = StateChanges::new("".to_string()); + let summary = assign!(RumaSummary::new(), { + heroes: vec![me.to_string(), matthew.to_string()], + }); + + changes.members.entry(room_id.to_owned()).or_default().insert( + matthew.to_owned(), + make_member_event(matthew, "Matthew") + ); + changes.members.entry(room_id.to_owned()).or_default().insert( + me.to_owned(), + make_member_event(me, "Me") + ); + store.save_changes(&changes).await.unwrap(); + + room.inner.write().unwrap().update_summary(&summary); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Calculated("Matthew".to_string())); } } \ No newline at end of file From 15e76b90b1f8a1311ab5ad76e0b508805b015674 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Mon, 25 Apr 2022 13:29:59 +0200 Subject: [PATCH 03/28] adding display name integration tests for DM invite --- crates/matrix-sdk-base/src/client.rs | 105 ++++++++++++++++++++++++++- crates/matrix-sdk-base/src/lib.rs | 2 +- 2 files changed, 103 insertions(+), 4 deletions(-) diff --git a/crates/matrix-sdk-base/src/client.rs b/crates/matrix-sdk-base/src/client.rs index 96d4865b6..9cde05836 100644 --- a/crates/matrix-sdk-base/src/client.rs +++ b/crates/matrix-sdk-base/src/client.rs @@ -1278,12 +1278,16 @@ impl Default for BaseClient { #[cfg(test)] mod tests { - use matrix_sdk_test::{async_test, EventBuilder}; - use ruma::{room_id, user_id}; + use matrix_sdk_test::{async_test, EventBuilder, response_from_file}; + use ruma::{ + api::IncomingResponse, + api::client as api, + room_id, user_id + }; use serde_json::json; use super::BaseClient; - use crate::{RoomType, Session}; + use crate::{RoomType, Session, DisplayName}; #[async_test] async fn invite_after_leaving() { @@ -1340,4 +1344,99 @@ mod tests { client.receive_sync_response(response).await.unwrap(); assert_eq!(client.get_room(room_id).unwrap().room_type(), RoomType::Invited); } + + #[async_test] + async fn invite_displayname_intergration_test() { + + let user_id = user_id!("@alice:example.org"); + let room_id = room_id!("!ithpyNKDtmhneaTQja:example.org"); + + let client = BaseClient::new(); + client + .restore_login(Session { + access_token: "token".to_owned(), + user_id: user_id.to_owned(), + device_id: "FOOBAR".into(), + }) + .await + .unwrap(); + + + let response = api::sync::sync_events::v3::Response::try_from_http_response(response_from_file(&json!({ + "next_batch": "asdkl;fjasdkl;fj;asdkl;f", + "device_one_time_keys_count": { + "signed_curve25519": 50u64 + }, + "device_unused_fallback_key_types": [ + "signed_curve25519" + ], + "rooms": { + "invite": { + "!ithpyNKDtmhneaTQja:example.org": { + "invite_state": { + "events": [ + { + "content": { + "creator": "@test:example.org", + "room_version": "9" + }, + "sender": "@test:example.org", + "state_key": "", + "type": "m.room.create" + }, + { + "content": { + "join_rule": "invite" + }, + "sender": "@test:example.org", + "state_key": "", + "type": "m.room.join_rules" + }, + { + "content": { + "algorithm": "m.megolm.v1.aes-sha2" + }, + "sender": "@test:example.org", + "state_key": "", + "type": "m.room.encryption" + }, + { + "content": { + "avatar_url": "mxc://example.org/dcBBDwuWEUrjfrOchvkirUST", + "displayname": "Kyra", + "membership": "join" + }, + "sender": "@test:example.org", + "state_key": "@test:example.org", + "type": "m.room.member" + }, + { + "content": { + "avatar_url": "mxc://example.org/ABFEXSDrESxovWwEnCYdNcHT", + "displayname": "alice", + "is_direct": true, + "membership": "invite" + }, + "origin_server_ts": 1650878657984u64, + "sender": "@test:example.org", + "state_key": "@alice:example.org", + "type": "m.room.member", + "unsigned": { + "age": 14u64 + }, + "event_id": "$fLDqltg9Puj-kWItLSFVHPGN4YkgpYQf2qImPzdmgrE" + } + ] + } + } + } + } + }))).expect("static json doesn't fail to parse"); + + client.receive_sync_response(response).await.unwrap(); + + let room = client.get_room(room_id).expect("Room not found"); + assert_eq!(room.room_type(), RoomType::Invited); + assert_eq!(room.display_name().await.expect("fetching display name failed"), DisplayName::Calculated("Kyra".to_string())); + } } diff --git a/crates/matrix-sdk-base/src/lib.rs b/crates/matrix-sdk-base/src/lib.rs index c02ca6af3..e62860a8d 100644 --- a/crates/matrix-sdk-base/src/lib.rs +++ b/crates/matrix-sdk-base/src/lib.rs @@ -38,5 +38,5 @@ pub use client::BaseClient; pub use http; #[cfg(feature = "encryption")] pub use matrix_sdk_crypto as crypto; -pub use rooms::{Room, RoomInfo, RoomMember, RoomType}; +pub use rooms::{Room, RoomInfo, RoomMember, RoomType, DisplayName}; pub use store::{StateChanges, StateStore, Store, StoreError}; From 7ea6cb3e95e3a138f664219179afd8528e700ab1 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Mon, 25 Apr 2022 13:31:45 +0200 Subject: [PATCH 04/28] rename Calculated -> Computed --- crates/matrix-sdk-base/src/client.rs | 3 +-- crates/matrix-sdk-base/src/rooms/mod.rs | 14 +++++++------- crates/matrix-sdk-base/src/rooms/normal.rs | 4 ++-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/crates/matrix-sdk-base/src/client.rs b/crates/matrix-sdk-base/src/client.rs index 9cde05836..4ead761a1 100644 --- a/crates/matrix-sdk-base/src/client.rs +++ b/crates/matrix-sdk-base/src/client.rs @@ -1361,7 +1361,6 @@ mod tests { .await .unwrap(); - let response = api::sync::sync_events::v3::Response::try_from_http_response(response_from_file(&json!({ "next_batch": "asdkl;fjasdkl;fj;asdkl;f", "device_one_time_keys_count": { @@ -1437,6 +1436,6 @@ mod tests { let room = client.get_room(room_id).expect("Room not found"); assert_eq!(room.room_type(), RoomType::Invited); - assert_eq!(room.display_name().await.expect("fetching display name failed"), DisplayName::Calculated("Kyra".to_string())); + assert_eq!(room.display_name().await.expect("fetching display name failed"), DisplayName::Computed("Kyra".to_string())); } } diff --git a/crates/matrix-sdk-base/src/rooms/mod.rs b/crates/matrix-sdk-base/src/rooms/mod.rs index c2dd49ada..6f7260d41 100644 --- a/crates/matrix-sdk-base/src/rooms/mod.rs +++ b/crates/matrix-sdk-base/src/rooms/mod.rs @@ -29,7 +29,7 @@ pub enum DisplayName { Aliased(String), /// The room has not given an explicit name but a name could be /// calculated - Calculated(String), + Computed(String), /// The room doesn't have a name right now, but used to have one /// e.g. because it was a DM and everyone has left the room EmptyWas(String), @@ -42,7 +42,7 @@ impl DisplayName { pub fn to_string(&self) -> String { match self { DisplayName::Named(s) - | DisplayName::Calculated(s) + | DisplayName::Computed(s) | DisplayName::Aliased(s) => s.clone(), DisplayName::EmptyWas(s) => format!("Empty Room (was {})", s), DisplayName::Empty => "Empty Room".to_string(), @@ -262,7 +262,7 @@ fn calculate_room_name( DisplayName::EmptyWas(names) } } else { - DisplayName::Calculated(names) + DisplayName::Computed(names) } } @@ -273,16 +273,16 @@ mod tests { fn test_calculate_room_name() { let mut actual = calculate_room_name(2, 0, vec!["a"]); - assert_eq!(DisplayName::Calculated("a".to_string()), actual); + assert_eq!(DisplayName::Computed("a".to_string()), actual); actual = calculate_room_name(3, 0, vec!["a", "b"]); - assert_eq!(DisplayName::Calculated("a, b".to_string()), actual); + assert_eq!(DisplayName::Computed("a, b".to_string()), actual); actual = calculate_room_name(4, 0, vec!["a", "b", "c"]); - assert_eq!(DisplayName::Calculated("a, b, c".to_string()), actual); + assert_eq!(DisplayName::Computed("a, b, c".to_string()), actual); actual = calculate_room_name(5, 0, vec!["a", "b", "c"]); - assert_eq!(DisplayName::Calculated("a, b, c, and 2 others".to_string()), actual); + assert_eq!(DisplayName::Computed("a, b, c, and 2 others".to_string()), actual); actual = calculate_room_name(0, 0, vec![]); assert_eq!(DisplayName::Empty, actual); diff --git a/crates/matrix-sdk-base/src/rooms/normal.rs b/crates/matrix-sdk-base/src/rooms/normal.rs index 8180c79b0..070f9dea6 100644 --- a/crates/matrix-sdk-base/src/rooms/normal.rs +++ b/crates/matrix-sdk-base/src/rooms/normal.rs @@ -825,7 +825,7 @@ mod test { store.save_changes(&changes).await.unwrap(); room.inner.write().unwrap().update_summary(&summary); - assert_eq!(room.display_name().await.unwrap(), DisplayName::Calculated("Matthew".to_string())); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Computed("Matthew".to_string())); } #[tokio::test] @@ -850,6 +850,6 @@ mod test { store.save_changes(&changes).await.unwrap(); room.inner.write().unwrap().update_summary(&summary); - assert_eq!(room.display_name().await.unwrap(), DisplayName::Calculated("Matthew".to_string())); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Computed("Matthew".to_string())); } } \ No newline at end of file From cfeda54fc6d6b5802375d59f6c80acd569ee9204 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Tue, 26 Apr 2022 13:35:06 +0200 Subject: [PATCH 05/28] fix(store): combine stripped and regular membership and allow fetching that --- crates/matrix-sdk-base/src/rooms/members.rs | 12 +-- crates/matrix-sdk-base/src/rooms/normal.rs | 91 +++++++++++++++++-- .../src/store/ambiguity_map.rs | 10 +- .../matrix-sdk-base/src/store/memory_store.rs | 59 ++++++++++-- crates/matrix-sdk-base/src/store/mod.rs | 14 +-- .../src/deserialized_responses.rs | 36 ++++++++ 6 files changed, 189 insertions(+), 33 deletions(-) diff --git a/crates/matrix-sdk-base/src/rooms/members.rs b/crates/matrix-sdk-base/src/rooms/members.rs index 158f1b81a..c88ab1064 100644 --- a/crates/matrix-sdk-base/src/rooms/members.rs +++ b/crates/matrix-sdk-base/src/rooms/members.rs @@ -25,12 +25,12 @@ use ruma::{ MxcUri, UserId, }; -use crate::deserialized_responses::MemberEvent; +use crate::deserialized_responses::EitherMemberEvent; /// A member of a room. #[derive(Clone, Debug)] pub struct RoomMember { - pub(crate) event: Arc, + pub(crate) event: Arc, pub(crate) profile: Arc>, #[allow(dead_code)] pub(crate) presence: Arc>, @@ -43,7 +43,7 @@ pub struct RoomMember { impl RoomMember { /// Get the unique user id of this member. pub fn user_id(&self) -> &UserId { - &self.event.state_key + self.event.user_id() } /// Get the display name of the member if there is one. @@ -51,7 +51,7 @@ impl RoomMember { if let Some(p) = self.profile.as_ref() { p.displayname.as_deref() } else { - self.event.content.displayname.as_deref() + self.event.content().displayname.as_deref() } } @@ -71,7 +71,7 @@ impl RoomMember { pub fn avatar_url(&self) -> Option<&MxcUri> { match self.profile.as_ref() { Some(p) => p.avatar_url.as_deref(), - None => self.event.content.avatar_url.as_deref(), + None => self.event.content().avatar_url.as_deref(), } } @@ -114,7 +114,7 @@ impl RoomMember { if let Some(p) = self.profile.as_ref() { &p.membership } else { - &self.event.content.membership + &self.event.content().membership } } } diff --git a/crates/matrix-sdk-base/src/rooms/normal.rs b/crates/matrix-sdk-base/src/rooms/normal.rs index 070f9dea6..95f6fd08d 100644 --- a/crates/matrix-sdk-base/src/rooms/normal.rs +++ b/crates/matrix-sdk-base/src/rooms/normal.rs @@ -336,11 +336,6 @@ impl Room { } inner.summary.clone() }; - // TODO what should we do here? We have correct counts only if lazy - // loading is used. - let joined = summary.joined_member_count; - let invited = summary.invited_member_count; - let heroes_count = summary.heroes.len() as u64; let is_own_member = |m: &RoomMember| m.user_id() == &*self.own_user_id; let is_own_user_id = |u: &str| u == self.own_user_id().as_str(); @@ -362,10 +357,22 @@ impl Room { members? }; + let (joined, invited) = match self.room_type() { + RoomType::Invited => { + // when we were invited we don't have a proper summary, we have to do best + // guessing + (members.len() as u64, 1u64) + } + RoomType::Joined if summary.joined_member_count == 0 => { + // joined but the summary is not completed yet + (members.len() as u64, summary.invited_member_count) + } + _ => (summary.joined_member_count, summary.invited_member_count), + }; + debug!( room_id = self.room_id().as_str(), own_user = self.own_user_id.as_str(), - heroes_count = heroes_count, heroes = ?summary.heroes, "Calculating name for a room", ); @@ -429,14 +436,14 @@ impl Room { .store .get_users_with_display_name( self.room_id(), - member_event.content.displayname.as_deref().unwrap_or_else(|| user_id.localpart()), + member_event.content().displayname.as_deref().unwrap_or_else(|| user_id.localpart()), ) .await? .len() > 1; Ok(Some(RoomMember { - event: member_event.into(), + event: Arc::new(member_event.into()), profile: profile.into(), presence: presence.into(), power_levels: power.into(), @@ -828,6 +835,27 @@ mod test { assert_eq!(room.display_name().await.unwrap(), DisplayName::Computed("Matthew".to_string())); } + #[tokio::test] + async fn test_display_name_dm_invited_no_heroes() { + let (store, room) = make_room(RoomType::Invited); + let room_id = room_id!("!test:localhost"); + let matthew = user_id!("@matthew:example.org"); + let me = user_id!("@me:example.org"); + let mut changes = StateChanges::new("".to_string()); + + changes.add_stripped_member( + &room_id, + make_stripped_member_event(matthew, "Matthew") + ); + changes.add_stripped_member( + &room_id, + make_stripped_member_event(me, "Me") + ); + store.save_changes(&changes).await.unwrap(); + + assert_eq!(room.display_name().await.unwrap(), DisplayName::Computed("Matthew".to_string())); + } + #[tokio::test] async fn test_display_name_dm_joined() { let (store, room) = make_room(RoomType::Joined); @@ -836,6 +864,7 @@ mod test { let me = user_id!("@me:example.org"); let mut changes = StateChanges::new("".to_string()); let summary = assign!(RumaSummary::new(), { + joined_member_count: Some(2u32.into()), heroes: vec![me.to_string(), matthew.to_string()], }); @@ -852,4 +881,50 @@ mod test { room.inner.write().unwrap().update_summary(&summary); assert_eq!(room.display_name().await.unwrap(), DisplayName::Computed("Matthew".to_string())); } + + #[tokio::test] + async fn test_display_name_dm_joined_no_heroes() { + let (store, room) = make_room(RoomType::Joined); + let room_id = room_id!("!test:localhost"); + let matthew = user_id!("@matthew:example.org"); + let me = user_id!("@me:example.org"); + let mut changes = StateChanges::new("".to_string()); + + changes.members.entry(room_id.to_owned()).or_default().insert( + matthew.to_owned(), + make_member_event(matthew, "Matthew") + ); + changes.members.entry(room_id.to_owned()).or_default().insert( + me.to_owned(), + make_member_event(me, "Me") + ); + store.save_changes(&changes).await.unwrap(); + + assert_eq!(room.display_name().await.unwrap(), DisplayName::Computed("Matthew".to_string())); + } + #[tokio::test] + async fn test_display_name_dm_alone() { + let (store, room) = make_room(RoomType::Joined); + let room_id = room_id!("!test:localhost"); + let matthew = user_id!("@matthew:example.org"); + let me = user_id!("@me:example.org"); + let mut changes = StateChanges::new("".to_string()); + let summary = assign!(RumaSummary::new(), { + joined_member_count: Some(1u32.into()), + heroes: vec![me.to_string(), matthew.to_string()], + }); + + changes.members.entry(room_id.to_owned()).or_default().insert( + matthew.to_owned(), + make_member_event(matthew, "Matthew") + ); + changes.members.entry(room_id.to_owned()).or_default().insert( + me.to_owned(), + make_member_event(me, "Me") + ); + store.save_changes(&changes).await.unwrap(); + + room.inner.write().unwrap().update_summary(&summary); + assert_eq!(room.display_name().await.unwrap(), DisplayName::EmptyWas("Matthew".to_string())); + } } \ No newline at end of file diff --git a/crates/matrix-sdk-base/src/store/ambiguity_map.rs b/crates/matrix-sdk-base/src/store/ambiguity_map.rs index 27e6e6dfe..526ee0f3c 100644 --- a/crates/matrix-sdk-base/src/store/ambiguity_map.rs +++ b/crates/matrix-sdk-base/src/store/ambiguity_map.rs @@ -14,7 +14,7 @@ use std::collections::{BTreeMap, BTreeSet}; -use matrix_sdk_common::deserialized_responses::{AmbiguityChange, MemberEvent}; +use matrix_sdk_common::deserialized_responses::{EitherMemberEvent, AmbiguityChange, MemberEvent}; use ruma::{events::room::member::MembershipState, EventId, RoomId, UserId}; use tracing::trace; @@ -158,13 +158,13 @@ impl AmbiguityCache { let old_event = if let Some(m) = changes.members.get(room_id).and_then(|m| m.get(&member_event.state_key)) { - Some(m.clone()) + Some(EitherMemberEvent::Full(m.clone())) } else { self.store.get_member_event(room_id, &member_event.state_key).await? }; let old_display_name = if let Some(event) = old_event { - if matches!(event.content.membership, Join | Invite) { + if matches!(event.content().membership, Join | Invite) { let display_name = if let Some(d) = changes .profiles .get(room_id) @@ -180,10 +180,10 @@ impl AmbiguityCache { { Some(d) } else { - event.content.displayname.clone() + event.content().displayname.clone() }; - Some(display_name.unwrap_or_else(|| event.state_key.localpart().to_owned())) + Some(display_name.unwrap_or_else(|| event.user_id().localpart().to_owned())) } else { None } diff --git a/crates/matrix-sdk-base/src/store/memory_store.rs b/crates/matrix-sdk-base/src/store/memory_store.rs index 2df59435e..49a1e627b 100644 --- a/crates/matrix-sdk-base/src/store/memory_store.rs +++ b/crates/matrix-sdk-base/src/store/memory_store.rs @@ -44,7 +44,7 @@ use tracing::{info, warn}; use super::{BoxStream, Result, RoomInfo, StateChanges, StateStore}; use crate::{ - deserialized_responses::{MemberEvent, StrippedMemberEvent, SyncRoomEvent}, + deserialized_responses::{EitherMemberEvent, MemberEvent, StrippedMemberEvent, SyncRoomEvent}, media::{MediaRequest, UniqueKey}, StoreError, }; @@ -239,6 +239,39 @@ impl MemoryStore { for (room, events) in &changes.stripped_members { for event in events.values() { + match event.content.membership { + MembershipState::Join => { + self.joined_user_ids + .entry(room.clone()) + .or_insert_with(DashSet::new) + .insert(event.state_key.clone()); + self.invited_user_ids + .entry(room.clone()) + .or_insert_with(DashSet::new) + .remove(&event.state_key); + } + MembershipState::Invite => { + self.invited_user_ids + .entry(room.clone()) + .or_insert_with(DashSet::new) + .insert(event.state_key.clone()); + self.joined_user_ids + .entry(room.clone()) + .or_insert_with(DashSet::new) + .remove(&event.state_key); + } + _ => { + self.joined_user_ids + .entry(room.clone()) + .or_insert_with(DashSet::new) + .remove(&event.state_key); + self.invited_user_ids + .entry(room.clone()) + .or_insert_with(DashSet::new) + .remove(&event.state_key); + } + } + self.stripped_members .entry(room.clone()) .or_insert_with(DashMap::new) @@ -452,15 +485,25 @@ impl MemoryStore { &self, room_id: &RoomId, state_key: &UserId, - ) -> Result> { - Ok(self.members.get(room_id).and_then(|m| m.get(state_key).map(|m| m.clone()))) + ) -> Result> { + if let Some(e) = self.members.get(room_id).and_then(|m| m.get(state_key).map(|m| m.clone())) { + Ok(Some(e.into())) + } else if let Some(e) = self.stripped_members.get(room_id).and_then(|m| m.get(state_key).map(|m| m.clone())) { + Ok(Some(e.into())) + } else { + Ok(None) + } } fn get_user_ids(&self, room_id: &RoomId) -> Vec> { - self.members - .get(room_id) - .map(|u| u.iter().map(|u| u.key().clone()).collect()) - .unwrap_or_default() + if let Some(u) = self.members.get(room_id) { + u.iter().map(|u| u.key().clone()).collect() + } else { + self.stripped_members + .get(room_id) + .map(|u| u.iter().map(|u| u.key().clone()).collect()) + .unwrap_or_default() + } } fn get_invited_user_ids(&self, room_id: &RoomId) -> Vec> { @@ -664,7 +707,7 @@ impl StateStore for MemoryStore { &self, room_id: &RoomId, state_key: &UserId, - ) -> Result> { + ) -> Result> { self.get_member_event(room_id, state_key).await } diff --git a/crates/matrix-sdk-base/src/store/mod.rs b/crates/matrix-sdk-base/src/store/mod.rs index 8869fff83..4de2bd728 100644 --- a/crates/matrix-sdk-base/src/store/mod.rs +++ b/crates/matrix-sdk-base/src/store/mod.rs @@ -54,7 +54,7 @@ use ruma::{ pub type BoxStream = Pin + Send>>; use crate::{ - deserialized_responses::{MemberEvent, StrippedMemberEvent, SyncRoomEvent, TimelineSlice}, + deserialized_responses::{EitherMemberEvent, MemberEvent, StrippedMemberEvent, SyncRoomEvent, TimelineSlice}, media::MediaRequest, rooms::{RoomInfo, RoomType}, Room, Session, @@ -175,7 +175,8 @@ pub trait StateStore: AsyncTraitDeps { user_id: &UserId, ) -> Result>; - /// Get a raw `MemberEvent` for the given state key in the given room id. + /// Get the `EitherMemberEvent` for the given state key in the given room id, + /// containing either the Raw `MemberEvent` or the `StrippedMemberEvent`. /// /// # Arguments /// @@ -186,17 +187,18 @@ pub trait StateStore: AsyncTraitDeps { &self, room_id: &RoomId, state_key: &UserId, - ) -> Result>; + ) -> Result>; - /// Get all the user ids of members for a given room. + /// Get all the user ids of members for a given room, for stripped and regular + /// rooms alike. async fn get_user_ids(&self, room_id: &RoomId) -> Result>>; /// Get all the user ids of members that are in the invited state for a - /// given room. + /// given room, for stripped and regular rooms alike. async fn get_invited_user_ids(&self, room_id: &RoomId) -> Result>>; /// Get all the user ids of members that are in the joined state for a - /// given room. + /// given room, for stripped and regular rooms alike. async fn get_joined_user_ids(&self, room_id: &RoomId) -> Result>>; /// Get all the pure `RoomInfo`s the store knows about. diff --git a/crates/matrix-sdk-common/src/deserialized_responses.rs b/crates/matrix-sdk-common/src/deserialized_responses.rs index 1703f68b1..d15e263f4 100644 --- a/crates/matrix-sdk-common/src/deserialized_responses.rs +++ b/crates/matrix-sdk-common/src/deserialized_responses.rs @@ -380,6 +380,42 @@ impl From for StrippedRoomMemberEvent { } } +/// Wrapper around both MemberEvent-Types +#[derive(Clone, Debug, Deserialize, Serialize)] +pub enum EitherMemberEvent { + Stripped(StrippedMemberEvent), + Full(MemberEvent), +} + +impl EitherMemberEvent { + /// The inner Content of the wrapped Event + pub fn content(&self) -> &RoomMemberEventContent { + match &*self { + EitherMemberEvent::Stripped(e) => &e.content, + EitherMemberEvent::Full(e) => &e.content, + } + } + + /// The user id associated to this member event + pub fn user_id(&self) -> &UserId { + match &*self { + EitherMemberEvent::Stripped(e) => &e.state_key, + EitherMemberEvent::Full(e) => &e.state_key, + } + } +} + +impl From for EitherMemberEvent { + fn from(other: StrippedMemberEvent) -> Self { + EitherMemberEvent::Stripped(other) + } +} +impl From for EitherMemberEvent { + fn from(other: MemberEvent) -> Self { + EitherMemberEvent::Full(other) + } +} + /// A deserialized response for the rooms members API call. /// /// [GET /_matrix/client/r0/rooms/{roomId}/members](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-rooms-roomid-members) From e9e21c1b25ada6fcd86f58e151884b0a75a4f71a Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Tue, 26 Apr 2022 15:34:49 +0200 Subject: [PATCH 06/28] rename computed -> calculated --- crates/matrix-sdk-base/src/client.rs | 2 +- crates/matrix-sdk-base/src/rooms/mod.rs | 14 +++++++------- crates/matrix-sdk-base/src/rooms/normal.rs | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/crates/matrix-sdk-base/src/client.rs b/crates/matrix-sdk-base/src/client.rs index 31a292732..42aa11fa5 100644 --- a/crates/matrix-sdk-base/src/client.rs +++ b/crates/matrix-sdk-base/src/client.rs @@ -1429,6 +1429,6 @@ mod tests { let room = client.get_room(room_id).expect("Room not found"); assert_eq!(room.room_type(), RoomType::Invited); - assert_eq!(room.display_name().await.expect("fetching display name failed"), DisplayName::Computed("Kyra".to_string())); + assert_eq!(room.display_name().await.expect("fetching display name failed"), DisplayName::Calculated("Kyra".to_string())); } } diff --git a/crates/matrix-sdk-base/src/rooms/mod.rs b/crates/matrix-sdk-base/src/rooms/mod.rs index 4a833bab5..d052c3999 100644 --- a/crates/matrix-sdk-base/src/rooms/mod.rs +++ b/crates/matrix-sdk-base/src/rooms/mod.rs @@ -29,7 +29,7 @@ pub enum DisplayName { Aliased(String), /// The room has not given an explicit name but a name could be /// calculated - Computed(String), + Calculated(String), /// The room doesn't have a name right now, but used to have one /// e.g. because it was a DM and everyone has left the room EmptyWas(String), @@ -42,7 +42,7 @@ impl DisplayName { pub fn to_string(&self) -> String { match self { DisplayName::Named(s) - | DisplayName::Computed(s) + | DisplayName::Calculated(s) | DisplayName::Aliased(s) => s.clone(), DisplayName::EmptyWas(s) => format!("Empty Room (was {})", s), DisplayName::Empty => "Empty Room".to_string(), @@ -262,7 +262,7 @@ fn calculate_room_name( DisplayName::EmptyWas(names) } } else { - DisplayName::Computed(names) + DisplayName::Calculated(names) } } @@ -273,16 +273,16 @@ mod tests { fn test_calculate_room_name() { let mut actual = calculate_room_name(2, 0, vec!["a"]); - assert_eq!(DisplayName::Computed("a".to_string()), actual); + assert_eq!(DisplayName::Calculated("a".to_string()), actual); actual = calculate_room_name(3, 0, vec!["a", "b"]); - assert_eq!(DisplayName::Computed("a, b".to_string()), actual); + assert_eq!(DisplayName::Calculated("a, b".to_string()), actual); actual = calculate_room_name(4, 0, vec!["a", "b", "c"]); - assert_eq!(DisplayName::Computed("a, b, c".to_string()), actual); + assert_eq!(DisplayName::Calculated("a, b, c".to_string()), actual); actual = calculate_room_name(5, 0, vec!["a", "b", "c"]); - assert_eq!(DisplayName::Computed("a, b, c, and 2 others".to_string()), actual); + assert_eq!(DisplayName::Calculated("a, b, c, and 2 others".to_string()), actual); actual = calculate_room_name(0, 0, vec![]); assert_eq!(DisplayName::Empty, actual); diff --git a/crates/matrix-sdk-base/src/rooms/normal.rs b/crates/matrix-sdk-base/src/rooms/normal.rs index 926b0ec0c..af4a60ab8 100644 --- a/crates/matrix-sdk-base/src/rooms/normal.rs +++ b/crates/matrix-sdk-base/src/rooms/normal.rs @@ -829,7 +829,7 @@ mod test { store.save_changes(&changes).await.unwrap(); room.inner.write().unwrap().update_summary(&summary); - assert_eq!(room.display_name().await.unwrap(), DisplayName::Computed("Matthew".to_string())); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Calculated("Matthew".to_string())); } #[tokio::test] @@ -850,7 +850,7 @@ mod test { ); store.save_changes(&changes).await.unwrap(); - assert_eq!(room.display_name().await.unwrap(), DisplayName::Computed("Matthew".to_string())); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Calculated("Matthew".to_string())); } #[tokio::test] @@ -876,7 +876,7 @@ mod test { store.save_changes(&changes).await.unwrap(); room.inner.write().unwrap().update_summary(&summary); - assert_eq!(room.display_name().await.unwrap(), DisplayName::Computed("Matthew".to_string())); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Calculated("Matthew".to_string())); } #[tokio::test] @@ -897,7 +897,7 @@ mod test { ); store.save_changes(&changes).await.unwrap(); - assert_eq!(room.display_name().await.unwrap(), DisplayName::Computed("Matthew".to_string())); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Calculated("Matthew".to_string())); } #[tokio::test] async fn test_display_name_dm_alone() { From 8cdfd438635e4f825e1bde69f09097dc82d06e27 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Tue, 26 Apr 2022 15:38:58 +0200 Subject: [PATCH 07/28] test(store): additional intergration test for stripped members --- .../src/store/integration_tests.rs | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/crates/matrix-sdk-base/src/store/integration_tests.rs b/crates/matrix-sdk-base/src/store/integration_tests.rs index 44d5f7d8e..01edf8c9b 100644 --- a/crates/matrix-sdk-base/src/store/integration_tests.rs +++ b/crates/matrix-sdk-base/src/store/integration_tests.rs @@ -258,6 +258,20 @@ macro_rules! statestore_integration_tests { serde_json::from_value(event).unwrap() } + fn stripped_membership_event() -> StrippedRoomMemberEvent { + custom_stripped_membership_event(user_id()) + } + + fn custom_stripped_membership_event( + user_id: &UserId, + ) -> StrippedRoomMemberEvent { + StrippedRoomMemberEvent { + content: RoomMemberEventContent::new(MembershipState::Join), + sender: user_id.to_owned(), + state_key: user_id.to_owned(), + } + } + fn membership_event() -> OriginalSyncRoomMemberEvent { custom_membership_event(user_id(), event_id!("$h29iv0s8:example.com").to_owned()) } @@ -274,7 +288,6 @@ macro_rules! statestore_integration_tests { state_key: user_id.to_owned(), unsigned: StateUnsigned::default(), } - } #[async_test] @@ -337,6 +350,27 @@ macro_rules! statestore_integration_tests { assert!(!members.is_empty(), "We expected to find members for the room") } + #[async_test] + async fn test_stripped_member_saving() { + let store = get_store().await.unwrap(); + let room_id = room_id!("!test_member_saving:localhost"); + let user_id = user_id(); + + assert!(store.get_member_event(room_id, user_id).await.unwrap().is_none()); + let mut changes = StateChanges::default(); + changes + .stripped_members + .entry(room_id.to_owned()) + .or_default() + .insert(user_id.to_owned(), stripped_membership_event()); + + store.save_changes(&changes).await.unwrap(); + assert!(store.get_member_event(room_id, user_id).await.unwrap().is_some()); + + let members = store.get_user_ids(room_id).await.unwrap(); + assert!(!members.is_empty(), "We expected to find members for the room") + } + #[async_test] async fn test_power_level_saving() { let store = get_store().await.unwrap(); From ca2f598d9eff65f0845630abf5f081561dca20f3 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Tue, 26 Apr 2022 16:23:22 +0200 Subject: [PATCH 08/28] fix(sled-store): implement merge room members --- crates/matrix-sdk-sled/src/state_store.rs | 41 ++++++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/crates/matrix-sdk-sled/src/state_store.rs b/crates/matrix-sdk-sled/src/state_store.rs index 58eeae824..ed89f9d9e 100644 --- a/crates/matrix-sdk-sled/src/state_store.rs +++ b/crates/matrix-sdk-sled/src/state_store.rs @@ -24,7 +24,7 @@ use async_stream::stream; use futures_core::stream::Stream; use futures_util::stream::{self, StreamExt, TryStreamExt}; use matrix_sdk_base::{ - deserialized_responses::SyncRoomEvent, + deserialized_responses::{MemberEvent, SyncRoomEvent}, media::{MediaRequest, UniqueKey}, store::{BoxStream, Result as StoreResult, StateChanges, StateStore, StoreError}, RoomInfo, @@ -36,7 +36,7 @@ use matrix_sdk_common::{ presence::PresenceEvent, receipt::Receipt, room::{ - member::{MembershipState, OriginalSyncRoomMemberEvent, RoomMemberEventContent}, + member::{MembershipState, RoomMemberEventContent}, redaction::SyncRoomRedactionEvent, }, AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, AnySyncMessageLikeEvent, @@ -509,6 +509,28 @@ impl SledStore { for (room, events) in &changes.stripped_members { for event in events.values() { + let key = (room, &event.state_key); + + match event.content.membership { + MembershipState::Join => { + joined.insert( + self.encode_key(JOINED_USER_ID, &key), + event.state_key.as_str(), + )?; + invited.remove(self.encode_key(INVITED_USER_ID, &key))?; + } + MembershipState::Invite => { + invited.insert( + self.encode_key(INVITED_USER_ID, &key), + event.state_key.as_str(), + )?; + joined.remove(self.encode_key(JOINED_USER_ID, &key))?; + } + _ => { + joined.remove(self.encode_key(JOINED_USER_ID, &key))?; + invited.remove(self.encode_key(INVITED_USER_ID, &key))?; + } + } stripped_members.insert( self.encode_key( STRIPPED_ROOM_MEMBER, @@ -648,10 +670,19 @@ impl SledStore { &self, room_id: &RoomId, state_key: &UserId, - ) -> Result> { + ) -> Result> { let db = self.clone(); let key = self.encode_key(MEMBER, (room_id, state_key)); - spawn_blocking(move || db.members.get(key)?.map(|v| db.deserialize_event(&v)).transpose()) + let stripped_key = self.encode_key(STRIPPED_ROOM_MEMBER, (room_id, state_key)); + spawn_blocking(move || { + if let Some(e) = db.members.get(key)?.map(|v| db.deserialize_event(&v)).transpose()? { + Ok(Some(MemberEvent::Full(e))) + } else if let Some(e) = db.stripped_members.get(stripped_key)?.map(|v| db.deserialize_event(&v)).transpose()? { + Ok(Some(MemberEvent::Stripped(e))) + } else { + Ok(None) + } + }) .await? } @@ -1278,7 +1309,7 @@ impl StateStore for SledStore { &self, room_id: &RoomId, state_key: &UserId, - ) -> StoreResult> { + ) -> StoreResult> { self.get_member_event(room_id, state_key).await.map_err(Into::into) } From 55b7fd617c1c983a3423f9a4186bf45918a942f1 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Tue, 26 Apr 2022 17:04:46 +0200 Subject: [PATCH 09/28] fix(indexeddb-store): implement merge room members --- crates/matrix-sdk-indexeddb/Cargo.toml | 1 + .../matrix-sdk-indexeddb/src/state_store.rs | 73 +++++++++++++++---- 2 files changed, 60 insertions(+), 14 deletions(-) diff --git a/crates/matrix-sdk-indexeddb/Cargo.toml b/crates/matrix-sdk-indexeddb/Cargo.toml index c2bcd9ced..264d29fd2 100644 --- a/crates/matrix-sdk-indexeddb/Cargo.toml +++ b/crates/matrix-sdk-indexeddb/Cargo.toml @@ -33,6 +33,7 @@ matrix-sdk-crypto = { path = "../matrix-sdk-crypto", optional = true } getrandom = { version = "0.2", features = ["js"] } [dev-dependencies] +matrix-sdk-common = { path = "../matrix-sdk-common" } matrix-sdk-base = { path = "../matrix-sdk-base", features = ["testing"] } matrix-sdk-crypto = { path = "../matrix-sdk-crypto", features = ["testing"] } matrix-sdk-test = { path = "../matrix-sdk-test" } diff --git a/crates/matrix-sdk-indexeddb/src/state_store.rs b/crates/matrix-sdk-indexeddb/src/state_store.rs index a79806fbb..e12459f91 100644 --- a/crates/matrix-sdk-indexeddb/src/state_store.rs +++ b/crates/matrix-sdk-indexeddb/src/state_store.rs @@ -19,14 +19,14 @@ use futures_util::stream; use indexed_db_futures::prelude::*; use matrix_sdk_base::{ async_trait, - deserialized_responses::SyncRoomEvent, + deserialized_responses::{SyncRoomEvent, MemberEvent}, media::{MediaRequest, UniqueKey}, ruma::{ events::{ presence::PresenceEvent, receipt::Receipt, room::{ - member::{MembershipState, OriginalSyncRoomMemberEvent, RoomMemberEventContent}, + member::{MembershipState, RoomMemberEventContent}, redaction::SyncRoomRedactionEvent, }, AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, AnySyncMessageLikeEvent, @@ -357,7 +357,6 @@ impl IndexeddbStore { (!changes.room_infos.is_empty() || !changes.timeline.is_empty(), KEYS::ROOM_INFOS), (!changes.receipts.is_empty(), KEYS::ROOM_EVENT_RECEIPTS), (!changes.stripped_state.is_empty(), KEYS::STRIPPED_ROOM_STATE), - (!changes.stripped_members.is_empty(), KEYS::STRIPPED_MEMBERS), (!changes.stripped_room_infos.is_empty(), KEYS::STRIPPED_ROOM_INFOS), ] .iter() @@ -373,6 +372,14 @@ impl IndexeddbStore { ]) } + if !changes.stripped_members.is_empty() { + stores.extend([ + KEYS::STRIPPED_MEMBERS, + KEYS::INVITED_USER_IDS, + KEYS::JOINED_USER_IDS, + ]) + } + if !changes.receipts.is_empty() { stores.extend([KEYS::ROOM_EVENT_RECEIPTS, KEYS::ROOM_USER_RECEIPTS]) } @@ -473,10 +480,34 @@ impl IndexeddbStore { if !changes.stripped_members.is_empty() { let store = tx.object_store(KEYS::STRIPPED_MEMBERS)?; + let joined = tx.object_store(KEYS::JOINED_USER_IDS)?; + let invited = tx.object_store(KEYS::INVITED_USER_IDS)?; for (room, events) in &changes.stripped_members { + for event in events.values() { - let key = self.encode_key(KEYS::STRIPPED_MEMBERS, (room, &event.state_key)); - store.put_key_val(&key, &self.serialize_event(&event)?)?; + let key = (room, &event.state_key); + + match event.content.membership { + MembershipState::Join => { + joined.put_key_val_owned( + &self.encode_key(KEYS::JOINED_USER_IDS, key), + &self.serialize_event(&event.state_key)?, + )?; + invited.delete(&self.encode_key(KEYS::INVITED_USER_IDS, key))?; + } + MembershipState::Invite => { + invited.put_key_val_owned( + &self.encode_key(KEYS::INVITED_USER_IDS, key), + &self.serialize_event(&event.state_key)?, + )?; + joined.delete(&self.encode_key(KEYS::JOINED_USER_IDS, key))?; + } + _ => { + joined.delete(&self.encode_key(KEYS::JOINED_USER_IDS, key))?; + invited.delete(&self.encode_key(KEYS::INVITED_USER_IDS, key))?; + } + } + store.put_key_val(&self.encode_key(KEYS::STRIPPED_MEMBERS, key), &self.serialize_event(&event)?)?; } } } @@ -495,14 +526,14 @@ impl IndexeddbStore { } if !changes.members.is_empty() { + let profiles_store = tx.object_store(KEYS::PROFILES)?; + let joined = tx.object_store(KEYS::JOINED_USER_IDS)?; + let invited = tx.object_store(KEYS::INVITED_USER_IDS)?; + let members = tx.object_store(KEYS::MEMBERS)?; + for (room, events) in &changes.members { let profile_changes = changes.profiles.get(room); - let profiles_store = tx.object_store(KEYS::PROFILES)?; - let joined = tx.object_store(KEYS::JOINED_USER_IDS)?; - let invited = tx.object_store(KEYS::INVITED_USER_IDS)?; - let members = tx.object_store(KEYS::MEMBERS)?; - for event in events.values() { let key = (room, &event.state_key); @@ -845,14 +876,28 @@ impl IndexeddbStore { &self, room_id: &RoomId, state_key: &UserId, - ) -> Result> { - self.inner + ) -> Result> { + if let Some(e) = self.inner .transaction_on_one_with_mode(KEYS::MEMBERS, IdbTransactionMode::Readonly)? .object_store(KEYS::MEMBERS)? .get(&self.encode_key(KEYS::MEMBERS, (room_id, state_key)))? .await? .map(|f| self.deserialize_event(f)) - .transpose() + .transpose()? + { + Ok(Some(MemberEvent::Full(e))) + } else if let Some(e) = self.inner + .transaction_on_one_with_mode(KEYS::STRIPPED_MEMBERS, IdbTransactionMode::Readonly)? + .object_store(KEYS::STRIPPED_MEMBERS)? + .get(&self.encode_key(KEYS::STRIPPED_MEMBERS, (room_id, state_key)))? + .await? + .map(|f| self.deserialize_event(f)) + .transpose()? + { + Ok(Some(MemberEvent::Stripped(e))) + } else { + Ok(None) + } } pub async fn get_user_ids_stream(&self, room_id: &RoomId) -> Result> { @@ -1217,7 +1262,7 @@ impl StateStore for IndexeddbStore { &self, room_id: &RoomId, state_key: &UserId, - ) -> StoreResult> { + ) -> StoreResult> { self.get_member_event(room_id, state_key).await.map_err(|e| e.into()) } From 592a9338eb0bb539e365931f8c0435cde0252330 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Tue, 26 Apr 2022 17:27:18 +0200 Subject: [PATCH 10/28] style, and other fixes --- crates/matrix-sdk-base/src/client.rs | 17 +- crates/matrix-sdk-base/src/lib.rs | 2 +- crates/matrix-sdk-base/src/rooms/mod.rs | 31 ++-- crates/matrix-sdk-base/src/rooms/normal.rs | 164 +++++++++--------- .../src/store/ambiguity_map.rs | 2 +- .../matrix-sdk-base/src/store/memory_store.rs | 11 +- crates/matrix-sdk-base/src/store/mod.rs | 6 +- .../src/deserialized_responses.rs | 13 +- .../matrix-sdk-indexeddb/src/state_store.rs | 20 +-- crates/matrix-sdk-sled/src/state_store.rs | 11 +- crates/matrix-sdk/src/client/mod.rs | 14 +- 11 files changed, 156 insertions(+), 135 deletions(-) diff --git a/crates/matrix-sdk-base/src/client.rs b/crates/matrix-sdk-base/src/client.rs index 42aa11fa5..8a0cb384e 100644 --- a/crates/matrix-sdk-base/src/client.rs +++ b/crates/matrix-sdk-base/src/client.rs @@ -1271,16 +1271,15 @@ impl Default for BaseClient { #[cfg(test)] mod tests { - use matrix_sdk_test::{async_test, EventBuilder, response_from_file}; + use matrix_sdk_test::{async_test, response_from_file, EventBuilder}; use ruma::{ - api::IncomingResponse, - api::client as api, - room_id, user_id + api::{client as api, IncomingResponse}, + room_id, user_id, }; use serde_json::json; use super::BaseClient; - use crate::{RoomType, Session, DisplayName}; + use crate::{DisplayName, RoomType, Session}; #[async_test] async fn invite_after_leaving() { @@ -1339,8 +1338,7 @@ mod tests { } #[async_test] - async fn invite_displayname_intergration_test() { - + async fn invite_displayname_integration_test() { let user_id = user_id!("@alice:example.org"); let room_id = room_id!("!ithpyNKDtmhneaTQja:example.org"); @@ -1429,6 +1427,9 @@ mod tests { let room = client.get_room(room_id).expect("Room not found"); assert_eq!(room.room_type(), RoomType::Invited); - assert_eq!(room.display_name().await.expect("fetching display name failed"), DisplayName::Calculated("Kyra".to_string())); + assert_eq!( + room.display_name().await.expect("fetching display name failed"), + DisplayName::Calculated("Kyra".to_owned()) + ); } } diff --git a/crates/matrix-sdk-base/src/lib.rs b/crates/matrix-sdk-base/src/lib.rs index e62860a8d..bb62d63f7 100644 --- a/crates/matrix-sdk-base/src/lib.rs +++ b/crates/matrix-sdk-base/src/lib.rs @@ -38,5 +38,5 @@ pub use client::BaseClient; pub use http; #[cfg(feature = "encryption")] pub use matrix_sdk_crypto as crypto; -pub use rooms::{Room, RoomInfo, RoomMember, RoomType, DisplayName}; +pub use rooms::{DisplayName, Room, RoomInfo, RoomMember, RoomType}; pub use store::{StateChanges, StateStore, Store, StoreError}; diff --git a/crates/matrix-sdk-base/src/rooms/mod.rs b/crates/matrix-sdk-base/src/rooms/mod.rs index d052c3999..86be1eaf0 100644 --- a/crates/matrix-sdk-base/src/rooms/mod.rs +++ b/crates/matrix-sdk-base/src/rooms/mod.rs @@ -1,7 +1,7 @@ mod members; mod normal; -use std::cmp::max; +use std::{cmp::max, fmt}; pub use members::RoomMember; pub use normal::{Room, RoomInfo, RoomType}; @@ -37,15 +37,14 @@ pub enum DisplayName { Empty, } -impl DisplayName { - /// Generate the caninocal String of the DisplayName in english - pub fn to_string(&self) -> String { +impl fmt::Display for DisplayName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - DisplayName::Named(s) - | DisplayName::Calculated(s) - | DisplayName::Aliased(s) => s.clone(), - DisplayName::EmptyWas(s) => format!("Empty Room (was {})", s), - DisplayName::Empty => "Empty Room".to_string(), + DisplayName::Named(s) | DisplayName::Calculated(s) | DisplayName::Aliased(s) => { + write!(f, "{}", s) + } + DisplayName::EmptyWas(s) => write!(f, "Empty Room (was {})", s), + DisplayName::Empty => write!(f, "Empty Room"), } } } @@ -273,16 +272,16 @@ mod tests { fn test_calculate_room_name() { let mut actual = calculate_room_name(2, 0, vec!["a"]); - assert_eq!(DisplayName::Calculated("a".to_string()), actual); + assert_eq!(DisplayName::Calculated("a".to_owned()), actual); actual = calculate_room_name(3, 0, vec!["a", "b"]); - assert_eq!(DisplayName::Calculated("a, b".to_string()), actual); + assert_eq!(DisplayName::Calculated("a, b".to_owned()), actual); actual = calculate_room_name(4, 0, vec!["a", "b", "c"]); - assert_eq!(DisplayName::Calculated("a, b, c".to_string()), actual); + assert_eq!(DisplayName::Calculated("a, b, c".to_owned()), actual); actual = calculate_room_name(5, 0, vec!["a", "b", "c"]); - assert_eq!(DisplayName::Calculated("a, b, c, and 2 others".to_string()), actual); + assert_eq!(DisplayName::Calculated("a, b, c, and 2 others".to_owned()), actual); actual = calculate_room_name(0, 0, vec![]); assert_eq!(DisplayName::Empty, actual); @@ -294,12 +293,12 @@ mod tests { assert_eq!(DisplayName::Empty, actual); actual = calculate_room_name(1, 0, vec!["a"]); - assert_eq!(DisplayName::EmptyWas("a".to_string()), actual); + assert_eq!(DisplayName::EmptyWas("a".to_owned()), actual); actual = calculate_room_name(1, 0, vec!["a", "b"]); - assert_eq!(DisplayName::EmptyWas("a, b".to_string()), actual); + assert_eq!(DisplayName::EmptyWas("a, b".to_owned()), actual); actual = calculate_room_name(1, 0, vec!["a", "b", "c"]); - assert_eq!(DisplayName::EmptyWas("a, b, c".to_string()), actual); + assert_eq!(DisplayName::EmptyWas("a, b, c".to_owned()), actual); } } diff --git a/crates/matrix-sdk-base/src/rooms/normal.rs b/crates/matrix-sdk-base/src/rooms/normal.rs index af4a60ab8..61641e4a8 100644 --- a/crates/matrix-sdk-base/src/rooms/normal.rs +++ b/crates/matrix-sdk-base/src/rooms/normal.rs @@ -40,7 +40,7 @@ use ruma::{ use serde::{Deserialize, Serialize}; use tracing::{debug, warn}; -use super::{BaseRoomInfo, RoomMember, DisplayName}; +use super::{BaseRoomInfo, DisplayName, RoomMember}; use crate::{ deserialized_responses::{SyncRoomEvent, TimelineSlice, UnreadNotificationsCount}, store::{Result as StoreResult, StateStore}, @@ -359,7 +359,7 @@ impl Room { }; let (joined, invited) = match self.room_type() { - RoomType::Invited => { + RoomType::Invited => { // when we were invited we don't have a proper summary, we have to do best // guessing (members.len() as u64, 1u64) @@ -437,14 +437,18 @@ impl Room { .store .get_users_with_display_name( self.room_id(), - member_event.content().displayname.as_deref().unwrap_or_else(|| user_id.localpart()), + member_event + .content() + .displayname + .as_deref() + .unwrap_or_else(|| user_id.localpart()), ) .await? .len() > 1; Ok(Some(RoomMember { - event: Arc::new(member_event.into()), + event: Arc::new(member_event), profile: profile.into(), presence: presence.into(), power_levels: power.into(), @@ -727,40 +731,36 @@ impl RoomInfo { #[cfg(test)] mod test { - use crate::store::{MemoryStore, StateChanges}; use std::sync::Arc; + + use assign::assign; use ruma::{ - user_id, room_id, event_id, RoomAliasId, - MilliSecondsSinceUnixEpoch, + event_id, events::{ room::member::{ + MembershipState, OriginalSyncRoomMemberEvent, RoomMemberEventContent, StrippedRoomMemberEvent, - OriginalSyncRoomMemberEvent, - RoomMemberEventContent, MembershipState }, StateUnsigned, }, + room_id, user_id, MilliSecondsSinceUnixEpoch, RoomAliasId, }; + use super::*; - use assign::assign; + use crate::store::{MemoryStore, StateChanges}; fn make_room(room_type: RoomType) -> (Arc, Room) { let store = Arc::new(MemoryStore::new()); let user_id = user_id!("@me:example.org"); let room_id = room_id!("!test:localhost"); - (store.clone(), Room::new( - &user_id, - store, - room_id, - room_type - )) + (store.clone(), Room::new(user_id, store, room_id, room_type)) } fn make_stripped_member_event(user_id: &UserId, name: &str) -> StrippedRoomMemberEvent { StrippedRoomMemberEvent { content: assign!(RoomMemberEventContent::new(MembershipState::Join), { - displayname: Some(name.to_string()) + displayname: Some(name.to_owned()) }), sender: user_id.to_owned(), state_key: user_id.to_owned(), @@ -770,14 +770,13 @@ mod test { fn make_member_event(user_id: &UserId, name: &str) -> OriginalSyncRoomMemberEvent { OriginalSyncRoomMemberEvent { content: assign!(RoomMemberEventContent::new(MembershipState::Join), { - displayname: Some(name.to_string()) + displayname: Some(name.to_owned()) }), sender: user_id.to_owned(), state_key: user_id.to_owned(), event_id: event_id!("$h29iv0s1:example.com").to_owned(), origin_server_ts: MilliSecondsSinceUnixEpoch(208u32.into()), unsigned: StateUnsigned::default(), - } } @@ -787,24 +786,25 @@ mod test { assert_eq!(room.display_name().await.unwrap(), DisplayName::Empty); // has precedence - room.inner.write().unwrap().base_info.canonical_alias = Some(RoomAliasId::parse("#test:example.com").unwrap()); - assert_eq!(room.display_name().await.unwrap(), DisplayName::Aliased("test".to_string())); + room.inner.write().unwrap().base_info.canonical_alias = + Some(RoomAliasId::parse("#test:example.com").unwrap()); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Aliased("test".to_owned())); // has precedence - room.inner.write().unwrap().base_info.name = Some("Test Room".to_string()); - assert_eq!(room.display_name().await.unwrap(), DisplayName::Named("Test Room".to_string())); + room.inner.write().unwrap().base_info.name = Some("Test Room".to_owned()); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Named("Test Room".to_owned())); let (_, room) = make_room(RoomType::Invited); assert_eq!(room.display_name().await.unwrap(), DisplayName::Empty); // has precedence - room.inner.write().unwrap().base_info.canonical_alias = Some(RoomAliasId::parse("#test:example.com").unwrap()); - assert_eq!(room.display_name().await.unwrap(), DisplayName::Aliased("test".to_string())); + room.inner.write().unwrap().base_info.canonical_alias = + Some(RoomAliasId::parse("#test:example.com").unwrap()); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Aliased("test".to_owned())); // has precedence - room.inner.write().unwrap().base_info.name = Some("Test Room".to_string()); - assert_eq!(room.display_name().await.unwrap(), DisplayName::Named("Test Room".to_string())); - + room.inner.write().unwrap().base_info.name = Some("Test Room".to_owned()); + assert_eq!(room.display_name().await.unwrap(), DisplayName::Named("Test Room".to_owned())); } #[tokio::test] @@ -813,23 +813,20 @@ mod test { let room_id = room_id!("!test:localhost"); let matthew = user_id!("@matthew:example.org"); let me = user_id!("@me:example.org"); - let mut changes = StateChanges::new("".to_string()); + let mut changes = StateChanges::new("".to_owned()); let summary = assign!(RumaSummary::new(), { heroes: vec![me.to_string(), matthew.to_string()], }); - changes.add_stripped_member( - &room_id, - make_stripped_member_event(matthew, "Matthew") - ); - changes.add_stripped_member( - &room_id, - make_stripped_member_event(me, "Me") - ); + changes.add_stripped_member(room_id, make_stripped_member_event(matthew, "Matthew")); + changes.add_stripped_member(room_id, make_stripped_member_event(me, "Me")); store.save_changes(&changes).await.unwrap(); room.inner.write().unwrap().update_summary(&summary); - assert_eq!(room.display_name().await.unwrap(), DisplayName::Calculated("Matthew".to_string())); + assert_eq!( + room.display_name().await.unwrap(), + DisplayName::Calculated("Matthew".to_owned()) + ); } #[tokio::test] @@ -838,19 +835,16 @@ mod test { let room_id = room_id!("!test:localhost"); let matthew = user_id!("@matthew:example.org"); let me = user_id!("@me:example.org"); - let mut changes = StateChanges::new("".to_string()); + let mut changes = StateChanges::new("".to_owned()); - changes.add_stripped_member( - &room_id, - make_stripped_member_event(matthew, "Matthew") - ); - changes.add_stripped_member( - &room_id, - make_stripped_member_event(me, "Me") - ); + changes.add_stripped_member(room_id, make_stripped_member_event(matthew, "Matthew")); + changes.add_stripped_member(room_id, make_stripped_member_event(me, "Me")); store.save_changes(&changes).await.unwrap(); - assert_eq!(room.display_name().await.unwrap(), DisplayName::Calculated("Matthew".to_string())); + assert_eq!( + room.display_name().await.unwrap(), + DisplayName::Calculated("Matthew".to_owned()) + ); } #[tokio::test] @@ -859,24 +853,29 @@ mod test { let room_id = room_id!("!test:localhost"); let matthew = user_id!("@matthew:example.org"); let me = user_id!("@me:example.org"); - let mut changes = StateChanges::new("".to_string()); + let mut changes = StateChanges::new("".to_owned()); let summary = assign!(RumaSummary::new(), { joined_member_count: Some(2u32.into()), heroes: vec![me.to_string(), matthew.to_string()], }); - changes.members.entry(room_id.to_owned()).or_default().insert( - matthew.to_owned(), - make_member_event(matthew, "Matthew") - ); - changes.members.entry(room_id.to_owned()).or_default().insert( - me.to_owned(), - make_member_event(me, "Me") - ); + changes + .members + .entry(room_id.to_owned()) + .or_default() + .insert(matthew.to_owned(), make_member_event(matthew, "Matthew")); + changes + .members + .entry(room_id.to_owned()) + .or_default() + .insert(me.to_owned(), make_member_event(me, "Me")); store.save_changes(&changes).await.unwrap(); room.inner.write().unwrap().update_summary(&summary); - assert_eq!(room.display_name().await.unwrap(), DisplayName::Calculated("Matthew".to_string())); + assert_eq!( + room.display_name().await.unwrap(), + DisplayName::Calculated("Matthew".to_owned()) + ); } #[tokio::test] @@ -885,19 +884,24 @@ mod test { let room_id = room_id!("!test:localhost"); let matthew = user_id!("@matthew:example.org"); let me = user_id!("@me:example.org"); - let mut changes = StateChanges::new("".to_string()); + let mut changes = StateChanges::new("".to_owned()); - changes.members.entry(room_id.to_owned()).or_default().insert( - matthew.to_owned(), - make_member_event(matthew, "Matthew") - ); - changes.members.entry(room_id.to_owned()).or_default().insert( - me.to_owned(), - make_member_event(me, "Me") - ); + changes + .members + .entry(room_id.to_owned()) + .or_default() + .insert(matthew.to_owned(), make_member_event(matthew, "Matthew")); + changes + .members + .entry(room_id.to_owned()) + .or_default() + .insert(me.to_owned(), make_member_event(me, "Me")); store.save_changes(&changes).await.unwrap(); - assert_eq!(room.display_name().await.unwrap(), DisplayName::Calculated("Matthew".to_string())); + assert_eq!( + room.display_name().await.unwrap(), + DisplayName::Calculated("Matthew".to_owned()) + ); } #[tokio::test] async fn test_display_name_dm_alone() { @@ -905,23 +909,25 @@ mod test { let room_id = room_id!("!test:localhost"); let matthew = user_id!("@matthew:example.org"); let me = user_id!("@me:example.org"); - let mut changes = StateChanges::new("".to_string()); + let mut changes = StateChanges::new("".to_owned()); let summary = assign!(RumaSummary::new(), { joined_member_count: Some(1u32.into()), heroes: vec![me.to_string(), matthew.to_string()], }); - changes.members.entry(room_id.to_owned()).or_default().insert( - matthew.to_owned(), - make_member_event(matthew, "Matthew") - ); - changes.members.entry(room_id.to_owned()).or_default().insert( - me.to_owned(), - make_member_event(me, "Me") - ); + changes + .members + .entry(room_id.to_owned()) + .or_default() + .insert(matthew.to_owned(), make_member_event(matthew, "Matthew")); + changes + .members + .entry(room_id.to_owned()) + .or_default() + .insert(me.to_owned(), make_member_event(me, "Me")); store.save_changes(&changes).await.unwrap(); room.inner.write().unwrap().update_summary(&summary); - assert_eq!(room.display_name().await.unwrap(), DisplayName::EmptyWas("Matthew".to_string())); + assert_eq!(room.display_name().await.unwrap(), DisplayName::EmptyWas("Matthew".to_owned())); } -} \ No newline at end of file +} diff --git a/crates/matrix-sdk-base/src/store/ambiguity_map.rs b/crates/matrix-sdk-base/src/store/ambiguity_map.rs index 84164695b..311778ff9 100644 --- a/crates/matrix-sdk-base/src/store/ambiguity_map.rs +++ b/crates/matrix-sdk-base/src/store/ambiguity_map.rs @@ -14,7 +14,7 @@ use std::collections::{BTreeMap, BTreeSet}; -use matrix_sdk_common::deserialized_responses::{MemberEvent, AmbiguityChange}; +use matrix_sdk_common::deserialized_responses::{AmbiguityChange, MemberEvent}; use ruma::{ events::room::member::{MembershipState, OriginalSyncRoomMemberEvent}, OwnedEventId, OwnedRoomId, OwnedUserId, RoomId, UserId, diff --git a/crates/matrix-sdk-base/src/store/memory_store.rs b/crates/matrix-sdk-base/src/store/memory_store.rs index 375ed5926..b860d414a 100644 --- a/crates/matrix-sdk-base/src/store/memory_store.rs +++ b/crates/matrix-sdk-base/src/store/memory_store.rs @@ -47,7 +47,7 @@ use tracing::{info, warn}; use super::{BoxStream, Result, RoomInfo, StateChanges, StateStore}; use crate::{ - deserialized_responses::{SyncRoomEvent, MemberEvent}, + deserialized_responses::{MemberEvent, SyncRoomEvent}, media::{MediaRequest, UniqueKey}, StoreError, }; @@ -489,9 +489,12 @@ impl MemoryStore { room_id: &RoomId, state_key: &UserId, ) -> Result> { - if let Some(e) = self.members.get(room_id).and_then(|m| m.get(state_key).map(|m| m.clone())) { + if let Some(e) = self.members.get(room_id).and_then(|m| m.get(state_key).map(|m| m.clone())) + { Ok(Some(e.into())) - } else if let Some(e) = self.stripped_members.get(room_id).and_then(|m| m.get(state_key).map(|m| m.clone())) { + } else if let Some(e) = + self.stripped_members.get(room_id).and_then(|m| m.get(state_key).map(|m| m.clone())) + { Ok(Some(e.into())) } else { Ok(None) @@ -501,7 +504,7 @@ impl MemoryStore { fn get_user_ids(&self, room_id: &RoomId) -> Vec { if let Some(u) = self.members.get(room_id) { u.iter().map(|u| u.key().clone()).collect() - } else { + } else { self.stripped_members .get(room_id) .map(|u| u.iter().map(|u| u.key().clone()).collect()) diff --git a/crates/matrix-sdk-base/src/store/mod.rs b/crates/matrix-sdk-base/src/store/mod.rs index 8d9d19758..56f764511 100644 --- a/crates/matrix-sdk-base/src/store/mod.rs +++ b/crates/matrix-sdk-base/src/store/mod.rs @@ -56,7 +56,7 @@ use ruma::{ pub type BoxStream = Pin + Send>>; use crate::{ - deserialized_responses::{SyncRoomEvent, MemberEvent, TimelineSlice}, + deserialized_responses::{MemberEvent, SyncRoomEvent, TimelineSlice}, media::MediaRequest, rooms::{RoomInfo, RoomType}, Room, Session, @@ -190,8 +190,8 @@ pub trait StateStore: AsyncTraitDeps { state_key: &UserId, ) -> Result>; - /// Get all the user ids of members for a given room, for stripped and regular - /// rooms alike. + /// Get all the user ids of members for a given room, for stripped and + /// regular rooms alike. async fn get_user_ids(&self, room_id: &RoomId) -> Result>; /// Get all the user ids of members that are in the invited state for a diff --git a/crates/matrix-sdk-common/src/deserialized_responses.rs b/crates/matrix-sdk-common/src/deserialized_responses.rs index d7b6cf1aa..3aef33b68 100644 --- a/crates/matrix-sdk-common/src/deserialized_responses.rs +++ b/crates/matrix-sdk-common/src/deserialized_responses.rs @@ -10,13 +10,13 @@ use ruma::{ }, events::{ room::member::{ - OriginalRoomMemberEvent, OriginalSyncRoomMemberEvent, StrippedRoomMemberEvent, - RoomMemberEventContent - }, - AnyRoomEvent, AnySyncRoomEvent}, + OriginalRoomMemberEvent, OriginalSyncRoomMemberEvent, RoomMemberEventContent, + StrippedRoomMemberEvent, + }, + AnyRoomEvent, AnySyncRoomEvent, + }, serde::Raw, - UserId, - DeviceKeyAlgorithm, OwnedDeviceId, OwnedEventId, OwnedRoomId, OwnedUserId, + DeviceKeyAlgorithm, OwnedDeviceId, OwnedEventId, OwnedRoomId, OwnedUserId, UserId, }; use serde::{Deserialize, Serialize}; @@ -296,6 +296,7 @@ impl TimelineSlice { } } +#[allow(clippy::large_enum_variant)] /// Wrapper around both MemberEvent-Types #[derive(Clone, Debug, Deserialize, Serialize)] pub enum MemberEvent { diff --git a/crates/matrix-sdk-indexeddb/src/state_store.rs b/crates/matrix-sdk-indexeddb/src/state_store.rs index e12459f91..9b9e68894 100644 --- a/crates/matrix-sdk-indexeddb/src/state_store.rs +++ b/crates/matrix-sdk-indexeddb/src/state_store.rs @@ -19,7 +19,7 @@ use futures_util::stream; use indexed_db_futures::prelude::*; use matrix_sdk_base::{ async_trait, - deserialized_responses::{SyncRoomEvent, MemberEvent}, + deserialized_responses::{MemberEvent, SyncRoomEvent}, media::{MediaRequest, UniqueKey}, ruma::{ events::{ @@ -373,11 +373,7 @@ impl IndexeddbStore { } if !changes.stripped_members.is_empty() { - stores.extend([ - KEYS::STRIPPED_MEMBERS, - KEYS::INVITED_USER_IDS, - KEYS::JOINED_USER_IDS, - ]) + stores.extend([KEYS::STRIPPED_MEMBERS, KEYS::INVITED_USER_IDS, KEYS::JOINED_USER_IDS]) } if !changes.receipts.is_empty() { @@ -483,7 +479,6 @@ impl IndexeddbStore { let joined = tx.object_store(KEYS::JOINED_USER_IDS)?; let invited = tx.object_store(KEYS::INVITED_USER_IDS)?; for (room, events) in &changes.stripped_members { - for event in events.values() { let key = (room, &event.state_key); @@ -507,7 +502,10 @@ impl IndexeddbStore { invited.delete(&self.encode_key(KEYS::INVITED_USER_IDS, key))?; } } - store.put_key_val(&self.encode_key(KEYS::STRIPPED_MEMBERS, key), &self.serialize_event(&event)?)?; + store.put_key_val( + &self.encode_key(KEYS::STRIPPED_MEMBERS, key), + &self.serialize_event(&event)?, + )?; } } } @@ -877,7 +875,8 @@ impl IndexeddbStore { room_id: &RoomId, state_key: &UserId, ) -> Result> { - if let Some(e) = self.inner + if let Some(e) = self + .inner .transaction_on_one_with_mode(KEYS::MEMBERS, IdbTransactionMode::Readonly)? .object_store(KEYS::MEMBERS)? .get(&self.encode_key(KEYS::MEMBERS, (room_id, state_key)))? @@ -886,7 +885,8 @@ impl IndexeddbStore { .transpose()? { Ok(Some(MemberEvent::Full(e))) - } else if let Some(e) = self.inner + } else if let Some(e) = self + .inner .transaction_on_one_with_mode(KEYS::STRIPPED_MEMBERS, IdbTransactionMode::Readonly)? .object_store(KEYS::STRIPPED_MEMBERS)? .get(&self.encode_key(KEYS::STRIPPED_MEMBERS, (room_id, state_key)))? diff --git a/crates/matrix-sdk-sled/src/state_store.rs b/crates/matrix-sdk-sled/src/state_store.rs index ed89f9d9e..3066bfdbd 100644 --- a/crates/matrix-sdk-sled/src/state_store.rs +++ b/crates/matrix-sdk-sled/src/state_store.rs @@ -677,13 +677,18 @@ impl SledStore { spawn_blocking(move || { if let Some(e) = db.members.get(key)?.map(|v| db.deserialize_event(&v)).transpose()? { Ok(Some(MemberEvent::Full(e))) - } else if let Some(e) = db.stripped_members.get(stripped_key)?.map(|v| db.deserialize_event(&v)).transpose()? { + } else if let Some(e) = db + .stripped_members + .get(stripped_key)? + .map(|v| db.deserialize_event(&v)) + .transpose()? + { Ok(Some(MemberEvent::Stripped(e))) - } else { + } else { Ok(None) } }) - .await? + .await? } pub async fn get_user_ids_stream( diff --git a/crates/matrix-sdk/src/client/mod.rs b/crates/matrix-sdk/src/client/mod.rs index c9a9cbee4..c3fd7457e 100644 --- a/crates/matrix-sdk/src/client/mod.rs +++ b/crates/matrix-sdk/src/client/mod.rs @@ -2249,7 +2249,10 @@ pub(crate) mod tests { use std::{collections::BTreeMap, convert::TryInto, io::Cursor, str::FromStr, time::Duration}; - use matrix_sdk_base::media::{MediaFormat, MediaRequest, MediaThumbnailSize}; + use matrix_sdk_base::{ + media::{MediaFormat, MediaRequest, MediaThumbnailSize}, + DisplayName, + }; use matrix_sdk_common::deserialized_responses::SyncRoomEvent; use matrix_sdk_test::{test_json, EventBuilder, EventsJson}; use mockito::{mock, Matcher}; @@ -3365,7 +3368,7 @@ pub(crate) mod tests { let _response = client.sync_once(sync_settings).await.unwrap(); let room = client.get_joined_room(room_id!("!SVkFJHzfwvuaIEawgC:localhost")).unwrap(); - assert_eq!("example2", room.display_name().await.unwrap()); + assert_eq!(DisplayName::Aliased("example2".to_owned()), room.display_name().await.unwrap()); } #[async_test] @@ -3443,7 +3446,7 @@ pub(crate) mod tests { assert_eq!(client.rooms().len(), 1); let room = client.get_joined_room(room_id!("!SVkFJHzfwvuaIEawgC:localhost")).unwrap(); - assert_eq!("tutorial".to_owned(), room.display_name().await.unwrap()); + assert_eq!(DisplayName::Named("tutorial".to_owned()), room.display_name().await.unwrap()); let _m = mock("GET", Matcher::Regex(r"^/_matrix/client/r0/sync\?.*$".to_owned())) .with_status(200) @@ -3457,7 +3460,10 @@ pub(crate) mod tests { assert_eq!(client.rooms().len(), 1); let invited_room = client.get_invited_room(room_id!("!696r7674:example.com")).unwrap(); - assert_eq!("My Room Name".to_owned(), invited_room.display_name().await.unwrap()); + assert_eq!( + DisplayName::Named("My Room Name".to_owned()), + invited_room.display_name().await.unwrap() + ); } #[async_test] From 3cdee30fc1196beee88cf646a0234a686aacd798 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Tue, 26 Apr 2022 17:33:17 +0200 Subject: [PATCH 11/28] fixing docs --- crates/matrix-sdk-base/src/rooms/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/matrix-sdk-base/src/rooms/mod.rs b/crates/matrix-sdk-base/src/rooms/mod.rs index 86be1eaf0..c297e028e 100644 --- a/crates/matrix-sdk-base/src/rooms/mod.rs +++ b/crates/matrix-sdk-base/src/rooms/mod.rs @@ -19,8 +19,7 @@ use ruma::{ use serde::{Deserialize, Serialize}; /// The name of the room, either from the metadata or calculaetd -/// according to [matrix specification][spec] -/// [spec]: +/// according to [matrix specification](https://matrix.org/docs/spec/client_server/latest#calculating-the-display-name-for-a-room) #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] pub enum DisplayName { /// The room has been named explicitly as From 4431a2d48a51313fe72e32df535db0cc88aa7e5c Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Tue, 26 Apr 2022 17:40:04 +0200 Subject: [PATCH 12/28] fix(room name): check for proper type --- crates/matrix-sdk/src/client/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/matrix-sdk/src/client/mod.rs b/crates/matrix-sdk/src/client/mod.rs index c3fd7457e..f9ffcea63 100644 --- a/crates/matrix-sdk/src/client/mod.rs +++ b/crates/matrix-sdk/src/client/mod.rs @@ -3368,7 +3368,7 @@ pub(crate) mod tests { let _response = client.sync_once(sync_settings).await.unwrap(); let room = client.get_joined_room(room_id!("!SVkFJHzfwvuaIEawgC:localhost")).unwrap(); - assert_eq!(DisplayName::Aliased("example2".to_owned()), room.display_name().await.unwrap()); + assert_eq!(DisplayName::Calculated("example2".to_owned()), room.display_name().await.unwrap()); } #[async_test] @@ -3446,7 +3446,7 @@ pub(crate) mod tests { assert_eq!(client.rooms().len(), 1); let room = client.get_joined_room(room_id!("!SVkFJHzfwvuaIEawgC:localhost")).unwrap(); - assert_eq!(DisplayName::Named("tutorial".to_owned()), room.display_name().await.unwrap()); + assert_eq!(DisplayName::Aliased("tutorial".to_owned()), room.display_name().await.unwrap()); let _m = mock("GET", Matcher::Regex(r"^/_matrix/client/r0/sync\?.*$".to_owned())) .with_status(200) From b5ab076546e0d2a92bd15f232cf121705e8f9fdd Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 27 Apr 2022 12:02:56 +0200 Subject: [PATCH 13/28] tests(matrix-sdk-base): allowing enable debugging logs for tests --- crates/matrix-sdk-base/Cargo.toml | 2 ++ crates/matrix-sdk-base/src/rooms/normal.rs | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/crates/matrix-sdk-base/Cargo.toml b/crates/matrix-sdk-base/Cargo.toml index 7090d8fce..324cd000a 100644 --- a/crates/matrix-sdk-base/Cargo.toml +++ b/crates/matrix-sdk-base/Cargo.toml @@ -48,8 +48,10 @@ http = { version = "0.2.4", optional = true } [dev-dependencies] futures = { version = "0.3.15", default-features = false, features = ["executor"] } +tracing = { version = "0.1.26", features = ["log"] } http = "0.2.4" assign = "1.1.1" +env_logger = "0.9.0" matrix-sdk-test = { version = "0.4.0", path = "../matrix-sdk-test" } tokio = { version = "1.7.1", default-features = false, features = [ "rt-multi-thread", diff --git a/crates/matrix-sdk-base/src/rooms/normal.rs b/crates/matrix-sdk-base/src/rooms/normal.rs index 61641e4a8..52c988516 100644 --- a/crates/matrix-sdk-base/src/rooms/normal.rs +++ b/crates/matrix-sdk-base/src/rooms/normal.rs @@ -374,7 +374,8 @@ impl Room { debug!( room_id = self.room_id().as_str(), own_user = self.own_user_id.as_str(), - heroes = ?summary.heroes, + joined, invited, + heroes = ?members, "Calculating name for a room", ); @@ -782,6 +783,7 @@ mod test { #[tokio::test] async fn test_display_name_default() { + let _ = env_logger::try_init(); let (_, room) = make_room(RoomType::Joined); assert_eq!(room.display_name().await.unwrap(), DisplayName::Empty); @@ -809,6 +811,7 @@ mod test { #[tokio::test] async fn test_display_name_dm_invited() { + let _ = env_logger::try_init(); let (store, room) = make_room(RoomType::Invited); let room_id = room_id!("!test:localhost"); let matthew = user_id!("@matthew:example.org"); @@ -831,6 +834,7 @@ mod test { #[tokio::test] async fn test_display_name_dm_invited_no_heroes() { + let _ = env_logger::try_init(); let (store, room) = make_room(RoomType::Invited); let room_id = room_id!("!test:localhost"); let matthew = user_id!("@matthew:example.org"); @@ -849,6 +853,7 @@ mod test { #[tokio::test] async fn test_display_name_dm_joined() { + let _ = env_logger::try_init(); let (store, room) = make_room(RoomType::Joined); let room_id = room_id!("!test:localhost"); let matthew = user_id!("@matthew:example.org"); @@ -880,6 +885,7 @@ mod test { #[tokio::test] async fn test_display_name_dm_joined_no_heroes() { + let _ = env_logger::try_init(); let (store, room) = make_room(RoomType::Joined); let room_id = room_id!("!test:localhost"); let matthew = user_id!("@matthew:example.org"); @@ -905,6 +911,7 @@ mod test { } #[tokio::test] async fn test_display_name_dm_alone() { + let _ = env_logger::try_init(); let (store, room) = make_room(RoomType::Joined); let room_id = room_id!("!test:localhost"); let matthew = user_id!("@matthew:example.org"); From 266d7c6da78242a799a03f42671d0c26cc75e62a Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 27 Apr 2022 12:06:15 +0200 Subject: [PATCH 14/28] fixing last broken display_name tests --- crates/matrix-sdk-base/src/rooms/normal.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/matrix-sdk-base/src/rooms/normal.rs b/crates/matrix-sdk-base/src/rooms/normal.rs index 52c988516..22f5eab26 100644 --- a/crates/matrix-sdk-base/src/rooms/normal.rs +++ b/crates/matrix-sdk-base/src/rooms/normal.rs @@ -366,7 +366,10 @@ impl Room { } RoomType::Joined if summary.joined_member_count == 0 => { // joined but the summary is not completed yet - (members.len() as u64, summary.invited_member_count) + ( + (members.len() as u64) + 1, // we've taken ourselfes out of the count + summary.invited_member_count + ) } _ => (summary.joined_member_count, summary.invited_member_count), }; From 48cb625f19d429111fe628a1722d99738c08a805 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 27 Apr 2022 12:06:42 +0200 Subject: [PATCH 15/28] fixing lints --- crates/matrix-sdk-base/src/rooms/normal.rs | 2 +- crates/matrix-sdk/src/client/mod.rs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/matrix-sdk-base/src/rooms/normal.rs b/crates/matrix-sdk-base/src/rooms/normal.rs index 22f5eab26..1809b5a0d 100644 --- a/crates/matrix-sdk-base/src/rooms/normal.rs +++ b/crates/matrix-sdk-base/src/rooms/normal.rs @@ -368,7 +368,7 @@ impl Room { // joined but the summary is not completed yet ( (members.len() as u64) + 1, // we've taken ourselfes out of the count - summary.invited_member_count + summary.invited_member_count, ) } _ => (summary.joined_member_count, summary.invited_member_count), diff --git a/crates/matrix-sdk/src/client/mod.rs b/crates/matrix-sdk/src/client/mod.rs index f9ffcea63..38915381c 100644 --- a/crates/matrix-sdk/src/client/mod.rs +++ b/crates/matrix-sdk/src/client/mod.rs @@ -3368,7 +3368,10 @@ pub(crate) mod tests { let _response = client.sync_once(sync_settings).await.unwrap(); let room = client.get_joined_room(room_id!("!SVkFJHzfwvuaIEawgC:localhost")).unwrap(); - assert_eq!(DisplayName::Calculated("example2".to_owned()), room.display_name().await.unwrap()); + assert_eq!( + DisplayName::Calculated("example2".to_owned()), + room.display_name().await.unwrap() + ); } #[async_test] From 703a95c48632a1f636a8e42ee24b1af714226a9e Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 27 Apr 2022 12:21:06 +0200 Subject: [PATCH 16/28] grumbles --- crates/matrix-sdk-base/src/rooms/normal.rs | 2 +- crates/matrix-sdk-common/src/deserialized_responses.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/matrix-sdk-base/src/rooms/normal.rs b/crates/matrix-sdk-base/src/rooms/normal.rs index 1809b5a0d..5fa6e77c9 100644 --- a/crates/matrix-sdk-base/src/rooms/normal.rs +++ b/crates/matrix-sdk-base/src/rooms/normal.rs @@ -367,7 +367,7 @@ impl Room { RoomType::Joined if summary.joined_member_count == 0 => { // joined but the summary is not completed yet ( - (members.len() as u64) + 1, // we've taken ourselfes out of the count + (members.len() as u64) + 1, // we've taken ourselves out of the count summary.invited_member_count, ) } diff --git a/crates/matrix-sdk-common/src/deserialized_responses.rs b/crates/matrix-sdk-common/src/deserialized_responses.rs index 3aef33b68..744bc3207 100644 --- a/crates/matrix-sdk-common/src/deserialized_responses.rs +++ b/crates/matrix-sdk-common/src/deserialized_responses.rs @@ -296,8 +296,8 @@ impl TimelineSlice { } } -#[allow(clippy::large_enum_variant)] /// Wrapper around both MemberEvent-Types +#[allow(clippy::large_enum_variant)] #[derive(Clone, Debug, Deserialize, Serialize)] pub enum MemberEvent { Stripped(StrippedRoomMemberEvent), From 628de099388eb0555d44299f8dd0028af0380ad1 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 27 Apr 2022 12:22:19 +0200 Subject: [PATCH 17/28] rename Full -> Original --- crates/matrix-sdk-base/src/store/ambiguity_map.rs | 2 +- crates/matrix-sdk-common/src/deserialized_responses.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/matrix-sdk-base/src/store/ambiguity_map.rs b/crates/matrix-sdk-base/src/store/ambiguity_map.rs index 311778ff9..f1e9a1f53 100644 --- a/crates/matrix-sdk-base/src/store/ambiguity_map.rs +++ b/crates/matrix-sdk-base/src/store/ambiguity_map.rs @@ -161,7 +161,7 @@ impl AmbiguityCache { let old_event = if let Some(m) = changes.members.get(room_id).and_then(|m| m.get(&member_event.state_key)) { - Some(MemberEvent::Full(m.clone())) + Some(MemberEvent::Original(m.clone())) } else { self.store.get_member_event(room_id, &member_event.state_key).await? }; diff --git a/crates/matrix-sdk-common/src/deserialized_responses.rs b/crates/matrix-sdk-common/src/deserialized_responses.rs index 744bc3207..e869d9625 100644 --- a/crates/matrix-sdk-common/src/deserialized_responses.rs +++ b/crates/matrix-sdk-common/src/deserialized_responses.rs @@ -301,7 +301,7 @@ impl TimelineSlice { #[derive(Clone, Debug, Deserialize, Serialize)] pub enum MemberEvent { Stripped(StrippedRoomMemberEvent), - Full(OriginalSyncRoomMemberEvent), + Original(OriginalSyncRoomMemberEvent), } impl MemberEvent { @@ -309,7 +309,7 @@ impl MemberEvent { pub fn content(&self) -> &RoomMemberEventContent { match &*self { MemberEvent::Stripped(e) => &e.content, - MemberEvent::Full(e) => &e.content, + MemberEvent::Original(e) => &e.content, } } @@ -317,7 +317,7 @@ impl MemberEvent { pub fn user_id(&self) -> &UserId { match &*self { MemberEvent::Stripped(e) => &e.state_key, - MemberEvent::Full(e) => &e.state_key, + MemberEvent::Original(e) => &e.state_key, } } } @@ -329,7 +329,7 @@ impl From for MemberEvent { } impl From for MemberEvent { fn from(other: OriginalSyncRoomMemberEvent) -> Self { - MemberEvent::Full(other) + MemberEvent::Original(other) } } From 66fcc1e486912720a7e6adf46d7a23977f73a4a4 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 27 Apr 2022 12:36:19 +0200 Subject: [PATCH 18/28] forgot two instances in rename --- crates/matrix-sdk-indexeddb/src/state_store.rs | 2 +- crates/matrix-sdk-sled/src/state_store.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/matrix-sdk-indexeddb/src/state_store.rs b/crates/matrix-sdk-indexeddb/src/state_store.rs index 9b9e68894..953247aa1 100644 --- a/crates/matrix-sdk-indexeddb/src/state_store.rs +++ b/crates/matrix-sdk-indexeddb/src/state_store.rs @@ -884,7 +884,7 @@ impl IndexeddbStore { .map(|f| self.deserialize_event(f)) .transpose()? { - Ok(Some(MemberEvent::Full(e))) + Ok(Some(MemberEvent::Original(e))) } else if let Some(e) = self .inner .transaction_on_one_with_mode(KEYS::STRIPPED_MEMBERS, IdbTransactionMode::Readonly)? diff --git a/crates/matrix-sdk-sled/src/state_store.rs b/crates/matrix-sdk-sled/src/state_store.rs index 3066bfdbd..ec3dae744 100644 --- a/crates/matrix-sdk-sled/src/state_store.rs +++ b/crates/matrix-sdk-sled/src/state_store.rs @@ -676,7 +676,7 @@ impl SledStore { let stripped_key = self.encode_key(STRIPPED_ROOM_MEMBER, (room_id, state_key)); spawn_blocking(move || { if let Some(e) = db.members.get(key)?.map(|v| db.deserialize_event(&v)).transpose()? { - Ok(Some(MemberEvent::Full(e))) + Ok(Some(MemberEvent::Original(e))) } else if let Some(e) = db .stripped_members .get(stripped_key)? From 1bf1147d18ce0cca71f736c66fc9dfc77ad1bd5b Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 27 Apr 2022 16:22:47 +0200 Subject: [PATCH 19/28] fixing style --- crates/matrix-sdk-base/src/rooms/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/matrix-sdk-base/src/rooms/mod.rs b/crates/matrix-sdk-base/src/rooms/mod.rs index b347201c9..f534d0f29 100644 --- a/crates/matrix-sdk-base/src/rooms/mod.rs +++ b/crates/matrix-sdk-base/src/rooms/mod.rs @@ -1,7 +1,7 @@ mod members; mod normal; -use std::{cmp::max, fmt, collections::HashSet}; +use std::{cmp::max, collections::HashSet, fmt}; pub use members::RoomMember; pub use normal::{Room, RoomInfo, RoomType}; From 301cf3561fd5ec53747acb97c1b0bd086e93d9b2 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Fri, 29 Apr 2022 10:41:14 +0200 Subject: [PATCH 20/28] chore(indexeddb): Fix merge leftover --- crates/matrix-sdk-indexeddb/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/matrix-sdk-indexeddb/Cargo.toml b/crates/matrix-sdk-indexeddb/Cargo.toml index e5fb1fced..1251a8f90 100644 --- a/crates/matrix-sdk-indexeddb/Cargo.toml +++ b/crates/matrix-sdk-indexeddb/Cargo.toml @@ -37,6 +37,5 @@ matrix-sdk-common = { path = "../matrix-sdk-common" } matrix-sdk-base = { path = "../matrix-sdk-base", features = ["testing"] } matrix-sdk-crypto = { path = "../matrix-sdk-crypto", features = ["testing"] } matrix-sdk-test = { path = "../matrix-sdk-test" } -matrix-sdk-common = { path = "../matrix-sdk-common" } uuid = "1.0.0" wasm-bindgen-test = "0.3.30" From d9d143eba72efd1d3618f748330b3bdbf928e168 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Fri, 29 Apr 2022 12:42:36 +0200 Subject: [PATCH 21/28] fix(sled-store): Seperate stripped and non-stripped buckets --- crates/matrix-sdk-sled/src/state_store.rs | 169 ++++++++++++++++------ 1 file changed, 126 insertions(+), 43 deletions(-) diff --git a/crates/matrix-sdk-sled/src/state_store.rs b/crates/matrix-sdk-sled/src/state_store.rs index f66084576..8f87e045e 100644 --- a/crates/matrix-sdk-sled/src/state_store.rs +++ b/crates/matrix-sdk-sled/src/state_store.rs @@ -131,6 +131,8 @@ const ROOM_STATE: &str = "room-state"; const ROOM_USER_RECEIPT: &str = "room-user-receipt"; const ROOM: &str = "room"; const SESSION: &str = "session"; +const STRIPPED_INVITED_USER_ID: &str = "stripped-invited-user-id"; +const STRIPPED_JOINED_USER_ID: &str = "stripped-joined-user-id"; const STRIPPED_ROOM_INFO: &str = "stripped-room-info"; const STRIPPED_ROOM_MEMBER: &str = "stripped-room-member"; const STRIPPED_ROOM_STATE: &str = "stripped-room-state"; @@ -154,6 +156,8 @@ pub struct SledStore { room_info: Tree, room_state: Tree, room_account_data: Tree, + stripped_joined_user_ids: Tree, + stripped_invited_user_ids: Tree, stripped_room_infos: Tree, stripped_room_state: Tree, stripped_members: Tree, @@ -197,6 +201,8 @@ impl SledStore { let presence = db.open_tree(PRESENCE)?; let room_account_data = db.open_tree(ROOM_ACCOUNT_DATA)?; + let stripped_joined_user_ids = db.open_tree(JOINED_USER_ID)?; + let stripped_invited_user_ids = db.open_tree(INVITED_USER_ID)?; let stripped_room_infos = db.open_tree(STRIPPED_ROOM_INFO)?; let stripped_members = db.open_tree(STRIPPED_ROOM_MEMBER)?; let stripped_room_state = db.open_tree(STRIPPED_ROOM_STATE)?; @@ -227,6 +233,8 @@ impl SledStore { presence, room_state, room_info, + stripped_joined_user_ids, + stripped_invited_user_ids, stripped_room_infos, stripped_members, stripped_room_state, @@ -359,9 +367,8 @@ impl SledStore { pub async fn save_changes(&self, changes: &StateChanges) -> Result<()> { let now = Instant::now(); + // room state & memberships let ret: Result<(), TransactionError> = ( - &self.session, - &self.account_data, &self.members, &self.profiles, &self.display_names, @@ -370,15 +377,14 @@ impl SledStore { &self.room_info, &self.room_state, &self.room_account_data, - &self.presence, + &self.stripped_joined_user_ids, + &self.stripped_invited_user_ids, &self.stripped_room_infos, &self.stripped_members, &self.stripped_room_state, ) .transaction( |( - session, - account_data, members, profiles, display_names, @@ -387,15 +393,12 @@ impl SledStore { rooms, state, room_account_data, - presence, + stripped_joined, + stripped_invited, striped_rooms, stripped_members, stripped_state, )| { - if let Some(s) = &changes.sync_token { - session.insert("sync_token".encode(), s.as_str())?; - } - for (room, events) in &changes.members { let profile_changes = changes.profiles.get(room); @@ -428,6 +431,12 @@ impl SledStore { self.serialize_event(&event) .map_err(ConflictableTransactionError::Abort)?, )?; + // clear out any remaining stripped data + stripped_members.remove(self.encode_key(STRIPPED_ROOM_MEMBER, &key))?; + stripped_joined + .remove(self.encode_key(STRIPPED_JOINED_USER_ID, &key))?; + stripped_invited + .remove(self.encode_key(STRIPPED_INVITED_USER_ID, &key))?; if let Some(profile) = profile_changes.and_then(|p| p.get(&event.state_key)) @@ -451,14 +460,6 @@ impl SledStore { } } - for (event_type, event) in &changes.account_data { - account_data.insert( - self.encode_key(ACCOUNT_DATA, event_type), - self.serialize_event(&event) - .map_err(ConflictableTransactionError::Abort)?, - )?; - } - for (room, events) in &changes.room_account_data { for (event_type, event) in events { room_account_data.insert( @@ -489,14 +490,6 @@ impl SledStore { )?; } - for (sender, event) in &changes.presence { - presence.insert( - self.encode_key(PRESENCE, sender), - self.serialize_event(&event) - .map_err(ConflictableTransactionError::Abort)?, - )?; - } - for (room_id, info) in &changes.stripped_room_infos { striped_rooms.insert( self.encode_key(STRIPPED_ROOM_INFO, room_id), @@ -511,32 +504,37 @@ impl SledStore { match event.content.membership { MembershipState::Join => { - joined.insert( - self.encode_key(JOINED_USER_ID, &key), + stripped_joined.insert( + self.encode_key(STRIPPED_JOINED_USER_ID, &key), event.state_key.as_str(), )?; - invited.remove(self.encode_key(INVITED_USER_ID, &key))?; + stripped_invited + .remove(self.encode_key(STRIPPED_INVITED_USER_ID, &key))?; } MembershipState::Invite => { - invited.insert( - self.encode_key(INVITED_USER_ID, &key), + stripped_invited.insert( + self.encode_key(STRIPPED_INVITED_USER_ID, &key), event.state_key.as_str(), )?; - joined.remove(self.encode_key(JOINED_USER_ID, &key))?; + stripped_joined + .remove(self.encode_key(STRIPPED_JOINED_USER_ID, &key))?; } _ => { - joined.remove(self.encode_key(JOINED_USER_ID, &key))?; - invited.remove(self.encode_key(INVITED_USER_ID, &key))?; + stripped_joined + .remove(self.encode_key(STRIPPED_JOINED_USER_ID, &key))?; + stripped_invited + .remove(self.encode_key(STRIPPED_INVITED_USER_ID, &key))?; } } stripped_members.insert( - self.encode_key( - STRIPPED_ROOM_MEMBER, - (room, event.state_key.to_string()), - ), + self.encode_key(STRIPPED_ROOM_MEMBER, &key), self.serialize_event(&event) .map_err(ConflictableTransactionError::Abort)?, )?; + + members.remove(self.encode_key(MEMBER, &key))?; + joined.remove(self.encode_key(JOINED_USER_ID, &key))?; + invited.remove(self.encode_key(INVITED_USER_ID, &key))?; } } @@ -562,8 +560,8 @@ impl SledStore { ret?; let ret: Result<(), TransactionError> = - (&self.room_user_receipts, &self.room_event_receipts).transaction( - |(room_user_receipts, room_event_receipts)| { + (&self.room_user_receipts, &self.room_event_receipts, &self.presence).transaction( + |(room_user_receipts, room_event_receipts, presence)| { for (room, content) in &changes.receipts { for (event_id, receipts) in &content.0 { for (receipt_type, receipts) in receipts { @@ -601,6 +599,14 @@ impl SledStore { } } + for (sender, event) in &changes.presence { + presence.insert( + self.encode_key(PRESENCE, sender), + self.serialize_event(&event) + .map_err(ConflictableTransactionError::Abort)?, + )?; + } + Ok(()) }, ); @@ -609,6 +615,26 @@ impl SledStore { self.save_room_timeline(changes).await?; + // user state + let ret: Result<(), TransactionError> = (&self.session, &self.account_data) + .transaction(|(session, account_data)| { + if let Some(s) = &changes.sync_token { + session.insert("sync_token".encode(), s.as_str())?; + } + + for (event_type, event) in &changes.account_data { + account_data.insert( + self.encode_key(ACCOUNT_DATA, event_type), + self.serialize_event(&event) + .map_err(ConflictableTransactionError::Abort)?, + )?; + } + + Ok(()) + }); + + ret?; + self.inner.flush_async().await?; info!("Saved changes in {:?}", now.elapsed()); @@ -698,6 +724,15 @@ impl SledStore { .await? .chain(self.get_invited_user_ids(room_id).await?)) } + pub async fn get_stripped_user_ids_stream( + &self, + room_id: &RoomId, + ) -> StoreResult>> { + Ok(self + .get_stripped_joined_user_ids(room_id) + .await? + .chain(self.get_stripped_invited_user_ids(room_id).await?)) + } pub async fn get_invited_user_ids( &self, @@ -735,6 +770,42 @@ impl SledStore { .map_err(|e| StoreError::Backend(anyhow!(e))) } + pub async fn get_stripped_invited_user_ids( + &self, + room_id: &RoomId, + ) -> StoreResult>> { + let db = self.clone(); + let key = self.encode_key(STRIPPED_INVITED_USER_ID, room_id); + spawn_blocking(move || { + stream::iter(db.stripped_invited_user_ids.scan_prefix(key).map(|u| { + UserId::parse(String::from_utf8_lossy( + &u.map_err(|e| StoreError::Backend(anyhow!(e)))?.1, + )) + .map_err(StoreError::Identifier) + })) + }) + .await + .map_err(|e| StoreError::Backend(anyhow!(e))) + } + + pub async fn get_stripped_joined_user_ids( + &self, + room_id: &RoomId, + ) -> StoreResult>> { + let db = self.clone(); + let key = self.encode_key(STRIPPED_JOINED_USER_ID, room_id); + spawn_blocking(move || { + stream::iter(db.stripped_joined_user_ids.scan_prefix(key).map(|u| { + UserId::parse(String::from_utf8_lossy( + &u.map_err(|e| StoreError::Backend(anyhow!(e)))?.1, + )) + .map_err(StoreError::Identifier) + })) + }) + .await + .map_err(|e| StoreError::Backend(anyhow!(e))) + } + pub async fn get_room_infos(&self) -> Result>> { let db = self.clone(); spawn_blocking(move || { @@ -1317,15 +1388,27 @@ impl StateStore for SledStore { } async fn get_user_ids(&self, room_id: &RoomId) -> StoreResult> { - self.get_user_ids_stream(room_id).await?.try_collect().await + let v: Vec = self.get_user_ids_stream(room_id).await?.try_collect().await?; + if !v.is_empty() { + return Ok(v); + } + self.get_stripped_user_ids_stream(room_id).await?.try_collect().await } async fn get_invited_user_ids(&self, room_id: &RoomId) -> StoreResult> { - self.get_invited_user_ids(room_id).await?.try_collect().await + let v: Vec = self.get_invited_user_ids(room_id).await?.try_collect().await?; + if !v.is_empty() { + return Ok(v); + } + self.get_stripped_invited_user_ids(room_id).await?.try_collect().await } async fn get_joined_user_ids(&self, room_id: &RoomId) -> StoreResult> { - self.get_joined_user_ids(room_id).await?.try_collect().await + let v: Vec = self.get_joined_user_ids(room_id).await?.try_collect().await?; + if !v.is_empty() { + return Ok(v); + } + self.get_stripped_joined_user_ids(room_id).await?.try_collect().await } async fn get_room_infos(&self) -> StoreResult> { From d077aa6a9073bd639973ce07c848a603bd7cb418 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Mon, 2 May 2022 12:07:40 +0200 Subject: [PATCH 22/28] chore(indexeddb): Merge fixes --- crates/matrix-sdk-indexeddb/src/state_store.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/matrix-sdk-indexeddb/src/state_store.rs b/crates/matrix-sdk-indexeddb/src/state_store.rs index 29171dfe9..d524fbcbe 100644 --- a/crates/matrix-sdk-indexeddb/src/state_store.rs +++ b/crates/matrix-sdk-indexeddb/src/state_store.rs @@ -19,7 +19,7 @@ use async_trait::async_trait; use futures_util::stream; use indexed_db_futures::prelude::*; use matrix_sdk_base::{ - deserialized_responses::SyncRoomEvent, + deserialized_responses::{SyncRoomEvent, MemberEvent}, media::{MediaRequest, UniqueKey}, store::{BoxStream, Result as StoreResult, StateChanges, StateStore, StoreError}, RoomInfo, @@ -30,7 +30,7 @@ use ruma::{ presence::PresenceEvent, receipt::Receipt, room::{ - member::{MembershipState, OriginalSyncRoomMemberEvent, RoomMemberEventContent}, + member::{MembershipState, RoomMemberEventContent}, redaction::SyncRoomRedactionEvent, }, AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, AnySyncMessageLikeEvent, From 4de29b81783c8376fd128c19a8e90bf22bf45ccb Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Tue, 3 May 2022 08:22:57 +0200 Subject: [PATCH 23/28] test(state tests): Put stripped_member test into its own DB to ensure separation --- crates/matrix-sdk-base/src/store/integration_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/matrix-sdk-base/src/store/integration_tests.rs b/crates/matrix-sdk-base/src/store/integration_tests.rs index e21a27359..63f7fd515 100644 --- a/crates/matrix-sdk-base/src/store/integration_tests.rs +++ b/crates/matrix-sdk-base/src/store/integration_tests.rs @@ -353,7 +353,7 @@ macro_rules! statestore_integration_tests { #[async_test] async fn test_stripped_member_saving() { let store = get_store().await.unwrap(); - let room_id = room_id!("!test_member_saving:localhost"); + let room_id = room_id!("!test_stripped_member_saving:localhost"); let user_id = user_id(); assert!(store.get_member_event(room_id, user_id).await.unwrap().is_none()); From f416ebfdd8636d70e350c204d8fa6bc79411bb5c Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Tue, 3 May 2022 08:44:52 +0200 Subject: [PATCH 24/28] fix(sled-store): Fix faulty mixing of stripped and regular user_ids --- crates/matrix-sdk-indexeddb/src/state_store.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/matrix-sdk-indexeddb/src/state_store.rs b/crates/matrix-sdk-indexeddb/src/state_store.rs index d524fbcbe..41a705ec5 100644 --- a/crates/matrix-sdk-indexeddb/src/state_store.rs +++ b/crates/matrix-sdk-indexeddb/src/state_store.rs @@ -19,7 +19,7 @@ use async_trait::async_trait; use futures_util::stream; use indexed_db_futures::prelude::*; use matrix_sdk_base::{ - deserialized_responses::{SyncRoomEvent, MemberEvent}, + deserialized_responses::{MemberEvent, SyncRoomEvent}, media::{MediaRequest, UniqueKey}, store::{BoxStream, Result as StoreResult, StateChanges, StateStore, StoreError}, RoomInfo, From 68d5097d961a6b0e7a68bf4c634d5370aa6e51c5 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Tue, 3 May 2022 09:03:13 +0200 Subject: [PATCH 25/28] fix(sled): Unmix stripped and regular user_ids --- crates/matrix-sdk-sled/src/state_store.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/matrix-sdk-sled/src/state_store.rs b/crates/matrix-sdk-sled/src/state_store.rs index 4d7813941..0d62a0aee 100644 --- a/crates/matrix-sdk-sled/src/state_store.rs +++ b/crates/matrix-sdk-sled/src/state_store.rs @@ -199,8 +199,8 @@ impl SledStore { let presence = db.open_tree(PRESENCE)?; let room_account_data = db.open_tree(ROOM_ACCOUNT_DATA)?; - let stripped_joined_user_ids = db.open_tree(JOINED_USER_ID)?; - let stripped_invited_user_ids = db.open_tree(INVITED_USER_ID)?; + let stripped_joined_user_ids = db.open_tree(STRIPPED_JOINED_USER_ID)?; + let stripped_invited_user_ids = db.open_tree(STRIPPED_INVITED_USER_ID)?; let stripped_room_infos = db.open_tree(STRIPPED_ROOM_INFO)?; let stripped_members = db.open_tree(STRIPPED_ROOM_MEMBER)?; let stripped_room_state = db.open_tree(STRIPPED_ROOM_STATE)?; From 5d3351f5ccbbcbc06a3dc31afbc747eae760b5b0 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 4 May 2022 10:52:17 +0200 Subject: [PATCH 26/28] chore(sledstore): Revert user-id removing code --- crates/matrix-sdk-sled/src/state_store.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/crates/matrix-sdk-sled/src/state_store.rs b/crates/matrix-sdk-sled/src/state_store.rs index 0d62a0aee..f56262eea 100644 --- a/crates/matrix-sdk-sled/src/state_store.rs +++ b/crates/matrix-sdk-sled/src/state_store.rs @@ -429,12 +429,6 @@ impl SledStore { self.serialize_event(&event) .map_err(ConflictableTransactionError::Abort)?, )?; - // clear out any remaining stripped data - stripped_members.remove(self.encode_key(STRIPPED_ROOM_MEMBER, &key))?; - stripped_joined - .remove(self.encode_key(STRIPPED_JOINED_USER_ID, &key))?; - stripped_invited - .remove(self.encode_key(STRIPPED_INVITED_USER_ID, &key))?; if let Some(profile) = profile_changes.and_then(|p| p.get(&event.state_key)) @@ -529,10 +523,6 @@ impl SledStore { self.serialize_event(&event) .map_err(ConflictableTransactionError::Abort)?, )?; - - members.remove(self.encode_key(MEMBER, &key))?; - joined.remove(self.encode_key(JOINED_USER_ID, &key))?; - invited.remove(self.encode_key(INVITED_USER_ID, &key))?; } } From 75f0fe94e834f949a97e16c68aba2d42a661205c Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 4 May 2022 16:02:02 +0200 Subject: [PATCH 27/28] fix(indexeddb): Separate stripped and regular user_id indixes --- .../matrix-sdk-indexeddb/src/state_store.rs | 91 ++++++++++++++++--- 1 file changed, 79 insertions(+), 12 deletions(-) diff --git a/crates/matrix-sdk-indexeddb/src/state_store.rs b/crates/matrix-sdk-indexeddb/src/state_store.rs index 41a705ec5..9a8281331 100644 --- a/crates/matrix-sdk-indexeddb/src/state_store.rs +++ b/crates/matrix-sdk-indexeddb/src/state_store.rs @@ -118,6 +118,8 @@ mod KEYS { pub const STRIPPED_ROOM_INFOS: &str = "stripped_room_infos"; pub const STRIPPED_MEMBERS: &str = "stripped_members"; pub const STRIPPED_ROOM_STATE: &str = "stripped_room_state"; + pub const STRIPPED_JOINED_USER_IDS: &str = "stripped_joined_user_ids"; + pub const STRIPPED_INVITED_USER_IDS: &str = "stripped_invited_user_ids"; pub const ROOM_USER_RECEIPTS: &str = "room_user_receipts"; pub const ROOM_EVENT_RECEIPTS: &str = "room_event_receipts"; @@ -178,6 +180,8 @@ impl IndexeddbStore { db.create_object_store(KEYS::STRIPPED_ROOM_INFOS)?; db.create_object_store(KEYS::STRIPPED_MEMBERS)?; db.create_object_store(KEYS::STRIPPED_ROOM_STATE)?; + db.create_object_store(KEYS::STRIPPED_JOINED_USER_IDS)?; + db.create_object_store(KEYS::STRIPPED_INVITED_USER_IDS)?; db.create_object_store(KEYS::ROOM_USER_RECEIPTS)?; db.create_object_store(KEYS::ROOM_EVENT_RECEIPTS)?; @@ -373,7 +377,11 @@ impl IndexeddbStore { } if !changes.stripped_members.is_empty() { - stores.extend([KEYS::STRIPPED_MEMBERS, KEYS::INVITED_USER_IDS, KEYS::JOINED_USER_IDS]) + stores.extend([ + KEYS::STRIPPED_MEMBERS, + KEYS::STRIPPED_INVITED_USER_IDS, + KEYS::STRIPPED_JOINED_USER_IDS, + ]) } if !changes.receipts.is_empty() { @@ -476,8 +484,8 @@ impl IndexeddbStore { if !changes.stripped_members.is_empty() { let store = tx.object_store(KEYS::STRIPPED_MEMBERS)?; - let joined = tx.object_store(KEYS::JOINED_USER_IDS)?; - let invited = tx.object_store(KEYS::INVITED_USER_IDS)?; + let joined = tx.object_store(KEYS::STRIPPED_JOINED_USER_IDS)?; + let invited = tx.object_store(KEYS::STRIPPED_INVITED_USER_IDS)?; for (room, events) in &changes.stripped_members { for event in events.values() { let key = (room, &event.state_key); @@ -485,21 +493,23 @@ impl IndexeddbStore { match event.content.membership { MembershipState::Join => { joined.put_key_val_owned( - &self.encode_key(KEYS::JOINED_USER_IDS, key), + &self.encode_key(KEYS::STRIPPED_JOINED_USER_IDS, key), &self.serialize_event(&event.state_key)?, )?; - invited.delete(&self.encode_key(KEYS::INVITED_USER_IDS, key))?; + invited + .delete(&self.encode_key(KEYS::STRIPPED_INVITED_USER_IDS, key))?; } MembershipState::Invite => { invited.put_key_val_owned( - &self.encode_key(KEYS::INVITED_USER_IDS, key), + &self.encode_key(KEYS::STRIPPED_INVITED_USER_IDS, key), &self.serialize_event(&event.state_key)?, )?; - joined.delete(&self.encode_key(KEYS::JOINED_USER_IDS, key))?; + joined.delete(&self.encode_key(KEYS::STRIPPED_JOINED_USER_IDS, key))?; } _ => { - joined.delete(&self.encode_key(KEYS::JOINED_USER_IDS, key))?; - invited.delete(&self.encode_key(KEYS::INVITED_USER_IDS, key))?; + joined.delete(&self.encode_key(KEYS::STRIPPED_JOINED_USER_IDS, key))?; + invited + .delete(&self.encode_key(KEYS::STRIPPED_INVITED_USER_IDS, key))?; } } store.put_key_val( @@ -933,6 +943,51 @@ impl IndexeddbStore { .collect::>()) } + pub async fn get_stripped_user_ids_stream(&self, room_id: &RoomId) -> Result> { + Ok([ + self.get_stripped_invited_user_ids(room_id).await?, + self.get_stripped_joined_user_ids(room_id).await?, + ] + .concat()) + } + + pub async fn get_stripped_invited_user_ids( + &self, + room_id: &RoomId, + ) -> Result> { + let range = self.encode_to_range(KEYS::STRIPPED_INVITED_USER_IDS, room_id)?; + let entries = self + .inner + .transaction_on_one_with_mode( + KEYS::STRIPPED_INVITED_USER_IDS, + IdbTransactionMode::Readonly, + )? + .object_store(KEYS::STRIPPED_INVITED_USER_IDS)? + .get_all_with_key(&range)? + .await? + .iter() + .filter_map(|f| self.deserialize_event::(f).ok()) + .collect::>(); + + Ok(entries) + } + + pub async fn get_stripped_joined_user_ids(&self, room_id: &RoomId) -> Result> { + let range = self.encode_to_range(KEYS::STRIPPED_JOINED_USER_IDS, room_id)?; + Ok(self + .inner + .transaction_on_one_with_mode( + KEYS::STRIPPED_JOINED_USER_IDS, + IdbTransactionMode::Readonly, + )? + .object_store(KEYS::STRIPPED_JOINED_USER_IDS)? + .get_all_with_key(&range)? + .await? + .iter() + .filter_map(|f| self.deserialize_event::(f).ok()) + .collect::>()) + } + pub async fn get_room_infos(&self) -> Result> { let entries: Vec<_> = self .inner @@ -1267,15 +1322,27 @@ impl StateStore for IndexeddbStore { } async fn get_user_ids(&self, room_id: &RoomId) -> StoreResult> { - self.get_user_ids_stream(room_id).await.map_err(|e| e.into()) + let ids: Vec = self.get_user_ids_stream(room_id).await?; + if !ids.is_empty() { + return Ok(ids); + } + self.get_stripped_user_ids_stream(room_id).await.map_err(|e| e.into()) } async fn get_invited_user_ids(&self, room_id: &RoomId) -> StoreResult> { - self.get_invited_user_ids(room_id).await.map_err(|e| e.into()) + let ids: Vec = self.get_invited_user_ids(room_id).await?; + if !ids.is_empty() { + return Ok(ids); + } + self.get_stripped_invited_user_ids(room_id).await.map_err(|e| e.into()) } async fn get_joined_user_ids(&self, room_id: &RoomId) -> StoreResult> { - self.get_joined_user_ids(room_id).await.map_err(|e| e.into()) + let ids: Vec = self.get_joined_user_ids(room_id).await?; + if !ids.is_empty() { + return Ok(ids); + } + self.get_stripped_joined_user_ids(room_id).await.map_err(|e| e.into()) } async fn get_room_infos(&self) -> StoreResult> { From 98fa629f3816804e22b5609e270f96fa6fe6d20b Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Wed, 4 May 2022 16:09:54 +0200 Subject: [PATCH 28/28] fix(memstore): Separate stripped and regular user indixes --- .../matrix-sdk-base/src/store/memory_store.rs | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/crates/matrix-sdk-base/src/store/memory_store.rs b/crates/matrix-sdk-base/src/store/memory_store.rs index a06205785..7811ab93f 100644 --- a/crates/matrix-sdk-base/src/store/memory_store.rs +++ b/crates/matrix-sdk-base/src/store/memory_store.rs @@ -77,6 +77,8 @@ pub struct MemoryStore { DashMap>>>, >, stripped_members: Arc>>, + stripped_joined_user_ids: Arc>>, + stripped_invited_user_ids: Arc>>, presence: Arc>>, room_user_receipts: Arc>>>, @@ -113,6 +115,8 @@ impl MemoryStore { stripped_room_infos: Default::default(), stripped_room_state: Default::default(), stripped_members: Default::default(), + stripped_joined_user_ids: Default::default(), + stripped_invited_user_ids: Default::default(), presence: Default::default(), room_user_receipts: Default::default(), room_event_receipts: Default::default(), @@ -245,31 +249,31 @@ impl MemoryStore { for event in events.values() { match event.content.membership { MembershipState::Join => { - self.joined_user_ids + self.stripped_joined_user_ids .entry(room.clone()) .or_insert_with(DashSet::new) .insert(event.state_key.clone()); - self.invited_user_ids + self.stripped_invited_user_ids .entry(room.clone()) .or_insert_with(DashSet::new) .remove(&event.state_key); } MembershipState::Invite => { - self.invited_user_ids + self.stripped_invited_user_ids .entry(room.clone()) .or_insert_with(DashSet::new) .insert(event.state_key.clone()); - self.joined_user_ids + self.stripped_joined_user_ids .entry(room.clone()) .or_insert_with(DashSet::new) .remove(&event.state_key); } _ => { - self.joined_user_ids + self.stripped_joined_user_ids .entry(room.clone()) .or_insert_with(DashSet::new) .remove(&event.state_key); - self.invited_user_ids + self.stripped_invited_user_ids .entry(room.clone()) .or_insert_with(DashSet::new) .remove(&event.state_key); @@ -527,6 +531,20 @@ impl MemoryStore { .unwrap_or_default() } + fn get_stripped_invited_user_ids(&self, room_id: &RoomId) -> Vec { + self.stripped_invited_user_ids + .get(room_id) + .map(|u| u.iter().map(|u| u.clone()).collect()) + .unwrap_or_default() + } + + fn get_stripped_joined_user_ids(&self, room_id: &RoomId) -> Vec { + self.stripped_joined_user_ids + .get(room_id) + .map(|u| u.iter().map(|u| u.clone()).collect()) + .unwrap_or_default() + } + fn get_room_infos(&self) -> Vec { self.room_info.iter().map(|r| r.clone()).collect() } @@ -723,11 +741,19 @@ impl StateStore for MemoryStore { } async fn get_invited_user_ids(&self, room_id: &RoomId) -> Result> { - Ok(self.get_invited_user_ids(room_id)) + let v = self.get_invited_user_ids(room_id); + if !v.is_empty() { + return Ok(v); + } + Ok(self.get_stripped_invited_user_ids(room_id)) } async fn get_joined_user_ids(&self, room_id: &RoomId) -> Result> { - Ok(self.get_joined_user_ids(room_id)) + let v = self.get_joined_user_ids(room_id); + if !v.is_empty() { + return Ok(v); + } + Ok(self.get_stripped_joined_user_ids(room_id)) } async fn get_room_infos(&self) -> Result> {