From 5548f383932ab49546f8b5a365233e23597838b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Thu, 9 Jan 2025 16:45:45 +0100 Subject: [PATCH] feat(ffi): Add FFI bindings for the new room privacy settings feature. --- bindings/matrix-sdk-ffi/src/client.rs | 25 ++-- bindings/matrix-sdk-ffi/src/error.rs | 6 + bindings/matrix-sdk-ffi/src/room.rs | 166 ++++++++++++++++++++++- bindings/matrix-sdk-ffi/src/room_info.rs | 8 +- bindings/matrix-sdk-ffi/src/room_list.rs | 2 +- 5 files changed, 190 insertions(+), 17 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/client.rs b/bindings/matrix-sdk-ffi/src/client.rs index 54e6ac79bda..af8ddb4389e 100644 --- a/bindings/matrix-sdk-ffi/src/client.rs +++ b/bindings/matrix-sdk-ffi/src/client.rs @@ -1152,17 +1152,6 @@ impl Client { let alias = RoomAliasId::parse(alias)?; self.inner.is_room_alias_available(&alias).await.map_err(Into::into) } - - /// Creates a new room alias associated with the provided room id. - pub async fn create_room_alias( - &self, - room_alias: String, - room_id: String, - ) -> Result<(), ClientError> { - let room_alias = RoomAliasId::parse(room_alias)?; - let room_id = RoomId::parse(room_id)?; - self.inner.create_room_alias(&room_alias, &room_id).await.map_err(Into::into) - } } #[matrix_sdk_ffi_macros::export(callback_interface)] @@ -1462,6 +1451,9 @@ pub enum RoomVisibility { /// Indicates that the room will not be shown in the published room list. Private, + + /// A custom value that's not present in the spec. + Custom { value: String }, } impl From for Visibility { @@ -1469,6 +1461,17 @@ impl From for Visibility { match value { RoomVisibility::Public => Self::Public, RoomVisibility::Private => Self::Private, + RoomVisibility::Custom { value } => value.as_str().into(), + } + } +} + +impl From for RoomVisibility { + fn from(value: Visibility) -> Self { + match value { + Visibility::Public => Self::Public, + Visibility::Private => Self::Private, + _ => Self::Custom { value: value.as_str().to_owned() }, } } } diff --git a/bindings/matrix-sdk-ffi/src/error.rs b/bindings/matrix-sdk-ffi/src/error.rs index 9d793b07020..5ce1bf48e33 100644 --- a/bindings/matrix-sdk-ffi/src/error.rs +++ b/bindings/matrix-sdk-ffi/src/error.rs @@ -155,6 +155,12 @@ impl From for ClientError { } } +impl From for ClientError { + fn from(_: NotYetImplemented) -> Self { + Self::new("This functionality is not implemented yet.") + } +} + /// Bindings version of the sdk type replacing OwnedUserId/DeviceIds with simple /// String. /// diff --git a/bindings/matrix-sdk-ffi/src/room.rs b/bindings/matrix-sdk-ffi/src/room.rs index e76395b381e..62f7b678021 100644 --- a/bindings/matrix-sdk-ffi/src/room.rs +++ b/bindings/matrix-sdk-ffi/src/room.rs @@ -20,7 +20,8 @@ use ruma::{ call::notify, room::{ avatar::ImageInfo as RumaAvatarImageInfo, - message::RoomMessageEventContentWithoutRelation, + history_visibility::HistoryVisibility as RumaHistoryVisibility, + join_rules::JoinRule as RumaJoinRule, message::RoomMessageEventContentWithoutRelation, power_levels::RoomPowerLevels as RumaPowerLevels, MediaSource, }, AnyMessageLikeEventContent, AnySyncTimelineEvent, TimelineEventType, @@ -33,7 +34,8 @@ use tracing::error; use super::RUNTIME; use crate::{ chunk_iterator::ChunkIterator, - error::{ClientError, MediaInfoError, RoomError}, + client::{JoinRule, RoomVisibility}, + error::{ClientError, MediaInfoError, NotYetImplemented, RoomError}, event::{MessageLikeEventType, RoomMessageEventMessageType, StateEventType}, identity_status_change::IdentityStatusChange, room_info::RoomInfo, @@ -345,7 +347,7 @@ impl Room { } pub async fn room_info(&self) -> Result { - Ok(RoomInfo::new(&self.inner).await?) + RoomInfo::new(&self.inner).await } pub fn subscribe_to_room_info_updates( @@ -941,6 +943,105 @@ impl Room { let (cache, _drop_guards) = self.inner.event_cache().await?; Ok(cache.debug_string().await) } + + /// Update the canonical alias of the room. + /// + /// Note that publishing the alias in the room directory is done separately. + pub async fn update_canonical_alias( + &self, + alias: Option, + alt_aliases: Vec, + ) -> Result<(), ClientError> { + let new_alias = alias.map(TryInto::try_into).transpose()?; + let new_alt_aliases = + alt_aliases.into_iter().map(RoomAliasId::parse).collect::>()?; + self.inner + .privacy_settings() + .update_canonical_alias(new_alias, new_alt_aliases) + .await + .map_err(Into::into) + } + + /// Publish a new room alias for this room in the room directory. + /// + /// Returns: + /// - `true` if the room alias didn't exist and it's now published. + /// - `false` if the room alias was already present so it couldn't be + /// published. + pub async fn publish_room_alias_in_room_directory( + &self, + alias: String, + ) -> Result { + let new_alias = RoomAliasId::parse(alias)?; + self.inner + .privacy_settings() + .publish_room_alias_in_room_directory(&new_alias) + .await + .map_err(Into::into) + } + + /// Remove an existing room alias for this room in the room directory. + /// + /// Returns: + /// - `true` if the room alias was present and it's now removed from the + /// room directory. + /// - `false` if the room alias didn't exist so it couldn't be removed. + pub async fn remove_room_alias_from_room_directory( + &self, + alias: String, + ) -> Result { + let alias = RoomAliasId::parse(alias)?; + self.inner + .privacy_settings() + .remove_room_alias_from_room_directory(&alias) + .await + .map_err(Into::into) + } + + /// Enable End-to-end encryption in this room. + pub async fn enable_encryption(&self) -> Result<(), ClientError> { + self.inner.enable_encryption().await.map_err(Into::into) + } + + /// Update room history visibility for this room. + pub async fn update_history_visibility( + &self, + visibility: RoomHistoryVisibility, + ) -> Result<(), ClientError> { + let visibility: RumaHistoryVisibility = visibility.try_into()?; + self.inner + .privacy_settings() + .update_room_history_visibility(visibility) + .await + .map_err(Into::into) + } + + /// Update the join rule for this room. + pub async fn update_join_rules(&self, new_rule: JoinRule) -> Result<(), ClientError> { + let new_rule: RumaJoinRule = new_rule.try_into()?; + self.inner.privacy_settings().update_join_rule(new_rule).await.map_err(Into::into) + } + + /// Update the room's visibility in the room directory. + pub async fn update_room_visibility( + &self, + visibility: RoomVisibility, + ) -> Result<(), ClientError> { + self.inner + .privacy_settings() + .update_room_visibility(visibility.into()) + .await + .map_err(Into::into) + } + + /// Returns the visibility for this room in the room directory. + /// + /// [Public](`RoomVisibility::Public`) rooms are listed in the room + /// directory and can be found using it. + pub async fn get_room_visibility(&self) -> Result { + let visibility = self.inner.privacy_settings().get_room_visibility().await?; + Ok(visibility.into()) + } } impl From for KnockRequest { @@ -1254,3 +1355,62 @@ impl TryFrom for SdkComposerDraftType { Ok(draft_type) } } + +#[derive(Debug, Clone, uniffi::Enum)] +pub enum RoomHistoryVisibility { + /// Previous events are accessible to newly joined members from the point + /// they were invited onwards. + /// + /// Events stop being accessible when the member's state changes to + /// something other than *invite* or *join*. + Invited, + + /// Previous events are accessible to newly joined members from the point + /// they joined the room onwards. + /// Events stop being accessible when the member's state changes to + /// something other than *join*. + Joined, + + /// Previous events are always accessible to newly joined members. + /// + /// All events in the room are accessible, even those sent when the member + /// was not a part of the room. + Shared, + + /// All events while this is the `HistoryVisibility` value may be shared by + /// any participating homeserver with anyone, regardless of whether they + /// have ever joined the room. + WorldReadable, + + /// A custom visibility value. + Custom { value: String }, +} + +impl TryFrom for RoomHistoryVisibility { + type Error = NotYetImplemented; + fn try_from(value: RumaHistoryVisibility) -> Result { + match value { + RumaHistoryVisibility::Invited => Ok(RoomHistoryVisibility::Invited), + RumaHistoryVisibility::Shared => Ok(RoomHistoryVisibility::Shared), + RumaHistoryVisibility::WorldReadable => Ok(RoomHistoryVisibility::WorldReadable), + RumaHistoryVisibility::Joined => Ok(RoomHistoryVisibility::Joined), + RumaHistoryVisibility::_Custom(_) => { + Ok(RoomHistoryVisibility::Custom { value: value.to_string() }) + } + _ => Err(NotYetImplemented), + } + } +} + +impl TryFrom for RumaHistoryVisibility { + type Error = NotYetImplemented; + fn try_from(value: RoomHistoryVisibility) -> Result { + match value { + RoomHistoryVisibility::Invited => Ok(RumaHistoryVisibility::Invited), + RoomHistoryVisibility::Shared => Ok(RumaHistoryVisibility::Shared), + RoomHistoryVisibility::Joined => Ok(RumaHistoryVisibility::Joined), + RoomHistoryVisibility::WorldReadable => Ok(RumaHistoryVisibility::WorldReadable), + RoomHistoryVisibility::Custom { .. } => Err(NotYetImplemented), + } + } +} diff --git a/bindings/matrix-sdk-ffi/src/room_info.rs b/bindings/matrix-sdk-ffi/src/room_info.rs index 1b0f27e7114..1ed6a48ddb9 100644 --- a/bindings/matrix-sdk-ffi/src/room_info.rs +++ b/bindings/matrix-sdk-ffi/src/room_info.rs @@ -5,8 +5,9 @@ use tracing::warn; use crate::{ client::JoinRule, + error::ClientError, notification_settings::RoomNotificationMode, - room::{Membership, RoomHero}, + room::{Membership, RoomHero, RoomHistoryVisibility}, room_member::RoomMember, }; @@ -60,10 +61,12 @@ pub struct RoomInfo { pinned_event_ids: Vec, /// The join rule for this room, if known. join_rule: Option, + /// The history visibility for this room, if known. + history_visibility: RoomHistoryVisibility, } impl RoomInfo { - pub(crate) async fn new(room: &matrix_sdk::Room) -> matrix_sdk::Result { + pub(crate) async fn new(room: &matrix_sdk::Room) -> Result { let unread_notification_counts = room.unread_notification_counts(); let power_levels_map = room.users_with_power_levels().await; @@ -128,6 +131,7 @@ impl RoomInfo { num_unread_mentions: room.num_unread_mentions(), pinned_event_ids, join_rule: join_rule.ok(), + history_visibility: room.history_visibility_or_default().try_into()?, }) } } diff --git a/bindings/matrix-sdk-ffi/src/room_list.rs b/bindings/matrix-sdk-ffi/src/room_list.rs index 1c193b0ac8d..09e49da741d 100644 --- a/bindings/matrix-sdk-ffi/src/room_list.rs +++ b/bindings/matrix-sdk-ffi/src/room_list.rs @@ -566,7 +566,7 @@ impl RoomListItem { } async fn room_info(&self) -> Result { - Ok(RoomInfo::new(self.inner.inner_room()).await?) + RoomInfo::new(self.inner.inner_room()).await } /// The room's current membership state.