From 47c8df0ef815634b18dfa66aa0c8d79650eb6f9f Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Thu, 19 Jun 2025 14:56:53 +0300 Subject: [PATCH] chore(ffi): move the room power levels to their own file and restructure the code --- .../src/{room.rs => room/mod.rs} | 163 +---------------- .../matrix-sdk-ffi/src/room/power_levels.rs | 167 ++++++++++++++++++ 2 files changed, 172 insertions(+), 158 deletions(-) rename bindings/matrix-sdk-ffi/src/{room.rs => room/mod.rs} (89%) create mode 100644 bindings/matrix-sdk-ffi/src/room/power_levels.rs diff --git a/bindings/matrix-sdk-ffi/src/room.rs b/bindings/matrix-sdk-ffi/src/room/mod.rs similarity index 89% rename from bindings/matrix-sdk-ffi/src/room.rs rename to bindings/matrix-sdk-ffi/src/room/mod.rs index 422277102..624d42d17 100644 --- a/bindings/matrix-sdk-ffi/src/room.rs +++ b/bindings/matrix-sdk-ffi/src/room/mod.rs @@ -26,20 +26,20 @@ use ruma::{ avatar::ImageInfo as RumaAvatarImageInfo, history_visibility::HistoryVisibility as RumaHistoryVisibility, join_rules::JoinRule as RumaJoinRule, message::RoomMessageEventContentWithoutRelation, - power_levels::RoomPowerLevels as RumaPowerLevels, MediaSource, + MediaSource, }, - AnyMessageLikeEventContent, AnySyncTimelineEvent, TimelineEventType, + AnyMessageLikeEventContent, AnySyncTimelineEvent, }, EventId, Int, OwnedDeviceId, OwnedRoomOrAliasId, OwnedServerName, OwnedUserId, RoomAliasId, ServerName, UserId, }; use tracing::{error, warn}; +use self::power_levels::RoomPowerLevels; use crate::{ chunk_iterator::ChunkIterator, client::{JoinRule, RoomVisibility}, error::{ClientError, MediaInfoError, NotYetImplemented, RoomError}, - event::{MessageLikeEventType, StateEventType}, identity_status_change::IdentityStatusChange, live_location_share::{LastLocation, LiveLocationShare}, room_info::RoomInfo, @@ -55,6 +55,8 @@ use crate::{ TaskHandle, }; +mod power_levels; + #[derive(Debug, Clone, uniffi::Enum)] pub enum Membership { Invited, @@ -1228,161 +1230,6 @@ pub fn matrix_to_room_alias_permalink( Ok(room_alias.matrix_to_uri().to_string()) } -#[derive(uniffi::Object)] -pub struct RoomPowerLevels { - inner: RumaPowerLevels, -} - -#[matrix_sdk_ffi_macros::export] -impl RoomPowerLevels { - fn values(&self) -> RoomPowerLevelsValues { - self.inner.clone().into() - } - - /// Returns true if the user with the given user_id is able to ban in the - /// room. - /// - /// The call may fail if there is an error in getting the power levels. - pub fn can_user_ban(&self, user_id: String) -> Result { - let user_id = UserId::parse(&user_id)?; - Ok(self.inner.user_can_ban(&user_id)) - } - - /// Returns true if the user with the given user_id is able to redact - /// their own messages in the room. - /// - /// The call may fail if there is an error in getting the power levels. - pub fn can_user_redact_own(&self, user_id: String) -> Result { - let user_id = UserId::parse(&user_id)?; - Ok(self.inner.user_can_redact_own_event(&user_id)) - } - - /// Returns true if the user with the given user_id is able to redact - /// messages of other users in the room. - /// - /// The call may fail if there is an error in getting the power levels. - pub fn can_user_redact_other(&self, user_id: String) -> Result { - let user_id = UserId::parse(&user_id)?; - Ok(self.inner.user_can_redact_event_of_other(&user_id)) - } - - /// Returns true if the user with the given user_id is able to kick in the - /// room. - /// - /// The call may fail if there is an error in getting the power levels. - pub fn can_user_invite(&self, user_id: String) -> Result { - let user_id = UserId::parse(&user_id)?; - Ok(self.inner.user_can_invite(&user_id)) - } - - /// Returns true if the user with the given user_id is able to kick in the - /// room. - /// - /// The call may fail if there is an error in getting the power levels. - pub fn can_user_kick(&self, user_id: String) -> Result { - let user_id = UserId::parse(&user_id)?; - Ok(self.inner.user_can_kick(&user_id)) - } - - /// Returns true if the user with the given user_id is able to send a - /// specific state event type in the room. - /// - /// The call may fail if there is an error in getting the power levels. - pub fn can_user_send_state( - &self, - user_id: String, - state_event: StateEventType, - ) -> Result { - let user_id = UserId::parse(&user_id)?; - Ok(self.inner.user_can_send_state(&user_id, state_event.into())) - } - - /// Returns true if the user with the given user_id is able to send a - /// specific message type in the room. - /// - /// The call may fail if there is an error in getting the power levels. - pub fn can_user_send_message( - &self, - user_id: String, - message: MessageLikeEventType, - ) -> Result { - let user_id = UserId::parse(&user_id)?; - Ok(self.inner.user_can_send_message(&user_id, message.into())) - } - - /// Returns true if the user with the given user_id is able to pin or unpin - /// events in the room. - /// - /// The call may fail if there is an error in getting the power levels. - pub fn can_user_pin_unpin(&self, user_id: String) -> Result { - let user_id = UserId::parse(&user_id)?; - Ok(self.inner.user_can_send_state(&user_id, StateEventType::RoomPinnedEvents.into())) - } - - /// Returns true if the user with the given user_id is able to trigger a - /// notification in the room. - /// - /// The call may fail if there is an error in getting the power levels. - pub fn can_user_trigger_room_notification(&self, user_id: String) -> Result { - let user_id = UserId::parse(&user_id)?; - Ok(self.inner.user_can_trigger_room_notification(&user_id)) - } -} - -impl From for RoomPowerLevels { - fn from(value: RumaPowerLevels) -> Self { - Self { inner: value } - } -} - -#[derive(uniffi::Record)] -pub struct RoomPowerLevelsValues { - /// The level required to ban a user. - pub ban: i64, - /// The level required to invite a user. - pub invite: i64, - /// The level required to kick a user. - pub kick: i64, - /// The level required to redact an event. - pub redact: i64, - /// The default level required to send message events. - pub events_default: i64, - /// The default level required to send state events. - pub state_default: i64, - /// The default power level for every user in the room. - pub users_default: i64, - /// The level required to change the room's name. - pub room_name: i64, - /// The level required to change the room's avatar. - pub room_avatar: i64, - /// The level required to change the room's topic. - pub room_topic: i64, -} - -impl From for RoomPowerLevelsValues { - fn from(value: RumaPowerLevels) -> Self { - fn state_event_level_for( - power_levels: &RumaPowerLevels, - event_type: &TimelineEventType, - ) -> i64 { - let default_state: i64 = power_levels.state_default.into(); - power_levels.events.get(event_type).map_or(default_state, |&level| level.into()) - } - Self { - ban: value.ban.into(), - invite: value.invite.into(), - kick: value.kick.into(), - redact: value.redact.into(), - events_default: value.events_default.into(), - state_default: value.state_default.into(), - users_default: value.users_default.into(), - room_name: state_event_level_for(&value, &TimelineEventType::RoomName), - room_avatar: state_event_level_for(&value, &TimelineEventType::RoomAvatar), - room_topic: state_event_level_for(&value, &TimelineEventType::RoomTopic), - } - } -} - #[matrix_sdk_ffi_macros::export(callback_interface)] pub trait RoomInfoListener: SyncOutsideWasm + SendOutsideWasm { fn call(&self, room_info: RoomInfo); diff --git a/bindings/matrix-sdk-ffi/src/room/power_levels.rs b/bindings/matrix-sdk-ffi/src/room/power_levels.rs new file mode 100644 index 000000000..3c55105f5 --- /dev/null +++ b/bindings/matrix-sdk-ffi/src/room/power_levels.rs @@ -0,0 +1,167 @@ +use anyhow::Result; +use ruma::{ + events::{room::power_levels::RoomPowerLevels as RumaPowerLevels, TimelineEventType}, + UserId, +}; + +use crate::{ + error::ClientError, + event::{MessageLikeEventType, StateEventType}, +}; + +#[derive(uniffi::Object)] +pub struct RoomPowerLevels { + inner: RumaPowerLevels, +} + +#[matrix_sdk_ffi_macros::export] +impl RoomPowerLevels { + fn values(&self) -> RoomPowerLevelsValues { + self.inner.clone().into() + } + + /// Returns true if the user with the given user_id is able to ban in the + /// room. + /// + /// The call may fail if there is an error in getting the power levels. + pub fn can_user_ban(&self, user_id: String) -> Result { + let user_id = UserId::parse(&user_id)?; + Ok(self.inner.user_can_ban(&user_id)) + } + + /// Returns true if the user with the given user_id is able to redact + /// their own messages in the room. + /// + /// The call may fail if there is an error in getting the power levels. + pub fn can_user_redact_own(&self, user_id: String) -> Result { + let user_id = UserId::parse(&user_id)?; + Ok(self.inner.user_can_redact_own_event(&user_id)) + } + + /// Returns true if the user with the given user_id is able to redact + /// messages of other users in the room. + /// + /// The call may fail if there is an error in getting the power levels. + pub fn can_user_redact_other(&self, user_id: String) -> Result { + let user_id = UserId::parse(&user_id)?; + Ok(self.inner.user_can_redact_event_of_other(&user_id)) + } + + /// Returns true if the user with the given user_id is able to kick in the + /// room. + /// + /// The call may fail if there is an error in getting the power levels. + pub fn can_user_invite(&self, user_id: String) -> Result { + let user_id = UserId::parse(&user_id)?; + Ok(self.inner.user_can_invite(&user_id)) + } + + /// Returns true if the user with the given user_id is able to kick in the + /// room. + /// + /// The call may fail if there is an error in getting the power levels. + pub fn can_user_kick(&self, user_id: String) -> Result { + let user_id = UserId::parse(&user_id)?; + Ok(self.inner.user_can_kick(&user_id)) + } + + /// Returns true if the user with the given user_id is able to send a + /// specific state event type in the room. + /// + /// The call may fail if there is an error in getting the power levels. + pub fn can_user_send_state( + &self, + user_id: String, + state_event: StateEventType, + ) -> Result { + let user_id = UserId::parse(&user_id)?; + Ok(self.inner.user_can_send_state(&user_id, state_event.into())) + } + + /// Returns true if the user with the given user_id is able to send a + /// specific message type in the room. + /// + /// The call may fail if there is an error in getting the power levels. + pub fn can_user_send_message( + &self, + user_id: String, + message: MessageLikeEventType, + ) -> Result { + let user_id = UserId::parse(&user_id)?; + Ok(self.inner.user_can_send_message(&user_id, message.into())) + } + + /// Returns true if the user with the given user_id is able to pin or unpin + /// events in the room. + /// + /// The call may fail if there is an error in getting the power levels. + pub fn can_user_pin_unpin(&self, user_id: String) -> Result { + let user_id = UserId::parse(&user_id)?; + Ok(self.inner.user_can_send_state(&user_id, StateEventType::RoomPinnedEvents.into())) + } + + /// Returns true if the user with the given user_id is able to trigger a + /// notification in the room. + /// + /// The call may fail if there is an error in getting the power levels. + pub fn can_user_trigger_room_notification(&self, user_id: String) -> Result { + let user_id = UserId::parse(&user_id)?; + Ok(self.inner.user_can_trigger_room_notification(&user_id)) + } +} + +impl From for RoomPowerLevels { + fn from(value: RumaPowerLevels) -> Self { + Self { inner: value } + } +} + +/// This intermediary struct is used to expose the power levels values through +/// FFI and work around it not exposing public exported object fields. +#[derive(uniffi::Record)] +pub struct RoomPowerLevelsValues { + /// The level required to ban a user. + pub ban: i64, + /// The level required to invite a user. + pub invite: i64, + /// The level required to kick a user. + pub kick: i64, + /// The level required to redact an event. + pub redact: i64, + /// The default level required to send message events. + pub events_default: i64, + /// The default level required to send state events. + pub state_default: i64, + /// The default power level for every user in the room. + pub users_default: i64, + /// The level required to change the room's name. + pub room_name: i64, + /// The level required to change the room's avatar. + pub room_avatar: i64, + /// The level required to change the room's topic. + pub room_topic: i64, +} + +impl From for RoomPowerLevelsValues { + fn from(value: RumaPowerLevels) -> Self { + fn state_event_level_for( + power_levels: &RumaPowerLevels, + event_type: &TimelineEventType, + ) -> i64 { + let default_state: i64 = power_levels.state_default.into(); + power_levels.events.get(event_type).map_or(default_state, |&level| level.into()) + } + Self { + ban: value.ban.into(), + invite: value.invite.into(), + kick: value.kick.into(), + redact: value.redact.into(), + events_default: value.events_default.into(), + state_default: value.state_default.into(), + users_default: value.users_default.into(), + room_name: state_event_level_for(&value, &TimelineEventType::RoomName), + room_avatar: state_event_level_for(&value, &TimelineEventType::RoomAvatar), + room_topic: state_event_level_for(&value, &TimelineEventType::RoomTopic), + } + } +}