chore: address first batch of review comments

This commit is contained in:
Benjamin Bouvier
2026-04-13 17:53:20 +02:00
parent 89b10f1f88
commit a9475f35e7
6 changed files with 55 additions and 21 deletions

View File

@@ -360,6 +360,17 @@ impl ClientBuilder {
Arc::new(builder)
}
/// Set up the search index store for this client, which is used to store
/// the message search index locally.
///
/// As soon as this is enabled, messages will start to be indexed, and can
/// be later queried for search.
///
/// `path` is the directory where the search index will be stored. It must
/// be unique per session.
///
/// `password` is an optional password to encrypt the search index at rest.
/// If `None`, the search index will be stored unencrypted.
pub fn with_search_index_store(
self: Arc<Self>,
path: String,

View File

@@ -24,10 +24,7 @@ use matrix_sdk::{
room::{calls::CallError, edit::EditError},
send_queue::RoomSendQueueError,
};
use matrix_sdk_ui::{
encryption_sync_service, notification_client, search::SearchError, spaces, sync_service,
timeline,
};
use matrix_sdk_ui::{encryption_sync_service, notification_client, spaces, sync_service, timeline};
use ruma::{
MilliSecondsSinceUnixEpoch,
api::error::{ErrorBody, ErrorKind as RumaApiErrorKind, RetryAfter, StandardErrorBody},
@@ -241,12 +238,6 @@ impl From<spaces::Error> for ClientError {
}
}
impl From<SearchError> for ClientError {
fn from(e: SearchError) -> Self {
Self::from_err(e)
}
}
/// Bindings version of the sdk type replacing OwnedUserId/DeviceIds with simple
/// String.
///

View File

@@ -16,7 +16,7 @@ use matrix_sdk::deserialized_responses::TimelineEvent;
use matrix_sdk_ui::{
search::{
GlobalSearchIterator as SdkGlobalSearchIterator,
RoomSearchIterator as SdkRoomSearchIterator,
RoomSearchIterator as SdkRoomSearchIterator, SearchError as SdkSearchError,
},
timeline::TimelineDetails,
};
@@ -30,6 +30,23 @@ use crate::{
utils::Timestamp,
};
#[derive(uniffi::Error, thiserror::Error, Debug)]
pub enum SearchError {
#[error("Failed to search through the index: {0}")]
IndexError(String),
#[error("Failed to load event content for search result: {0}")]
EventLoadError(String),
}
impl From<SdkSearchError> for SearchError {
fn from(err: SdkSearchError) -> Self {
match err {
SdkSearchError::IndexError(err) => SearchError::IndexError(err.to_string()),
SdkSearchError::EventLoadError(err) => SearchError::EventLoadError(err.to_string()),
}
}
}
#[matrix_sdk_ffi_macros::export]
impl Room {
pub fn search(&self, query: String) -> RoomSearchIterator {
@@ -50,7 +67,7 @@ pub struct RoomSearchIterator {
impl RoomSearchIterator {
/// Return a list of events for the next batch of search results, or `None`
/// if there are no more results.
pub async fn next_events(&self) -> Result<Option<Vec<RoomSearchResult>>, ClientError> {
pub async fn next_events(&self) -> Result<Option<Vec<RoomSearchResult>>, SearchError> {
let Some(events) = self.inner.lock().await.next_events(20).await? else {
return Ok(None);
};
@@ -103,16 +120,18 @@ impl RoomSearchResult {
#[derive(Clone, uniffi::Enum)]
pub enum SearchRoomFilter {
/// All the joined rooms (= DMs + groups).
/// All the joined rooms (= DMs + non-DMs).
Rooms,
/// Only joined DM rooms.
Dms,
/// Only joined non-DM (group) rooms.
Groups,
NonDms,
}
#[matrix_sdk_ffi_macros::export]
impl Client {
/// Search across all all rooms for the given query, returning an iterator
/// over the results.
pub async fn search(
&self,
query: String,
@@ -124,7 +143,7 @@ impl Client {
match filter {
SearchRoomFilter::Rooms => {}
SearchRoomFilter::Dms => search = search.only_dm_rooms().await?,
SearchRoomFilter::Groups => search = search.only_groups().await?,
SearchRoomFilter::NonDms => search = search.no_dms().await?,
}
Ok(GlobalSearchIterator { sdk_client, inner: Mutex::new(search.build()) })
@@ -156,7 +175,7 @@ impl GlobalSearchIterator {
pub async fn next_events(
&self,
num_results: u64,
) -> Result<Option<Vec<GlobalSearchResult>>, ClientError> {
) -> Result<Option<Vec<GlobalSearchResult>>, SearchError> {
let Some(events) = self.inner.lock().await.next_events(num_results as usize).await? else {
return Ok(None);
};

View File

@@ -28,7 +28,7 @@ experimental-encrypted-state-events = [
"ruma/unstable-msc4362"
]
experimental-search = ["matrix-sdk/experimental-search", "matrix-sdk-search"]
experimental-search = ["matrix-sdk/experimental-search", "dep:matrix-sdk-search"]
[dependencies]
as_variant.workspace = true

View File

@@ -12,6 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! High-level search helpers that provide more convenient APIs on top of the
//! low-level search API provided by the `search` module, such as streams for
//! paginating search results and builders for configuring search queries.
use std::collections::HashMap;
use imbl::HashSet;
@@ -20,6 +24,8 @@ use matrix_sdk_base::RoomStateFilter;
use matrix_sdk_search::error::IndexError;
use ruma::{OwnedEventId, OwnedRoomId};
/// An error that can occur while searching messages, using the high-level
/// search helpers provided by this module provided by this module.
#[derive(thiserror::Error, Debug)]
pub enum SearchError {
#[error(transparent)]
@@ -57,6 +63,8 @@ impl RoomSearchIterator {
return Ok(None);
}
// TODO: use the client/server API search endpoint for public rooms, as those
// may require lots of time for indexing all events.
let result = self.room.search(&self.query, num_results, self.offset).await?;
if result.is_empty() {
@@ -101,8 +109,8 @@ impl GlobalSearchRoomState {
}
}
/// A builder for a [`GlobalSearchIterator`] that allows to configure the initial
/// working set of rooms to search in.
/// A builder for a [`GlobalSearchIterator`] that allows to configure the
/// initial working set of rooms to search in.
pub struct GlobalSearchBuilder {
/// The search query, directly forwarded to the search API.
query: String,
@@ -135,7 +143,7 @@ impl GlobalSearchBuilder {
}
/// Keep only non-DM rooms (groups) from the initial working set.
pub async fn only_groups(mut self) -> Result<Self, matrix_sdk::Error> {
pub async fn no_dms(mut self) -> Result<Self, matrix_sdk::Error> {
let mut to_remove = HashSet::new();
for room in &self.room_set {
if room.is_direct().await? {
@@ -496,7 +504,7 @@ mod tests {
// Search for an existing keyword, by event, only in groups.
{
let mut search = GlobalSearchIterator::builder(client.clone(), "world".to_owned())
.only_groups()
.no_dms()
.await
.unwrap()
.build();

View File

@@ -737,6 +737,11 @@ pub enum TimelineDetails<T> {
}
impl<T> TimelineDetails<T> {
/// Create a [`TimelineDetails`] from an initial value that may or may not
/// be available.
///
/// Will be [`TimelineDetails::Ready`] if the value is `Some(_)`, and
/// [`TimelineDetails::Unavailable`] if the value is `None`.
pub fn from_initial_value(value: Option<T>) -> Self {
match value {
Some(v) => Self::Ready(v),