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