Skip to content

Commit 9c2013d

Browse files
committed
Replace custom channelrepository by ThreadBoundRunner
1 parent 53f5f9b commit 9c2013d

File tree

3 files changed

+64
-85
lines changed

3 files changed

+64
-85
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/bitwarden-wasm-internal/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ bitwarden-exporters = { workspace = true, features = ["wasm"] }
2424
bitwarden-generators = { workspace = true, features = ["wasm"] }
2525
bitwarden-ipc = { workspace = true, features = ["wasm"] }
2626
bitwarden-ssh = { workspace = true, features = ["wasm"] }
27+
bitwarden-threading = { workspace = true }
2728
bitwarden-vault = { workspace = true, features = ["wasm"] }
2829
chrono = { workspace = true }
2930
console_error_panic_hook = "0.1.7"
Lines changed: 62 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,4 @@
1-
use ::tokio::sync::oneshot::Sender;
2-
use bitwarden_core::client::repository::RepositoryError;
3-
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
4-
5-
pub enum RepositoryMessage<T> {
6-
Get(String, Sender<Result<Option<T>, RepositoryError>>),
7-
List(Sender<Result<Vec<T>, RepositoryError>>),
8-
Set(String, T, Sender<Result<(), RepositoryError>>),
9-
Remove(String, Sender<Result<(), RepositoryError>>),
10-
}
11-
12-
#[derive(Debug, Clone)]
13-
pub struct ChannelRepository<T> {
14-
pub sender: ::tokio::sync::mpsc::Sender<RepositoryMessage<T>>,
15-
}
16-
17-
impl<T> ChannelRepository<T> {
18-
async fn send<Res>(&self, func: impl FnOnce(Sender<Res>) -> RepositoryMessage<T>) -> Res {
19-
let (tx, rx) = tokio::sync::oneshot::channel();
20-
self.sender
21-
.send(func(tx))
22-
.await
23-
.expect("must always send a message");
24-
rx.await.expect("must always receive a response")
25-
}
26-
}
27-
28-
#[async_trait::async_trait]
29-
impl<T: Send> bitwarden_core::client::repository::Repository<T> for ChannelRepository<T> {
30-
async fn get(&self, id: String) -> Result<Option<T>, RepositoryError> {
31-
self.send(|tx| RepositoryMessage::Get(id, tx)).await
32-
}
33-
async fn list(&self) -> Result<Vec<T>, RepositoryError> {
34-
self.send(|tx| RepositoryMessage::List(tx)).await
35-
}
36-
async fn set(&self, id: String, value: T) -> Result<(), RepositoryError> {
37-
self.send(|tx| RepositoryMessage::Set(id, value, tx)).await
38-
}
39-
async fn remove(&self, id: String) -> Result<(), RepositoryError> {
40-
self.send(|tx| RepositoryMessage::Remove(id, tx)).await
41-
}
42-
}
1+
use wasm_bindgen::prelude::wasm_bindgen;
432

443
#[wasm_bindgen(typescript_custom_section)]
454
const REPOSITORY_CUSTOM_TS_TYPE: &'static str = r#"
@@ -50,16 +9,6 @@ export interface Repository<T> {
509
remove(id: string): Promise<void>;
5110
}
5211
"#;
53-
pub fn convert_result<T: serde::de::DeserializeOwned>(
54-
result: Result<JsValue, JsValue>,
55-
) -> Result<T, RepositoryError> {
56-
result
57-
.map_err(|e| RepositoryError::Internal(format!("{e:?}")))
58-
.and_then(|value| {
59-
::tsify_next::serde_wasm_bindgen::from_value(value)
60-
.map_err(|e| RepositoryError::Internal(e.to_string()))
61-
})
62-
}
6312

6413
macro_rules! create_wasm_repository {
6514
($name:ident, $ty:ty) => {
@@ -92,44 +41,72 @@ macro_rules! create_wasm_repository {
9241
impl $name {
9342
pub fn into_channel_impl(
9443
self,
95-
) -> ::std::sync::Arc<$crate::platform::repository::ChannelRepository<$ty>> {
96-
let (tx, mut rx) = tokio::sync::mpsc::channel(16);
44+
) -> ::std::sync::Arc<impl bitwarden_core::client::repository::Repository<$ty>> {
45+
use ::bitwarden_core::client::repository::*;
9746

98-
use $crate::platform::repository::RepositoryMessage;
47+
use crate::platform::repository::__macro_internal::*;
9948

100-
wasm_bindgen_futures::spawn_local(async move {
101-
while let Some(cmd) = rx.recv().await {
102-
match cmd {
103-
RepositoryMessage::Get(id, sender) => {
104-
let result = self.get(id).await;
105-
let _ = sender
106-
.send($crate::platform::repository::convert_result(result));
107-
}
108-
RepositoryMessage::List(sender) => {
109-
let result = self.list().await;
110-
let _ = sender
111-
.send($crate::platform::repository::convert_result(result));
112-
}
113-
RepositoryMessage::Set(id, value, sender) => {
114-
let result = self.set(id, value).await;
115-
let _ = sender.send($crate::platform::repository::convert_result(
116-
result.and(Ok(::wasm_bindgen::JsValue::UNDEFINED)),
117-
));
118-
}
119-
RepositoryMessage::Remove(id, sender) => {
120-
let result = self.remove(id).await;
121-
let _ = sender.send($crate::platform::repository::convert_result(
122-
result.and(Ok(::wasm_bindgen::JsValue::UNDEFINED)),
123-
));
124-
}
125-
}
49+
struct Store(::bitwarden_threading::ThreadBoundRunner<CipherRepository>);
50+
let store = Store(::bitwarden_threading::ThreadBoundRunner::new(self));
51+
52+
#[async_trait::async_trait]
53+
impl Repository<Cipher> for Store {
54+
async fn get(&self, id: String) -> Result<Option<Cipher>, RepositoryError> {
55+
run_convert(&self.0, |s| async move { s.get(id).await }).await
56+
}
57+
async fn list(&self) -> Result<Vec<Cipher>, RepositoryError> {
58+
run_convert(&self.0, |s| async move { s.list().await }).await
59+
}
60+
async fn set(&self, id: String, value: Cipher) -> Result<(), RepositoryError> {
61+
run_convert(&self.0, |s| async move { s.set(id, value).await.and(UNIT) })
62+
.await
63+
}
64+
async fn remove(&self, id: String) -> Result<(), RepositoryError> {
65+
run_convert(&self.0, |s| async move { s.remove(id).await.and(UNIT) }).await
12666
}
127-
});
128-
::std::sync::Arc::new($crate::platform::repository::ChannelRepository {
129-
sender: tx,
130-
})
67+
}
68+
69+
::std::sync::Arc::new(store)
13170
}
13271
}
13372
};
13473
}
13574
pub(super) use create_wasm_repository;
75+
76+
/// Some utilities to handle the conversion of JsValue to Rust types.
77+
/// They exist outside the macro to try to reduce code bloat in the generated code.
78+
#[doc(hidden)]
79+
pub mod __macro_internal {
80+
use std::{future::Future, rc::Rc};
81+
82+
use bitwarden_core::client::repository::RepositoryError;
83+
use wasm_bindgen::JsValue;
84+
85+
pub const UNIT: Result<JsValue, JsValue> = Ok(JsValue::UNDEFINED);
86+
87+
pub async fn run_convert<T: 'static, Func, Fut, Ret>(
88+
runner: &::bitwarden_threading::ThreadBoundRunner<T>,
89+
f: Func,
90+
) -> Result<Ret, RepositoryError>
91+
where
92+
Func: FnOnce(Rc<T>) -> Fut + Send + 'static,
93+
Fut: Future<Output = Result<JsValue, JsValue>>,
94+
Ret: serde::de::DeserializeOwned + Send + Sync + 'static,
95+
{
96+
runner
97+
.run_in_thread(|state| async move { convert_result(f(state).await) })
98+
.await
99+
.expect("Task should not panic")
100+
}
101+
102+
fn convert_result<T: serde::de::DeserializeOwned>(
103+
result: Result<JsValue, JsValue>,
104+
) -> Result<T, RepositoryError> {
105+
result
106+
.map_err(|e| RepositoryError::Internal(format!("{e:?}")))
107+
.and_then(|value| {
108+
::tsify_next::serde_wasm_bindgen::from_value(value)
109+
.map_err(|e| RepositoryError::Internal(e.to_string()))
110+
})
111+
}
112+
}

0 commit comments

Comments
 (0)