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;
43
2
44
3
#[ wasm_bindgen( typescript_custom_section) ]
45
4
const REPOSITORY_CUSTOM_TS_TYPE : & ' static str = r#"
@@ -50,16 +9,6 @@ export interface Repository<T> {
50
9
remove(id: string): Promise<void>;
51
10
}
52
11
"# ;
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
- }
63
12
64
13
macro_rules! create_wasm_repository {
65
14
( $name: ident, $ty: ty) => {
@@ -92,44 +41,72 @@ macro_rules! create_wasm_repository {
92
41
impl $name {
93
42
pub fn into_channel_impl(
94
43
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 :: * ;
97
46
98
- use $ crate:: platform:: repository:: RepositoryMessage ;
47
+ use crate :: platform:: repository:: __macro_internal :: * ;
99
48
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
126
66
}
127
- } ) ;
128
- :: std:: sync:: Arc :: new( $crate:: platform:: repository:: ChannelRepository {
129
- sender: tx,
130
- } )
67
+ }
68
+
69
+ :: std:: sync:: Arc :: new( store)
131
70
}
132
71
}
133
72
} ;
134
73
}
135
74
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