diff --git a/crates/water/src/runtime/client.rs b/crates/water/src/runtime/client.rs index 90c1f46..de4694e 100644 --- a/crates/water/src/runtime/client.rs +++ b/crates/water/src/runtime/client.rs @@ -61,6 +61,35 @@ impl WATERClient { self.debug = debug; } + pub fn connect(&mut self, addr: &str, port: u16) -> Result<(), anyhow::Error> { + info!("[HOST] WATERClient connecting ..."); + + match &mut self.stream { + WATERClientType::Dialer(dialer) => { + dialer.connect(&self.config, addr, port)?; + } + _ => { + return Err(anyhow::anyhow!("[HOST] This client is not a Dialer")); + } + } + Ok(()) + } + + pub fn listen(&mut self, addr: &str, port: u16) -> Result<(), anyhow::Error> { + info!("[HOST] WATERClient listening ..."); + + match &mut self.stream { + WATERClientType::Listener(listener) => { + listener.listen(&self.config, addr, port)?; + } + _ => { + return Err(anyhow::anyhow!("[HOST] This client is not a Listener")); + } + } + Ok(()) + } + + // this will start a worker(WATM) in a separate thread -- returns a JoinHandle pub fn run_worker( &mut self, ) -> Result>, anyhow::Error> { @@ -72,6 +101,7 @@ impl WATERClient { } } + // this will run the extry_fn(WATM) in the current thread -- replace Host when running pub fn execute(&mut self) -> Result<(), anyhow::Error> { info!("[HOST] WATERClient Executing ..."); @@ -89,6 +119,7 @@ impl WATERClient { Ok(()) } + // v0 func for Host to set pipe for canceling later pub fn cancel_with(&mut self) -> Result<(), anyhow::Error> { info!("[HOST] WATERClient cancel_with ..."); @@ -97,12 +128,14 @@ impl WATERClient { dialer.cancel_with(&self.config)?; } _ => { - return Err(anyhow::anyhow!("This client is not a Dialer")); + // for now this is only implemented for v0 dialer + return Err(anyhow::anyhow!("This client is not a v0 Dialer")); } } Ok(()) } + // v0 func for Host to terminate the separate thread running worker(WATM) pub fn cancel(&mut self) -> Result<(), anyhow::Error> { info!("[HOST] WATERClient canceling ..."); @@ -111,41 +144,16 @@ impl WATERClient { dialer.cancel(&self.config)?; } _ => { - return Err(anyhow::anyhow!("This client is not a Dialer")); - } - } - Ok(()) - } - - pub fn connect(&mut self, addr: &str, port: u16) -> Result<(), anyhow::Error> { - info!("[HOST] WATERClient connecting ..."); - - match &mut self.stream { - WATERClientType::Dialer(dialer) => { - dialer.connect(&self.config, addr, port)?; - } - _ => { - return Err(anyhow::anyhow!("This client is not a listener")); - } - } - Ok(()) - } - - pub fn listen(&mut self, addr: &str, port: u16) -> Result<(), anyhow::Error> { - info!("[HOST] WATERClient listening ..."); - - match &mut self.stream { - WATERClientType::Listener(listener) => { - listener.listen(&self.config, addr, port)?; - } - _ => { - return Err(anyhow::anyhow!("This client is not a listener")); + // for now this is only implemented for v0 dialer + return Err(anyhow::anyhow!("This client is not a v0 Dialer")); } } Ok(()) } pub fn read(&mut self, buf: &mut Vec) -> Result { + info!("[HOST] WATERClient reading ..."); + let read_bytes = match &mut self.stream { WATERClientType::Dialer(dialer) => dialer.read(buf)?, WATERClientType::Listener(listener) => listener.read(buf)?, diff --git a/crates/water/src/runtime/core.rs b/crates/water/src/runtime/core.rs index fb1e193..3ecf326 100644 --- a/crates/water/src/runtime/core.rs +++ b/crates/water/src/runtime/core.rs @@ -35,27 +35,21 @@ impl H2O { let mut error_occured = None; + // Get the version global from WATM let version = module.exports().find_map(|global| { - info!( - "[HOST] WATERCore finding exported symbols from WASM bin: {:?}", - global.name() - ); match Version::parse(global.name()) { Some(mut v) => { info!("[HOST] WATERCore found version: {:?}", v.as_str()); match v { - Version::V0(_) => { - info!("[HOST] WATERCore configuring for V0"); - match v.config_v0(conf) { - Ok(v) => Some(v), - Err(e) => { - info!("failed to configure for V0: {}", e); - error_occured = Some(e); - None - } + Version::V0(_) => match v.config_v0(conf) { + Ok(v) => Some(v), + Err(e) => { + info!("[HOST] WATERCore failed to configure for V0: {}", e); + error_occured = Some(e); + None } - } - _ => Some(v), + }, + _ => Some(v), // for now only V0 needs to be configured } } None => None, @@ -66,18 +60,20 @@ impl H2O { if let Some(e) = error_occured { return Err(e); } - return Err(anyhow::Error::msg("WASM module version not found")); + return Err(anyhow::Error::msg("WATM module version not found")); } store.data_mut().preview1_ctx = Some(WasiCtxBuilder::new().inherit_stdio().build()); if store.data().preview1_ctx.is_none() { - return Err(anyhow::anyhow!("Failed to retrieve preview1_ctx from Host")); + return Err(anyhow::anyhow!( + "[HOST] WATERCore Failed to retrieve preview1_ctx from Host" + )); } wasmtime_wasi::add_to_linker(&mut linker, |h: &mut Host| h.preview1_ctx.as_mut().unwrap())?; - // initializing stuff for multithreading + // initializing stuff for multithreading -- currently not used yet (v1+ feature) #[cfg(feature = "multithread")] { store.data_mut().wasi_threads = Some(Arc::new(WasiThreadsCtx::new( @@ -117,7 +113,9 @@ impl H2O { } // export functions -- version independent - version_common::funcs::export_config(&mut linker, conf.config_wasm.clone())?; + { + version_common::funcs::export_config(&mut linker, conf.config_wasm.clone())?; + } let instance = linker.instantiate(&mut store, &module)?; @@ -138,14 +136,13 @@ impl H2O { } pub fn _prepare(&mut self, conf: &WATERConfig) -> Result<(), anyhow::Error> { - // NOTE: version has been checked at the very beginning self._init(conf.debug)?; - self._process_config(conf)?; + self._process_config(conf)?; // This is for now needed only by v1_preview Ok(()) } pub fn _init(&mut self, debug: bool) -> Result<(), anyhow::Error> { - info!("[HOST] WATERCore H2O calling _init from WASM..."); + info!("[HOST] WATERCore calling _init from WASM..."); let store_lock_result = self.store.lock(); @@ -171,7 +168,7 @@ impl H2O { } pub fn _process_config(&mut self, config: &WATERConfig) -> Result<(), anyhow::Error> { - info!("[HOST] WATERCore H2O calling _process_config from WASM..."); + info!("[HOST] WATERCore calling _process_config from WASM..."); let store_lock_result = self.store.lock(); @@ -185,13 +182,9 @@ impl H2O { Some(func) => func, None => { // Currently not going to return error, where V0 don't need config; - // TODO: also remove this function, where config will be pulled from WASM + // NOTE: remove this function for v1_preview as well, where config will be pulled from WASM info!("config function not found -- skipping"); return Ok(()); - - // return Err(anyhow::Error::msg( - // "_process_config function not found in WASM", - // )) } }; @@ -217,6 +210,8 @@ impl H2O { .preview1_ctx .as_mut() .ok_or(anyhow::anyhow!("preview1_ctx in Store is None"))?; + + // push the config file into WATM let config_fd = ctx.push_file(Box::new(wasi_file), FileAccessMode::all())? as i32; let params = vec![Val::I32(config_fd); config_fn.ty(&*store).params().len()]; diff --git a/crates/water/src/runtime/listener.rs b/crates/water/src/runtime/listener.rs index dfc12fd..1cc946b 100644 --- a/crates/water/src/runtime/listener.rs +++ b/crates/water/src/runtime/listener.rs @@ -18,6 +18,137 @@ pub struct WATERListener { } impl WATERListener { + pub fn init(_conf: &WATERConfig, core: H2O) -> Result { + info!("[HOST] WATERStream init..."); + + // constructing 2 pairs of UnixStream for communicating between WASM and Host + // returns (read_end, write_end) for caller + let (caller_reader, water_writer) = UnixStream::pair()?; + let (water_reader, caller_writer) = UnixStream::pair()?; + + let water_write_file = unsafe { cap_std::fs::File::from_raw_fd(water_writer.as_raw_fd()) }; + let water_read_file = unsafe { cap_std::fs::File::from_raw_fd(water_reader.as_raw_fd()) }; + + // insert file here + let wasi_water_reader = wasmtime_wasi::sync::file::File::from_cap_std(water_read_file); + let wasi_water_writer = wasmtime_wasi::sync::file::File::from_cap_std(water_write_file); + + std::mem::forget(water_writer); + std::mem::forget(water_reader); + + let reader; + let writer; + + { + let mut store = core + .store + .lock() + .map_err(|e| anyhow::Error::msg(format!("Failed to lock store: {}", e)))?; + let ctx = store + .data_mut() + .preview1_ctx + .as_mut() + .ok_or(anyhow::anyhow!("preview1_ctx in Store is None"))?; + let water_reader_fd = + ctx.push_file(Box::new(wasi_water_reader), FileAccessMode::all())?; + let water_writer_fd = + ctx.push_file(Box::new(wasi_water_writer), FileAccessMode::all())?; + + let water_bridging = match core.instance.get_func(&mut *store, WATER_BRIDGING_FN) { + Some(func) => func, + None => { + return Err(anyhow::Error::msg(format!( + "{} function not found in WASM", + WATER_BRIDGING_FN + ))) + } + }; + + let params = vec![ + Val::I32(water_reader_fd as i32), + Val::I32(water_writer_fd as i32), + ]; + match water_bridging.call(&mut *store, ¶ms, &mut []) { + Ok(_) => {} + Err(e) => { + return Err(anyhow::Error::msg(format!( + "{} function failed: {}", + WATER_BRIDGING_FN, e + ))) + } + } + + // getting reader & writer func from WASM + reader = match core.instance.get_func(&mut *store, READER_FN) { + Some(func) => func, + None => { + return Err(anyhow::Error::msg(format!( + "{} function not found in WASM", + READER_FN + ))) + } + }; + + writer = match core.instance.get_func(&mut *store, WRITER_FN) { + Some(func) => func, + None => { + return Err(anyhow::Error::msg(format!( + "{} function not found in WASM", + WRITER_FN + ))) + } + }; + } + + let runtime = WATERListener { + reader, + writer, + + caller_reader, + caller_writer, + + core, + }; + + Ok(runtime) + } + + /// Listening at the addr:port with running the WASM listen function + pub fn listen( + &mut self, + conf: &WATERConfig, + _addr: &str, + _port: u16, + ) -> Result<(), anyhow::Error> { + info!("[HOST] WATERStream listening..."); + + let store_lock_result = self.core.store.lock(); + + let mut store = match store_lock_result { + Ok(store) => store, + Err(e) => return Err(anyhow::Error::msg(format!("Failed to lock store: {}", e))), + }; + + // TODO: add addr:port sharing with WASM, for now WASM is using config.json's remote_addr:port + let fnc = self + .core + .instance + .get_func(&mut *store, &conf.entry_fn) + .context(format!("Failed to get function {}", &conf.entry_fn))?; + + match fnc.call(&mut *store, &[], &mut []) { + Ok(_) => {} + Err(e) => { + return Err(anyhow::Error::msg(format!( + "connect function failed: {}", + e + ))) + } + } + + Ok(()) + } + /// Read from the target address pub fn read(&mut self, buf: &mut Vec) -> Result { info!("[HOST] WATERStream reading..."); @@ -117,135 +248,4 @@ impl WATERListener { Ok(()) } - - /// Listening at the addr:port with running the WASM listen function - pub fn listen( - &mut self, - conf: &WATERConfig, - _addr: &str, - _port: u16, - ) -> Result<(), anyhow::Error> { - info!("[HOST] WATERStream listening..."); - - let store_lock_result = self.core.store.lock(); - - let mut store = match store_lock_result { - Ok(store) => store, - Err(e) => return Err(anyhow::Error::msg(format!("Failed to lock store: {}", e))), - }; - - // TODO: add addr:port sharing with WASM, for now WASM is using config.json's remote_addr:port - let fnc = self - .core - .instance - .get_func(&mut *store, &conf.entry_fn) - .context(format!("Failed to get function {}", &conf.entry_fn))?; - - match fnc.call(&mut *store, &[], &mut []) { - Ok(_) => {} - Err(e) => { - return Err(anyhow::Error::msg(format!( - "connect function failed: {}", - e - ))) - } - } - - Ok(()) - } - - pub fn init(_conf: &WATERConfig, core: H2O) -> Result { - info!("[HOST] WATERStream init..."); - - // constructing 2 pairs of UnixStream for communicating between WASM and Host - // returns (read_end, write_end) for caller - let (caller_reader, water_writer) = UnixStream::pair()?; - let (water_reader, caller_writer) = UnixStream::pair()?; - - let water_write_file = unsafe { cap_std::fs::File::from_raw_fd(water_writer.as_raw_fd()) }; - let water_read_file = unsafe { cap_std::fs::File::from_raw_fd(water_reader.as_raw_fd()) }; - - // insert file here - let wasi_water_reader = wasmtime_wasi::sync::file::File::from_cap_std(water_read_file); - let wasi_water_writer = wasmtime_wasi::sync::file::File::from_cap_std(water_write_file); - - std::mem::forget(water_writer); - std::mem::forget(water_reader); - - let reader; - let writer; - - { - let mut store = core - .store - .lock() - .map_err(|e| anyhow::Error::msg(format!("Failed to lock store: {}", e)))?; - let ctx = store - .data_mut() - .preview1_ctx - .as_mut() - .ok_or(anyhow::anyhow!("preview1_ctx in Store is None"))?; - let water_reader_fd = - ctx.push_file(Box::new(wasi_water_reader), FileAccessMode::all())?; - let water_writer_fd = - ctx.push_file(Box::new(wasi_water_writer), FileAccessMode::all())?; - - let water_bridging = match core.instance.get_func(&mut *store, WATER_BRIDGING_FN) { - Some(func) => func, - None => { - return Err(anyhow::Error::msg(format!( - "{} function not found in WASM", - WATER_BRIDGING_FN - ))) - } - }; - - let params = vec![ - Val::I32(water_reader_fd as i32), - Val::I32(water_writer_fd as i32), - ]; - match water_bridging.call(&mut *store, ¶ms, &mut []) { - Ok(_) => {} - Err(e) => { - return Err(anyhow::Error::msg(format!( - "{} function failed: {}", - WATER_BRIDGING_FN, e - ))) - } - } - - // getting reader & writer func from WASM - reader = match core.instance.get_func(&mut *store, READER_FN) { - Some(func) => func, - None => { - return Err(anyhow::Error::msg(format!( - "{} function not found in WASM", - READER_FN - ))) - } - }; - - writer = match core.instance.get_func(&mut *store, WRITER_FN) { - Some(func) => func, - None => { - return Err(anyhow::Error::msg(format!( - "{} function not found in WASM", - WRITER_FN - ))) - } - }; - } - - let runtime = WATERListener { - reader, - writer, - - caller_reader, - caller_writer, - - core, - }; - - Ok(runtime) - } } diff --git a/crates/water/src/runtime/stream.rs b/crates/water/src/runtime/stream.rs index b41062d..9d92230 100644 --- a/crates/water/src/runtime/stream.rs +++ b/crates/water/src/runtime/stream.rs @@ -3,22 +3,30 @@ use crate::runtime::*; pub trait WATERStreamTrait: Send { fn connect(&mut self, conf: &WATERConfig, _addr: &str, _port: u16) -> Result<(), anyhow::Error>; + + fn read(&mut self, _buf: &mut Vec) -> Result { + Err(anyhow::anyhow!("Method not supported")) + } + + fn write(&mut self, _buf: &[u8]) -> Result<(), anyhow::Error> { + Err(anyhow::anyhow!("Method not supported")) + } + + // v0 only fn cancel_with(&mut self, _conf: &WATERConfig) -> Result<(), anyhow::Error> { Err(anyhow::anyhow!("Method not supported")) } + + // v0 only fn cancel(&mut self, _conf: &WATERConfig) -> Result<(), anyhow::Error> { Err(anyhow::anyhow!("Method not supported")) } + + // v0 only fn run_entry_fn( &mut self, _conf: &WATERConfig, ) -> Result>, anyhow::Error> { Err(anyhow::anyhow!("Method not supported")) } - fn read(&mut self, _buf: &mut Vec) -> Result { - Err(anyhow::anyhow!("Method not supported")) - } - fn write(&mut self, _buf: &[u8]) -> Result<(), anyhow::Error> { - Err(anyhow::anyhow!("Method not supported")) - } } diff --git a/crates/water/src/runtime/v0/stream.rs b/crates/water/src/runtime/v0/stream.rs index 243a315..16f7fba 100644 --- a/crates/water/src/runtime/v0/stream.rs +++ b/crates/water/src/runtime/v0/stream.rs @@ -33,6 +33,7 @@ impl WATERStreamTrait for WATERStream { let (caller_io, water_io) = UnixStream::pair()?; self.caller_io = Some(caller_io); + // push the WATM end of the Unixpipe to WATM let water_io_file = unsafe { cap_std::fs::File::from_raw_fd(water_io.as_raw_fd()) }; // insert file here @@ -64,7 +65,7 @@ impl WATERStreamTrait for WATERStream { } }; - // let params = vec![Val::I32(water_reader_fd as i32), Val::I32(water_writer_fd as i32)]; + // calling the WASM dial function let params: Vec = vec![Val::I32(water_io_fd as i32)]; let mut res = vec![Val::I32(0); _water_dial.ty(&*store).results().len()]; match _water_dial.call(&mut *store, ¶ms, &mut res) { @@ -119,12 +120,11 @@ impl WATERStreamTrait for WATERStream { None => { return Err(anyhow::Error::msg(format!( "{} function not found in WASM", - DIAL_FN + CANCEL_FN ))) } }; - // let params = vec![Val::I32(water_reader_fd as i32), Val::I32(water_writer_fd as i32)]; let params: Vec = vec![Val::I32(water_io_fd as i32)]; let mut res = vec![Val::I32(0); _water_cancel_with.ty(&*store).results().len()]; match _water_cancel_with.call(&mut *store, ¶ms, &mut res) { @@ -197,6 +197,7 @@ impl WATERStreamTrait for WATERStream { } }; + // run the entry_fn in a thread -- Host will still have the ability to control it (e.g. with cancel) let handle = std::thread::spawn(move || { let mut store = store .lock() @@ -212,7 +213,7 @@ impl WATERStreamTrait for WATERStream { } fn read(&mut self, buf: &mut Vec) -> Result { - info!("[HOST] WATERStream reading..."); + info!("[HOST] WATERStream v0 reading..."); // read from WASM's caller_reader match self.caller_io { @@ -231,7 +232,7 @@ impl WATERStreamTrait for WATERStream { } fn write(&mut self, buf: &[u8]) -> Result<(), anyhow::Error> { - info!("[HOST] WATERStream writing..."); + info!("[HOST] WATERStream v0 writing..."); // write to WASM's caller_writer match self.caller_io { diff --git a/crates/water/src/runtime/v1/funcs.rs b/crates/water/src/runtime/v1/funcs.rs index b54480a..be4a7e9 100644 --- a/crates/water/src/runtime/v1/funcs.rs +++ b/crates/water/src/runtime/v1/funcs.rs @@ -5,7 +5,6 @@ use crate::runtime::*; use std::convert::TryInto; use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4}; -// TODO: rename this to dial_v1, since it has the ability to let WASM choose ip:port pub fn export_tcp_connect(linker: &mut Linker) -> Result<(), anyhow::Error> { linker .func_wrap( @@ -75,7 +74,6 @@ pub fn export_tcp_connect(linker: &mut Linker) -> Result<(), anyhow::Error Ok(()) } -// TODO: rename this to dial_v1, since it has the ability to let WASM listen on a TcpListener pub fn export_tcplistener_create(linker: &mut Linker) -> Result<(), anyhow::Error> { linker .func_wrap( @@ -135,20 +133,3 @@ pub fn export_tcplistener_create(linker: &mut Linker) -> Result<(), anyhow .context("Failed to export TcpListener create function to WASM")?; Ok(()) } - -// Generically link dial functions -// pub fn linkDialFns(linker: &mut Linker) { -// let network = vec!["tcplistener", "tlslistener", "udp"]; - -// for net in &network { -// match linker.func_wrap("env", &format!("connect_{}", net), move |mut caller: Caller<'_, Host>, ptr: u32, size: u32| -> i32{ -// // TODO: get addr from WASM - -// let socket_fd = dialer.Dial(net, addr).unwrap(); -// socket_fd -// }) { -// Ok(_) => {}, -// Err(e) => { eprintln!("Failed to define function: {}", e) }, -// }; -// } -// } diff --git a/crates/water/src/runtime/v1/stream.rs b/crates/water/src/runtime/v1/stream.rs index 73d6937..0c96cd8 100644 --- a/crates/water/src/runtime/v1/stream.rs +++ b/crates/water/src/runtime/v1/stream.rs @@ -31,11 +31,11 @@ impl WATERStreamTrait for WATERStream { /// Connect to the target address with running the WASM connect function fn connect( &mut self, - conf: &WATERConfig, + _conf: &WATERConfig, _addr: &str, _port: u16, ) -> Result<(), anyhow::Error> { - info!("[HOST] WATERStream connecting..."); + info!("[HOST] WATERStream v1_preview connecting..."); let store_lock_result = self.core.store.lock(); @@ -44,14 +44,12 @@ impl WATERStreamTrait for WATERStream { Err(e) => return Err(anyhow::Error::msg(format!("Failed to lock store: {}", e))), }; - // TODO: add addr:port sharing with WASM, for now WASM is using config.json's remote_addr:port - // let fnc = self.core.instance.get_func(&mut self.core.store, &conf.entry_fn).unwrap(); let fnc = match self.core.instance.get_func(&mut *store, DIAL_FN) { Some(func) => func, None => { return Err(anyhow::Error::msg(format!( "{} function not found in WASM", - conf.entry_fn + DIAL_FN ))) } }; @@ -71,7 +69,7 @@ impl WATERStreamTrait for WATERStream { /// Read from the target address fn read(&mut self, buf: &mut Vec) -> Result { - debug!("[HOST] WATERStream reading..."); + debug!("[HOST] WATERStream v1_preview reading..."); let store_lock_result = self.core.store.lock(); @@ -118,7 +116,7 @@ impl WATERStreamTrait for WATERStream { /// Write to the target address fn write(&mut self, buf: &[u8]) -> Result<(), anyhow::Error> { - debug!("[HOST] WATERStream writing..."); + debug!("[HOST] WATERStream v1_preview writing..."); let store_lock_result = self.core.store.lock(); @@ -172,7 +170,7 @@ impl WATERStreamTrait for WATERStream { impl WATERStream { pub fn init(_conf: &WATERConfig, core: H2O) -> Result { - info!("[HOST] WATERStream v0_init..."); + info!("[HOST] WATERStream v1_preview..."); // constructing a pair of UnixStream for communicating between WASM and Host let (caller_io, water_io) = UnixStream::pair()?; @@ -210,7 +208,6 @@ impl WATERStream { } }; - // let params = vec![Val::I32(water_reader_fd as i32), Val::I32(water_writer_fd as i32)]; let params: Vec = vec![Val::I32(water_io_fd as i32)]; match water_bridging.call(&mut *store, ¶ms, &mut []) { Ok(_) => {} diff --git a/crates/water/src/runtime/version.rs b/crates/water/src/runtime/version.rs index 2486054..627bd4a 100644 --- a/crates/water/src/runtime/version.rs +++ b/crates/water/src/runtime/version.rs @@ -19,7 +19,10 @@ impl Version { } } + // Current API v0 needs some configurations at the beginning pub fn config_v0(&mut self, conf: &WATERConfig) -> Result { + info!("[HOST] WATERCore configuring for V0"); + let wasm_config = Config::from(&conf.config_wasm)?; let v = match conf.client_type { @@ -29,7 +32,6 @@ impl Version { wasm_config.remote_address.clone(), wasm_config.remote_port, )?; - // v0_conf.conn = V0CRole::Dialer(std::net::TcpStream::connect(format!("{}:{}", wasm_config.remote_address, wasm_config.remote_port))?); Version::V0(Some(v0_conf)) } WaterBinType::Listen => { @@ -38,12 +40,10 @@ impl Version { wasm_config.local_address.clone(), wasm_config.local_port, )?; - // v0_conf.conn = V0CRole::Listener(std::net::TcpListener::bind(format!("{}:{}", wasm_config.local_address, wasm_config.local_port))?); Version::V0(Some(v0_conf)) } WaterBinType::Unknown => { Version::Unknown // WATER is setting up? - // return Err(anyhow::anyhow!("Invalid client type")); } _ => { unimplemented!("This client type is not supported yet") diff --git a/tests/tests/ss_testing.rs b/tests/tests/ss_testing.rs index 3011b4c..346fc1c 100644 --- a/tests/tests/ss_testing.rs +++ b/tests/tests/ss_testing.rs @@ -166,3 +166,23 @@ async fn wasm_managed_shadowsocks_async() { let http_status = b"HTTP/1.0 200 OK\r\n"; assert!(buf.starts_with(http_status)); } + +// Here is a test that runs the ss_client that has to be ended with signal +// #[test] +fn execute_wasm_shadowsocks_client() { + tracing_subscriber::fmt().with_max_level(Level::INFO).init(); + + // ==== setup WASM Shadowsocks client ==== + let conf = config::WATERConfig::init( + String::from("./test_wasm/ss_client_wasm.wasm"), + String::from("v1_listen"), + String::from("./test_data/config.json"), + config::WaterBinType::Runner, + false, + ) + .unwrap(); + + let mut water_client = runtime::client::WATERClient::new(conf).unwrap(); + + water_client.execute().unwrap(); +}