From ffda84c0ef28d7b92705590988a1635eeb4b2e74 Mon Sep 17 00:00:00 2001 From: hanadi92 Date: Wed, 6 Mar 2024 21:37:51 +0100 Subject: [PATCH 1/8] sdk: fetch unstable_features supported by homeserver Signed-off-by: hanadi92 --- crates/matrix-sdk/src/client/builder.rs | 5 +- crates/matrix-sdk/src/client/mod.rs | 67 +++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/crates/matrix-sdk/src/client/builder.rs b/crates/matrix-sdk/src/client/builder.rs index c000075ba20..44c5a269bba 100644 --- a/crates/matrix-sdk/src/client/builder.rs +++ b/crates/matrix-sdk/src/client/builder.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{fmt, sync::Arc}; +use std::{collections::BTreeMap, fmt, sync::Arc}; use matrix_sdk_base::{store::StoreConfig, BaseClient}; use ruma::{ @@ -90,6 +90,7 @@ pub struct ClientBuilder { request_config: RequestConfig, respect_login_well_known: bool, server_versions: Option>, + unstable_features: Option>, handle_refresh_tokens: bool, base_client: Option, #[cfg(feature = "e2e-encryption")] @@ -107,6 +108,7 @@ impl ClientBuilder { request_config: Default::default(), respect_login_well_known: true, server_versions: None, + unstable_features: None, handle_refresh_tokens: false, base_client: None, #[cfg(feature = "e2e-encryption")] @@ -508,6 +510,7 @@ impl ClientBuilder { http_client, base_client, self.server_versions, + self.unstable_features, self.respect_login_well_known, event_cache, #[cfg(feature = "e2e-encryption")] diff --git a/crates/matrix-sdk/src/client/mod.rs b/crates/matrix-sdk/src/client/mod.rs index 87c43fd1e90..52fdbcb67e2 100644 --- a/crates/matrix-sdk/src/client/mod.rs +++ b/crates/matrix-sdk/src/client/mod.rs @@ -235,6 +235,9 @@ pub(crate) struct ClientInner { /// The Matrix versions the server supports (well-known ones only) server_versions: OnceCell>, + /// The unstable features and their on/off state on the server + unstable_features: OnceCell>, + /// Collection of locks individual client methods might want to use, either /// to ensure that only a single call to a method happens at once or to /// deduplicate multiple calls to a method. @@ -292,6 +295,7 @@ impl ClientInner { http_client: HttpClient, base_client: BaseClient, server_versions: Option>, + unstable_features: Option>, respect_login_well_known: bool, event_cache: OnceCell, #[cfg(feature = "e2e-encryption")] encryption_settings: EncryptionSettings, @@ -305,6 +309,7 @@ impl ClientInner { base_client, locks: Default::default(), server_versions: OnceCell::new_with(server_versions), + unstable_features: OnceCell::new_with(unstable_features), typing_notice_times: Default::default(), event_handlers: Default::default(), notification_handlers: Default::default(), @@ -1401,6 +1406,49 @@ impl Client { Ok(server_versions) } + /// Fetch unstable_features from homeserver + async fn request_unstable_features(&self) -> HttpResult> { + let unstable_features: BTreeMap = self + .inner + .http_client + .send( + get_supported_versions::Request::new(), + None, + self.homeserver().to_string(), + None, + &[MatrixVersion::V1_0], + Default::default(), + ) + .await? + .unstable_features; + + Ok(unstable_features) + } + + /// Get unstable features from `request_unstable_features` or cache + /// + /// # Examples + /// + /// ```no_run + /// # use matrix_sdk::{Client, config::SyncSettings}; + /// # use url::Url; + /// # async { + /// # let homeserver = Url::parse("http://localhost:8080")?; + /// # let mut client = Client::new(homeserver).await?; + /// let unstable_features = client.unstable_features().await.unwrap(); + /// let msc_x = unstable_features.get("msc_x").unwrap_or(&false); + /// # anyhow::Ok(()) }; + /// ``` + pub async fn unstable_features(&self) -> HttpResult<&BTreeMap> { + let unstable_features = self + .inner + .unstable_features + .get_or_try_init(|| self.request_unstable_features()) + .await?; + + Ok(unstable_features) + } + /// Get information of all our own devices. /// /// # Examples @@ -2006,6 +2054,7 @@ impl Client { self.inner.http_client.clone(), self.inner.base_client.clone_with_in_memory_state_store(), self.inner.server_versions.get().cloned(), + self.inner.unstable_features.get().cloned(), self.inner.respect_login_well_known, self.inner.event_cache.clone(), #[cfg(feature = "e2e-encryption")] @@ -2269,4 +2318,22 @@ pub(crate) mod tests { assert_eq!(result.avatar_url.clone().unwrap().to_string(), "mxc://example.me/someid"); assert!(!response.limited); } + + #[async_test] + async fn test_homeserver_server_versions() { + let server = MockServer::start().await; + let client = logged_in_client(Some(server.uri())).await; + + Mock::given(method("GET")) + .and(path("_matrix/client/versions")) + .respond_with( + ResponseTemplate::new(200).set_body_json(&*test_json::api_responses::VERSIONS), + ) + .mount(&server) + .await; + let unstable_features = client.request_unstable_features().await.unwrap(); + + assert_eq!(unstable_features.get("org.matrix.e2e_cross_signing"), Some(&true)); + assert_eq!(unstable_features, client.unstable_features().await.unwrap().clone()) + } } From 175fae5a3240d95ed43e04cae76ea85b1c45f3ef Mon Sep 17 00:00:00 2001 From: hanadi92 Date: Wed, 6 Mar 2024 21:40:19 +0100 Subject: [PATCH 2/8] ffi: add can_homeserver_push_encrypted_event_to_device method Signed-off-by: hanadi92 --- bindings/matrix-sdk-ffi/src/notification_settings.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bindings/matrix-sdk-ffi/src/notification_settings.rs b/bindings/matrix-sdk-ffi/src/notification_settings.rs index a4cfa77c902..4e42e74ed22 100644 --- a/bindings/matrix-sdk-ffi/src/notification_settings.rs +++ b/bindings/matrix-sdk-ffi/src/notification_settings.rs @@ -319,6 +319,16 @@ impl NotificationSettings { } } + /// Check whether [MSC 4028 push rule][rule] is enabled on the homeserver. + /// + /// [rule]: https://github.com/matrix-org/matrix-spec-proposals/blob/giomfo/push_encrypted_events/proposals/4028-push-all-encrypted-events-except-for-muted-rooms.md + pub async fn can_homeserver_push_encrypted_event_to_device(&self) -> bool { + match self.sdk_client.unstable_features().await { + Ok(unstable_feature) => *unstable_feature.get("org.matrix.msc4028").unwrap_or(&false), + Err(_) => false, + } + } + /// Set whether user mentions are enabled. pub async fn set_user_mention_enabled( &self, From c6f41193b58d0b5a472095e7e079d5f8f86d6e76 Mon Sep 17 00:00:00 2001 From: Hanadi Date: Thu, 7 Mar 2024 18:51:14 +0100 Subject: [PATCH 3/8] fix: use copied instead of dereferencing Co-authored-by: Benjamin Bouvier Signed-off-by: Hanadi --- bindings/matrix-sdk-ffi/src/notification_settings.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/matrix-sdk-ffi/src/notification_settings.rs b/bindings/matrix-sdk-ffi/src/notification_settings.rs index 4e42e74ed22..7e519e0c479 100644 --- a/bindings/matrix-sdk-ffi/src/notification_settings.rs +++ b/bindings/matrix-sdk-ffi/src/notification_settings.rs @@ -324,7 +324,7 @@ impl NotificationSettings { /// [rule]: https://github.com/matrix-org/matrix-spec-proposals/blob/giomfo/push_encrypted_events/proposals/4028-push-all-encrypted-events-except-for-muted-rooms.md pub async fn can_homeserver_push_encrypted_event_to_device(&self) -> bool { match self.sdk_client.unstable_features().await { - Ok(unstable_feature) => *unstable_feature.get("org.matrix.msc4028").unwrap_or(&false), + Ok(unstable_feature) => unstable_feature.get("org.matrix.msc4028").copied().unwrap_or(false), Err(_) => false, } } From d9ed0207ff111a869996dc015aa5f55b9bf821ad Mon Sep 17 00:00:00 2001 From: hanadi92 Date: Thu, 7 Mar 2024 22:47:38 +0100 Subject: [PATCH 4/8] fix: move can_homeserver_push_encrypted_event_to_device logic to sdk Signed-off-by: hanadi92 --- .../src/notification_settings.rs | 5 +-- crates/matrix-sdk/src/client/mod.rs | 44 ++++++++++++++++++- .../src/test_json/api_responses.rs | 3 +- 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/notification_settings.rs b/bindings/matrix-sdk-ffi/src/notification_settings.rs index 7e519e0c479..81cbf6b8431 100644 --- a/bindings/matrix-sdk-ffi/src/notification_settings.rs +++ b/bindings/matrix-sdk-ffi/src/notification_settings.rs @@ -323,10 +323,7 @@ impl NotificationSettings { /// /// [rule]: https://github.com/matrix-org/matrix-spec-proposals/blob/giomfo/push_encrypted_events/proposals/4028-push-all-encrypted-events-except-for-muted-rooms.md pub async fn can_homeserver_push_encrypted_event_to_device(&self) -> bool { - match self.sdk_client.unstable_features().await { - Ok(unstable_feature) => unstable_feature.get("org.matrix.msc4028").copied().unwrap_or(false), - Err(_) => false, - } + self.sdk_client.can_homeserver_push_encrypted_event_to_device().await.unwrap() } /// Set whether user mentions are enabled. diff --git a/crates/matrix-sdk/src/client/mod.rs b/crates/matrix-sdk/src/client/mod.rs index 52fdbcb67e2..a7dbe21be41 100644 --- a/crates/matrix-sdk/src/client/mod.rs +++ b/crates/matrix-sdk/src/client/mod.rs @@ -1449,6 +1449,29 @@ impl Client { Ok(unstable_features) } + /// Check whether [MSC 4028 push rule][rule] is enabled on the homeserver. + /// + /// # Examples + /// + /// ```no_run + /// # use matrix_sdk::{Client, config::SyncSettings}; + /// # use url::Url; + /// # async { + /// # let homeserver = Url::parse("http://localhost:8080")?; + /// # let mut client = Client::new(homeserver).await?; + /// let msc4028_enabled = + /// client.can_homeserver_push_encrypted_event_to_device().await.unwrap(); + /// # anyhow::Ok(()) }; + /// ``` + pub async fn can_homeserver_push_encrypted_event_to_device(&self) -> HttpResult { + match self.unstable_features().await { + Ok(unstable_feature) => { + Ok(unstable_feature.get("org.matrix.msc4028").copied().unwrap_or(false)) + } + Err(_) => Ok(false), + } + } + /// Get information of all our own devices. /// /// # Examples @@ -2320,7 +2343,7 @@ pub(crate) mod tests { } #[async_test] - async fn test_homeserver_server_versions() { + async fn test_request_unstable_features() { let server = MockServer::start().await; let client = logged_in_client(Some(server.uri())).await; @@ -2334,6 +2357,23 @@ pub(crate) mod tests { let unstable_features = client.request_unstable_features().await.unwrap(); assert_eq!(unstable_features.get("org.matrix.e2e_cross_signing"), Some(&true)); - assert_eq!(unstable_features, client.unstable_features().await.unwrap().clone()) + assert_eq!(unstable_features, client.unstable_features().await.unwrap().clone()); + } + + #[async_test] + async fn test_can_homeserver_push_encrypted_event_to_device() { + let server = MockServer::start().await; + let client = logged_in_client(Some(server.uri())).await; + + Mock::given(method("GET")) + .and(path("_matrix/client/versions")) + .respond_with( + ResponseTemplate::new(200).set_body_json(&*test_json::api_responses::VERSIONS), + ) + .mount(&server) + .await; + + let msc4028_enabled = client.can_homeserver_push_encrypted_event_to_device().await.unwrap(); + assert_eq!(msc4028_enabled, true); } } diff --git a/testing/matrix-sdk-test/src/test_json/api_responses.rs b/testing/matrix-sdk-test/src/test_json/api_responses.rs index d534697717a..8d052f209a7 100644 --- a/testing/matrix-sdk-test/src/test_json/api_responses.rs +++ b/testing/matrix-sdk-test/src/test_json/api_responses.rs @@ -324,7 +324,8 @@ pub static VERSIONS: Lazy = Lazy::new(|| { ], "unstable_features": { "org.matrix.label_based_filtering":true, - "org.matrix.e2e_cross_signing":true + "org.matrix.e2e_cross_signing":true, + "org.matrix.msc4028":true } }) }); From de21aaf998e80f3c33141e15eacc40606a0a93d1 Mon Sep 17 00:00:00 2001 From: hanadi92 Date: Thu, 7 Mar 2024 22:48:50 +0100 Subject: [PATCH 5/8] fix: remove unused unstable features param in client builder Signed-off-by: hanadi92 --- crates/matrix-sdk/src/client/builder.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/matrix-sdk/src/client/builder.rs b/crates/matrix-sdk/src/client/builder.rs index 44c5a269bba..053d68b948a 100644 --- a/crates/matrix-sdk/src/client/builder.rs +++ b/crates/matrix-sdk/src/client/builder.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{collections::BTreeMap, fmt, sync::Arc}; +use std::{fmt, sync::Arc}; use matrix_sdk_base::{store::StoreConfig, BaseClient}; use ruma::{ @@ -90,7 +90,6 @@ pub struct ClientBuilder { request_config: RequestConfig, respect_login_well_known: bool, server_versions: Option>, - unstable_features: Option>, handle_refresh_tokens: bool, base_client: Option, #[cfg(feature = "e2e-encryption")] @@ -108,7 +107,6 @@ impl ClientBuilder { request_config: Default::default(), respect_login_well_known: true, server_versions: None, - unstable_features: None, handle_refresh_tokens: false, base_client: None, #[cfg(feature = "e2e-encryption")] @@ -510,7 +508,7 @@ impl ClientBuilder { http_client, base_client, self.server_versions, - self.unstable_features, + None, self.respect_login_well_known, event_cache, #[cfg(feature = "e2e-encryption")] From fca34482507699fb158d096a4ae1c979b77bf7fc Mon Sep 17 00:00:00 2001 From: hanadi92 Date: Thu, 7 Mar 2024 23:12:46 +0100 Subject: [PATCH 6/8] fix: use assert instead of asserteq for bool check Signed-off-by: hanadi92 --- crates/matrix-sdk/src/client/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/matrix-sdk/src/client/mod.rs b/crates/matrix-sdk/src/client/mod.rs index a7dbe21be41..0085a384758 100644 --- a/crates/matrix-sdk/src/client/mod.rs +++ b/crates/matrix-sdk/src/client/mod.rs @@ -2374,6 +2374,6 @@ pub(crate) mod tests { .await; let msc4028_enabled = client.can_homeserver_push_encrypted_event_to_device().await.unwrap(); - assert_eq!(msc4028_enabled, true); + assert!(msc4028_enabled); } } From d84b61184c7581aea9cb652d6cde7d459a45ae30 Mon Sep 17 00:00:00 2001 From: hanadi92 Date: Thu, 7 Mar 2024 23:24:01 +0100 Subject: [PATCH 7/8] fix: documentation Signed-off-by: hanadi92 --- crates/matrix-sdk/src/client/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/matrix-sdk/src/client/mod.rs b/crates/matrix-sdk/src/client/mod.rs index 0085a384758..45102af092b 100644 --- a/crates/matrix-sdk/src/client/mod.rs +++ b/crates/matrix-sdk/src/client/mod.rs @@ -1449,7 +1449,7 @@ impl Client { Ok(unstable_features) } - /// Check whether [MSC 4028 push rule][rule] is enabled on the homeserver. + /// Check whether MSC 4028 is enabled on the homeserver. /// /// # Examples /// From d8ffdd5f7298ab39d40c3d5da4d9fcea91a87a62 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Fri, 8 Mar 2024 11:03:43 +0100 Subject: [PATCH 8/8] Apply suggestions from code review Signed-off-by: Benjamin Bouvier --- crates/matrix-sdk/src/client/mod.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/crates/matrix-sdk/src/client/mod.rs b/crates/matrix-sdk/src/client/mod.rs index 45102af092b..e372634ed9b 100644 --- a/crates/matrix-sdk/src/client/mod.rs +++ b/crates/matrix-sdk/src/client/mod.rs @@ -1435,7 +1435,7 @@ impl Client { /// # async { /// # let homeserver = Url::parse("http://localhost:8080")?; /// # let mut client = Client::new(homeserver).await?; - /// let unstable_features = client.unstable_features().await.unwrap(); + /// let unstable_features = client.unstable_features().await?; /// let msc_x = unstable_features.get("msc_x").unwrap_or(&false); /// # anyhow::Ok(()) }; /// ``` @@ -1460,16 +1460,11 @@ impl Client { /// # let homeserver = Url::parse("http://localhost:8080")?; /// # let mut client = Client::new(homeserver).await?; /// let msc4028_enabled = - /// client.can_homeserver_push_encrypted_event_to_device().await.unwrap(); + /// client.can_homeserver_push_encrypted_event_to_device().await?; /// # anyhow::Ok(()) }; /// ``` pub async fn can_homeserver_push_encrypted_event_to_device(&self) -> HttpResult { - match self.unstable_features().await { - Ok(unstable_feature) => { - Ok(unstable_feature.get("org.matrix.msc4028").copied().unwrap_or(false)) - } - Err(_) => Ok(false), - } + Ok(self.unstable_features().await?.get("org.matrix.msc4028").copied().unwrap_or(false)) } /// Get information of all our own devices.