From f3f017b703ec4eee771aedb85d4504cd46536470 Mon Sep 17 00:00:00 2001 From: Lucas Feijo Date: Tue, 7 Apr 2026 16:21:21 -0300 Subject: [PATCH 1/5] expose room account data getter and setter --- bindings/matrix-sdk-ffi/src/room/mod.rs | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/bindings/matrix-sdk-ffi/src/room/mod.rs b/bindings/matrix-sdk-ffi/src/room/mod.rs index 8c0cfc92f61..b87798e10d4 100644 --- a/bindings/matrix-sdk-ffi/src/room/mod.rs +++ b/bindings/matrix-sdk-ffi/src/room/mod.rs @@ -38,6 +38,7 @@ use ruma::{ ServerName, UserId, assign, events::{ AnyMessageLikeEventContent, AnySyncTimelineEvent, + RoomAccountDataEventType as RumaRoomAccountDataEventType, receipt::ReceiptThread, room::{ MediaSource as RumaMediaSource, avatar::ImageInfo as RumaAvatarImageInfo, @@ -45,6 +46,7 @@ use ruma::{ join_rules::JoinRule as RumaJoinRule, message::RoomMessageEventContentWithoutRelation, }, }, + serde::Raw, }; use tracing::{error, warn}; @@ -699,6 +701,34 @@ impl Room { Ok(self.inner.set_unread_flag(new_value).await?) } + /// Get the content of the event of the given type out of the room's + /// account data store. + /// + /// It will be returned as a JSON string. + pub async fn account_data( + &self, + event_type: String, + ) -> Result, ClientError> { + let event_type = RumaRoomAccountDataEventType::from(event_type); + let event = self.inner.account_data(event_type).await?; + Ok(event.map(|e| e.json().get().to_owned())) + } + + /// Set the given account data content for the given event type in + /// this room. + /// + /// It should be supplied as a JSON string. + pub async fn set_account_data( + &self, + event_type: String, + content: String, + ) -> Result<(), ClientError> { + let event_type = RumaRoomAccountDataEventType::from(event_type); + let raw_content = Raw::from_json_string(content)?; + self.inner.set_account_data_raw(event_type, raw_content).await?; + Ok(()) + } + /// Mark a room as read, by attaching a read receipt on the latest event. /// /// Note: this does NOT unset the unread flag; it's the caller's From f4aab6ceed37e0a306e87c0b08ef6b69eed20ba9 Mon Sep 17 00:00:00 2001 From: Lucas Feijo Date: Tue, 7 Apr 2026 17:22:43 -0300 Subject: [PATCH 2/5] expose room state events getter --- bindings/matrix-sdk-ffi/src/room/mod.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/bindings/matrix-sdk-ffi/src/room/mod.rs b/bindings/matrix-sdk-ffi/src/room/mod.rs index b87798e10d4..04ef5da7e33 100644 --- a/bindings/matrix-sdk-ffi/src/room/mod.rs +++ b/bindings/matrix-sdk-ffi/src/room/mod.rs @@ -33,12 +33,14 @@ use matrix_sdk_ui::{ unable_to_decrypt_hook::UtdHookManager, }; use mime::Mime; +use matrix_sdk_base::deserialized_responses::RawAnySyncOrStrippedState; use ruma::{ EventId, Int, OwnedDeviceId, OwnedRoomOrAliasId, OwnedServerName, OwnedUserId, RoomAliasId, ServerName, UserId, assign, events::{ AnyMessageLikeEventContent, AnySyncTimelineEvent, RoomAccountDataEventType as RumaRoomAccountDataEventType, + StateEventType as RumaStateEventType, receipt::ReceiptThread, room::{ MediaSource as RumaMediaSource, avatar::ImageInfo as RumaAvatarImageInfo, @@ -729,6 +731,23 @@ impl Room { Ok(()) } + /// Get a specific state event in this room, from the local store. + /// + /// It will be returned as a raw JSON string, or `None` if no such + /// state event exists. + pub async fn get_state_event( + &self, + event_type: String, + state_key: String, + ) -> Result, ClientError> { + let event_type = RumaStateEventType::from(event_type); + let raw = self.inner.get_state_event(event_type, &state_key).await?; + Ok(raw.map(|e| match e { + RawAnySyncOrStrippedState::Sync(ev) => ev.json().get().to_owned(), + RawAnySyncOrStrippedState::Stripped(ev) => ev.json().get().to_owned(), + })) + } + /// Mark a room as read, by attaching a read receipt on the latest event. /// /// Note: this does NOT unset the unread flag; it's the caller's From 34ed326bbdb66f3af9f1ad2373c3b47699e840fc Mon Sep 17 00:00:00 2001 From: Lucas Feijo Date: Thu, 9 Apr 2026 14:29:01 -0300 Subject: [PATCH 3/5] chore(ffi): add changelog entry for room state and account data methods Made-with: Cursor --- bindings/matrix-sdk-ffi/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bindings/matrix-sdk-ffi/CHANGELOG.md b/bindings/matrix-sdk-ffi/CHANGELOG.md index 99db0fb5dd8..e54d31b461e 100644 --- a/bindings/matrix-sdk-ffi/CHANGELOG.md +++ b/bindings/matrix-sdk-ffi/CHANGELOG.md @@ -41,6 +41,9 @@ All notable changes to this project will be documented in this file. ### Features +- Expose `Room.account_data()`, `Room.set_account_data()`, and `Room.get_state_event()` + through FFI bindings, allowing non-Rust clients to read/write room-scoped account data + and read room state events. - Added the `Client::import_secrets_bundle` method. ([#6212](https://github.com/matrix-org/matrix-rust-sdk/pull/6212)) - [**breaking**] Remove support for `native-tls` and remove all feature From a22205743b49aa30920b4cfbfb05d0a24808b173 Mon Sep 17 00:00:00 2001 From: Lucas Feijo Date: Thu, 9 Apr 2026 14:47:26 -0300 Subject: [PATCH 4/5] style: fix import ordering and function signature formatting Move `matrix_sdk_base` import to alphabetical position and collapse single-param `account_data` signature to one line per rustfmt. Made-with: Cursor --- bindings/matrix-sdk-ffi/src/room/mod.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/room/mod.rs b/bindings/matrix-sdk-ffi/src/room/mod.rs index 04ef5da7e33..80f447828dc 100644 --- a/bindings/matrix-sdk-ffi/src/room/mod.rs +++ b/bindings/matrix-sdk-ffi/src/room/mod.rs @@ -27,13 +27,13 @@ use matrix_sdk::{ }, send_queue::RoomSendQueueUpdate as SdkRoomSendQueueUpdate, }; +use matrix_sdk_base::deserialized_responses::RawAnySyncOrStrippedState; use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm}; use matrix_sdk_ui::{ timeline::{RoomExt, TimelineBuilder, default_event_filter}, unable_to_decrypt_hook::UtdHookManager, }; use mime::Mime; -use matrix_sdk_base::deserialized_responses::RawAnySyncOrStrippedState; use ruma::{ EventId, Int, OwnedDeviceId, OwnedRoomOrAliasId, OwnedServerName, OwnedUserId, RoomAliasId, ServerName, UserId, assign, @@ -707,10 +707,7 @@ impl Room { /// account data store. /// /// It will be returned as a JSON string. - pub async fn account_data( - &self, - event_type: String, - ) -> Result, ClientError> { + pub async fn account_data(&self, event_type: String) -> Result, ClientError> { let event_type = RumaRoomAccountDataEventType::from(event_type); let event = self.inner.account_data(event_type).await?; Ok(event.map(|e| e.json().get().to_owned())) From 4e78fa78f43106864b192e5b46c4f47314a92bd1 Mon Sep 17 00:00:00 2001 From: Lucas Feijo Date: Mon, 13 Apr 2026 13:31:35 -0300 Subject: [PATCH 5/5] rename room ffi json methods Made-with: Cursor --- bindings/matrix-sdk-ffi/src/room/mod.rs | 26 +++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/room/mod.rs b/bindings/matrix-sdk-ffi/src/room/mod.rs index 80f447828dc..b4b8c3f8cad 100644 --- a/bindings/matrix-sdk-ffi/src/room/mod.rs +++ b/bindings/matrix-sdk-ffi/src/room/mod.rs @@ -704,20 +704,25 @@ impl Room { } /// Get the content of the event of the given type out of the room's - /// account data store. + /// account data store as a JSON string. /// - /// It will be returned as a JSON string. - pub async fn account_data(&self, event_type: String) -> Result, ClientError> { + /// This is mostly useful for custom event types that are not modeled by + /// typed SDK APIs. + pub async fn account_data_json( + &self, + event_type: String, + ) -> Result, ClientError> { let event_type = RumaRoomAccountDataEventType::from(event_type); let event = self.inner.account_data(event_type).await?; Ok(event.map(|e| e.json().get().to_owned())) } /// Set the given account data content for the given event type in - /// this room. + /// this room, from a JSON string. /// - /// It should be supplied as a JSON string. - pub async fn set_account_data( + /// This is mostly useful for custom event types that are not modeled by + /// typed SDK APIs. + pub async fn set_account_data_json( &self, event_type: String, content: String, @@ -728,11 +733,12 @@ impl Room { Ok(()) } - /// Get a specific state event in this room, from the local store. + /// Get a specific state event in this room, from the local store, as a + /// JSON string. /// - /// It will be returned as a raw JSON string, or `None` if no such - /// state event exists. - pub async fn get_state_event( + /// This is mostly useful for custom event types that are not modeled by + /// typed SDK APIs. Returns `None` if no such state event exists. + pub async fn get_state_event_json( &self, event_type: String, state_key: String,