3
3
//! as Wurbo).
4
4
//! That wat the WIT interface can simply import the same API and use it to communicate with the
5
5
6
- pub mod blockstore_idb;
7
-
8
- use futures:: SinkExt ;
9
6
use futures:: { channel:: mpsc, StreamExt } ;
10
7
use gloo_utils:: format:: JsValueSerdeExt ;
11
- pub use peerpiper_core:: events:: PeerPiperCommand ;
8
+ pub use peerpiper_core:: events:: { PeerPiperCommand , SystemCommand } ;
9
+ use peerpiper_core:: Commander ;
12
10
use std:: sync:: Mutex ;
13
11
use std:: sync:: OnceLock ;
14
12
use wasm_bindgen:: prelude:: * ;
15
13
use wasm_bindgen_futures:: spawn_local;
16
- use wnfs:: common:: CODEC_RAW ;
17
- use wnfs:: common:: { BlockStore , Storable } ;
18
- use wnfs_unixfs_file:: {
19
- builder:: { Config , FileBuilder } ,
20
- chunker:: { Chunker , ChunkerConfig } ,
21
- } ;
14
+
15
+ use crate :: blockstore:: BrowserBlockStore ;
22
16
23
17
const MAX_CHANNELS : usize = 16 ;
24
18
25
- /// This wraps command_sender in a Mutex so we can call it from multiple wasm_bindgen functions
26
- /// without worrying about thread safety.
27
- /// Make the OnceLock inner value mutable so we can call get_mut() on it.
28
- /// This makes our wasm API clean enough to interface directly to WIT world.
29
- static COMMAND_SENDER : OnceLock < Mutex < mpsc:: Sender < PeerPiperCommand > > > = OnceLock :: new ( ) ;
30
- /// BrowserBlockStore
31
- static BSTORE : OnceLock < Mutex < blockstore_idb:: BrowserBlockStore > > = OnceLock :: new ( ) ;
19
+ static COMMANDER : OnceLock < Mutex < Commander < BrowserBlockStore > > > = OnceLock :: new ( ) ;
32
20
33
21
cfg_if:: cfg_if! {
34
22
if #[ cfg( feature = "logging" ) ] {
@@ -60,11 +48,13 @@ cfg_if::cfg_if! {
60
48
pub async fn start ( ) -> Result < ( ) , JsValue > {
61
49
init_log ( ) ;
62
50
63
- // Set up a blockstore in the browser
64
- let blockstore = blockstore_idb:: BrowserBlockStore :: new ( "peerpiper" ) ;
65
- blockstore. open ( ) . await ?;
66
-
67
- BSTORE . get_or_init ( || Mutex :: new ( blockstore) ) ;
51
+ let blockstore = BrowserBlockStore :: new ( "peerpiper" ) ;
52
+ blockstore
53
+ . open ( )
54
+ . await
55
+ . map_err ( |err| JsValue :: from_str ( & format ! ( "Error opening blockstore: {:?}" , err) ) ) ?;
56
+ let commander = Commander :: new ( blockstore) ;
57
+ COMMANDER . get_or_init ( || Mutex :: new ( commander) ) ;
68
58
69
59
Ok ( ( ) )
70
60
}
@@ -76,8 +66,13 @@ pub async fn connect(libp2p_endpoint: &str, on_event: &js_sys::Function) -> Resu
76
66
// command_sender will be used by other wasm_bindgen functions to send commands to the network
77
67
// so we will need to wrap it in a Mutex or something to make it thread safe.
78
68
let ( command_sender, command_receiver) = mpsc:: channel ( 8 ) ;
79
- // move command_sender into COMMAND_SENDER
80
- COMMAND_SENDER . get_or_init ( || Mutex :: new ( command_sender) ) ;
69
+ // move command_sender into COMMANDER
70
+ COMMANDER
71
+ . get ( )
72
+ . ok_or_else ( || JsError :: new ( "Commander not initialized. Did `start()` complete?" ) ) ?
73
+ . lock ( )
74
+ . map_err ( |err| JsError :: new ( & format ! ( "Failed to lock commander: {}" , err) ) ) ?
75
+ . with_network ( command_sender) ;
81
76
82
77
let endpoint = libp2p_endpoint. to_string ( ) . clone ( ) ;
83
78
@@ -99,49 +94,11 @@ pub async fn connect(libp2p_endpoint: &str, on_event: &js_sys::Function) -> Resu
99
94
Ok ( ( ) )
100
95
}
101
96
102
- /// Uses COMMAND_SENDER (if initialized) to send a command to the network.
103
- /// Else, returns an error.
104
- pub async fn send_command ( command : PeerPiperCommand ) -> Result < ( ) , JsError > {
105
- tracing:: trace!( "Sending command" ) ;
106
- let command_sender = COMMAND_SENDER . get ( ) . ok_or_else ( || {
107
- JsError :: new (
108
- "Command sender not initialized. Did you call `connect()` first to establish a connection?" ,
109
- )
110
- } ) ?;
111
-
112
- command_sender
113
- . lock ( )
114
- . map_err ( |err| JsError :: new ( & format ! ( "Failed to lock command sender: {}" , err) ) ) ?
115
- . send ( command)
116
- . await
117
- . map_err ( |err| JsError :: new ( & format ! ( "Failed to send command: {}" , err) ) ) ?;
118
- Ok ( ( ) )
119
- }
120
-
121
- /// Publish to this topic String these bytes
122
- #[ wasm_bindgen]
123
- pub async fn publish ( topic : String , data : Vec < u8 > ) -> Result < ( ) , JsError > {
124
- send_command ( PeerPiperCommand :: Publish { topic, data } ) . await
125
- }
126
-
127
- /// Subscribe to this topic String
128
- #[ wasm_bindgen]
129
- pub async fn subscribe ( topic : String ) -> Result < ( ) , JsError > {
130
- send_command ( PeerPiperCommand :: Subscribe { topic } ) . await
131
- }
132
-
133
- /// Unsubscribe from this topic String
134
- /// This will stop receiving messages from this topic.
135
- #[ wasm_bindgen]
136
- pub async fn unsubscribe ( topic : String ) -> Result < ( ) , JsError > {
137
- send_command ( PeerPiperCommand :: Unsubscribe { topic } ) . await
138
- }
139
-
140
- /// Takes any json string and tries to deserialize it into a PeerPiperCommand,
141
- /// then sends it to the network.
97
+ /// Takes any json string from a Guest Component, and tries to deserialize it into a PeerPiperCommand,
98
+ /// then sends it to the COMMANDER who routes it to either the network or the system depending on the command.
142
99
/// If it fails, returns an error.
143
100
#[ wasm_bindgen]
144
- pub async fn command ( json : & str ) -> Result < ( ) , JsError > {
101
+ pub async fn command ( json : & str ) -> Result < JsValue , JsError > {
145
102
let example_publish = PeerPiperCommand :: Publish {
146
103
topic : "example" . to_string ( ) ,
147
104
data : vec ! [ 1 , 2 , 3 ] ,
@@ -153,36 +110,21 @@ pub async fn command(json: &str) -> Result<(), JsError> {
153
110
serde_json:: to_string( & example_publish) . unwrap( )
154
111
) )
155
112
} ) ?;
156
- send_command ( command) . await
157
- }
158
-
159
- /// Allows the user to save a file to the system (IndexedDB. TODO: Memory too?)
160
- #[ wasm_bindgen]
161
- pub async fn save ( data : Vec < u8 > ) -> Result < ( ) , JsError > {
162
- tracing:: info!( "Saving to blockstore bytes {:?}" , data. len( ) ) ;
163
113
164
- let blockstore = BSTORE
114
+ let maybe_result = COMMANDER
165
115
. get ( )
166
- . ok_or_else ( || {
167
- JsError :: new (
168
- "Blockstore not initialized. Did you call `start()` first to establish a connection?" ,
169
- )
170
- } ) ?
116
+ . ok_or_else ( || JsError :: new ( "Commander not initialized. Did `start()` complete?" ) ) ?
171
117
. lock ( )
172
- . unwrap ( ) ;
173
-
174
- // The chunker needs to be here because it is specific to IndexedDB having a max size of 256 *
175
- // 1024 bytes. In another system (like a desktop disk) it could be chunked differently.
176
- let root_cid = FileBuilder :: new ( )
177
- . content_bytes ( data. clone ( ) )
178
- . fixed_chunker ( 256 * 1024 )
179
- . build ( )
180
- . map_err ( |err| JsError :: new ( & format ! ( "Failed to build file: {}" , err) ) ) ?
181
- . store ( & blockstore. clone ( ) )
118
+ . map_err ( |err| JsError :: new ( & format ! ( "Failed to lock commander: {}" , err) ) ) ?
119
+ . order ( command)
182
120
. await
183
- . map_err ( |err| JsError :: new ( & format ! ( "Failed to store file: {}" , err) ) ) ?;
184
-
185
- tracing:: info!( "Saved file to blockstore with CID: {:?}" , root_cid) ;
121
+ . map_err ( |err| JsError :: new ( & format ! ( "Failed to send command: {}" , err) ) ) ?;
186
122
187
- Ok ( ( ) )
123
+ // convert the ReturnValues enum to a JsValue (Cid as String, Vec<u8> as Uint8Array, or null)
124
+ let js_val = match maybe_result {
125
+ peerpiper_core:: ReturnValues :: Data ( data) => JsValue :: from_serde ( & data) ?,
126
+ peerpiper_core:: ReturnValues :: ID ( cid) => JsValue :: from_str ( & cid. to_string ( ) ) ,
127
+ peerpiper_core:: ReturnValues :: None => JsValue :: null ( ) ,
128
+ } ;
129
+ Ok ( js_val)
188
130
}
0 commit comments