Skip to content

Commit 1be6c69

Browse files
committed
Use generic data store trait and create a macro to do the messaging
1 parent 6c7fb65 commit 1be6c69

File tree

9 files changed

+416
-156
lines changed

9 files changed

+416
-156
lines changed

crates/bitwarden-core/src/client/client.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use super::internal::InternalClient;
88
use crate::client::flags::Flags;
99
use crate::client::{
1010
client_settings::ClientSettings,
11+
data_store::DataStoreMap,
1112
internal::{ApiConfigurations, Tokens},
1213
};
1314

@@ -82,8 +83,8 @@ impl Client {
8283
})),
8384
external_client,
8485
key_store: KeyStore::default(),
85-
86-
cipher_store: RwLock::new(None),
86+
#[cfg(feature = "internal")]
87+
data_stores: RwLock::new(DataStoreMap::default()),
8788
},
8889
}
8990
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
use std::{
2+
any::{Any, TypeId},
3+
collections::HashMap,
4+
sync::Arc,
5+
};
6+
7+
#[async_trait::async_trait]
8+
pub trait DataStore<T>: Send + Sync {
9+
async fn get(&self, key: String) -> Option<T>;
10+
async fn list(&self) -> Vec<T>;
11+
async fn set(&self, key: String, value: T);
12+
async fn remove(&self, key: String);
13+
}
14+
15+
#[derive(Default)]
16+
pub struct DataStoreMap {
17+
stores: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
18+
}
19+
20+
impl std::fmt::Debug for DataStoreMap {
21+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22+
f.debug_struct("DataStoreMap")
23+
.field("stores", &self.stores.keys())
24+
.finish()
25+
}
26+
}
27+
28+
impl DataStoreMap {
29+
pub fn new() -> Self {
30+
DataStoreMap {
31+
stores: HashMap::new(),
32+
}
33+
}
34+
35+
pub fn insert<T: 'static>(&mut self, value: Arc<dyn DataStore<T>>) {
36+
self.stores.insert(TypeId::of::<T>(), Box::new(value));
37+
}
38+
39+
pub fn get<T: 'static>(&self) -> Option<Arc<dyn DataStore<T>>> {
40+
self.stores
41+
.get(&TypeId::of::<T>())
42+
.and_then(|boxed| boxed.downcast_ref::<Arc<dyn DataStore<T>>>())
43+
.map(Arc::clone)
44+
}
45+
}
46+
47+
#[cfg(test)]
48+
mod tests {
49+
use super::*;
50+
51+
macro_rules! impl_data_store {
52+
($name:ident, $ty:ty) => {
53+
#[async_trait::async_trait]
54+
impl DataStore<$ty> for $name {
55+
async fn get(&self, _key: String) -> Option<$ty> {
56+
Some(self.0.clone())
57+
}
58+
async fn list(&self) -> Vec<$ty> {
59+
unimplemented!()
60+
}
61+
async fn set(&self, _key: String, _value: $ty) {
62+
unimplemented!()
63+
}
64+
async fn remove(&self, _key: String) {
65+
unimplemented!()
66+
}
67+
}
68+
};
69+
}
70+
71+
#[derive(PartialEq, Eq, Debug)]
72+
struct TestA(usize);
73+
#[derive(PartialEq, Eq, Debug)]
74+
struct TestB(String);
75+
#[derive(PartialEq, Eq, Debug)]
76+
struct TestC(Vec<u8>);
77+
78+
impl_data_store!(TestA, usize);
79+
impl_data_store!(TestB, String);
80+
impl_data_store!(TestC, Vec<u8>);
81+
82+
#[tokio::test]
83+
async fn test_data_stores_map() {
84+
let a = Arc::new(TestA(145832));
85+
let b = Arc::new(TestB("test".to_string()));
86+
let c = Arc::new(TestC(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]));
87+
88+
let mut map = DataStoreMap::new();
89+
90+
async fn get<T: 'static>(map: &DataStoreMap) -> Option<T> {
91+
map.get::<T>().unwrap().get(String::new()).await
92+
}
93+
94+
assert!(map.get::<usize>().is_none());
95+
assert!(map.get::<String>().is_none());
96+
assert!(map.get::<Vec<u8>>().is_none());
97+
98+
map.insert(a.clone());
99+
assert_eq!(get(&map).await, Some(a.0));
100+
assert!(map.get::<String>().is_none());
101+
assert!(map.get::<Vec<u8>>().is_none());
102+
103+
map.insert(b.clone());
104+
assert_eq!(get(&map).await, Some(a.0));
105+
assert_eq!(get(&map).await, Some(b.0.clone()));
106+
assert!(map.get::<Vec<u8>>().is_none());
107+
108+
map.insert(c.clone());
109+
assert_eq!(get(&map).await, Some(a.0));
110+
assert_eq!(get(&map).await, Some(b.0.clone()));
111+
assert_eq!(get(&map).await, Some(c.0.clone()));
112+
}
113+
}

crates/bitwarden-core/src/client/internal.rs

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::{
1818
};
1919
#[cfg(feature = "internal")]
2020
use crate::{
21+
client::data_store::{DataStore, DataStoreMap},
2122
client::encryption_settings::EncryptionSettingsError,
2223
client::{flags::Flags, login_method::UserLoginMethod},
2324
error::NotAuthenticatedError,
@@ -61,7 +62,8 @@ pub struct InternalClient {
6162

6263
pub(super) key_store: KeyStore<KeyIds>,
6364

64-
pub(super) cipher_store: RwLock<Option<Arc<dyn CipherStore>>>,
65+
#[cfg(feature = "internal")]
66+
pub(super) data_stores: RwLock<DataStoreMap>,
6567
}
6668

6769
impl InternalClient {
@@ -222,26 +224,19 @@ impl InternalClient {
222224
EncryptionSettings::set_org_keys(org_keys, &self.key_store)
223225
}
224226

225-
pub fn register_cipher_store(&self, store: Arc<dyn CipherStore>) {
226-
self.cipher_store
227+
#[cfg(feature = "internal")]
228+
pub fn register_data_store<T: 'static + DataStore<V>, V: 'static>(&self, store: Arc<T>) {
229+
self.data_stores
227230
.write()
228231
.expect("RwLock is not poisoned")
229-
.replace(store);
232+
.insert(store);
230233
}
231234

232-
pub fn get_cipher_store(&self) -> Option<Arc<dyn CipherStore>> {
233-
self.cipher_store
235+
#[cfg(feature = "internal")]
236+
pub fn get_data_store<T: 'static>(&self) -> Option<Arc<dyn DataStore<T>>> {
237+
self.data_stores
234238
.read()
235239
.expect("RwLock is not poisoned")
236-
.clone()
240+
.get()
237241
}
238242
}
239-
240-
// TODO: We can't expose the store as returning a bitwarden_vault::Cipher to avoid a circular dependency, we'll fix that at some point somehow
241-
#[async_trait::async_trait]
242-
pub trait CipherStore: std::fmt::Debug + Send + Sync {
243-
async fn get(&self, key: &str) -> Option<String>;
244-
async fn list(&self) -> Vec<String>;
245-
async fn set(&self, key: &str, value: String);
246-
async fn remove(&self, key: &str);
247-
}

crates/bitwarden-core/src/client/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@ pub use client_settings::{ClientSettings, DeviceType};
1818

1919
#[cfg(feature = "internal")]
2020
pub mod test_accounts;
21+
22+
#[cfg(feature = "internal")]
23+
pub mod data_store;

crates/bitwarden-error-macro/src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ mod attribute;
55
mod basic;
66
mod flat;
77
mod full;
8+
mod wasm_ipc;
89

910
/// A procedural macro for generating error types with customizable serialization behavior.
1011
///
@@ -120,3 +121,14 @@ pub fn bitwarden_error(
120121
) -> proc_macro::TokenStream {
121122
attribute::bitwarden_error(args, item)
122123
}
124+
125+
#[proc_macro_attribute]
126+
pub fn bitwarden_wasm_ipc_channel(
127+
args: proc_macro::TokenStream,
128+
item: proc_macro::TokenStream,
129+
) -> proc_macro::TokenStream {
130+
match wasm_ipc::bitwarden_wasm_ipc_channel_internal(args, item) {
131+
Ok(v) => v,
132+
Err(e) => proc_macro::TokenStream::from(e.to_compile_error()),
133+
}
134+
}

0 commit comments

Comments
 (0)