Skip to content

Commit

Permalink
feat(ffi): Add FFI bindings for the new room privacy settings feature.
Browse files Browse the repository at this point in the history
  • Loading branch information
jmartinesp committed Jan 13, 2025
1 parent d9c1188 commit 5548f38
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 17 deletions.
25 changes: 14 additions & 11 deletions bindings/matrix-sdk-ffi/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -1462,13 +1451,27 @@ 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<RoomVisibility> for Visibility {
fn from(value: RoomVisibility) -> Self {
match value {
RoomVisibility::Public => Self::Public,
RoomVisibility::Private => Self::Private,
RoomVisibility::Custom { value } => value.as_str().into(),
}
}
}

impl From<Visibility> 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() },
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions bindings/matrix-sdk-ffi/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ impl From<RoomSendQueueError> for ClientError {
}
}

impl From<NotYetImplemented> 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.
///
Expand Down
166 changes: 163 additions & 3 deletions bindings/matrix-sdk-ffi/src/room.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -345,7 +347,7 @@ impl Room {
}

pub async fn room_info(&self) -> Result<RoomInfo, ClientError> {
Ok(RoomInfo::new(&self.inner).await?)
RoomInfo::new(&self.inner).await
}

pub fn subscribe_to_room_info_updates(
Expand Down Expand Up @@ -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<String>,
alt_aliases: Vec<String>,
) -> Result<(), ClientError> {
let new_alias = alias.map(TryInto::try_into).transpose()?;
let new_alt_aliases =
alt_aliases.into_iter().map(RoomAliasId::parse).collect::<Result<_, _>>()?;
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<bool, ClientError> {
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<bool, ClientError> {
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<RoomVisibility, ClientError> {
let visibility = self.inner.privacy_settings().get_room_visibility().await?;
Ok(visibility.into())
}
}

impl From<matrix_sdk::room::knock_requests::KnockRequest> for KnockRequest {
Expand Down Expand Up @@ -1254,3 +1355,62 @@ impl TryFrom<ComposerDraftType> 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<RumaHistoryVisibility> for RoomHistoryVisibility {
type Error = NotYetImplemented;
fn try_from(value: RumaHistoryVisibility) -> Result<Self, Self::Error> {
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<RoomHistoryVisibility> for RumaHistoryVisibility {
type Error = NotYetImplemented;
fn try_from(value: RoomHistoryVisibility) -> Result<Self, Self::Error> {
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),
}
}
}
8 changes: 6 additions & 2 deletions bindings/matrix-sdk-ffi/src/room_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -60,10 +61,12 @@ pub struct RoomInfo {
pinned_event_ids: Vec<String>,
/// The join rule for this room, if known.
join_rule: Option<JoinRule>,
/// 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<Self> {
pub(crate) async fn new(room: &matrix_sdk::Room) -> Result<Self, ClientError> {
let unread_notification_counts = room.unread_notification_counts();

let power_levels_map = room.users_with_power_levels().await;
Expand Down Expand Up @@ -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()?,
})
}
}
2 changes: 1 addition & 1 deletion bindings/matrix-sdk-ffi/src/room_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ impl RoomListItem {
}

async fn room_info(&self) -> Result<RoomInfo, ClientError> {
Ok(RoomInfo::new(self.inner.inner_room()).await?)
RoomInfo::new(self.inner.inner_room()).await
}

/// The room's current membership state.
Expand Down

0 comments on commit 5548f38

Please sign in to comment.