matrix_sdk_ffi/
room_directory_search.rs1use std::{fmt::Debug, sync::Arc};
17
18use eyeball_im::VectorDiff;
19use futures_util::StreamExt;
20use matrix_sdk::room_directory_search::RoomDirectorySearch as SdkRoomDirectorySearch;
21use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm};
22use ruma::ServerName;
23use tokio::sync::RwLock;
24
25use crate::{error::ClientError, runtime::get_runtime_handle, task_handle::TaskHandle};
26
27#[derive(uniffi::Enum)]
28pub enum PublicRoomJoinRule {
29 Public,
30 Knock,
31 Restricted,
32 KnockRestricted,
33 Invite,
34}
35
36impl TryFrom<ruma::room::JoinRuleKind> for PublicRoomJoinRule {
37 type Error = String;
38
39 fn try_from(value: ruma::room::JoinRuleKind) -> Result<Self, Self::Error> {
40 match value {
41 ruma::room::JoinRuleKind::Public => Ok(Self::Public),
42 ruma::room::JoinRuleKind::Knock => Ok(Self::Knock),
43 ruma::room::JoinRuleKind::Restricted => Ok(Self::Restricted),
44 ruma::room::JoinRuleKind::KnockRestricted => Ok(Self::KnockRestricted),
45 ruma::room::JoinRuleKind::Invite => Ok(Self::Invite),
46 rule => Err(format!("unsupported join rule: {rule:?}")),
47 }
48 }
49}
50
51#[derive(uniffi::Record)]
52pub struct RoomDescription {
53 pub room_id: String,
54 pub name: Option<String>,
55 pub topic: Option<String>,
56 pub alias: Option<String>,
57 pub avatar_url: Option<String>,
58 pub join_rule: Option<PublicRoomJoinRule>,
59 pub is_world_readable: bool,
60 pub joined_members: u64,
61}
62
63impl From<matrix_sdk::room_directory_search::RoomDescription> for RoomDescription {
64 fn from(value: matrix_sdk::room_directory_search::RoomDescription) -> Self {
65 Self {
66 room_id: value.room_id.to_string(),
67 name: value.name,
68 topic: value.topic,
69 alias: value.alias.map(|alias| alias.to_string()),
70 avatar_url: value.avatar_url.map(|url| url.to_string()),
71 join_rule: value.join_rule.try_into().ok(),
72 is_world_readable: value.is_world_readable,
73 joined_members: value.joined_members,
74 }
75 }
76}
77
78#[derive(uniffi::Object)]
85pub struct RoomDirectorySearch {
86 pub(crate) inner: RwLock<SdkRoomDirectorySearch>,
87}
88
89impl RoomDirectorySearch {
90 pub fn new(inner: SdkRoomDirectorySearch) -> Self {
91 Self { inner: RwLock::new(inner) }
92 }
93}
94
95#[matrix_sdk_ffi_macros::export]
96impl RoomDirectorySearch {
97 pub async fn next_page(&self) -> Result<(), ClientError> {
99 let mut inner = self.inner.write().await;
100 inner.next_page().await?;
101 Ok(())
102 }
103
104 pub async fn search(
115 &self,
116 filter: Option<String>,
117 batch_size: u32,
118 via_server_name: Option<String>,
119 ) -> Result<(), ClientError> {
120 let server = via_server_name.map(ServerName::parse).transpose()?;
121 let mut inner = self.inner.write().await;
122 inner.search(filter, batch_size, server).await?;
123 Ok(())
124 }
125
126 pub async fn loaded_pages(&self) -> Result<u32, ClientError> {
128 let inner = self.inner.read().await;
129 Ok(inner.loaded_pages() as u32)
130 }
131
132 pub async fn is_at_last_page(&self) -> Result<bool, ClientError> {
134 let inner = self.inner.read().await;
135 Ok(inner.is_at_last_page())
136 }
137
138 pub async fn results(
141 &self,
142 listener: Box<dyn RoomDirectorySearchEntriesListener>,
143 ) -> Arc<TaskHandle> {
144 let (initial_values, mut stream) = self.inner.read().await.results();
145
146 listener.on_update(vec![RoomDirectorySearchEntryUpdate::Reset {
147 values: initial_values.into_iter().map(Into::into).collect(),
148 }]);
149
150 Arc::new(TaskHandle::new(get_runtime_handle().spawn(async move {
151 while let Some(diffs) = stream.next().await {
152 listener.on_update(diffs.into_iter().map(|diff| diff.into()).collect());
153 }
154 })))
155 }
156}
157
158#[derive(uniffi::Enum)]
159pub enum RoomDirectorySearchEntryUpdate {
160 Append { values: Vec<RoomDescription> },
161 Clear,
162 PushFront { value: RoomDescription },
163 PushBack { value: RoomDescription },
164 PopFront,
165 PopBack,
166 Insert { index: u32, value: RoomDescription },
167 Set { index: u32, value: RoomDescription },
168 Remove { index: u32 },
169 Truncate { length: u32 },
170 Reset { values: Vec<RoomDescription> },
171}
172
173impl From<VectorDiff<matrix_sdk::room_directory_search::RoomDescription>>
174 for RoomDirectorySearchEntryUpdate
175{
176 fn from(diff: VectorDiff<matrix_sdk::room_directory_search::RoomDescription>) -> Self {
177 match diff {
178 VectorDiff::Append { values } => {
179 Self::Append { values: values.into_iter().map(|v| v.into()).collect() }
180 }
181 VectorDiff::Clear => Self::Clear,
182 VectorDiff::PushFront { value } => Self::PushFront { value: value.into() },
183 VectorDiff::PushBack { value } => Self::PushBack { value: value.into() },
184 VectorDiff::PopFront => Self::PopFront,
185 VectorDiff::PopBack => Self::PopBack,
186 VectorDiff::Insert { index, value } => {
187 Self::Insert { index: index as u32, value: value.into() }
188 }
189 VectorDiff::Set { index, value } => {
190 Self::Set { index: index as u32, value: value.into() }
191 }
192 VectorDiff::Remove { index } => Self::Remove { index: index as u32 },
193 VectorDiff::Truncate { length } => Self::Truncate { length: length as u32 },
194 VectorDiff::Reset { values } => {
195 Self::Reset { values: values.into_iter().map(|v| v.into()).collect() }
196 }
197 }
198 }
199}
200
201#[matrix_sdk_ffi_macros::export(callback_interface)]
202pub trait RoomDirectorySearchEntriesListener: SendOutsideWasm + SyncOutsideWasm + Debug {
203 fn on_update(&self, room_entries_update: Vec<RoomDirectorySearchEntryUpdate>);
204}