matrix_sdk/client/
search.rs1use std::{collections::hash_map::HashMap, path::PathBuf, sync::Arc};
16
17use matrix_sdk_search::{error::IndexError, index::RoomIndex};
18use ruma::{events::AnySyncMessageLikeEvent, OwnedEventId, OwnedRoomId, RoomId};
19use tokio::sync::{Mutex, MutexGuard};
20use tracing::{debug, error};
21
22#[derive(Clone, Debug)]
24pub enum SearchIndexStoreKind {
25 Directory(PathBuf),
27 InMemory,
29}
30
31#[derive(Clone, Debug)]
33pub(crate) struct SearchIndex {
34 room_indexes: Arc<Mutex<HashMap<OwnedRoomId, RoomIndex>>>,
36
37 search_index_store_kind: SearchIndexStoreKind,
39}
40
41impl SearchIndex {
42 pub fn new(
44 room_indexes: Arc<Mutex<HashMap<OwnedRoomId, RoomIndex>>>,
45 search_index_store_kind: SearchIndexStoreKind,
46 ) -> Self {
47 Self { room_indexes, search_index_store_kind }
48 }
49
50 pub async fn lock(&self) -> SearchIndexGuard<'_> {
51 SearchIndexGuard {
52 index_map: self.room_indexes.lock().await,
53 search_index_store_kind: &self.search_index_store_kind,
54 }
55 }
56}
57
58pub(crate) struct SearchIndexGuard<'a> {
59 index_map: MutexGuard<'a, HashMap<OwnedRoomId, RoomIndex>>,
61
62 search_index_store_kind: &'a SearchIndexStoreKind,
64}
65
66impl SearchIndexGuard<'_> {
67 fn create_index(&self, room_id: &RoomId) -> Result<RoomIndex, IndexError> {
68 let index = match self.search_index_store_kind {
69 SearchIndexStoreKind::Directory(path) => RoomIndex::open_or_create(path, room_id)?,
70 SearchIndexStoreKind::InMemory => RoomIndex::new_in_memory(room_id)?,
71 };
72 Ok(index)
73 }
74
75 pub(crate) fn handle_event(
81 &mut self,
82 event: AnySyncMessageLikeEvent,
83 room_id: &RoomId,
84 ) -> Result<(), IndexError> {
85 if !self.index_map.contains_key(room_id) {
86 let index = self.create_index(room_id)?;
87 self.index_map.insert(room_id.to_owned(), index);
88 }
89
90 let index = self.index_map.get_mut(room_id).expect("index should exist");
91 let result = index.handle_event(event);
92
93 match result {
94 Ok(_) => {}
95 Err(IndexError::CannotIndexRedactedMessage)
96 | Err(IndexError::EmptyMessage)
97 | Err(IndexError::MessageTypeNotSupported) => {
98 debug!("failed to parse event for indexing: {result:?}")
99 }
100 Err(IndexError::TantivyError(err)) => {
101 error!("failed to handle event in index: {err:?}")
102 }
103 Err(_) => error!("unexpected error during indexing: {result:?}"),
104 }
105 Ok(())
106 }
107
108 pub(crate) fn search(
111 &self,
112 query: &str,
113 max_number_of_results: usize,
114 room_id: &RoomId,
115 ) -> Option<Vec<OwnedEventId>> {
116 if let Some(index) = self.index_map.get(room_id) {
117 index
118 .search(query, max_number_of_results)
119 .inspect_err(|err| {
120 error!("error occurred while searching index: {err:?}");
121 })
122 .ok()
123 } else {
124 debug!("Tried to search in a room with no index");
125 None
126 }
127 }
128
129 pub(crate) fn commit_and_reload(&mut self, room_id: &RoomId) {
131 if let Some(index) = self.index_map.get_mut(room_id) {
132 let _ = index.commit_and_reload().inspect_err(|err| {
133 error!("error occurred while committing: {err:?}");
134 });
135 }
136 }
137}