matrix_sdk_search/index/
builder.rs

1use std::{fs, path::PathBuf, sync::Arc};
2
3use ruma::OwnedRoomId;
4use tantivy::{
5    Index,
6    directory::{MmapDirectory, error::OpenDirectoryError},
7};
8use zeroize::Zeroizing;
9
10use crate::{
11    encrypted::encrypted_dir::{EncryptedMmapDirectory, PBKDF_COUNT},
12    error::IndexError,
13    index::RoomIndex,
14    schema::{MatrixSearchIndexSchema, RoomMessageSchema},
15};
16
17/// Builder for [`RoomIndex`].
18pub struct RoomIndexBuilder {}
19
20impl RoomIndexBuilder {
21    /// Make an index on disk
22    pub fn new_on_disk<R: Into<OwnedRoomId>>(
23        path: PathBuf,
24        room_id: R,
25    ) -> PhysicalRoomIndexBuilder {
26        PhysicalRoomIndexBuilder::new(path, room_id.into())
27    }
28
29    /// Make an index in memory
30    pub fn new_in_memory<R: Into<OwnedRoomId>>(room_id: R) -> MemoryRoomIndexBuilder {
31        MemoryRoomIndexBuilder::new(room_id.into())
32    }
33}
34
35/// Incomplete builder for [`RoomIndex`] on disk.
36pub struct PhysicalRoomIndexBuilder {
37    path: PathBuf,
38    room_id: OwnedRoomId,
39}
40
41impl PhysicalRoomIndexBuilder {
42    /// Make an new [`PhysicalRoomIndexBuilder`]
43    pub(crate) fn new(path: PathBuf, room_id: OwnedRoomId) -> PhysicalRoomIndexBuilder {
44        PhysicalRoomIndexBuilder { path, room_id }
45    }
46
47    /// Make an unencrypted index
48    pub fn unencrypted(&self) -> UnencryptedPhysicalRoomIndexBuilder {
49        UnencryptedPhysicalRoomIndexBuilder {
50            path: self.path.clone(),
51            room_id: self.room_id.clone(),
52        }
53    }
54
55    /// Make an encrypted index
56    pub fn encrypted<P: Into<String>>(&self, password: P) -> EncryptedPhysicalRoomIndexBuilder {
57        EncryptedPhysicalRoomIndexBuilder {
58            path: self.path.clone(),
59            room_id: self.room_id.clone(),
60            password: Zeroizing::new(password.into()),
61        }
62    }
63}
64
65/// Complete builder for [`RoomIndex`] on disk.
66pub struct UnencryptedPhysicalRoomIndexBuilder {
67    path: PathBuf,
68    room_id: OwnedRoomId,
69}
70
71impl UnencryptedPhysicalRoomIndexBuilder {
72    /// Build the [`RoomIndex`]
73    pub fn build(&self) -> Result<RoomIndex, IndexError> {
74        let path = self.path.join(self.room_id.as_str());
75        let mmap_dir = match MmapDirectory::open(path) {
76            Ok(dir) => Ok(dir),
77            Err(err) => match err {
78                OpenDirectoryError::DoesNotExist(path) => {
79                    fs::create_dir_all(path.clone()).map_err(|err| {
80                        OpenDirectoryError::IoError {
81                            io_error: Arc::new(err),
82                            directory_path: path.to_path_buf(),
83                        }
84                    })?;
85                    MmapDirectory::open(path)
86                }
87                _ => Err(err),
88            },
89        }?;
90        let schema = RoomMessageSchema::new();
91        let index = Index::open_or_create(mmap_dir, schema.as_tantivy_schema())?;
92        Ok(RoomIndex::new_with(index, schema, &self.room_id))
93    }
94}
95
96/// Complete builder for [`RoomIndex`] on disk.
97pub struct EncryptedPhysicalRoomIndexBuilder {
98    path: PathBuf,
99    room_id: OwnedRoomId,
100    password: Zeroizing<String>,
101}
102
103impl EncryptedPhysicalRoomIndexBuilder {
104    /// Build the [`RoomIndex`]
105    pub fn build(&self) -> Result<RoomIndex, IndexError> {
106        let path = self.path.join(self.room_id.as_str());
107        let mmap_dir =
108            match EncryptedMmapDirectory::open_or_create(path, &self.password, PBKDF_COUNT) {
109                Ok(dir) => Ok(dir),
110                Err(err) => match err {
111                    OpenDirectoryError::DoesNotExist(path) => {
112                        fs::create_dir_all(path.clone()).map_err(|err| {
113                            OpenDirectoryError::IoError {
114                                io_error: Arc::new(err),
115                                directory_path: path.to_path_buf(),
116                            }
117                        })?;
118                        EncryptedMmapDirectory::open_or_create(path, &self.password, PBKDF_COUNT)
119                    }
120                    _ => Err(err),
121                },
122            }?;
123        let schema = RoomMessageSchema::new();
124        let index = Index::open_or_create(mmap_dir, schema.as_tantivy_schema())?;
125        Ok(RoomIndex::new_with(index, schema, &self.room_id))
126    }
127}
128
129/// Builder for [`RoomIndex`] in memory
130pub struct MemoryRoomIndexBuilder {
131    room_id: OwnedRoomId,
132}
133
134impl MemoryRoomIndexBuilder {
135    /// Make an new [`MemoryIndexBuilder`]
136    pub(crate) fn new(room_id: OwnedRoomId) -> MemoryRoomIndexBuilder {
137        MemoryRoomIndexBuilder { room_id }
138    }
139
140    /// Build the [`RoomIndex`]
141    pub fn build(&self) -> RoomIndex {
142        let schema = RoomMessageSchema::new();
143        let index = Index::create_in_ram(schema.as_tantivy_schema());
144        RoomIndex::new_with(index, schema, &self.room_id)
145    }
146}