core_crypto_keystore/connection/
mod.rs1pub mod platform {
18 cfg_if::cfg_if! {
19 if #[cfg(target_family = "wasm")] {
20 mod wasm;
21 pub use wasm::keystore_v_1_0_0;
22 pub use self::wasm::WasmConnection as KeystoreDatabaseConnection;
23 pub use wasm::storage;
24 pub use self::wasm::storage::WasmStorageTransaction as TransactionWrapper;
25 } else {
26 mod generic;
27 pub use self::generic::SqlCipherConnection as KeystoreDatabaseConnection;
28 pub use self::generic::TransactionWrapper;
29 }
30 }
31}
32
33pub use self::platform::*;
34use crate::entities::{Entity, EntityFindParams, StringEntityId};
35use std::ops::DerefMut;
36
37use crate::entities::{EntityTransactionExt, UniqueEntity};
38use crate::transaction::KeystoreTransaction;
39use crate::{CryptoKeystoreError, CryptoKeystoreResult};
40use async_lock::{Mutex, MutexGuard, Semaphore};
41use std::sync::Arc;
42
43pub const MAX_BLOB_LEN: usize = 1_000_000_000;
51
52#[cfg(not(target_family = "wasm"))]
53pub trait DatabaseConnectionRequirements: Sized + Send {}
55#[cfg(target_family = "wasm")]
56pub trait DatabaseConnectionRequirements: Sized {}
58
59#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
60#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
61pub trait DatabaseConnection: DatabaseConnectionRequirements {
62 async fn open(name: &str, key: &str) -> CryptoKeystoreResult<Self>;
63
64 async fn open_in_memory(name: &str, key: &str) -> CryptoKeystoreResult<Self>;
65
66 async fn close(self) -> CryptoKeystoreResult<()>;
67
68 async fn wipe(self) -> CryptoKeystoreResult<()> {
70 self.close().await
71 }
72
73 fn check_buffer_size(size: usize) -> CryptoKeystoreResult<()> {
74 #[cfg(not(target_family = "wasm"))]
75 if size > i32::MAX as usize {
76 return Err(CryptoKeystoreError::BlobTooBig);
77 }
78
79 if size >= MAX_BLOB_LEN {
80 return Err(CryptoKeystoreError::BlobTooBig);
81 }
82
83 Ok(())
84 }
85 #[cfg(not(target_family = "wasm"))]
86 async fn new_transaction(&mut self) -> CryptoKeystoreResult<TransactionWrapper<'_>>;
87 #[cfg(target_family = "wasm")]
88 async fn new_transaction<T: AsRef<str>>(
89 &mut self,
90 tables: &[T],
91 ) -> CryptoKeystoreResult<crate::connection::TransactionWrapper<'_>>;
92}
93
94#[derive(Debug, Clone)]
95pub struct Connection {
96 pub(crate) conn: Arc<Mutex<KeystoreDatabaseConnection>>,
97 pub(crate) transaction: Arc<Mutex<Option<KeystoreTransaction>>>,
98 transaction_semaphore: Arc<Semaphore>,
99}
100
101const ALLOWED_CONCURRENT_TRANSACTIONS_COUNT: usize = 1;
102
103#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
106#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
107pub trait FetchFromDatabase: Send + Sync {
108 async fn find<E: Entity<ConnectionType = KeystoreDatabaseConnection>>(
109 &self,
110 id: &[u8],
111 ) -> CryptoKeystoreResult<Option<E>>;
112
113 async fn find_unique<U: UniqueEntity<ConnectionType = KeystoreDatabaseConnection>>(
114 &self,
115 ) -> CryptoKeystoreResult<U>;
116
117 async fn find_all<E: Entity<ConnectionType = KeystoreDatabaseConnection>>(
118 &self,
119 params: EntityFindParams,
120 ) -> CryptoKeystoreResult<Vec<E>>;
121
122 async fn find_many<E: Entity<ConnectionType = KeystoreDatabaseConnection>>(
123 &self,
124 ids: &[Vec<u8>],
125 ) -> CryptoKeystoreResult<Vec<E>>;
126 async fn count<E: Entity<ConnectionType = KeystoreDatabaseConnection>>(&self) -> CryptoKeystoreResult<usize>;
127}
128
129unsafe impl Send for Connection {}
131unsafe impl Sync for Connection {}
132
133impl Connection {
134 pub async fn open_with_key(name: impl AsRef<str>, key: impl AsRef<str>) -> CryptoKeystoreResult<Self> {
135 let conn = KeystoreDatabaseConnection::open(name.as_ref(), key.as_ref())
136 .await?
137 .into();
138 #[allow(clippy::arc_with_non_send_sync)] let conn = Arc::new(conn);
140 Ok(Self {
141 conn,
142 transaction: Default::default(),
143 transaction_semaphore: Arc::new(Semaphore::new(ALLOWED_CONCURRENT_TRANSACTIONS_COUNT)),
144 })
145 }
146
147 pub async fn open_in_memory_with_key(name: impl AsRef<str>, key: impl AsRef<str>) -> CryptoKeystoreResult<Self> {
148 let conn = KeystoreDatabaseConnection::open_in_memory(name.as_ref(), key.as_ref())
149 .await?
150 .into();
151 #[allow(clippy::arc_with_non_send_sync)] let conn = Arc::new(conn);
153 Ok(Self {
154 conn,
155 transaction: Default::default(),
156 transaction_semaphore: Arc::new(Semaphore::new(ALLOWED_CONCURRENT_TRANSACTIONS_COUNT)),
157 })
158 }
159
160 pub async fn borrow_conn(&self) -> CryptoKeystoreResult<MutexGuard<'_, KeystoreDatabaseConnection>> {
161 Ok(self.conn.lock().await)
162 }
163
164 pub async fn wipe(self) -> CryptoKeystoreResult<()> {
165 if self.transaction.lock().await.is_some() {
166 return Err(CryptoKeystoreError::TransactionInProgress {
167 attempted_operation: "wipe()".to_string(),
168 });
169 }
170 let conn: KeystoreDatabaseConnection = Arc::into_inner(self.conn).unwrap().into_inner();
171 conn.wipe().await?;
172 Ok(())
173 }
174
175 pub async fn close(self) -> CryptoKeystoreResult<()> {
176 if self.transaction.lock().await.is_some() {
177 return Err(CryptoKeystoreError::TransactionInProgress {
178 attempted_operation: "close()".to_string(),
179 });
180 }
181 let conn: KeystoreDatabaseConnection = Arc::into_inner(self.conn).unwrap().into_inner();
182 conn.close().await?;
183 Ok(())
184 }
185
186 pub async fn new_transaction(&self) -> CryptoKeystoreResult<()> {
188 let semaphore = self.transaction_semaphore.acquire_arc().await;
189 let mut transaction_guard = self.transaction.lock().await;
190 *transaction_guard = Some(KeystoreTransaction::new(semaphore).await?);
191 Ok(())
192 }
193
194 pub async fn commit_transaction(&self) -> CryptoKeystoreResult<()> {
195 let mut transaction_guard = self.transaction.lock().await;
196 let Some(transaction) = transaction_guard.as_ref() else {
197 return Err(CryptoKeystoreError::MutatingOperationWithoutTransaction);
198 };
199 transaction.commit(self).await?;
200 *transaction_guard = None;
201 Ok(())
202 }
203
204 pub async fn rollback_transaction(&self) -> CryptoKeystoreResult<()> {
205 let mut transaction_guard = self.transaction.lock().await;
206 if transaction_guard.is_none() {
207 return Err(CryptoKeystoreError::MutatingOperationWithoutTransaction);
208 };
209 *transaction_guard = None;
210 Ok(())
211 }
212
213 pub async fn child_groups<
214 E: Entity<ConnectionType = KeystoreDatabaseConnection> + crate::entities::PersistedMlsGroupExt + Sync,
215 >(
216 &self,
217 entity: E,
218 ) -> CryptoKeystoreResult<Vec<E>> {
219 let mut conn = self.conn.lock().await;
220 let persisted_records = entity.child_groups(conn.deref_mut()).await?;
221
222 let transaction_guard = self.transaction.lock().await;
223 let Some(transaction) = transaction_guard.as_ref() else {
224 return Ok(persisted_records);
225 };
226 transaction.child_groups(entity, persisted_records).await
227 }
228
229 pub async fn save<E: Entity<ConnectionType = KeystoreDatabaseConnection> + Sync + EntityTransactionExt>(
230 &self,
231 entity: E,
232 ) -> CryptoKeystoreResult<E> {
233 let transaction_guard = self.transaction.lock().await;
234 let Some(transaction) = transaction_guard.as_ref() else {
235 return Err(CryptoKeystoreError::MutatingOperationWithoutTransaction);
236 };
237 transaction.save_mut(entity).await
238 }
239
240 pub async fn remove<
241 E: Entity<ConnectionType = KeystoreDatabaseConnection> + EntityTransactionExt,
242 S: AsRef<[u8]>,
243 >(
244 &self,
245 id: S,
246 ) -> CryptoKeystoreResult<()> {
247 let transaction_guard = self.transaction.lock().await;
248 let Some(transaction) = transaction_guard.as_ref() else {
249 return Err(CryptoKeystoreError::MutatingOperationWithoutTransaction);
250 };
251 transaction.remove::<E, S>(id).await
252 }
253
254 pub async fn cred_delete_by_credential(&self, cred: Vec<u8>) -> CryptoKeystoreResult<()> {
255 let transaction_guard = self.transaction.lock().await;
256 let Some(transaction) = transaction_guard.as_ref() else {
257 return Err(CryptoKeystoreError::MutatingOperationWithoutTransaction);
258 };
259 transaction.cred_delete_by_credential(cred).await
260 }
261}
262
263#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
264#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
265impl FetchFromDatabase for Connection {
266 async fn find<E: Entity<ConnectionType = KeystoreDatabaseConnection>>(
267 &self,
268 id: &[u8],
269 ) -> CryptoKeystoreResult<Option<E>> {
270 if let Some(transaction) = self.transaction.lock().await.as_ref() {
272 if let Some(result) = transaction.find::<E>(id).await? {
274 return Ok(result);
276 }
277 }
278
279 let mut conn = self.conn.lock().await;
281 E::find_one(&mut conn, &id.into()).await
282 }
283
284 async fn find_unique<U: UniqueEntity>(&self) -> CryptoKeystoreResult<U> {
285 if let Some(transaction) = self.transaction.lock().await.as_ref() {
287 if let Some(result) = transaction.find_unique::<U>().await? {
289 return Ok(result);
291 }
292 }
293 let mut conn = self.conn.lock().await;
295 U::find_unique(&mut conn).await
296 }
297
298 async fn find_all<E: Entity<ConnectionType = KeystoreDatabaseConnection>>(
299 &self,
300 params: EntityFindParams,
301 ) -> CryptoKeystoreResult<Vec<E>> {
302 let mut conn = self.conn.lock().await;
303 let persisted_records = E::find_all(&mut conn, params.clone()).await?;
304
305 let transaction_guard = self.transaction.lock().await;
306 let Some(transaction) = transaction_guard.as_ref() else {
307 return Ok(persisted_records);
308 };
309 transaction.find_all(persisted_records, params).await
310 }
311
312 async fn find_many<E: Entity<ConnectionType = KeystoreDatabaseConnection>>(
313 &self,
314 ids: &[Vec<u8>],
315 ) -> CryptoKeystoreResult<Vec<E>> {
316 let entity_ids: Vec<StringEntityId> = ids.iter().map(|id| id.as_slice().into()).collect();
317 let mut conn = self.conn.lock().await;
318 let persisted_records = E::find_many(&mut conn, &entity_ids).await?;
319
320 let transaction_guard = self.transaction.lock().await;
321 let Some(transaction) = transaction_guard.as_ref() else {
322 return Ok(persisted_records);
323 };
324 transaction.find_many(persisted_records, ids).await
325 }
326
327 async fn count<E: Entity<ConnectionType = KeystoreDatabaseConnection>>(&self) -> CryptoKeystoreResult<usize> {
328 if self.transaction.lock().await.is_some() {
329 return Ok(self.find_all::<E>(Default::default()).await?.len());
332 };
333 let mut conn = self.conn.lock().await;
334 E::count(&mut conn).await
335 }
336}