bitwarden_state/sdk_managed/
mod.rs

1use std::sync::Arc;
2
3use bitwarden_error::bitwarden_error;
4use thiserror::Error;
5
6use crate::repository::{Repository, RepositoryError, RepositoryItem, RepositoryMigrations};
7
8mod configuration;
9pub use configuration::DatabaseConfiguration;
10
11#[cfg(target_arch = "wasm32")]
12mod indexed_db;
13#[cfg(target_arch = "wasm32")]
14pub(super) type SystemDatabase = indexed_db::IndexedDbDatabase;
15#[cfg(target_arch = "wasm32")]
16type InternalError = ::indexed_db::Error<indexed_db::IndexedDbInternalError>;
17
18#[cfg(not(target_arch = "wasm32"))]
19mod sqlite;
20#[cfg(not(target_arch = "wasm32"))]
21pub(super) type SystemDatabase = sqlite::SqliteDatabase;
22#[cfg(not(target_arch = "wasm32"))]
23type InternalError = ::rusqlite::Error;
24
25#[bitwarden_error(flat)]
26#[derive(Debug, Error)]
27pub enum DatabaseError {
28    #[error("Database not supported on this platform: {0:?}")]
29    UnsupportedConfiguration(DatabaseConfiguration),
30
31    #[error(transparent)]
32    ThreadBoundRunner(#[from] bitwarden_threading::CallError),
33
34    #[error("Serialization error: {0}")]
35    Serialization(#[from] serde_json::Error),
36
37    #[error("JS error: {0}")]
38    JS(String),
39
40    #[error(transparent)]
41    Internal(#[from] InternalError),
42}
43
44pub trait Database {
45    async fn initialize(
46        configuration: DatabaseConfiguration,
47        registrations: RepositoryMigrations,
48    ) -> Result<Self, DatabaseError>
49    where
50        Self: Sized;
51
52    async fn get<T: RepositoryItem>(&self, key: &str) -> Result<Option<T>, DatabaseError>;
53
54    async fn list<T: RepositoryItem>(&self) -> Result<Vec<T>, DatabaseError>;
55
56    async fn set<T: RepositoryItem>(&self, key: &str, value: T) -> Result<(), DatabaseError>;
57
58    async fn remove<T: RepositoryItem>(&self, key: &str) -> Result<(), DatabaseError>;
59}
60
61struct DBRepository<T: RepositoryItem> {
62    database: SystemDatabase,
63    _marker: std::marker::PhantomData<T>,
64}
65
66#[async_trait::async_trait]
67impl<V: RepositoryItem> Repository<V> for DBRepository<V> {
68    async fn get(&self, key: String) -> Result<Option<V>, RepositoryError> {
69        let value = self.database.get::<V>(&key).await?;
70        Ok(value)
71    }
72    async fn list(&self) -> Result<Vec<V>, RepositoryError> {
73        let values = self.database.list::<V>().await?;
74        Ok(values)
75    }
76    async fn set(&self, key: String, value: V) -> Result<(), RepositoryError> {
77        Ok(self.database.set::<V>(&key, value).await?)
78    }
79    async fn remove(&self, key: String) -> Result<(), RepositoryError> {
80        Ok(self.database.remove::<V>(&key).await?)
81    }
82}
83
84impl SystemDatabase {
85    pub(super) fn get_repository<V: RepositoryItem>(&self) -> Arc<dyn Repository<V>> {
86        Arc::new(DBRepository {
87            database: self.clone(),
88            _marker: std::marker::PhantomData,
89        })
90    }
91}