Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sdk&ffi: server unstable features support for MSC4028 #3192

Merged
7 changes: 7 additions & 0 deletions bindings/matrix-sdk-ffi/src/notification_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,13 @@ 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 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a bit of logic here, and I think that this could be useful for other clients. Could this method go to the SDK, next to unstable_features, please? (and add a test for it too 🙏)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

of course! good hint. let me know if what I pushed goes in the direction of ur suggestion 👍

self.sdk_client.can_homeserver_push_encrypted_event_to_device().await.unwrap()
}

/// Set whether user mentions are enabled.
pub async fn set_user_mention_enabled(
&self,
Expand Down
1 change: 1 addition & 0 deletions crates/matrix-sdk/src/client/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@ impl ClientBuilder {
http_client,
base_client,
self.server_versions,
None,
self.respect_login_well_known,
event_cache,
#[cfg(feature = "e2e-encryption")]
Expand Down
102 changes: 102 additions & 0 deletions crates/matrix-sdk/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ pub(crate) struct ClientInner {
/// The Matrix versions the server supports (well-known ones only)
server_versions: OnceCell<Box<[MatrixVersion]>>,

/// The unstable features and their on/off state on the server
unstable_features: OnceCell<BTreeMap<String, bool>>,

/// 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.
Expand Down Expand Up @@ -292,6 +295,7 @@ impl ClientInner {
http_client: HttpClient,
base_client: BaseClient,
server_versions: Option<Box<[MatrixVersion]>>,
unstable_features: Option<BTreeMap<String, bool>>,
respect_login_well_known: bool,
event_cache: OnceCell<EventCache>,
#[cfg(feature = "e2e-encryption")] encryption_settings: EncryptionSettings,
Expand All @@ -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(),
Expand Down Expand Up @@ -1401,6 +1406,67 @@ impl Client {
Ok(server_versions)
}

/// Fetch unstable_features from homeserver
async fn request_unstable_features(&self) -> HttpResult<BTreeMap<String, bool>> {
let unstable_features: BTreeMap<String, bool> = 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?;
/// let msc_x = unstable_features.get("msc_x").unwrap_or(&false);
/// # anyhow::Ok(()) };
/// ```
pub async fn unstable_features(&self) -> HttpResult<&BTreeMap<String, bool>> {
let unstable_features = self
.inner
.unstable_features
.get_or_try_init(|| self.request_unstable_features())
.await?;

Ok(unstable_features)
}

/// Check whether MSC 4028 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?;
/// # anyhow::Ok(()) };
/// ```
pub async fn can_homeserver_push_encrypted_event_to_device(&self) -> HttpResult<bool> {
Ok(self.unstable_features().await?.get("org.matrix.msc4028").copied().unwrap_or(false))
}

/// Get information of all our own devices.
///
/// # Examples
Expand Down Expand Up @@ -2006,6 +2072,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")]
Expand Down Expand Up @@ -2269,4 +2336,39 @@ 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_request_unstable_features() {
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());
}

#[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!(msc4028_enabled);
}
}
3 changes: 2 additions & 1 deletion testing/matrix-sdk-test/src/test_json/api_responses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,8 @@ pub static VERSIONS: Lazy<JsonValue> = 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
}
})
});
Expand Down
Loading