From 1460a6ea0d394c1c2c48aa5f0c162e881d4fcb3f Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Wed, 30 Aug 2023 16:22:38 +0200 Subject: [PATCH 01/26] wip: flattened test structure --- Cargo.toml | 4 ++-- examples/wit_components/Cargo.toml | 9 +++++++++ .../{records/protocol.wit => records.wit} | 0 .../wit_components/records/{guest => }/Cargo.toml | 2 +- examples/wit_components/records/guest/.gitignore | 2 -- examples/wit_components/records/host/.gitignore | 2 -- examples/wit_components/records/host/Cargo.toml | 8 -------- .../wit_components/records/{guest => }/src/lib.rs | 2 +- examples/wit_components/src/lib.rs | 1 + .../{records/host/src/main.rs => tests/records.rs} | 13 ++++++------- recipes.json | 14 ++++++++++++++ 11 files changed, 34 insertions(+), 23 deletions(-) create mode 100644 examples/wit_components/Cargo.toml rename examples/wit_components/{records/protocol.wit => records.wit} (100%) rename examples/wit_components/records/{guest => }/Cargo.toml (85%) delete mode 100644 examples/wit_components/records/guest/.gitignore delete mode 100644 examples/wit_components/records/host/.gitignore delete mode 100644 examples/wit_components/records/host/Cargo.toml rename examples/wit_components/records/{guest => }/src/lib.rs (87%) create mode 100644 examples/wit_components/src/lib.rs rename examples/wit_components/{records/host/src/main.rs => tests/records.rs} (86%) create mode 100644 recipes.json diff --git a/Cargo.toml b/Cargo.toml index 369dd7f4..d7af9361 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,8 @@ members = [ "crates/wasm-bridge", "crates/wasm-bridge-js", "crates/wasm-bridge-macros", - "examples/wit_components/*/*", - "examples/wasi_components/*/*", + "examples/wit_components/", + "examples/wit_components/records/", ] exclude = [ diff --git a/examples/wit_components/Cargo.toml b/examples/wit_components/Cargo.toml new file mode 100644 index 00000000..cab44ea4 --- /dev/null +++ b/examples/wit_components/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "tests-wit-components" +edition.workspace = true +version = "0.0.0" + +[dependencies] +wasm-bridge = { path = "../../crates/wasm-bridge/", features = ["component-model"]} +wasm-bindgen-test = "0.3" + diff --git a/examples/wit_components/records/protocol.wit b/examples/wit_components/records.wit similarity index 100% rename from examples/wit_components/records/protocol.wit rename to examples/wit_components/records.wit diff --git a/examples/wit_components/records/guest/Cargo.toml b/examples/wit_components/records/Cargo.toml similarity index 85% rename from examples/wit_components/records/guest/Cargo.toml rename to examples/wit_components/records/Cargo.toml index cc2058fc..0490a588 100644 --- a/examples/wit_components/records/guest/Cargo.toml +++ b/examples/wit_components/records/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "example-records-guest" +name = "test-records-guest" edition.workspace = true version = "0.0.0" diff --git a/examples/wit_components/records/guest/.gitignore b/examples/wit_components/records/guest/.gitignore deleted file mode 100644 index 4fffb2f8..00000000 --- a/examples/wit_components/records/guest/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -/Cargo.lock diff --git a/examples/wit_components/records/host/.gitignore b/examples/wit_components/records/host/.gitignore deleted file mode 100644 index 4fffb2f8..00000000 --- a/examples/wit_components/records/host/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -/Cargo.lock diff --git a/examples/wit_components/records/host/Cargo.toml b/examples/wit_components/records/host/Cargo.toml deleted file mode 100644 index 73a809c0..00000000 --- a/examples/wit_components/records/host/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "example-records-host" -edition.workspace = true -version = "0.0.0" - -[dependencies] -wasm-bridge = { path = "../../../../crates/wasm-bridge/", features = ["component-model"]} - diff --git a/examples/wit_components/records/guest/src/lib.rs b/examples/wit_components/records/src/lib.rs similarity index 87% rename from examples/wit_components/records/guest/src/lib.rs rename to examples/wit_components/records/src/lib.rs index 15837ce7..1c32d9e4 100644 --- a/examples/wit_components/records/guest/src/lib.rs +++ b/examples/wit_components/records/src/lib.rs @@ -1,5 +1,5 @@ wit_bindgen::generate!({ - path: "../protocol.wit", + path: "../records.wit", world: "records", }); diff --git a/examples/wit_components/src/lib.rs b/examples/wit_components/src/lib.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/examples/wit_components/src/lib.rs @@ -0,0 +1 @@ + diff --git a/examples/wit_components/records/host/src/main.rs b/examples/wit_components/tests/records.rs similarity index 86% rename from examples/wit_components/records/host/src/main.rs rename to examples/wit_components/tests/records.rs index 14123507..5ea6c154 100644 --- a/examples/wit_components/records/host/src/main.rs +++ b/examples/wit_components/tests/records.rs @@ -3,8 +3,11 @@ use wasm_bridge::{ Config, Engine, Result, Store, }; +const GUEST_BYTES: &[u8] = + include_bytes!("../../../target/wasm32-unknown-unknown/debug/example_records_guest.wasm"); + wasm_bridge::component::bindgen!({ - path: "../protocol.wit", + path: "./records.wit", world: "records", }); @@ -15,10 +18,8 @@ impl RecordsImports for Host { } } -const GUEST_BYTES: &[u8] = - include_bytes!("../../../../../target/wasm32-unknown-unknown/debug/example_records_guest.wasm"); - -fn main() -> Result<()> { +#[test] +fn records() { let mut config = Config::new(); config.wasm_component_model(true); @@ -43,6 +44,4 @@ fn main() -> Result<()> { .unwrap(); assert_eq!(result, vec![2, 6, 7]); - - Ok(()) } diff --git a/recipes.json b/recipes.json new file mode 100644 index 00000000..63b68556 --- /dev/null +++ b/recipes.json @@ -0,0 +1,14 @@ +{ + "test-io": { + "cmd": [ + "./examples/wasi_components/run_examples.sh", + "io_redirect" + ], + "components": { + "qf": { + "compiler": "cargo" + } + }, + "cwd": "./examples/wasi_components/" + } +} From 16eed47be20f623eed04a8a4524aaa6219a196a7 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Wed, 30 Aug 2023 17:33:50 +0200 Subject: [PATCH 02/26] feat: flatten io redirect test --- Cargo.toml | 2 ++ examples/wasi_components/Cargo.toml | 12 ++++++++++++ .../{io_redirect/protocol.wit => io_redirect.wit} | 0 .../io_redirect/{guest => }/.gitignore | 0 .../io_redirect/{guest => }/Cargo.toml | 2 +- .../wasi_components/io_redirect/host/.gitignore | 2 -- .../wasi_components/io_redirect/host/Cargo.toml | 12 ------------ .../io_redirect/{guest => }/src/lib.rs | 2 +- examples/wasi_components/src/lib.rs | 1 + .../host/src/main.rs => tests/io_redirect.rs} | 15 +++++++++------ examples/wit_components/Cargo.toml | 2 +- examples/wit_components/records/Cargo.toml | 2 +- examples/wit_components/tests/records.rs | 2 +- 13 files changed, 29 insertions(+), 25 deletions(-) create mode 100644 examples/wasi_components/Cargo.toml rename examples/wasi_components/{io_redirect/protocol.wit => io_redirect.wit} (100%) rename examples/wasi_components/io_redirect/{guest => }/.gitignore (100%) rename examples/wasi_components/io_redirect/{guest => }/Cargo.toml (84%) delete mode 100644 examples/wasi_components/io_redirect/host/.gitignore delete mode 100644 examples/wasi_components/io_redirect/host/Cargo.toml rename examples/wasi_components/io_redirect/{guest => }/src/lib.rs (93%) create mode 100644 examples/wasi_components/src/lib.rs rename examples/wasi_components/{io_redirect/host/src/main.rs => tests/io_redirect.rs} (95%) diff --git a/Cargo.toml b/Cargo.toml index d7af9361..cb8cad0f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,8 @@ members = [ "crates/wasm-bridge-macros", "examples/wit_components/", "examples/wit_components/records/", + "examples/wasi_components/", + "examples/wasi_components/io_redirect", ] exclude = [ diff --git a/examples/wasi_components/Cargo.toml b/examples/wasi_components/Cargo.toml new file mode 100644 index 00000000..8dd6781b --- /dev/null +++ b/examples/wasi_components/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "wasi-components-tests" +edition.workspace = true +version = "0.0.0" + +[dependencies] +wasm-bridge = { path = "../../crates/wasm-bridge/", features = ["component-model", "async", "wasi"]} +wasm-bindgen-test = "0.3" +bytes = "1.4" + +[target."cfg(not(target_arch = \"wasm32\"))".dependencies] +tokio = { version = "1.32", features = ["full"] } diff --git a/examples/wasi_components/io_redirect/protocol.wit b/examples/wasi_components/io_redirect.wit similarity index 100% rename from examples/wasi_components/io_redirect/protocol.wit rename to examples/wasi_components/io_redirect.wit diff --git a/examples/wasi_components/io_redirect/guest/.gitignore b/examples/wasi_components/io_redirect/.gitignore similarity index 100% rename from examples/wasi_components/io_redirect/guest/.gitignore rename to examples/wasi_components/io_redirect/.gitignore diff --git a/examples/wasi_components/io_redirect/guest/Cargo.toml b/examples/wasi_components/io_redirect/Cargo.toml similarity index 84% rename from examples/wasi_components/io_redirect/guest/Cargo.toml rename to examples/wasi_components/io_redirect/Cargo.toml index 2cb29574..f112b454 100644 --- a/examples/wasi_components/io_redirect/guest/Cargo.toml +++ b/examples/wasi_components/io_redirect/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "example-io_redirect-guest" +name = "io-redirect-guest" edition.workspace = true version = "0.0.0" diff --git a/examples/wasi_components/io_redirect/host/.gitignore b/examples/wasi_components/io_redirect/host/.gitignore deleted file mode 100644 index 4fffb2f8..00000000 --- a/examples/wasi_components/io_redirect/host/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/target -/Cargo.lock diff --git a/examples/wasi_components/io_redirect/host/Cargo.toml b/examples/wasi_components/io_redirect/host/Cargo.toml deleted file mode 100644 index 53c9051c..00000000 --- a/examples/wasi_components/io_redirect/host/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "example-io_redirect-host" -edition = "2021" -version = "0.0.0" - -[dependencies] -wasm-bridge = { path = "../../../../crates/wasm-bridge/", default-features = false, features = ["component-model", "wasi"]} -rand_core = { version = "0.6.4" } -tokio = { version = "1.29.1", features = ["macros", "rt"] } -async-trait = "0.1" -bytes = "1.4" - diff --git a/examples/wasi_components/io_redirect/guest/src/lib.rs b/examples/wasi_components/io_redirect/src/lib.rs similarity index 93% rename from examples/wasi_components/io_redirect/guest/src/lib.rs rename to examples/wasi_components/io_redirect/src/lib.rs index 9caf4069..f6c8a22d 100644 --- a/examples/wasi_components/io_redirect/guest/src/lib.rs +++ b/examples/wasi_components/io_redirect/src/lib.rs @@ -1,5 +1,5 @@ wit_bindgen::generate!({ - path: "../protocol.wit", + path: "../io_redirect.wit", world: "io-redirect", }); diff --git a/examples/wasi_components/src/lib.rs b/examples/wasi_components/src/lib.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/examples/wasi_components/src/lib.rs @@ -0,0 +1 @@ + diff --git a/examples/wasi_components/io_redirect/host/src/main.rs b/examples/wasi_components/tests/io_redirect.rs similarity index 95% rename from examples/wasi_components/io_redirect/host/src/main.rs rename to examples/wasi_components/tests/io_redirect.rs index b7c25aac..5e284fbf 100644 --- a/examples/wasi_components/io_redirect/host/src/main.rs +++ b/examples/wasi_components/tests/io_redirect.rs @@ -10,7 +10,7 @@ use wasm_bridge::wasi::preview2::*; use std::sync::{Arc, Mutex}; wasm_bridge::component::bindgen!({ - path: "../protocol.wit", + path: "./io_redirect.wit", world: "io-redirect", async: true, }); @@ -35,10 +35,11 @@ impl WasiView for State { } } -#[tokio::main] -pub async fn main() -> Result<()> { +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] +#[cfg_attr(not(target_arch = "wasm32"), tokio::test)] +pub async fn io_redirect() -> Result<()> { const GUEST_BYTES: &[u8] = - include_bytes!("../../../../../target/wasm32-wasi/debug/example_io_redirect_guest.wasm"); + include_bytes!("../../../target/wasm32-wasi/debug/io_redirect_guest.wasm"); no_config(GUEST_BYTES).await?; inherit(GUEST_BYTES).await?; @@ -71,6 +72,7 @@ async fn no_config(component_bytes: &[u8]) -> Result<()> { instance .call_writeln_to_stdout(&mut store, "NO_PRINT") .await?; + instance .call_writeln_to_stderr(&mut store, "NO_PRINT") .await?; @@ -103,6 +105,7 @@ async fn inherit(component_bytes: &[u8]) -> Result<()> { instance .call_writeln_to_stdout(&mut store, "PRINT_OUT_1") .await?; + instance .call_writeln_to_stderr(&mut store, "PRINT_ERR_1") .await?; @@ -204,7 +207,7 @@ impl OutputStream for OutStream { } #[cfg(not(target_arch = "wasm32"))] -#[async_trait::async_trait] +#[wasm_bridge::async_trait] impl HostOutputStream for OutStream { fn write(&mut self, bytes: Bytes) -> Result<(usize, StreamState), wasm_bridge::Error> { let amount = bytes.len().min(self.max); @@ -249,7 +252,7 @@ impl InputStream for InStream { } } #[cfg(not(target_arch = "wasm32"))] -#[async_trait::async_trait] +#[wasm_bridge::async_trait] impl HostInputStream for InStream { fn read(&mut self, size: usize) -> Result<(Bytes, StreamState), wasm_bridge::Error> { let len = size.min(self.data.len() - self.offset).min(self.max); diff --git a/examples/wit_components/Cargo.toml b/examples/wit_components/Cargo.toml index cab44ea4..0873192b 100644 --- a/examples/wit_components/Cargo.toml +++ b/examples/wit_components/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "tests-wit-components" +name = "wit-components-tests" edition.workspace = true version = "0.0.0" diff --git a/examples/wit_components/records/Cargo.toml b/examples/wit_components/records/Cargo.toml index 0490a588..ce0b9ebf 100644 --- a/examples/wit_components/records/Cargo.toml +++ b/examples/wit_components/records/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "test-records-guest" +name = "records-guest" edition.workspace = true version = "0.0.0" diff --git a/examples/wit_components/tests/records.rs b/examples/wit_components/tests/records.rs index 5ea6c154..53529e23 100644 --- a/examples/wit_components/tests/records.rs +++ b/examples/wit_components/tests/records.rs @@ -4,7 +4,7 @@ use wasm_bridge::{ }; const GUEST_BYTES: &[u8] = - include_bytes!("../../../target/wasm32-unknown-unknown/debug/example_records_guest.wasm"); + include_bytes!("../../../target/wasm32-unknown-unknown/debug/records_guest.wasm"); wasm_bridge::component::bindgen!({ path: "./records.wit", From d0ccb3993ccd1ae2c412ac30476788f29838f510 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Wed, 30 Aug 2023 17:44:18 +0200 Subject: [PATCH 03/26] chore: move guest examples into dedicated directory --- Cargo.toml | 4 ++-- examples/wasi_components/{ => guest}/io_redirect/.gitignore | 0 examples/wasi_components/{ => guest}/io_redirect/Cargo.toml | 0 examples/wasi_components/{ => guest}/io_redirect/src/lib.rs | 2 +- examples/wit_components/{run_examples.sh => build_guest.sh} | 0 examples/wit_components/{ => guest}/records/Cargo.toml | 0 examples/wit_components/{ => guest}/records/src/lib.rs | 2 +- 7 files changed, 4 insertions(+), 4 deletions(-) rename examples/wasi_components/{ => guest}/io_redirect/.gitignore (100%) rename examples/wasi_components/{ => guest}/io_redirect/Cargo.toml (100%) rename examples/wasi_components/{ => guest}/io_redirect/src/lib.rs (92%) rename examples/wit_components/{run_examples.sh => build_guest.sh} (100%) rename examples/wit_components/{ => guest}/records/Cargo.toml (100%) rename examples/wit_components/{ => guest}/records/src/lib.rs (86%) diff --git a/Cargo.toml b/Cargo.toml index cb8cad0f..f2e97e14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,9 +5,9 @@ members = [ "crates/wasm-bridge-js", "crates/wasm-bridge-macros", "examples/wit_components/", - "examples/wit_components/records/", + "examples/wit_components/guest/records/", "examples/wasi_components/", - "examples/wasi_components/io_redirect", + "examples/wasi_components/guest/io_redirect", ] exclude = [ diff --git a/examples/wasi_components/io_redirect/.gitignore b/examples/wasi_components/guest/io_redirect/.gitignore similarity index 100% rename from examples/wasi_components/io_redirect/.gitignore rename to examples/wasi_components/guest/io_redirect/.gitignore diff --git a/examples/wasi_components/io_redirect/Cargo.toml b/examples/wasi_components/guest/io_redirect/Cargo.toml similarity index 100% rename from examples/wasi_components/io_redirect/Cargo.toml rename to examples/wasi_components/guest/io_redirect/Cargo.toml diff --git a/examples/wasi_components/io_redirect/src/lib.rs b/examples/wasi_components/guest/io_redirect/src/lib.rs similarity index 92% rename from examples/wasi_components/io_redirect/src/lib.rs rename to examples/wasi_components/guest/io_redirect/src/lib.rs index f6c8a22d..7a944819 100644 --- a/examples/wasi_components/io_redirect/src/lib.rs +++ b/examples/wasi_components/guest/io_redirect/src/lib.rs @@ -1,5 +1,5 @@ wit_bindgen::generate!({ - path: "../io_redirect.wit", + path: "../../io_redirect.wit", world: "io-redirect", }); diff --git a/examples/wit_components/run_examples.sh b/examples/wit_components/build_guest.sh similarity index 100% rename from examples/wit_components/run_examples.sh rename to examples/wit_components/build_guest.sh diff --git a/examples/wit_components/records/Cargo.toml b/examples/wit_components/guest/records/Cargo.toml similarity index 100% rename from examples/wit_components/records/Cargo.toml rename to examples/wit_components/guest/records/Cargo.toml diff --git a/examples/wit_components/records/src/lib.rs b/examples/wit_components/guest/records/src/lib.rs similarity index 86% rename from examples/wit_components/records/src/lib.rs rename to examples/wit_components/guest/records/src/lib.rs index 1c32d9e4..a1074edf 100644 --- a/examples/wit_components/records/src/lib.rs +++ b/examples/wit_components/guest/records/src/lib.rs @@ -1,5 +1,5 @@ wit_bindgen::generate!({ - path: "../records.wit", + path: "../../records.wit", world: "records", }); From 5078f52a616d72dddecd0715772d73d8492b3438 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Thu, 31 Aug 2023 10:59:08 +0200 Subject: [PATCH 04/26] fix: module hierarchy mismatch wasm-bridge-js and wasmtime --- crates/wasm-bridge-js/Cargo.toml | 3 ++- .../src/wasi/preview2/{wasi => }/command.rs | 2 +- crates/wasm-bridge-js/src/wasi/preview2/mod.rs | 10 +++++----- crates/wasm-bridge-js/src/wasi/preview2/wasi/mod.rs | 1 - 4 files changed, 8 insertions(+), 8 deletions(-) rename crates/wasm-bridge-js/src/wasi/preview2/{wasi => }/command.rs (96%) delete mode 100644 crates/wasm-bridge-js/src/wasi/preview2/wasi/mod.rs diff --git a/crates/wasm-bridge-js/Cargo.toml b/crates/wasm-bridge-js/Cargo.toml index 2612720a..d8b8477c 100644 --- a/crates/wasm-bridge-js/Cargo.toml +++ b/crates/wasm-bridge-js/Cargo.toml @@ -18,6 +18,7 @@ js-component-bindgen = { version = "0.9.5", optional = true } anyhow = { version = "1.0.22" } heck = { version = "0.4.1" } rand_core = { version = "0.6.4", optional = true } +getrandom = { version = "0.2.10", optional = true } [dev-dependencies] wasm-bindgen-test = "0.3.37" @@ -25,5 +26,5 @@ wasm-bindgen-test = "0.3.37" [features] component-model = ["wasm-bridge-macros", "js-component-bindgen"] async = ["wasm-bridge-macros/async"] -wasi = ["async", "rand_core"] +wasi = ["async", "rand_core", "getrandom", "getrandom/js"] error-logging = [] diff --git a/crates/wasm-bridge-js/src/wasi/preview2/wasi/command.rs b/crates/wasm-bridge-js/src/wasi/preview2/command.rs similarity index 96% rename from crates/wasm-bridge-js/src/wasi/preview2/wasi/command.rs rename to crates/wasm-bridge-js/src/wasi/preview2/command.rs index 3c4b7b6c..39e53632 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/wasi/command.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/command.rs @@ -6,7 +6,7 @@ use crate::wasi::preview2::{clocks, WasiView}; use crate::{Result, StoreContextMut}; static WASI_IMPORTS_STR: &str = - include_str!("../../../../../../resources/transformed/preview2-shim/bundled.js"); + include_str!("../../../../../resources/transformed/preview2-shim/bundled.js"); const STDIN_IDENT: u32 = 0; const STDOUT_IDENT: u32 = 1; diff --git a/crates/wasm-bridge-js/src/wasi/preview2/mod.rs b/crates/wasm-bridge-js/src/wasi/preview2/mod.rs index 10c5e5e0..ed7477ed 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/mod.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/mod.rs @@ -1,16 +1,16 @@ mod wasi_ctx_builder; -pub use wasi_ctx_builder::*; +pub use wasi_ctx_builder::WasiCtxBuilder; mod wasi_ctx; -pub use wasi_ctx::*; +pub use wasi_ctx::WasiCtx; mod table; -pub use table::*; +pub use table::Table; mod wasi_view; -pub use wasi_view::*; +pub use wasi_view::WasiView; -pub mod wasi; +pub mod command; pub mod stream; pub use stream::*; diff --git a/crates/wasm-bridge-js/src/wasi/preview2/wasi/mod.rs b/crates/wasm-bridge-js/src/wasi/preview2/wasi/mod.rs deleted file mode 100644 index 9fe79612..00000000 --- a/crates/wasm-bridge-js/src/wasi/preview2/wasi/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod command; From c1bd3b137fc85c3ee6aff970720fb0bff928268a Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Thu, 31 Aug 2023 11:58:03 +0200 Subject: [PATCH 05/26] fix: negative head not supported on MacOS --- crates/wasm-bridge-js/src/wasi/preview2/command.rs | 5 ++++- recipes.json | 11 +++++++++++ resources/transformed/preview2-shim/bundled.js | 2 ++ resources/transformed/preview2-shim/bundled_new.js | 0 resources/transformed/transform.sh | 2 +- 5 files changed, 18 insertions(+), 2 deletions(-) delete mode 100644 resources/transformed/preview2-shim/bundled_new.js diff --git a/crates/wasm-bridge-js/src/wasi/preview2/command.rs b/crates/wasm-bridge-js/src/wasi/preview2/command.rs index 39e53632..91cf9674 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/command.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/command.rs @@ -72,7 +72,10 @@ pub fn add_to_linker(linker: &mut Linker) -> Result<() fn get_imports() -> Object { let imports = js_sys::eval(WASI_IMPORTS_STR).expect("eval bundled wasi imports"); - assert!(imports.is_object(), "wasi imports must be an object"); + assert!( + imports.is_object(), + "wasi imports must be an object, {imports:#?}" + ); imports.into() } diff --git a/recipes.json b/recipes.json index 63b68556..d1c775a1 100644 --- a/recipes.json +++ b/recipes.json @@ -1,4 +1,15 @@ { + "test-wasm": { + "cmd": [ + "wasm-pack", + "test", + "--node", + "./examples/wasi_components/" + ], + "qf": { + "compiler": "cargo" + } + }, "test-io": { "cmd": [ "./examples/wasi_components/run_examples.sh", diff --git a/resources/transformed/preview2-shim/bundled.js b/resources/transformed/preview2-shim/bundled.js index 259ead6e..077a4d22 100644 --- a/resources/transformed/preview2-shim/bundled.js +++ b/resources/transformed/preview2-shim/bundled.js @@ -739,4 +739,6 @@ } return wasiExports; } + + return getWasiImports(); })(); diff --git a/resources/transformed/preview2-shim/bundled_new.js b/resources/transformed/preview2-shim/bundled_new.js deleted file mode 100644 index e69de29b..00000000 diff --git a/resources/transformed/transform.sh b/resources/transformed/transform.sh index b0cd0d7a..240fb1c5 100755 --- a/resources/transformed/transform.sh +++ b/resources/transformed/transform.sh @@ -21,7 +21,7 @@ cp ../random.js browser/random.js esbuild index.js --bundle --outfile=bundled.js # return the import object from the bundle -head -n -1 bundled.js > bundled_new.js +tail -r bundled.js | tail +2 | tail -r > bundled_new.js echo >> bundled_new.js echo ' return getWasiImports();' >> bundled_new.js echo '})();' >> bundled_new.js From cfbd85571eb34b2e270a8026c08a44d29954e815 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Thu, 31 Aug 2023 15:19:02 +0200 Subject: [PATCH 06/26] feat: wasi:cli-base/environment --- Cargo.toml | 6 ++-- .../wasm-bridge-js/src/component/component.rs | 2 +- .../src/component/component_loader.rs | 2 ++ .../src/wasi/preview2/command.rs | 3 ++ .../src/wasi/preview2/environment.rs | 35 +++++++++++++++++++ .../wasm-bridge-js/src/wasi/preview2/mod.rs | 3 ++ .../src/wasi/preview2/wasi_ctx.rs | 10 ++++++ .../src/wasi/preview2/wasi_ctx_builder.rs | 12 +++++++ examples/wasi_components/build_guest.sh | 17 +++++++++ .../guest/{io_redirect => io}/.gitignore | 0 .../guest/{io_redirect => io}/Cargo.toml | 2 +- .../guest/{io_redirect => io}/src/lib.rs | 0 examples/wasi_components/run_examples.sh | 22 ------------ .../tests/{io_redirect.rs => io.rs} | 12 ++++--- examples/wit_components/build_guest.sh | 13 +++---- 15 files changed, 99 insertions(+), 40 deletions(-) create mode 100644 crates/wasm-bridge-js/src/wasi/preview2/environment.rs create mode 100755 examples/wasi_components/build_guest.sh rename examples/wasi_components/guest/{io_redirect => io}/.gitignore (100%) rename examples/wasi_components/guest/{io_redirect => io}/Cargo.toml (87%) rename examples/wasi_components/guest/{io_redirect => io}/src/lib.rs (100%) delete mode 100755 examples/wasi_components/run_examples.sh rename examples/wasi_components/tests/{io_redirect.rs => io.rs} (96%) diff --git a/Cargo.toml b/Cargo.toml index f2e97e14..01f71811 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,10 +4,12 @@ members = [ "crates/wasm-bridge", "crates/wasm-bridge-js", "crates/wasm-bridge-macros", + "examples/wit_components/", - "examples/wit_components/guest/records/", + "examples/wit_components/guest/*/", + "examples/wasi_components/", - "examples/wasi_components/guest/io_redirect", + "examples/wasi_components/guest/*", ] exclude = [ diff --git a/crates/wasm-bridge-js/src/component/component.rs b/crates/wasm-bridge-js/src/component/component.rs index 1de94576..83a86134 100644 --- a/crates/wasm-bridge-js/src/component/component.rs +++ b/crates/wasm-bridge-js/src/component/component.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, rc::Rc}; +use std::{collections::HashMap, io::Write, rc::Rc}; use js_sys::{Function, WebAssembly}; use wasm_bindgen::prelude::*; diff --git a/crates/wasm-bridge-js/src/component/component_loader.rs b/crates/wasm-bridge-js/src/component/component_loader.rs index 53612623..3622396b 100644 --- a/crates/wasm-bridge-js/src/component/component_loader.rs +++ b/crates/wasm-bridge-js/src/component/component_loader.rs @@ -1,3 +1,5 @@ +use std::io::Write; + use anyhow::{bail, Context}; use js_component_bindgen::{transpile, TranspileOpts}; use js_sys::Function; diff --git a/crates/wasm-bridge-js/src/wasi/preview2/command.rs b/crates/wasm-bridge-js/src/wasi/preview2/command.rs index 91cf9674..5b016016 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/command.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/command.rs @@ -5,6 +5,8 @@ use crate::component::Linker; use crate::wasi::preview2::{clocks, WasiView}; use crate::{Result, StoreContextMut}; +use super::environment; + static WASI_IMPORTS_STR: &str = include_str!("../../../../../resources/transformed/preview2-shim/bundled.js"); @@ -66,6 +68,7 @@ pub fn add_to_linker(linker: &mut Linker) -> Result<() clocks::add_to_linker(linker)?; + environment::add_to_linker(linker)?; Ok(()) } diff --git a/crates/wasm-bridge-js/src/wasi/preview2/environment.rs b/crates/wasm-bridge-js/src/wasi/preview2/environment.rs new file mode 100644 index 00000000..930885ae --- /dev/null +++ b/crates/wasm-bridge-js/src/wasi/preview2/environment.rs @@ -0,0 +1,35 @@ +//! Provides environment interaction for WASI. +//! +//! See: + +use crate::{component::Linker, Result, StoreContextMut}; + +use super::WasiView; + +/// Adds environment integration to the linker +pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { + linker.instance("wasi:cli-base/environment")?.func_wrap( + "get-environment", + |data: StoreContextMut, (): ()| { + Ok(data + .ctx() + .environment() + .iter() + .map(|(k, v)| (k.to_owned(), v.to_owned())) + .collect::>()) + }, + )?; + + linker.instance("wasi:cli-base/environment")?.func_wrap( + "get-arguments", + |_data: StoreContextMut, (): ()| -> Result { unimplemented!() }, + )?; + + linker + .instance("wasi:cli-base/environment")? + .func_wrap("initial-cwd", |_data: StoreContextMut, (): ()| { + Ok(String::from(".")) + })?; + + Ok(()) +} diff --git a/crates/wasm-bridge-js/src/wasi/preview2/mod.rs b/crates/wasm-bridge-js/src/wasi/preview2/mod.rs index ed7477ed..7c2209b5 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/mod.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/mod.rs @@ -20,3 +20,6 @@ pub use clocks::*; mod random; pub(crate) use random::*; + +mod environment; +pub(crate) use environment::add_to_linker; diff --git a/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx.rs b/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx.rs index 8b78b4d2..04731854 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use super::*; pub struct WasiCtx { @@ -9,6 +11,8 @@ pub struct WasiCtx { wall_clock: Box, monotonic_clock: Box, + + env: HashMap, } impl WasiCtx { @@ -19,6 +23,7 @@ impl WasiCtx { random: Option, wall_clock: Option>, monotonic_clock: Option>, + env: HashMap, ) -> Self { Self { stdin: stdin.unwrap_or_else(|| Box::new(void_stream())), @@ -27,6 +32,7 @@ impl WasiCtx { random: random.unwrap_or_else(js_rand), wall_clock: wall_clock.unwrap_or_else(|| Box::new(real_wall_clock())), monotonic_clock: monotonic_clock.unwrap_or_else(|| Box::new(default_monotonic_clock())), + env, } } @@ -53,4 +59,8 @@ impl WasiCtx { pub(crate) fn monotonic_clock(&self) -> &dyn HostMonotonicClock { &*self.monotonic_clock } + + pub(crate) fn environment(&self) -> &HashMap { + &self.env + } } diff --git a/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx_builder.rs b/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx_builder.rs index d2fc49ec..e22c1f2e 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx_builder.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx_builder.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use rand_core::RngCore; use super::*; @@ -13,6 +15,7 @@ pub struct WasiCtxBuilder { wall_clock: Option>, monotonic_clock: Option>, + env: HashMap, } impl WasiCtxBuilder { @@ -28,6 +31,7 @@ impl WasiCtxBuilder { self.random, self.wall_clock, self.monotonic_clock, + self.env, )) } @@ -105,4 +109,12 @@ impl WasiCtxBuilder { ..self } } + + pub fn set_env(mut self, env: &[(impl AsRef, impl AsRef)]) -> Self { + self.env = env + .iter() + .map(|(k, v)| (k.as_ref().to_string(), v.as_ref().to_string())) + .collect(); + self + } } diff --git a/examples/wasi_components/build_guest.sh b/examples/wasi_components/build_guest.sh new file mode 100755 index 00000000..a255d144 --- /dev/null +++ b/examples/wasi_components/build_guest.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -e + +if [[ $1 ]]; then + echo "-> Building $1" + EXAMPLES=$1 +else + EXAMPLES=`ls guest` +fi + + +# Build the guest +for EXAMPLE in $EXAMPLES; do + echo "-> Building $EXAMPLE" + cargo component build -p $EXAMPLE-guest +done diff --git a/examples/wasi_components/guest/io_redirect/.gitignore b/examples/wasi_components/guest/io/.gitignore similarity index 100% rename from examples/wasi_components/guest/io_redirect/.gitignore rename to examples/wasi_components/guest/io/.gitignore diff --git a/examples/wasi_components/guest/io_redirect/Cargo.toml b/examples/wasi_components/guest/io/Cargo.toml similarity index 87% rename from examples/wasi_components/guest/io_redirect/Cargo.toml rename to examples/wasi_components/guest/io/Cargo.toml index f112b454..73265c22 100644 --- a/examples/wasi_components/guest/io_redirect/Cargo.toml +++ b/examples/wasi_components/guest/io/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "io-redirect-guest" +name = "io-guest" edition.workspace = true version = "0.0.0" diff --git a/examples/wasi_components/guest/io_redirect/src/lib.rs b/examples/wasi_components/guest/io/src/lib.rs similarity index 100% rename from examples/wasi_components/guest/io_redirect/src/lib.rs rename to examples/wasi_components/guest/io/src/lib.rs diff --git a/examples/wasi_components/run_examples.sh b/examples/wasi_components/run_examples.sh deleted file mode 100755 index 7b364145..00000000 --- a/examples/wasi_components/run_examples.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash - -set -e - -if [[ $1 ]]; then - echo "-> Building $1" - EXAMPLES=$1 -else - EXAMPLES=`ls ` -fi - - -# Build the guest -for example in $EXAMPLES; do - if [[ ! -d $example ]]; then - continue - fi - - echo "-> Running $example" - cargo component build -p example-$example-guest - cargo run -p example-$example-host -done diff --git a/examples/wasi_components/tests/io_redirect.rs b/examples/wasi_components/tests/io.rs similarity index 96% rename from examples/wasi_components/tests/io_redirect.rs rename to examples/wasi_components/tests/io.rs index 5e284fbf..e13b612d 100644 --- a/examples/wasi_components/tests/io_redirect.rs +++ b/examples/wasi_components/tests/io.rs @@ -7,7 +7,10 @@ use wasm_bridge::{ use wasm_bridge::wasi::preview2::*; -use std::sync::{Arc, Mutex}; +use std::{ + io::Write, + sync::{Arc, Mutex}, +}; wasm_bridge::component::bindgen!({ path: "./io_redirect.wit", @@ -37,9 +40,8 @@ impl WasiView for State { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] -pub async fn io_redirect() -> Result<()> { - const GUEST_BYTES: &[u8] = - include_bytes!("../../../target/wasm32-wasi/debug/io_redirect_guest.wasm"); +pub async fn test() -> Result<()> { + const GUEST_BYTES: &[u8] = include_bytes!("../../../target/wasm32-wasi/debug/io_guest.wasm"); no_config(GUEST_BYTES).await?; inherit(GUEST_BYTES).await?; @@ -59,7 +61,7 @@ async fn no_config(component_bytes: &[u8]) -> Result<()> { let engine = Engine::new(&config)?; let mut store = Store::new(&engine, State { table, wasi }); - let component = Component::new(&store.engine(), &component_bytes)?; + let component = Component::new(store.engine(), component_bytes)?; let mut linker = Linker::new(store.engine()); wasi::preview2::command::add_to_linker(&mut linker)?; diff --git a/examples/wit_components/build_guest.sh b/examples/wit_components/build_guest.sh index 627fac2d..acc0e2bd 100755 --- a/examples/wit_components/build_guest.sh +++ b/examples/wit_components/build_guest.sh @@ -6,17 +6,12 @@ if [[ $1 ]]; then echo "-> Building $1" EXAMPLES=$1 else - EXAMPLES=`ls ` + EXAMPLES=`ls guest` fi # Build the guest -for example in $EXAMPLES; do - if [[ ! -d $example ]]; then - continue - fi - - echo "-> Running $example" - cargo component build --target wasm32-unknown-unknown -p example-$example-guest - cargo run -p example-$example-host +for EXAMPLE in $EXAMPLES; do + echo "-> Building $EXAMPLE" + cargo component build --target wasm32-unknown-unknown -p $EXAMPLE-guest done From 1a3882ddb32e23460a85dbfafeb6aff4a0c07449 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Tue, 5 Sep 2023 09:45:57 +0200 Subject: [PATCH 07/26] feat: stdio --- crates/wasm-bridge-js/src/component/linker.rs | 6 ++-- .../src/wasi/preview2/command.rs | 18 ++++++++---- .../wasm-bridge-js/src/wasi/preview2/mod.rs | 4 +-- .../wasm-bridge-js/src/wasi/preview2/stdio.rs | 28 +++++++++++++++++++ 4 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 crates/wasm-bridge-js/src/wasi/preview2/stdio.rs diff --git a/crates/wasm-bridge-js/src/component/linker.rs b/crates/wasm-bridge-js/src/component/linker.rs index 27b0c692..16c687b8 100644 --- a/crates/wasm-bridge-js/src/component/linker.rs +++ b/crates/wasm-bridge-js/src/component/linker.rs @@ -72,7 +72,7 @@ impl Linker { self } - pub fn func_wrap(&mut self, name: &str, func: F) -> Result<()> + pub fn func_wrap(&mut self, name: &str, func: F) -> Result<&mut Self> where T: 'static, F: IntoMakeClosure, @@ -80,10 +80,10 @@ impl Linker { self.fns .push(PreparedFn::new(name, func.into_make_closure())); - Ok(()) + Ok(self) } - pub fn func_wrap_async(&mut self, name: &str, func: F) -> Result<()> + pub fn func_wrap_async(&mut self, name: &str, func: F) -> Result<&mut Self> where T: 'static, F: IntoMakeClosure, diff --git a/crates/wasm-bridge-js/src/wasi/preview2/command.rs b/crates/wasm-bridge-js/src/wasi/preview2/command.rs index 5b016016..81099af6 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/command.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/command.rs @@ -5,15 +5,12 @@ use crate::component::Linker; use crate::wasi::preview2::{clocks, WasiView}; use crate::{Result, StoreContextMut}; -use super::environment; +use super::stdio::{STDERR_IDENT, STDIN_IDENT, STDOUT_IDENT}; +use super::{environment, stdio}; static WASI_IMPORTS_STR: &str = include_str!("../../../../../resources/transformed/preview2-shim/bundled.js"); -const STDIN_IDENT: u32 = 0; -const STDOUT_IDENT: u32 = 1; -const STDERR_IDENT: u32 = 2; - pub fn add_to_linker(linker: &mut Linker) -> Result<()> { // Default imports linker.set_wasi_imports(get_imports()); @@ -66,7 +63,18 @@ pub fn add_to_linker(linker: &mut Linker) -> Result<() Ok(data.ctx_mut().random().next_u64()) })?; + linker.instance("wasi:cli-base/exit")?.func_wrap( + "exit", + |_data: StoreContextMut, + (_status,): (std::result::Result<(), ()>,)| + -> anyhow::Result<()> { + todo!("exit called"); + // Ok(()) + }, + )?; + clocks::add_to_linker(linker)?; + stdio::add_to_linker(linker)?; environment::add_to_linker(linker)?; Ok(()) diff --git a/crates/wasm-bridge-js/src/wasi/preview2/mod.rs b/crates/wasm-bridge-js/src/wasi/preview2/mod.rs index 7c2209b5..65a9a4d1 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/mod.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/mod.rs @@ -1,3 +1,4 @@ +pub mod stdio; mod wasi_ctx_builder; pub use wasi_ctx_builder::WasiCtxBuilder; @@ -21,5 +22,4 @@ pub use clocks::*; mod random; pub(crate) use random::*; -mod environment; -pub(crate) use environment::add_to_linker; +pub(crate) mod environment; diff --git a/crates/wasm-bridge-js/src/wasi/preview2/stdio.rs b/crates/wasm-bridge-js/src/wasi/preview2/stdio.rs new file mode 100644 index 00000000..d8aface7 --- /dev/null +++ b/crates/wasm-bridge-js/src/wasi/preview2/stdio.rs @@ -0,0 +1,28 @@ +use crate::{component::Linker, Result, StoreContextMut}; + +use super::WasiView; + +pub(crate) const STDIN_IDENT: u32 = 0; +pub(crate) const STDOUT_IDENT: u32 = 1; +pub(crate) const STDERR_IDENT: u32 = 2; +pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { + linker + .instance("wasi:cli-base/stdout")? + .func_wrap("get-stdout", |_data: StoreContextMut, (): ()| { + Ok(STDOUT_IDENT) + })?; + + linker + .instance("wasi:cli-base/stderr")? + .func_wrap("get-stderr", |_data: StoreContextMut, (): ()| { + Ok(STDERR_IDENT) + })?; + + linker + .instance("wasi:cli-base/stdin")? + .func_wrap("get-stdin", |_data: StoreContextMut, (): ()| { + Ok(STDIN_IDENT) + })?; + + Ok(()) +} From 8a310b89c4e854bb260c305b8e9ae82fe0a6c8c8 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Thu, 31 Aug 2023 17:36:53 +0200 Subject: [PATCH 08/26] feat: implement filesystem stream support --- .../src/wasi/preview2/command.rs | 5 +- .../src/wasi/preview2/filesystem.rs | 52 +++++++++++++++++++ .../wasm-bridge-js/src/wasi/preview2/mod.rs | 4 +- .../src/wasi/preview2/preopens.rs | 12 +++++ 4 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 crates/wasm-bridge-js/src/wasi/preview2/filesystem.rs create mode 100644 crates/wasm-bridge-js/src/wasi/preview2/preopens.rs diff --git a/crates/wasm-bridge-js/src/wasi/preview2/command.rs b/crates/wasm-bridge-js/src/wasi/preview2/command.rs index 81099af6..32d3f12c 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/command.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/command.rs @@ -6,7 +6,7 @@ use crate::wasi::preview2::{clocks, WasiView}; use crate::{Result, StoreContextMut}; use super::stdio::{STDERR_IDENT, STDIN_IDENT, STDOUT_IDENT}; -use super::{environment, stdio}; +use super::{environment, filesystem, preopens, stdio}; static WASI_IMPORTS_STR: &str = include_str!("../../../../../resources/transformed/preview2-shim/bundled.js"); @@ -77,6 +77,9 @@ pub fn add_to_linker(linker: &mut Linker) -> Result<() stdio::add_to_linker(linker)?; environment::add_to_linker(linker)?; + preopens::add_to_linker(linker)?; + filesystem::add_to_linker(linker)?; + Ok(()) } diff --git a/crates/wasm-bridge-js/src/wasi/preview2/filesystem.rs b/crates/wasm-bridge-js/src/wasi/preview2/filesystem.rs new file mode 100644 index 00000000..cabaffad --- /dev/null +++ b/crates/wasm-bridge-js/src/wasi/preview2/filesystem.rs @@ -0,0 +1,52 @@ +use std::io; + +use crate::{component::Linker, Result, StoreContextMut}; + +use super::{stream, WasiView}; + +pub type Descriptor = u32; +pub type OutputStream = u32; +pub type InputStream = u32; + +pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { + linker + .instance("wasi:filesystem/filesystem")? + .func_wrap( + "append-via-stream", + |_data: StoreContextMut, + (_this,): (Descriptor,)| + -> Result> { + Err(io::Error::new(io::ErrorKind::Unsupported, "append-via-stream").into()) + }, + )? + .func_wrap( + "drop-descriptor", + |_data: StoreContextMut, (_this,): (Descriptor,)| -> Result<()> { + Err(io::Error::new(io::ErrorKind::Unsupported, "drop-descriptor").into()) + }, + )? + .func_wrap( + "get-type", + |_data: StoreContextMut, (_this,): (Descriptor,)| -> Result> { + Err(io::Error::new(io::ErrorKind::Unsupported, "get-type").into()) + }, + )? + .func_wrap( + "read-via-stream", + |_data: StoreContextMut, + (_this, _off): (Descriptor, u64)| + -> Result> { + Err(io::Error::new(io::ErrorKind::Unsupported, "read-via-stream").into()) + }, + )? + .func_wrap( + "write-via-stream", + |_data: StoreContextMut, + (_this, _off): (Descriptor, u64)| + -> Result> { + Err(io::Error::new(io::ErrorKind::Unsupported, "write-via-stream").into()) + }, + )?; + + Ok(()) +} diff --git a/crates/wasm-bridge-js/src/wasi/preview2/mod.rs b/crates/wasm-bridge-js/src/wasi/preview2/mod.rs index 65a9a4d1..19de114b 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/mod.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/mod.rs @@ -1,4 +1,3 @@ -pub mod stdio; mod wasi_ctx_builder; pub use wasi_ctx_builder::WasiCtxBuilder; @@ -23,3 +22,6 @@ mod random; pub(crate) use random::*; pub(crate) mod environment; +pub(crate) mod filesystem; +pub(crate) mod preopens; +pub(crate) mod stdio; diff --git a/crates/wasm-bridge-js/src/wasi/preview2/preopens.rs b/crates/wasm-bridge-js/src/wasi/preview2/preopens.rs new file mode 100644 index 00000000..e1532412 --- /dev/null +++ b/crates/wasm-bridge-js/src/wasi/preview2/preopens.rs @@ -0,0 +1,12 @@ +use crate::{component::Linker, Result, StoreContextMut}; + +use super::WasiView; + +pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { + linker.instance("wasi:cli-base/preopens")?.func_wrap( + "get-directories", + |_data: StoreContextMut, (): ()| -> Result> { Ok(vec![]) }, + )?; + + Ok(()) +} From 1edf0770d628ea3911e69d3f194abcd00c6b30dd Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Thu, 31 Aug 2023 18:14:02 +0200 Subject: [PATCH 09/26] fix: update streams to newest wit --- .../src/component/component_loader.rs | 4 ++ .../src/wasi/preview2/command.rs | 46 +++++++++--------- .../wasm-bridge-js/src/wasi/preview2/mod.rs | 1 + .../src/wasi/preview2/stream/input_stream.rs | 8 ++-- .../src/wasi/preview2/stream/mod.rs | 5 ++ .../src/wasi/preview2/stream/output_stream.rs | 13 +++-- .../src/wasi/preview2/streams.rs | 47 +++++++++++++++++++ examples/wasi_components/tests/io.rs | 15 ++++-- 8 files changed, 104 insertions(+), 35 deletions(-) create mode 100644 crates/wasm-bridge-js/src/wasi/preview2/streams.rs diff --git a/crates/wasm-bridge-js/src/component/component_loader.rs b/crates/wasm-bridge-js/src/component/component_loader.rs index 3622396b..f788529a 100644 --- a/crates/wasm-bridge-js/src/component/component_loader.rs +++ b/crates/wasm-bridge-js/src/component/component_loader.rs @@ -31,6 +31,10 @@ impl ComponentLoader { if name.ends_with(".wasm") { wasm_cores.push((name, bytes)); } else if name.ends_with(".js") { + // panic!( + // "{}", + // String::from_utf8_lossy(&bytes) + // ); // TODO: test that instantiate is not already Some? instantiate = Some(load_instantiate_fn(&bytes)?); } diff --git a/crates/wasm-bridge-js/src/wasi/preview2/command.rs b/crates/wasm-bridge-js/src/wasi/preview2/command.rs index 32d3f12c..22e8669b 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/command.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/command.rs @@ -16,36 +16,36 @@ pub fn add_to_linker(linker: &mut Linker) -> Result<() linker.set_wasi_imports(get_imports()); // Overrides - linker.instance("wasi:io/streams")?.func_wrap( - "read", - |data: StoreContextMut, (id, max_bytes): (u32, u64)| { - if id != STDIN_IDENT { - bail!("unexpected read stream id: {id}"); - } + // linker.instance("wasi:io/streams")?.func_wrap( + // "read", + // |data: StoreContextMut, (id, max_bytes): (u32, u64)| { + // if id != STDIN_IDENT { + // bail!("unexpected read stream id: {id}"); + // } - let mut bytes = vec![0u8; max_bytes as usize]; + // let mut bytes = vec![0u8; max_bytes as usize]; - let (bytes_written, stream_ended) = data.ctx_mut().stdin().read(&mut bytes)?; + // let (bytes_written, stream_ended) = data.ctx_mut().stdin().read(&mut bytes)?; - bytes.truncate(bytes_written as _); + // bytes.truncate(bytes_written as _); - Ok((bytes, stream_ended)) - }, - )?; + // Ok((bytes, stream_ended)) + // }, + // )?; - linker.instance("wasi:io/streams")?.func_wrap( - "write", - |data: StoreContextMut, (id, buffer): (u32, Vec)| { - let bytes_written = match id { - STDOUT_IDENT => data.ctx_mut().stdout().write(&buffer)?, + // linker.instance("wasi:io/streams")?.func_wrap( + // "write", + // |data: StoreContextMut, (id, buffer): (u32, Vec)| { + // let bytes_written = match id { + // STDOUT_IDENT => data.ctx_mut().stdout().write(&buffer)?, - STDERR_IDENT => data.ctx_mut().stderr().write(&buffer)?, + // STDERR_IDENT => data.ctx_mut().stderr().write(&buffer)?, - id => bail!("unexpected write stream id: {id}"), - }; - Ok(bytes_written) - }, - )?; + // id => bail!("unexpected write stream id: {id}"), + // }; + // Ok(bytes_written) + // }, + // )?; linker.instance("wasi:random/random")?.func_wrap( "get-random-bytes", diff --git a/crates/wasm-bridge-js/src/wasi/preview2/mod.rs b/crates/wasm-bridge-js/src/wasi/preview2/mod.rs index 19de114b..0561fca1 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/mod.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/mod.rs @@ -1,3 +1,4 @@ +mod streams; mod wasi_ctx_builder; pub use wasi_ctx_builder::WasiCtxBuilder; diff --git a/crates/wasm-bridge-js/src/wasi/preview2/stream/input_stream.rs b/crates/wasm-bridge-js/src/wasi/preview2/stream/input_stream.rs index 78921337..a9a4730e 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/stream/input_stream.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/stream/input_stream.rs @@ -1,11 +1,13 @@ use crate::Result; +use super::StreamStatus; + pub trait InputStream: Send { fn as_any(&self) -> &dyn std::any::Any; fn readable(&self) -> Result<()>; - fn read(&mut self, buf: &mut [u8]) -> Result<(u64, bool)>; + fn read(&mut self, buf: &mut [u8]) -> Result<(u64, StreamStatus)>; fn num_ready_bytes(&self) -> Result; } @@ -21,8 +23,8 @@ impl InputStream for VoidStream { Ok(()) } - fn read(&mut self, _buf: &mut [u8]) -> Result<(u64, bool)> { - Ok((0, true)) + fn read(&mut self, _buf: &mut [u8]) -> Result<(u64, StreamStatus)> { + Ok((0, StreamStatus::Open)) } fn num_ready_bytes(&self) -> Result { diff --git a/crates/wasm-bridge-js/src/wasi/preview2/stream/mod.rs b/crates/wasm-bridge-js/src/wasi/preview2/stream/mod.rs index 4faee984..c1ede2e2 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/stream/mod.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/stream/mod.rs @@ -5,3 +5,8 @@ pub use output_stream::*; mod input_stream; pub use input_stream::*; + +pub enum StreamStatus { + Open, + Ended, +} diff --git a/crates/wasm-bridge-js/src/wasi/preview2/stream/output_stream.rs b/crates/wasm-bridge-js/src/wasi/preview2/stream/output_stream.rs index 8aa71670..d1a76176 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/stream/output_stream.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/stream/output_stream.rs @@ -3,12 +3,14 @@ use wasm_bindgen::JsValue; use crate::{helpers::map_js_error, Result}; +use super::StreamStatus; + pub trait OutputStream: Send { fn as_any(&self) -> &dyn std::any::Any; fn writable(&self) -> Result<()>; - fn write(&mut self, buf: &[u8]) -> Result; + fn write(&mut self, buf: &[u8]) -> Result<(usize, StreamStatus)>; } struct VoidingStream; @@ -22,8 +24,9 @@ impl OutputStream for VoidingStream { Ok(()) } - fn write(&mut self, buf: &[u8]) -> Result { - Ok(buf.len() as _) + /// Non blocking write + fn write(&mut self, buf: &[u8]) -> Result<(usize, StreamStatus)> { + Ok((buf.len(), StreamStatus::Open)) } } @@ -42,7 +45,7 @@ impl OutputStream for InheritStream { Ok(()) } - fn write(&mut self, buf: &[u8]) -> Result { + fn write(&mut self, buf: &[u8]) -> Result<(usize, StreamStatus)> { let text = String::from_utf8_lossy(buf); // Do not store the js Function, it makes the stream not Send @@ -55,7 +58,7 @@ impl OutputStream for InheritStream { .call1(&JsValue::UNDEFINED, &text.as_ref().into()) .map_err(map_js_error("Call output stream function"))?; - Ok(buf.len() as _) + Ok((buf.len() as _, StreamStatus::Open)) } } diff --git a/crates/wasm-bridge-js/src/wasi/preview2/streams.rs b/crates/wasm-bridge-js/src/wasi/preview2/streams.rs new file mode 100644 index 00000000..731b813b --- /dev/null +++ b/crates/wasm-bridge-js/src/wasi/preview2/streams.rs @@ -0,0 +1,47 @@ +use anyhow::bail; + +use crate::{component::Linker, Result, StoreContextMut}; + +use super::{stdio::STDIN_IDENT, WasiView}; + +// See: +pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { + linker + .instance("wasi:io/streams")? + .func_wrap( + "read", + |data: StoreContextMut, + (id, max_bytes): (u32, u64)| + -> Result, u32), ()>> { + if id != STDIN_IDENT { + bail!("unexpected read stream id: {id}") + } + + let mut bytes = vec![0u8; max_bytes as usize]; + + let (bytes_written, status) = data.ctx_mut().stdin().read(&mut bytes)?; + + bytes.truncate(bytes_written as _); + + Ok(Ok((bytes, status as u32))) + }, + )? + .func_wrap( + "write", + |data: StoreContextMut, + (id, buffer): (u32, Vec)| + -> Result> { + let (bytes_written, status) = match id { + STDOUT_IDENT => data.ctx_mut().stdout().write(&buffer)?, + + STDERR_IDENT => data.ctx_mut().stderr().write(&buffer)?, + + id => bail!("unexpected write stream id: {id}"), + }; + + Ok(Ok((bytes_written as u64, status as u32))) + }, + )?; + + Ok(()) +} diff --git a/examples/wasi_components/tests/io.rs b/examples/wasi_components/tests/io.rs index e13b612d..3fb31fd0 100644 --- a/examples/wasi_components/tests/io.rs +++ b/examples/wasi_components/tests/io.rs @@ -201,10 +201,10 @@ impl OutputStream for OutStream { Ok(()) } - async fn write(&mut self, buf: &[u8]) -> Result { + async fn write(&mut self, buf: &[u8]) -> Result<(usize, StreamStatus)> { let amount = buf.len().min(self.max); self.data.try_lock().unwrap().extend(&buf[..amount]); - Ok(amount as u64) + Ok((amount as usize, StreamStatus::Open)) } } @@ -239,14 +239,21 @@ impl InputStream for InStream { Ok(()) } - async fn read(&mut self, buf: &mut [u8]) -> Result<(u64, bool)> { + async fn read(&mut self, buf: &mut [u8]) -> Result<(u64, StreamStatus)> { let len = buf.len().min(self.data.len() - self.offset).min(self.max); let from_slice = &self.data[self.offset..(self.offset + len)]; (&mut buf[..len]).copy_from_slice(from_slice); self.offset += len; - Ok((len as _, self.data.len() == self.offset)) + Ok(( + len as _, + if self.data.len() == self.offset { + StreamStatus::Ended + } else { + StreamStatus::Open + }, + )) } async fn num_ready_bytes(&self) -> Result { From 069b3085f7f1cbec1194817f1f6727227f49815a Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Fri, 1 Sep 2023 10:04:43 +0200 Subject: [PATCH 10/26] wip: sync streams --- .../src/component/component_loader.rs | 5 +---- .../wasm-bridge-js/src/wasi/preview2/filesystem.rs | 14 ++++---------- examples/wasi_components/tests/io.rs | 1 + resources/original/preview2-shim/browser/io.js | 2 +- resources/transformed/preview2-shim/browser/io.js | 2 +- resources/transformed/preview2-shim/bundled.js | 2 +- 6 files changed, 9 insertions(+), 17 deletions(-) diff --git a/crates/wasm-bridge-js/src/component/component_loader.rs b/crates/wasm-bridge-js/src/component/component_loader.rs index f788529a..ccc9500b 100644 --- a/crates/wasm-bridge-js/src/component/component_loader.rs +++ b/crates/wasm-bridge-js/src/component/component_loader.rs @@ -31,10 +31,7 @@ impl ComponentLoader { if name.ends_with(".wasm") { wasm_cores.push((name, bytes)); } else if name.ends_with(".js") { - // panic!( - // "{}", - // String::from_utf8_lossy(&bytes) - // ); + // panic!("{}", String::from_utf8_lossy(&bytes)); // TODO: test that instantiate is not already Some? instantiate = Some(load_instantiate_fn(&bytes)?); } diff --git a/crates/wasm-bridge-js/src/wasi/preview2/filesystem.rs b/crates/wasm-bridge-js/src/wasi/preview2/filesystem.rs index cabaffad..668f19d2 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/filesystem.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/filesystem.rs @@ -13,9 +13,7 @@ pub(crate) fn add_to_linker(linker: &mut Linker) -> Re .instance("wasi:filesystem/filesystem")? .func_wrap( "append-via-stream", - |_data: StoreContextMut, - (_this,): (Descriptor,)| - -> Result> { + |_data: StoreContextMut, (_this,): (Descriptor,)| -> Result { Err(io::Error::new(io::ErrorKind::Unsupported, "append-via-stream").into()) }, )? @@ -27,23 +25,19 @@ pub(crate) fn add_to_linker(linker: &mut Linker) -> Re )? .func_wrap( "get-type", - |_data: StoreContextMut, (_this,): (Descriptor,)| -> Result> { + |_data: StoreContextMut, (_this,): (Descriptor,)| -> Result { Err(io::Error::new(io::ErrorKind::Unsupported, "get-type").into()) }, )? .func_wrap( "read-via-stream", - |_data: StoreContextMut, - (_this, _off): (Descriptor, u64)| - -> Result> { + |_data: StoreContextMut, (_this, _off): (Descriptor, u64)| -> Result { Err(io::Error::new(io::ErrorKind::Unsupported, "read-via-stream").into()) }, )? .func_wrap( "write-via-stream", - |_data: StoreContextMut, - (_this, _off): (Descriptor, u64)| - -> Result> { + |_data: StoreContextMut, (_this, _off): (Descriptor, u64)| -> Result { Err(io::Error::new(io::ErrorKind::Unsupported, "write-via-stream").into()) }, )?; diff --git a/examples/wasi_components/tests/io.rs b/examples/wasi_components/tests/io.rs index 3fb31fd0..af714146 100644 --- a/examples/wasi_components/tests/io.rs +++ b/examples/wasi_components/tests/io.rs @@ -260,6 +260,7 @@ impl InputStream for InStream { Ok((self.data.len() - self.offset) as _) } } + #[cfg(not(target_arch = "wasm32"))] #[wasm_bridge::async_trait] impl HostInputStream for InStream { diff --git a/resources/original/preview2-shim/browser/io.js b/resources/original/preview2-shim/browser/io.js index 3422382d..5a757304 100644 --- a/resources/original/preview2-shim/browser/io.js +++ b/resources/original/preview2-shim/browser/io.js @@ -1,6 +1,6 @@ export const streams = { read(s, len) { - console.log(`[streams] Read ${s} ${len}`); + console.log(`[streams] Original Read ${s} ${len}`); }, blockingRead(s, len) { console.log(`[streams] Blocking read ${s} ${len}`); diff --git a/resources/transformed/preview2-shim/browser/io.js b/resources/transformed/preview2-shim/browser/io.js index 3422382d..85e98f09 100644 --- a/resources/transformed/preview2-shim/browser/io.js +++ b/resources/transformed/preview2-shim/browser/io.js @@ -1,6 +1,6 @@ export const streams = { read(s, len) { - console.log(`[streams] Read ${s} ${len}`); + console.log(`[streams] Browser Read ${s} ${len}`); }, blockingRead(s, len) { console.log(`[streams] Blocking read ${s} ${len}`); diff --git a/resources/transformed/preview2-shim/bundled.js b/resources/transformed/preview2-shim/bundled.js index 077a4d22..a9dfc782 100644 --- a/resources/transformed/preview2-shim/bundled.js +++ b/resources/transformed/preview2-shim/bundled.js @@ -343,7 +343,7 @@ }); var streams = { read(s, len) { - console.log(`[streams] Read ${s} ${len}`); + console.log(`[streams] Bundled Read ${s} ${len}`); }, blockingRead(s, len) { console.log(`[streams] Blocking read ${s} ${len}`); From 38fba21f66267226bbf55a465755eeb058e0c5a0 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Fri, 1 Sep 2023 10:12:19 +0200 Subject: [PATCH 11/26] feat: expose sync feature --- crates/wasm-bridge/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/wasm-bridge/Cargo.toml b/crates/wasm-bridge/Cargo.toml index f036a8a7..7c6264a5 100644 --- a/crates/wasm-bridge/Cargo.toml +++ b/crates/wasm-bridge/Cargo.toml @@ -24,6 +24,7 @@ default = ["wat", "error-logging"] wat = ["wasmtime/wat", "wasm-bridge-js/wat"] component-model = ["wasmtime/component-model", "wasm-bridge-macros", "wasm-bridge-js/component-model"] async = ["wasmtime/async", "async-trait", "wasm-bridge-macros/async", "wasm-bridge-js/async"] +sync = [ "wasmtime-wasi/sync" ] wasi = ["wasmtime-wasi", "wasm-bridge-js/wasi", "async"] error-logging = ["wasm-bridge-js/error-logging"] From 6b598fb891924b39fd7f78f23fbb7d4df76280b4 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Tue, 22 Aug 2023 14:27:17 +0200 Subject: [PATCH 12/26] chore: use git dependency --- crates/wasm-bridge-js/Cargo.toml | 2 +- crates/wasm-bridge/Cargo.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/wasm-bridge-js/Cargo.toml b/crates/wasm-bridge-js/Cargo.toml index d8b8477c..88159352 100644 --- a/crates/wasm-bridge-js/Cargo.toml +++ b/crates/wasm-bridge-js/Cargo.toml @@ -12,7 +12,7 @@ categories.workspace = true js-sys = { version = "0.3.64" } wasm-bindgen = "0.2.87" wasm-bindgen-futures = { version = "0.4.37" } -wat = { version = "1.0.66", optional = true } +wat = { version = "1.0.70", git = "https://github.com/bytecodealliance/wasm-tools", optional = true } wasm-bridge-macros = { path = "../wasm-bridge-macros", version = "0.2.2", optional = true } js-component-bindgen = { version = "0.9.5", optional = true } anyhow = { version = "1.0.22" } diff --git a/crates/wasm-bridge/Cargo.toml b/crates/wasm-bridge/Cargo.toml index 7c6264a5..f4912fce 100644 --- a/crates/wasm-bridge/Cargo.toml +++ b/crates/wasm-bridge/Cargo.toml @@ -10,8 +10,8 @@ categories.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -wasmtime = { version = "12.0.0", default-features = false, features = ["cranelift"] } -wasmtime-wasi = { version = "12.0.0", optional = true } +wasmtime = { version = "13.0.0", git = "https://github.com/bytecodealliance/wasmtime", default-features = false, features = ["cranelift"] } +wasmtime-wasi = { version = "13.0.0", git = "https://github.com/bytecodealliance/wasmtime", optional = true } wasm-bridge-macros = { path = "../wasm-bridge-macros", version = "0.2.2", optional = true } async-trait = { version = "0.1.73", optional = true } From 80692265746bea76e7a10bacca59ebd942b98504 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Wed, 23 Aug 2023 10:34:21 +0200 Subject: [PATCH 13/26] chore: sync WasiCtxBuilder with upstream --- .../wasm-bridge-js/src/wasi/preview2/mod.rs | 2 +- .../src/wasi/preview2/wasi_ctx_builder.rs | 107 +++++++++--------- examples/wasi_components/tests/io.rs | 6 +- 3 files changed, 55 insertions(+), 60 deletions(-) diff --git a/crates/wasm-bridge-js/src/wasi/preview2/mod.rs b/crates/wasm-bridge-js/src/wasi/preview2/mod.rs index 0561fca1..be01b885 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/mod.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/mod.rs @@ -1,6 +1,6 @@ mod streams; mod wasi_ctx_builder; -pub use wasi_ctx_builder::WasiCtxBuilder; +pub use wasi_ctx_builder::{IsATTY, WasiCtxBuilder}; mod wasi_ctx; pub use wasi_ctx::WasiCtx; diff --git a/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx_builder.rs b/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx_builder.rs index e22c1f2e..85c1d098 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx_builder.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx_builder.rs @@ -5,6 +5,11 @@ use rand_core::RngCore; use super::*; use crate::Result; +pub enum IsATTY { + Yes, + No, +} + #[derive(Default)] pub struct WasiCtxBuilder { stdin: Option>, @@ -23,91 +28,81 @@ impl WasiCtxBuilder { Default::default() } - pub fn build(self, _table: &mut Table) -> Result { + pub fn build(&mut self, _table: &mut Table) -> Result { + let v = std::mem::take(self); + Ok(WasiCtx::new( - self.stdin, - self.stdout, - self.stderr, - self.random, - self.wall_clock, - self.monotonic_clock, - self.env, + v.stdin, + v.stdout, + v.stderr, + v.random, + v.wall_clock, + v.monotonic_clock, + v.env, )) } - pub fn set_stdin(self, in_stream: impl InputStream + 'static) -> Self { - Self { - stdin: Some(Box::new(in_stream)), - ..self - } + /// *NOTE*: is_atty is currently ignored + pub fn stdin(&mut self, in_stream: impl InputStream + 'static, _is_atty: IsATTY) -> &mut Self { + self.stdin = Some(Box::new(in_stream)); + self } - pub fn set_stdout(self, out: impl OutputStream + 'static) -> Self { - Self { - stdout: Some(Box::new(out)), - ..self - } + /// *NOTE*: is_atty is currently ignored + pub fn stdout(&mut self, out: impl OutputStream + 'static, _is_atty: IsATTY) -> &mut Self { + self.stdout = Some(Box::new(out)); + self } - pub fn set_stderr(self, err: impl OutputStream + 'static) -> Self { - Self { - stderr: Some(Box::new(err)), - ..self - } + /// *NOTE*: is_atty is currently ignored + pub fn stderr(&mut self, err: impl OutputStream + 'static, _is_atty: IsATTY) -> &mut Self { + self.stderr = Some(Box::new(err)); + self } - pub fn inherit_stdin(self) -> Self { + pub fn inherit_stdin(&mut self) -> &mut Self { // TODO: could be implemented at least on node, but readline is asynchronous self } - pub fn inherit_stdout(self) -> Self { - Self { - stdout: Some(Box::new(console_log_stream())), - ..self - } + pub fn inherit_stdout(&mut self) -> &mut Self { + self.stdout = Some(Box::new(console_log_stream())); + self } - pub fn inherit_stderr(self) -> Self { - Self { - stderr: Some(Box::new(console_error_stream())), - ..self - } + pub fn inherit_stderr(&mut self) -> &mut Self { + self.stderr = Some(Box::new(console_error_stream())); + self } - pub fn inherit_stdio(self) -> Self { + pub fn inherit_stdio(&mut self) -> &mut Self { self.inherit_stdin().inherit_stdout().inherit_stderr() } - pub fn set_secure_random(self) -> Self { - Self { - random: None, // Will be filled later - ..self - } + pub fn set_secure_random(&mut self) -> &mut Self { + self.random = None; + self } pub fn set_secure_random_to_custom_generator( - self, + &mut self, random: impl RngCore + Send + Sync + 'static, - ) -> Self { - Self { - random: Some(Box::new(random)), - ..self - } + ) -> &mut Self { + self.random = Some(Box::new(random)); + self } - pub fn set_wall_clock(self, wall_clock: impl HostWallClock + 'static) -> Self { - Self { - wall_clock: Some(Box::new(wall_clock)), - ..self - } + pub fn set_wall_clock(&mut self, wall_clock: impl HostWallClock + 'static) -> &mut Self { + self.wall_clock = Some(Box::new(wall_clock)); + self } - pub fn set_monotonic_clock(self, monotonic_clock: impl HostMonotonicClock + 'static) -> Self { - Self { - monotonic_clock: Some(Box::new(monotonic_clock)), - ..self - } + pub fn set_monotonic_clock( + &mut self, + monotonic_clock: impl HostMonotonicClock + 'static, + ) -> &mut Self { + self.monotonic_clock = Some(Box::new(monotonic_clock)); + self } pub fn set_env(mut self, env: &[(impl AsRef, impl AsRef)]) -> Self { diff --git a/examples/wasi_components/tests/io.rs b/examples/wasi_components/tests/io.rs index af714146..1e18dfc9 100644 --- a/examples/wasi_components/tests/io.rs +++ b/examples/wasi_components/tests/io.rs @@ -141,9 +141,9 @@ async fn capture(component_bytes: &[u8]) -> Result<()> { let mut table = Table::new(); let wasi = WasiCtxBuilder::new() - .set_stdin(in_stream) - .set_stdout(out_stream) - .set_stderr(err_stream) + .stdin(in_stream, IsATTY::No) + .stdout(out_stream, IsATTY::No) + .stderr(err_stream, IsATTY::No) .build(&mut table)?; let engine = Engine::new(&config)?; From 3cf0f45d47c4429619a342a4b6a26a145f1267c6 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Wed, 23 Aug 2023 10:49:36 +0200 Subject: [PATCH 14/26] chore: expose sync feature --- crates/wasm-bridge/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/wasm-bridge/Cargo.toml b/crates/wasm-bridge/Cargo.toml index f4912fce..a5908d00 100644 --- a/crates/wasm-bridge/Cargo.toml +++ b/crates/wasm-bridge/Cargo.toml @@ -24,7 +24,7 @@ default = ["wat", "error-logging"] wat = ["wasmtime/wat", "wasm-bridge-js/wat"] component-model = ["wasmtime/component-model", "wasm-bridge-macros", "wasm-bridge-js/component-model"] async = ["wasmtime/async", "async-trait", "wasm-bridge-macros/async", "wasm-bridge-js/async"] -sync = [ "wasmtime-wasi/sync" ] +sync = ["wasmtime-wasi/sync"] wasi = ["wasmtime-wasi", "wasm-bridge-js/wasi", "async"] error-logging = ["wasm-bridge-js/error-logging"] From 04bf82ee81a9a28508b091c2b1191a7bb3f0c15c Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Fri, 25 Aug 2023 11:28:13 +0200 Subject: [PATCH 15/26] fix: wasm-bridge-js build --- .vscode/settings.json | 3 ++- recipes.json | 12 ------------ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index b48948ab..69ae6071 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "rust-analyzer.showUnlinkedFileNotification": false + "rust-analyzer.showUnlinkedFileNotification": false, + "rust-analyzer.cargo.features": "all" } diff --git a/recipes.json b/recipes.json index d1c775a1..534709c8 100644 --- a/recipes.json +++ b/recipes.json @@ -9,17 +9,5 @@ "qf": { "compiler": "cargo" } - }, - "test-io": { - "cmd": [ - "./examples/wasi_components/run_examples.sh", - "io_redirect" - ], - "components": { - "qf": { - "compiler": "cargo" - } - }, - "cwd": "./examples/wasi_components/" } } From 11e12f75a6b1ac8af81c164c61bc28053ee0e459 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Fri, 1 Sep 2023 11:56:28 +0200 Subject: [PATCH 16/26] feat: terminal --- .../src/wasi/preview2/command.rs | 3 ++- .../wasm-bridge-js/src/wasi/preview2/mod.rs | 1 + .../src/wasi/preview2/terminal.rs | 23 +++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 crates/wasm-bridge-js/src/wasi/preview2/terminal.rs diff --git a/crates/wasm-bridge-js/src/wasi/preview2/command.rs b/crates/wasm-bridge-js/src/wasi/preview2/command.rs index 22e8669b..4cc67e7b 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/command.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/command.rs @@ -6,7 +6,7 @@ use crate::wasi::preview2::{clocks, WasiView}; use crate::{Result, StoreContextMut}; use super::stdio::{STDERR_IDENT, STDIN_IDENT, STDOUT_IDENT}; -use super::{environment, filesystem, preopens, stdio}; +use super::{environment, filesystem, preopens, stdio, terminal}; static WASI_IMPORTS_STR: &str = include_str!("../../../../../resources/transformed/preview2-shim/bundled.js"); @@ -79,6 +79,7 @@ pub fn add_to_linker(linker: &mut Linker) -> Result<() environment::add_to_linker(linker)?; preopens::add_to_linker(linker)?; filesystem::add_to_linker(linker)?; + terminal::add_to_linker(linker)?; Ok(()) } diff --git a/crates/wasm-bridge-js/src/wasi/preview2/mod.rs b/crates/wasm-bridge-js/src/wasi/preview2/mod.rs index be01b885..213b6bb3 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/mod.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/mod.rs @@ -26,3 +26,4 @@ pub(crate) mod environment; pub(crate) mod filesystem; pub(crate) mod preopens; pub(crate) mod stdio; +pub(crate) mod terminal; diff --git a/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs b/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs new file mode 100644 index 00000000..08d574d1 --- /dev/null +++ b/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs @@ -0,0 +1,23 @@ +use std::io; + +use crate::{component::Linker, Result, StoreContextMut}; + +use super::{stream, WasiView}; + +pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { + linker + .instance("wasi:filesystem/terminal-input")? + .func_wrap( + "drop-terminal-input", + |_data: StoreContextMut, (_this,): (u32,)| -> Result<()> { Ok(()) }, + )?; + + linker + .instance("wasi:filesystem/terminal-output")? + .func_wrap( + "drop-terminal-output", + |_data: StoreContextMut, (_this,): (u32,)| -> Result<()> { Ok(()) }, + )?; + + Ok(()) +} From ed437e103888dbe60d93c5a8ddaf3a9c6d88b99f Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Fri, 1 Sep 2023 12:09:11 +0200 Subject: [PATCH 17/26] fix: terminal world --- .../src/wasi/preview2/terminal.rs | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs b/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs index 08d574d1..ce75da67 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs @@ -5,19 +5,15 @@ use crate::{component::Linker, Result, StoreContextMut}; use super::{stream, WasiView}; pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { - linker - .instance("wasi:filesystem/terminal-input")? - .func_wrap( - "drop-terminal-input", - |_data: StoreContextMut, (_this,): (u32,)| -> Result<()> { Ok(()) }, - )?; + linker.instance("wasi:cli/terminal-input")?.func_wrap( + "drop-terminal-input", + |_data: StoreContextMut, (_this,): (u32,)| -> Result<()> { Ok(()) }, + )?; - linker - .instance("wasi:filesystem/terminal-output")? - .func_wrap( - "drop-terminal-output", - |_data: StoreContextMut, (_this,): (u32,)| -> Result<()> { Ok(()) }, - )?; + linker.instance("wasi:cli/terminal-output")?.func_wrap( + "drop-terminal-output", + |_data: StoreContextMut, (_this,): (u32,)| -> Result<()> { Ok(()) }, + )?; Ok(()) } From 19de05e187fdeb4ad8f36483523586bc3ccfbbc5 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Fri, 1 Sep 2023 12:12:45 +0200 Subject: [PATCH 18/26] feat: more terminal --- .../wasm-bridge-js/src/wasi/preview2/terminal.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs b/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs index ce75da67..ff61f6ab 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs @@ -15,5 +15,20 @@ pub(crate) fn add_to_linker(linker: &mut Linker) -> Re |_data: StoreContextMut, (_this,): (u32,)| -> Result<()> { Ok(()) }, )?; + linker.instance("wasi:cli/terminal-stdin")?.func_wrap( + "get-terminal-stdin", + |_data: StoreContextMut, (_this,): (u32,)| -> Result> { Ok(None) }, + )?; + + linker.instance("wasi:cli/terminal-stdout")?.func_wrap( + "get-terminal-stdout", + |_data: StoreContextMut, (_this,): (u32,)| -> Result> { Ok(None) }, + )?; + + linker.instance("wasi:cli/terminal-stderr")?.func_wrap( + "get-terminal-stderr", + |_data: StoreContextMut, (_this,): (u32,)| -> Result> { Ok(None) }, + )?; + Ok(()) } From 58f1dda61fa312a6c5949bb80cb970dc98b6acd8 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Fri, 1 Sep 2023 17:37:50 +0200 Subject: [PATCH 19/26] feat: tracing --- crates/wasm-bridge-js/Cargo.toml | 1 + crates/wasm-bridge-js/src/component/component_loader.rs | 2 ++ crates/wasm-bridge-js/src/component/linker.rs | 4 ++++ crates/wasm-bridge-js/src/wasi/preview2/command.rs | 1 + crates/wasm-bridge-js/src/wasi/preview2/terminal.rs | 6 +++--- examples/wasi_components/Cargo.toml | 6 ++++++ 6 files changed, 17 insertions(+), 3 deletions(-) diff --git a/crates/wasm-bridge-js/Cargo.toml b/crates/wasm-bridge-js/Cargo.toml index 88159352..82b08670 100644 --- a/crates/wasm-bridge-js/Cargo.toml +++ b/crates/wasm-bridge-js/Cargo.toml @@ -19,6 +19,7 @@ anyhow = { version = "1.0.22" } heck = { version = "0.4.1" } rand_core = { version = "0.6.4", optional = true } getrandom = { version = "0.2.10", optional = true } +tracing = "0.1" [dev-dependencies] wasm-bindgen-test = "0.3.37" diff --git a/crates/wasm-bridge-js/src/component/component_loader.rs b/crates/wasm-bridge-js/src/component/component_loader.rs index ccc9500b..cc76f7c3 100644 --- a/crates/wasm-bridge-js/src/component/component_loader.rs +++ b/crates/wasm-bridge-js/src/component/component_loader.rs @@ -31,6 +31,8 @@ impl ComponentLoader { if name.ends_with(".wasm") { wasm_cores.push((name, bytes)); } else if name.ends_with(".js") { + let s = String::from_utf8_lossy(&bytes); + tracing::debug!(s = %&*s, "js loader"); // panic!("{}", String::from_utf8_lossy(&bytes)); // TODO: test that instantiate is not already Some? instantiate = Some(load_instantiate_fn(&bytes)?); diff --git a/crates/wasm-bridge-js/src/component/linker.rs b/crates/wasm-bridge-js/src/component/linker.rs index 16c687b8..e567cbd6 100644 --- a/crates/wasm-bridge-js/src/component/linker.rs +++ b/crates/wasm-bridge-js/src/component/linker.rs @@ -29,9 +29,11 @@ impl Linker { component: &Component, ) -> Result { let import_object = js_sys::Object::new(); + if let Some(imports) = &self.wasi_imports { js_sys::Object::assign(&import_object, imports); } + let import_object: JsValue = import_object.into(); let mut closures = Vec::with_capacity(self.fns.len()); @@ -121,6 +123,7 @@ impl PreparedFn { #[must_use] fn add_to_imports(&self, imports: &JsValue, handle: DataHandle) -> DropHandle { + tracing::debug!("import func {}", self.name); let (js_val, handler) = (self.creator)(handle); let object: JsValue = Object::new().into(); @@ -133,6 +136,7 @@ impl PreparedFn { #[must_use] fn add_to_instance_imports(&self, imports: &JsValue, handle: DataHandle) -> DropHandle { + tracing::debug!("instance func {}", self.name); let (js_val, handler) = (self.creator)(handle); Reflect::set(imports, &self.name.to_lower_camel_case().into(), &js_val) diff --git a/crates/wasm-bridge-js/src/wasi/preview2/command.rs b/crates/wasm-bridge-js/src/wasi/preview2/command.rs index 4cc67e7b..9a47a626 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/command.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/command.rs @@ -84,6 +84,7 @@ pub fn add_to_linker(linker: &mut Linker) -> Result<() Ok(()) } +/// Returns the shims import objects fn get_imports() -> Object { let imports = js_sys::eval(WASI_IMPORTS_STR).expect("eval bundled wasi imports"); diff --git a/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs b/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs index ff61f6ab..6ec156ee 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/terminal.rs @@ -17,17 +17,17 @@ pub(crate) fn add_to_linker(linker: &mut Linker) -> Re linker.instance("wasi:cli/terminal-stdin")?.func_wrap( "get-terminal-stdin", - |_data: StoreContextMut, (_this,): (u32,)| -> Result> { Ok(None) }, + |_data: StoreContextMut, (): ()| -> Result> { Ok(None) }, )?; linker.instance("wasi:cli/terminal-stdout")?.func_wrap( "get-terminal-stdout", - |_data: StoreContextMut, (_this,): (u32,)| -> Result> { Ok(None) }, + |_data: StoreContextMut, (): ()| -> Result> { Ok(None) }, )?; linker.instance("wasi:cli/terminal-stderr")?.func_wrap( "get-terminal-stderr", - |_data: StoreContextMut, (_this,): (u32,)| -> Result> { Ok(None) }, + |_data: StoreContextMut, (): ()| -> Result> { Ok(None) }, )?; Ok(()) diff --git a/examples/wasi_components/Cargo.toml b/examples/wasi_components/Cargo.toml index 8dd6781b..182346ab 100644 --- a/examples/wasi_components/Cargo.toml +++ b/examples/wasi_components/Cargo.toml @@ -10,3 +10,9 @@ bytes = "1.4" [target."cfg(not(target_arch = \"wasm32\"))".dependencies] tokio = { version = "1.32", features = ["full"] } + +[dev-dependencies] +tracing-web = "0.1" +tracing-subscriber = { version = "0.3", features = ["time"] } +wasm-bindgen-test = "0.3" +time = { version = "0.3", features = ["wasm-bindgen"] } From 68e35a4f3110df34cb031833efc068a4c9eac591 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Mon, 4 Sep 2023 18:19:38 +0200 Subject: [PATCH 20/26] fix: wasi shims --- crates/wasm-bridge-js/Cargo.toml | 2 +- .../wasm-bridge-js/src/component/component.rs | 1 + .../wasm-bridge-js/src/component/exports.rs | 9 ++-- crates/wasm-bridge-js/src/component/linker.rs | 16 ++++-- .../src/wasi/preview2/command.rs | 7 +-- .../src/wasi/preview2/stream/input_stream.rs | 2 +- .../src/wasi/preview2/stream/mod.rs | 8 +++ .../src/wasi/preview2/streams.rs | 53 +++++++++++++++++-- .../src/wasi/preview2/wasi_ctx_builder.rs | 1 + examples/wasi_components/Cargo.toml | 1 - examples/wasi_components/tests/io.rs | 11 ++++ examples/wit_components/Cargo.toml | 4 ++ examples/wit_components/tests/records.rs | 14 +++++ recipes.json | 13 ++++- .../transformed/preview2-shim/browser/io.js | 2 +- .../transformed/preview2-shim/bundled.js | 8 ++- resources/transformed/preview2-shim/index.js | 12 +++++ 17 files changed, 143 insertions(+), 21 deletions(-) diff --git a/crates/wasm-bridge-js/Cargo.toml b/crates/wasm-bridge-js/Cargo.toml index 82b08670..8c0c175c 100644 --- a/crates/wasm-bridge-js/Cargo.toml +++ b/crates/wasm-bridge-js/Cargo.toml @@ -16,10 +16,10 @@ wat = { version = "1.0.70", git = "https://github.com/bytecodealliance/wasm-tool wasm-bridge-macros = { path = "../wasm-bridge-macros", version = "0.2.2", optional = true } js-component-bindgen = { version = "0.9.5", optional = true } anyhow = { version = "1.0.22" } -heck = { version = "0.4.1" } rand_core = { version = "0.6.4", optional = true } getrandom = { version = "0.2.10", optional = true } tracing = "0.1" +convert_case = "0.6.0" [dev-dependencies] wasm-bindgen-test = "0.3.37" diff --git a/crates/wasm-bridge-js/src/component/component.rs b/crates/wasm-bridge-js/src/component/component.rs index 83a86134..e7bc38d9 100644 --- a/crates/wasm-bridge-js/src/component/component.rs +++ b/crates/wasm-bridge-js/src/component/component.rs @@ -50,6 +50,7 @@ impl Component { import_object: &JsValue, closures: Rc<[DropHandle]>, ) -> Result { + tracing::debug!("instantiate {:#?}", import_object); let exports = self .instantiate .call3( diff --git a/crates/wasm-bridge-js/src/component/exports.rs b/crates/wasm-bridge-js/src/component/exports.rs index 0589dacc..05745f64 100644 --- a/crates/wasm-bridge-js/src/component/exports.rs +++ b/crates/wasm-bridge-js/src/component/exports.rs @@ -1,7 +1,7 @@ use std::{collections::HashMap, marker::PhantomData, rc::Rc}; use anyhow::Context; -use heck::ToLowerCamelCase; +use convert_case::Casing; use js_sys::{Object, Reflect}; use wasm_bindgen::JsValue; @@ -61,7 +61,7 @@ impl ExportsRoot { pub fn typed_func(&self, name: &str) -> Result> { // TODO: converting in the opposite direction when storing would be slightly faster - let name = name.to_lower_camel_case(); + let name = name.to_case(convert_case::Case::Camel); let func = self .exported_fns @@ -77,7 +77,10 @@ impl ExportsRoot { self.exported_objects .get(name) // TODO: This is a workaround for https://github.com/bytecodealliance/jco/issues/110 - .or_else(|| self.exported_objects.get(&name.to_lower_camel_case()))?, + .or_else(|| { + self.exported_objects + .get(&name.to_case(convert_case::Case::Camel)) + })?, )) } } diff --git a/crates/wasm-bridge-js/src/component/linker.rs b/crates/wasm-bridge-js/src/component/linker.rs index e567cbd6..57752225 100644 --- a/crates/wasm-bridge-js/src/component/linker.rs +++ b/crates/wasm-bridge-js/src/component/linker.rs @@ -1,6 +1,6 @@ use std::{collections::HashMap, rc::Rc}; -use heck::ToLowerCamelCase; +use convert_case::Casing; use js_sys::{Object, Reflect}; use wasm_bindgen::JsValue; @@ -31,6 +31,7 @@ impl Linker { let import_object = js_sys::Object::new(); if let Some(imports) = &self.wasi_imports { + tracing::debug!("assign wasi imports"); js_sys::Object::assign(&import_object, imports); } @@ -44,12 +45,17 @@ impl Linker { closures.push(drop_handle); } + // JCO makes instance functions use camel case for (instance_name, instance_linker) in self.instances.iter() { + let _span = tracing::debug_span!("link instance", instance_name).entered(); let instance_obj = Object::new(); for function in instance_linker.fns.iter() { + tracing::debug!(function = function.name.as_str(), "link instance func"); + let drop_handle = function.add_to_instance_imports(&instance_obj, data_handle.clone()); + closures.push(drop_handle); } @@ -136,11 +142,13 @@ impl PreparedFn { #[must_use] fn add_to_instance_imports(&self, imports: &JsValue, handle: DataHandle) -> DropHandle { - tracing::debug!("instance func {}", self.name); let (js_val, handler) = (self.creator)(handle); - Reflect::set(imports, &self.name.to_lower_camel_case().into(), &js_val) - .expect("imports is object"); + let name = self.name.to_case(convert_case::Case::Camel); + + tracing::debug!(?name, "instance func"); + + Reflect::set(imports, &name.into(), &js_val).expect("imports is object"); handler } diff --git a/crates/wasm-bridge-js/src/wasi/preview2/command.rs b/crates/wasm-bridge-js/src/wasi/preview2/command.rs index 9a47a626..6d2a73f1 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/command.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/command.rs @@ -6,14 +6,14 @@ use crate::wasi::preview2::{clocks, WasiView}; use crate::{Result, StoreContextMut}; use super::stdio::{STDERR_IDENT, STDIN_IDENT, STDOUT_IDENT}; -use super::{environment, filesystem, preopens, stdio, terminal}; +use super::{environment, filesystem, preopens, stdio, streams, terminal}; static WASI_IMPORTS_STR: &str = include_str!("../../../../../resources/transformed/preview2-shim/bundled.js"); pub fn add_to_linker(linker: &mut Linker) -> Result<()> { // Default imports - linker.set_wasi_imports(get_imports()); + // linker.set_wasi_imports(get_imports()); // Overrides // linker.instance("wasi:io/streams")?.func_wrap( @@ -80,11 +80,12 @@ pub fn add_to_linker(linker: &mut Linker) -> Result<() preopens::add_to_linker(linker)?; filesystem::add_to_linker(linker)?; terminal::add_to_linker(linker)?; + streams::add_to_linker(linker)?; Ok(()) } -/// Returns the shims import objects +/// Fills the wasi imports by the browser shim fn get_imports() -> Object { let imports = js_sys::eval(WASI_IMPORTS_STR).expect("eval bundled wasi imports"); diff --git a/crates/wasm-bridge-js/src/wasi/preview2/stream/input_stream.rs b/crates/wasm-bridge-js/src/wasi/preview2/stream/input_stream.rs index a9a4730e..70f1f549 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/stream/input_stream.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/stream/input_stream.rs @@ -24,7 +24,7 @@ impl InputStream for VoidStream { } fn read(&mut self, _buf: &mut [u8]) -> Result<(u64, StreamStatus)> { - Ok((0, StreamStatus::Open)) + Ok((0, StreamStatus::Ended)) } fn num_ready_bytes(&self) -> Result { diff --git a/crates/wasm-bridge-js/src/wasi/preview2/stream/mod.rs b/crates/wasm-bridge-js/src/wasi/preview2/stream/mod.rs index c1ede2e2..59b3c96a 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/stream/mod.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/stream/mod.rs @@ -10,3 +10,11 @@ pub enum StreamStatus { Open, Ended, } +impl StreamStatus { + pub(crate) fn to_variant(&self) -> String { + match self { + Self::Open => "open".into(), + Self::Ended => "ended".into(), + } + } +} diff --git a/crates/wasm-bridge-js/src/wasi/preview2/streams.rs b/crates/wasm-bridge-js/src/wasi/preview2/streams.rs index 731b813b..d805d5a6 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/streams.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/streams.rs @@ -2,7 +2,10 @@ use anyhow::bail; use crate::{component::Linker, Result, StoreContextMut}; -use super::{stdio::STDIN_IDENT, WasiView}; +use super::{ + stdio::{STDERR_IDENT, STDIN_IDENT, STDOUT_IDENT}, + WasiView, +}; // See: pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { @@ -12,7 +15,28 @@ pub(crate) fn add_to_linker(linker: &mut Linker) -> Re "read", |data: StoreContextMut, (id, max_bytes): (u32, u64)| - -> Result, u32), ()>> { + -> Result, String), ()>> { + // tracing::debug!(?id, ?max_bytes, "read"); + if id != STDIN_IDENT { + bail!("unexpected read stream id: {id}") + } + + let mut bytes = vec![0u8; max_bytes as usize]; + + let (count, status) = data.ctx_mut().stdin().read(&mut bytes)?; + // tracing::debug!(?count, "bytes read"); + + bytes.truncate(count as _); + + Ok(Ok((bytes, status.to_variant()))) + }, + )? + .func_wrap( + "blocking-read", + |data: StoreContextMut, + (id, max_bytes): (u32, u64)| + -> Result, String), ()>> { + tracing::debug!(?id, ?max_bytes, "blocking-read"); if id != STDIN_IDENT { bail!("unexpected read stream id: {id}") } @@ -23,14 +47,33 @@ pub(crate) fn add_to_linker(linker: &mut Linker) -> Re bytes.truncate(bytes_written as _); - Ok(Ok((bytes, status as u32))) + Ok(Ok((bytes, status.to_variant()))) }, )? .func_wrap( "write", |data: StoreContextMut, (id, buffer): (u32, Vec)| - -> Result> { + -> Result> { + tracing::debug!(?id, "write"); + let (bytes_written, status) = match id { + STDOUT_IDENT => data.ctx_mut().stdout().write(&buffer)?, + + STDERR_IDENT => data.ctx_mut().stderr().write(&buffer)?, + + id => bail!("unexpected write stream id: {id}"), + }; + + Ok(Ok((bytes_written as u64, status.to_variant()))) + }, + )? + // blocking write has the same signature, thank god + .func_wrap( + "blocking-write", + |data: StoreContextMut, + (id, buffer): (u32, Vec)| + -> Result> { + tracing::debug!(?id, "blocking-write"); let (bytes_written, status) = match id { STDOUT_IDENT => data.ctx_mut().stdout().write(&buffer)?, @@ -39,7 +82,7 @@ pub(crate) fn add_to_linker(linker: &mut Linker) -> Re id => bail!("unexpected write stream id: {id}"), }; - Ok(Ok((bytes_written as u64, status as u32))) + Ok(Ok((bytes_written as u64, status.to_variant()))) }, )?; diff --git a/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx_builder.rs b/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx_builder.rs index 85c1d098..153d3a90 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx_builder.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/wasi_ctx_builder.rs @@ -30,6 +30,7 @@ impl WasiCtxBuilder { pub fn build(&mut self, _table: &mut Table) -> Result { let v = std::mem::take(self); + tracing::debug!("stdin {}", v.stdin.is_some()); Ok(WasiCtx::new( v.stdin, diff --git a/examples/wasi_components/Cargo.toml b/examples/wasi_components/Cargo.toml index 182346ab..ec173de4 100644 --- a/examples/wasi_components/Cargo.toml +++ b/examples/wasi_components/Cargo.toml @@ -15,4 +15,3 @@ tokio = { version = "1.32", features = ["full"] } tracing-web = "0.1" tracing-subscriber = { version = "0.3", features = ["time"] } wasm-bindgen-test = "0.3" -time = { version = "0.3", features = ["wasm-bindgen"] } diff --git a/examples/wasi_components/tests/io.rs b/examples/wasi_components/tests/io.rs index 1e18dfc9..d37e4a02 100644 --- a/examples/wasi_components/tests/io.rs +++ b/examples/wasi_components/tests/io.rs @@ -41,6 +41,17 @@ impl WasiView for State { #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)] #[cfg_attr(not(target_arch = "wasm32"), tokio::test)] pub async fn test() -> Result<()> { + use tracing_subscriber::prelude::*; + #[cfg(target_arch = "wasm32")] + let fmt_layer = tracing_subscriber::fmt::layer() + .with_ansi(true) // Only partially supported across browsers + .without_time() + .with_writer(tracing_web::MakeConsoleWriter); // write events to the console + + #[cfg(not(target_arch = "wasm32"))] + let fmt_layer = tracing_subscriber::fmt::layer().with_ansi(true); + + tracing_subscriber::registry().with(fmt_layer).init(); const GUEST_BYTES: &[u8] = include_bytes!("../../../target/wasm32-wasi/debug/io_guest.wasm"); no_config(GUEST_BYTES).await?; diff --git a/examples/wit_components/Cargo.toml b/examples/wit_components/Cargo.toml index 0873192b..d5926644 100644 --- a/examples/wit_components/Cargo.toml +++ b/examples/wit_components/Cargo.toml @@ -7,3 +7,7 @@ version = "0.0.0" wasm-bridge = { path = "../../crates/wasm-bridge/", features = ["component-model"]} wasm-bindgen-test = "0.3" +[dev-dependencies] +tracing-web = "0.1" +tracing-subscriber = { version = "0.3", features = ["time"] } +wasm-bindgen-test = "0.3" diff --git a/examples/wit_components/tests/records.rs b/examples/wit_components/tests/records.rs index 53529e23..2e2c8ebd 100644 --- a/examples/wit_components/tests/records.rs +++ b/examples/wit_components/tests/records.rs @@ -1,3 +1,4 @@ +use wasm_bindgen_test::wasm_bindgen_test; use wasm_bridge::{ component::{Component, Linker}, Config, Engine, Result, Store, @@ -19,7 +20,20 @@ impl RecordsImports for Host { } #[test] +#[wasm_bindgen_test] fn records() { + use tracing_subscriber::prelude::*; + #[cfg(target_arch = "wasm32")] + let fmt_layer = tracing_subscriber::fmt::layer() + .with_ansi(true) // Only partially supported across browsers + .without_time() + .with_writer(tracing_web::MakeConsoleWriter); // write events to the console + + #[cfg(not(target_arch = "wasm32"))] + let fmt_layer = tracing_subscriber::fmt::layer().with_ansi(true); + + tracing_subscriber::registry().with(fmt_layer).init(); + let mut config = Config::new(); config.wasm_component_model(true); diff --git a/recipes.json b/recipes.json index 534709c8..bf4dc901 100644 --- a/recipes.json +++ b/recipes.json @@ -1,5 +1,5 @@ { - "test-wasm": { + "test-wasi": { "cmd": [ "wasm-pack", "test", @@ -9,5 +9,16 @@ "qf": { "compiler": "cargo" } + }, + "test-wit": { + "cmd": [ + "wasm-pack", + "test", + "--node", + "./examples/wit_components/" + ], + "qf": { + "compiler": "cargo" + } } } diff --git a/resources/transformed/preview2-shim/browser/io.js b/resources/transformed/preview2-shim/browser/io.js index 85e98f09..5a757304 100644 --- a/resources/transformed/preview2-shim/browser/io.js +++ b/resources/transformed/preview2-shim/browser/io.js @@ -1,6 +1,6 @@ export const streams = { read(s, len) { - console.log(`[streams] Browser Read ${s} ${len}`); + console.log(`[streams] Original Read ${s} ${len}`); }, blockingRead(s, len) { console.log(`[streams] Blocking read ${s} ${len}`); diff --git a/resources/transformed/preview2-shim/bundled.js b/resources/transformed/preview2-shim/bundled.js index a9dfc782..1860eeb3 100644 --- a/resources/transformed/preview2-shim/bundled.js +++ b/resources/transformed/preview2-shim/bundled.js @@ -343,7 +343,7 @@ }); var streams = { read(s, len) { - console.log(`[streams] Bundled Read ${s} ${len}`); + console.log(`[streams] Original Read ${s} ${len}`); }, blockingRead(s, len) { console.log(`[streams] Blocking read ${s} ${len}`); @@ -734,6 +734,12 @@ if (export_name == "wallClock") { export_name_tr = "wall-clock"; } + let funcs = Object.entries( + exports[package_name][export_name] + ).map(([key, _]) => { + return key; + }).join(", "); + console.log(`export wasi:${package_name}/${export_name_tr} as ${export_name} ${funcs}`); wasiExports[`wasi:${package_name}/${export_name_tr}`] = exports[package_name][export_name]; } } diff --git a/resources/transformed/preview2-shim/index.js b/resources/transformed/preview2-shim/index.js index 44b0d4e6..0066c7cc 100644 --- a/resources/transformed/preview2-shim/index.js +++ b/resources/transformed/preview2-shim/index.js @@ -1,5 +1,9 @@ import importObject from "./browser"; +function to_kebab_case(str) { + return str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(); +} + export function getWasiImports() { let exports = { ...importObject, "cli-base": importObject.cliBase }; @@ -15,6 +19,14 @@ export function getWasiImports() { export_name_tr = "wall-clock"; } + let funcs = + Object.entries( + exports[package_name][export_name] + ).map(([key, _]) => { + return key + }).join(", "); + + console.log(`export wasi:${package_name}/${export_name_tr} as ${export_name} ${funcs}`) wasiExports[`wasi:${package_name}/${export_name_tr}`] = exports[package_name][export_name]; } From 547d5258c9cde0720461210c33a6cbc6260d6ee7 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Tue, 5 Sep 2023 09:38:54 +0200 Subject: [PATCH 21/26] chore! remove wasi js shim This creates a mostly stubbed js fallback for functions, which leads to unexpected errors such as `e is not iterable`, and will additionally poke more holes in the sandbox than expected. --- .../src/wasi/preview2/command.rs | 29 - resources/original/.gitignore | 1 - resources/original/README.md | 4 - resources/original/fetch_original.sh | 27 - resources/original/preview2-shim/LICENSE | 220 ----- resources/original/preview2-shim/README.md | 14 - .../original/preview2-shim/browser/cli.js | 86 -- .../original/preview2-shim/browser/clocks.js | 46 -- .../preview2-shim/browser/filesystem.js | 157 ---- .../original/preview2-shim/browser/http.js | 146 ---- .../original/preview2-shim/browser/index.js | 25 - .../original/preview2-shim/browser/io.js | 60 -- .../original/preview2-shim/browser/logging.js | 14 - .../original/preview2-shim/browser/poll.js | 9 - .../original/preview2-shim/browser/random.js | 56 -- .../original/preview2-shim/browser/sockets.js | 200 ----- .../original/preview2-shim/http/error.js | 11 - .../preview2-shim/http/make-request.js | 30 - .../preview2-shim/http/synckit/index.d.ts | 71 -- .../preview2-shim/http/synckit/index.js | 141 ---- .../original/preview2-shim/http/wasi-http.js | 347 -------- resources/transformed/README.md | 4 - resources/transformed/preview2-shim/LICENSE | 220 ----- resources/transformed/preview2-shim/README.md | 17 - .../preview2-shim/browser/cli-base.js | 48 -- .../transformed/preview2-shim/browser/cli.js | 86 -- .../preview2-shim/browser/clocks.js | 46 -- .../preview2-shim/browser/filesystem.js | 157 ---- .../transformed/preview2-shim/browser/http.js | 146 ---- .../preview2-shim/browser/index.js | 25 - .../transformed/preview2-shim/browser/io.js | 60 -- .../preview2-shim/browser/logging.js | 14 - .../transformed/preview2-shim/browser/poll.js | 9 - .../preview2-shim/browser/random.js | 41 - .../preview2-shim/browser/sockets.js | 200 ----- .../transformed/preview2-shim/bundled.js | 750 ------------------ .../transformed/preview2-shim/http/error.js | 11 - .../preview2-shim/http/make-request.js | 30 - .../preview2-shim/http/synckit/index.d.ts | 71 -- .../preview2-shim/http/synckit/index.js | 141 ---- .../preview2-shim/http/wasi-http.js | 347 -------- .../preview2-shim/http/wasi-http.js-E | 347 -------- resources/transformed/preview2-shim/index.js | 36 - resources/transformed/random.js | 41 - resources/transformed/transform.sh | 30 - 45 files changed, 4571 deletions(-) delete mode 100644 resources/original/.gitignore delete mode 100644 resources/original/README.md delete mode 100755 resources/original/fetch_original.sh delete mode 100644 resources/original/preview2-shim/LICENSE delete mode 100644 resources/original/preview2-shim/README.md delete mode 100644 resources/original/preview2-shim/browser/cli.js delete mode 100644 resources/original/preview2-shim/browser/clocks.js delete mode 100644 resources/original/preview2-shim/browser/filesystem.js delete mode 100644 resources/original/preview2-shim/browser/http.js delete mode 100644 resources/original/preview2-shim/browser/index.js delete mode 100644 resources/original/preview2-shim/browser/io.js delete mode 100644 resources/original/preview2-shim/browser/logging.js delete mode 100644 resources/original/preview2-shim/browser/poll.js delete mode 100644 resources/original/preview2-shim/browser/random.js delete mode 100644 resources/original/preview2-shim/browser/sockets.js delete mode 100644 resources/original/preview2-shim/http/error.js delete mode 100644 resources/original/preview2-shim/http/make-request.js delete mode 100644 resources/original/preview2-shim/http/synckit/index.d.ts delete mode 100644 resources/original/preview2-shim/http/synckit/index.js delete mode 100644 resources/original/preview2-shim/http/wasi-http.js delete mode 100644 resources/transformed/README.md delete mode 100644 resources/transformed/preview2-shim/LICENSE delete mode 100644 resources/transformed/preview2-shim/README.md delete mode 100644 resources/transformed/preview2-shim/browser/cli-base.js delete mode 100644 resources/transformed/preview2-shim/browser/cli.js delete mode 100644 resources/transformed/preview2-shim/browser/clocks.js delete mode 100644 resources/transformed/preview2-shim/browser/filesystem.js delete mode 100644 resources/transformed/preview2-shim/browser/http.js delete mode 100644 resources/transformed/preview2-shim/browser/index.js delete mode 100644 resources/transformed/preview2-shim/browser/io.js delete mode 100644 resources/transformed/preview2-shim/browser/logging.js delete mode 100644 resources/transformed/preview2-shim/browser/poll.js delete mode 100644 resources/transformed/preview2-shim/browser/random.js delete mode 100644 resources/transformed/preview2-shim/browser/sockets.js delete mode 100644 resources/transformed/preview2-shim/bundled.js delete mode 100644 resources/transformed/preview2-shim/http/error.js delete mode 100644 resources/transformed/preview2-shim/http/make-request.js delete mode 100644 resources/transformed/preview2-shim/http/synckit/index.d.ts delete mode 100644 resources/transformed/preview2-shim/http/synckit/index.js delete mode 100644 resources/transformed/preview2-shim/http/wasi-http.js delete mode 100644 resources/transformed/preview2-shim/http/wasi-http.js-E delete mode 100644 resources/transformed/preview2-shim/index.js delete mode 100644 resources/transformed/random.js delete mode 100755 resources/transformed/transform.sh diff --git a/crates/wasm-bridge-js/src/wasi/preview2/command.rs b/crates/wasm-bridge-js/src/wasi/preview2/command.rs index 6d2a73f1..7d7ff7bc 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/command.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/command.rs @@ -5,16 +5,9 @@ use crate::component::Linker; use crate::wasi::preview2::{clocks, WasiView}; use crate::{Result, StoreContextMut}; -use super::stdio::{STDERR_IDENT, STDIN_IDENT, STDOUT_IDENT}; use super::{environment, filesystem, preopens, stdio, streams, terminal}; -static WASI_IMPORTS_STR: &str = - include_str!("../../../../../resources/transformed/preview2-shim/bundled.js"); - pub fn add_to_linker(linker: &mut Linker) -> Result<()> { - // Default imports - // linker.set_wasi_imports(get_imports()); - // Overrides // linker.instance("wasi:io/streams")?.func_wrap( // "read", @@ -84,25 +77,3 @@ pub fn add_to_linker(linker: &mut Linker) -> Result<() Ok(()) } - -/// Fills the wasi imports by the browser shim -fn get_imports() -> Object { - let imports = js_sys::eval(WASI_IMPORTS_STR).expect("eval bundled wasi imports"); - - assert!( - imports.is_object(), - "wasi imports must be an object, {imports:#?}" - ); - - imports.into() -} - -#[cfg(test)] -mod tests { - use super::*; - - #[wasm_bindgen_test::wasm_bindgen_test] - fn should_get_imports() { - let _ = get_imports(); - } -} diff --git a/resources/original/.gitignore b/resources/original/.gitignore deleted file mode 100644 index 428fb5ce..00000000 --- a/resources/original/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/jco-repo/ diff --git a/resources/original/README.md b/resources/original/README.md deleted file mode 100644 index 6918c061..00000000 --- a/resources/original/README.md +++ /dev/null @@ -1,4 +0,0 @@ -### Source - -The folders in this repo are "cloned" from the [jco repo](https://github.com/bytecodealliance/jco), -and come with their "Apache-2.0 WITH LLVM-exception" license. diff --git a/resources/original/fetch_original.sh b/resources/original/fetch_original.sh deleted file mode 100755 index cceecc50..00000000 --- a/resources/original/fetch_original.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/sh -set -e - -## First, clone and update the repo - -# clone the repo if it doesn't exist -if [ ! -d "./jco-repo" ]; then - git clone https://github.com/bytecodealliance/jco.git jco-repo -fi - -# update the repo -cd jco-repo -git reset --hard -git pull -cd .. - - -## Preview shim - -# copy the wasi shims from jco -rm -rf preview2-shim/browser -rm -rf preview2-shim/http -cp -r jco-repo/packages/preview2-shim/lib/browser ./preview2-shim/ -cp -r jco-repo/packages/preview2-shim/lib/http ./preview2-shim/ - -# remove uneeded files from the shim -rm -rf preview2-shim/nodejs diff --git a/resources/original/preview2-shim/LICENSE b/resources/original/preview2-shim/LICENSE deleted file mode 100644 index f9d81955..00000000 --- a/resources/original/preview2-shim/LICENSE +++ /dev/null @@ -1,220 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - ---- LLVM Exceptions to the Apache 2.0 License ---- - -As an exception, if, as a result of your compiling your source code, portions -of this Software are embedded into an Object form of such source code, you -may redistribute such embedded portions in such Object form without complying -with the conditions of Sections 4(a), 4(b) and 4(d) of the License. - -In addition, if you combine or link compiled forms of this Software with -software that is licensed under the GPLv2 ("Combined Software") and if a -court of competent jurisdiction determines that the patent provision (Section -3), the indemnity provision (Section 9) or other Section of the License -conflicts with the conditions of the GPLv2, you may retroactively and -prospectively choose to deem waived or otherwise exclude such Section(s) of -the License, but only in their entirety and only with respect to the Combined -Software. - diff --git a/resources/original/preview2-shim/README.md b/resources/original/preview2-shim/README.md deleted file mode 100644 index 820e8f3e..00000000 --- a/resources/original/preview2-shim/README.md +++ /dev/null @@ -1,14 +0,0 @@ -### Source - -This folder is a direct copy of the -[`packages/preview2-shim/lib`](https://github.com/bytecodealliance/jco/tree/main/packages/preview2-shim/lib) -folder in jco. - -### License - -The code in this folder is licensed under the "Apache-2.0 WITH LLVM-exception" license, -see [LICENSE](./LICENSE). - -### Changes - -- Removed the `nodejs` folder diff --git a/resources/original/preview2-shim/browser/cli.js b/resources/original/preview2-shim/browser/cli.js deleted file mode 100644 index 4d9acebf..00000000 --- a/resources/original/preview2-shim/browser/cli.js +++ /dev/null @@ -1,86 +0,0 @@ -let _env, _args = [], _cwd = null; -export function _setEnv (envObj) { - _env = Object.entries(envObj); -} - -export function _setArgs (args) { - _args = args; -} - -export function _setCwd (cwd) { - _cwd = cwd; -} - -export const environment = { - getEnvironment () { - if (!_env) _setEnv(process.env); - return _env; - }, - getArguments () { - return _args; - }, - initialCwd () { - return _cwd; - } -}; - -class ComponentExit extends Error { - constructor(code) { - super(`Component exited ${code === 0 ? 'successfully' : 'with error'}`); - this.code = code; - } -} - -export const exit = { - exit (status) { - throw new ComponentExit(status.tag === 'err' ? 1 : 0); - } -}; - -export const stdin = { - getStdin () { - return 0; - } -}; - -export const stdout = { - getStdout () { - return 1; - } -}; - -export const stderr = { - getStderr () { - return 2; - } -}; - -export const terminalInput = { - dropTerminalInput () { - - } -}; - -export const terminalOutput = { - dropTerminalOutput () { - - } -}; - -export const terminalStderr = { - getTerminalStderr () { - return 0; - } -}; - -export const terminalStdin = { - getTerminalStdin () { - return 1; - } -}; - -export const terminalStdout = { - getTerminalStdout () { - return 2; - } -}; diff --git a/resources/original/preview2-shim/browser/clocks.js b/resources/original/preview2-shim/browser/clocks.js deleted file mode 100644 index 1500a420..00000000 --- a/resources/original/preview2-shim/browser/clocks.js +++ /dev/null @@ -1,46 +0,0 @@ -function _hrtimeBigint () { - // performance.now() is in milliseconds, but we want nanoseconds - return BigInt(Math.floor(performance.now() * 1e6)); -} - -let _hrStart = _hrtimeBigint(); - -export const monotonicClock = { - resolution() { - return 1n; - }, - now () { - return _hrtimeBigint() - _hrStart; - }, - subscribe (_when, _absolute) { - console.log(`[monotonic-clock] Subscribe`); - } -}; - -export const timezone = { - display (timezone, when) { - console.log(`[timezone] DISPLAY ${timezone} ${when}`); - }, - - utcOffset (timezone, when) { - console.log(`[timezone] UTC OFFSET ${timezone} ${when}`); - return 0; - }, - - dropTimezone (timezone) { - console.log(`[timezone] DROP ${timezone}`); - } -}; - -export const wallClock = { - now() { - let now = Date.now(); // in milliseconds - const seconds = BigInt(Math.floor(now / 1e3)); - const nanoseconds = (now % 1e3) * 1e6; - return { seconds, nanoseconds }; - }, - - resolution() { - console.log(`[wall-clock] Wall clock resolution`); - } -}; diff --git a/resources/original/preview2-shim/browser/filesystem.js b/resources/original/preview2-shim/browser/filesystem.js deleted file mode 100644 index d0a1e4ab..00000000 --- a/resources/original/preview2-shim/browser/filesystem.js +++ /dev/null @@ -1,157 +0,0 @@ -export const preopens = { - getDirectories () { - return []; - } -} - -export const types = { - readViaStream(fd, offset) { - console.log(`[filesystem] READ STREAM ${fd} ${offset}`); - }, - - writeViaStream(fd, offset) { - console.log(`[filesystem] WRITE STREAM ${fd} ${offset}`); - }, - - appendViaStream(fd) { - console.log(`[filesystem] APPEND STREAM ${fd}`); - }, - - advise(fd, offset, length, advice) { - console.log(`[filesystem] ADVISE`, fd, offset, length, advice); - }, - - syncData(fd) { - console.log(`[filesystem] SYNC DATA ${fd}`); - }, - - getFlags(fd) { - console.log(`[filesystem] FLAGS FOR ${fd}`); - }, - - getType(fd) { - console.log(`[filesystem] GET TYPE ${fd}`); - }, - - setFlags(fd, flags) { - console.log(`[filesystem] SET FLAGS ${fd} ${JSON.stringify(flags)}`); - }, - - setSize(fd, size) { - console.log(`[filesystem] SET SIZE`, fd, size); - }, - - setTimes(fd, dataAccessTimestamp, dataModificationTimestamp) { - console.log(`[filesystem] SET TIMES`, fd, dataAccessTimestamp, dataModificationTimestamp); - }, - - read(fd, length, offset) { - console.log(`[filesystem] READ`, fd, length, offset); - }, - - write(fd, buffer, offset) { - console.log(`[filesystem] WRITE`, fd, buffer, offset); - }, - - readDirectory(fd) { - console.log(`[filesystem] READ DIR`, fd); - }, - - sync(fd) { - console.log(`[filesystem] SYNC`, fd); - }, - - createDirectoryAt(fd, path) { - console.log(`[filesystem] CREATE DIRECTORY`, fd, path); - }, - - stat(fd) { - console.log(`[filesystem] STAT`, fd); - }, - - statAt(fd, pathFlags, path) { - console.log(`[filesystem] STAT`, fd, pathFlags, path); - }, - - setTimesAt(fd) { - console.log(`[filesystem] SET TIMES AT`, fd); - }, - - linkAt(fd) { - console.log(`[filesystem] LINK AT`, fd); - }, - - openAt(fd) { - console.log(`[filesystem] OPEN AT ${fd}`); - }, - - readlinkAt(fd) { - console.log(`[filesystem] READLINK AT`, fd); - }, - - removeDirectoryAt(fd) { - console.log(`[filesystem] REMOVE DIR AT`, fd); - }, - - renameAt(fd) { - console.log(`[filesystem] RENAME AT`, fd); - }, - - symlinkAt(fd) { - console.log(`[filesystem] SYMLINK AT`, fd); - }, - - unlinkFileAt(fd) { - console.log(`[filesystem] UNLINK FILE AT`, fd); - }, - - changeFilePermissionsAt(fd) { - console.log(`[filesystem] CHANGE FILE PERMISSIONS AT`, fd); - }, - - changeDirectoryPermissionsAt(fd) { - console.log(`[filesystem] CHANGE DIR PERMISSIONS AT`, fd); - }, - - lockShared(fd) { - console.log(`[filesystem] LOCK SHARED`, fd); - }, - - lockExclusive(fd) { - console.log(`[filesystem] LOCK EXCLUSIVE`, fd); - }, - - tryLockShared(fd) { - console.log(`[filesystem] TRY LOCK SHARED`, fd); - }, - - tryLockExclusive(fd) { - console.log(`[filesystem] TRY LOCK EXCLUSIVE`, fd); - }, - - unlock(fd) { - console.log(`[filesystem] UNLOCK`, fd); - }, - - dropDescriptor(fd) { - console.log(`[filesystem] DROP DESCRIPTOR`, fd); - }, - - readDirectoryEntry(stream) { - console.log(`[filesystem] READ DIRECTRY ENTRY`, stream); - }, - - dropDirectoryEntryStream(stream) { - console.log(`[filesystem] DROP DIRECTORY ENTRY`, stream); - }, - - metadataHash(fd) { - console.log(`[filesystem] METADATA HASH`, fd); - }, - - metadataHashAt(fd, pathFlags, path) { - console.log(`[filesystem] METADATA HASH AT `, fd, pathFlags, path); - } -}; - -export { types as filesystemTypes } diff --git a/resources/original/preview2-shim/browser/http.js b/resources/original/preview2-shim/browser/http.js deleted file mode 100644 index 592b3ad4..00000000 --- a/resources/original/preview2-shim/browser/http.js +++ /dev/null @@ -1,146 +0,0 @@ -import { UnexpectedError } from "../http/error.js"; - -/** - * @param {import("../../types/imports/wasi-http-types").Request} req - * @returns {string} - */ -export function send(req) { - console.log(`[http] Send (browser) ${req.uri}`); - try { - const xhr = new XMLHttpRequest(); - xhr.open(req.method.toString(), req.uri, false); - const requestHeaders = new Headers(req.headers); - for (let [name, value] of requestHeaders.entries()) { - if (name !== "user-agent" && name !== "host") { - xhr.setRequestHeader(name, value); - } - } - xhr.send(req.body && req.body.length > 0 ? req.body : null); - const body = xhr.response ? new TextEncoder().encode(xhr.response) : undefined; - const headers = []; - xhr.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach((line) => { - var parts = line.split(': '); - var key = parts.shift(); - var value = parts.join(': '); - headers.push([key, value]); - }); - return { - status: xhr.status, - headers, - body, - }; - } catch (err) { - throw new UnexpectedError(err.message); - } -} - -export const incomingHandler = { - handle () { - - } -}; - -export const outgoingHandler = { - handle () { - - } -}; - -export const types = { - dropFields(_fields) { - console.log("[types] Drop fields"); - }, - newFields(_entries) { - console.log("[types] New fields"); - }, - fieldsGet(_fields, _name) { - console.log("[types] Fields get"); - }, - fieldsSet(_fields, _name, _value) { - console.log("[types] Fields set"); - }, - fieldsDelete(_fields, _name) { - console.log("[types] Fields delete"); - }, - fieldsAppend(_fields, _name, _value) { - console.log("[types] Fields append"); - }, - fieldsEntries(_fields) { - console.log("[types] Fields entries"); - }, - fieldsClone(_fields) { - console.log("[types] Fields clone"); - }, - finishIncomingStream(s) { - console.log(`[types] Finish incoming stream ${s}`); - }, - finishOutgoingStream(s, _trailers) { - console.log(`[types] Finish outgoing stream ${s}`); - }, - dropIncomingRequest(_req) { - console.log("[types] Drop incoming request"); - }, - dropOutgoingRequest(_req) { - console.log("[types] Drop outgoing request"); - }, - incomingRequestMethod(_req) { - console.log("[types] Incoming request method"); - }, - incomingRequestPathWithQuery(_req) { - console.log("[types] Incoming request path with query"); - }, - incomingRequestScheme(_req) { - console.log("[types] Incoming request scheme"); - }, - incomingRequestAuthority(_req) { - console.log("[types] Incoming request authority"); - }, - incomingRequestHeaders(_req) { - console.log("[types] Incoming request headers"); - }, - incomingRequestConsume(_req) { - console.log("[types] Incoming request consume"); - }, - newOutgoingRequest(_method, _pathWithQuery, _scheme, _authority, _headers) { - console.log("[types] New outgoing request"); - }, - outgoingRequestWrite(_req) { - console.log("[types] Outgoing request write"); - }, - dropResponseOutparam(_res) { - console.log("[types] Drop response outparam"); - }, - setResponseOutparam(_response) { - console.log("[types] Drop fields"); - }, - dropIncomingResponse(_res) { - console.log("[types] Drop incoming response"); - }, - dropOutgoingResponse(_res) { - console.log("[types] Drop outgoing response"); - }, - incomingResponseStatus(_res) { - console.log("[types] Incoming response status"); - }, - incomingResponseHeaders(_res) { - console.log("[types] Incoming response headers"); - }, - incomingResponseConsume(_res) { - console.log("[types] Incoming response consume"); - }, - newOutgoingResponse(_statusCode, _headers) { - console.log("[types] New outgoing response"); - }, - outgoingResponseWrite(_res) { - console.log("[types] Outgoing response write"); - }, - dropFutureIncomingResponse(_f) { - console.log("[types] Drop future incoming response"); - }, - futureIncomingResponseGet(_f) { - console.log("[types] Future incoming response get"); - }, - listenToFutureIncomingResponse(_f) { - console.log("[types] Listen to future incoming response"); - } -}; diff --git a/resources/original/preview2-shim/browser/index.js b/resources/original/preview2-shim/browser/index.js deleted file mode 100644 index 11add6fa..00000000 --- a/resources/original/preview2-shim/browser/index.js +++ /dev/null @@ -1,25 +0,0 @@ -import * as clocks from "./clocks.js"; -import * as filesystem from "./filesystem.js"; -import * as http from "./http.js"; -import * as io from "./io.js"; -import * as logging from "./logging.js"; -import * as poll from "./poll.js"; -import * as random from "./random.js"; -import * as sockets from "./sockets.js"; -import * as cli from "./cli.js"; - -export const importObject = { - clocks, - filesystem, - http, - io, - logging, - poll, - random, - sockets, - cli, -}; - -export { WasiHttp } from "../http/wasi-http.js"; - -export default importObject; diff --git a/resources/original/preview2-shim/browser/io.js b/resources/original/preview2-shim/browser/io.js deleted file mode 100644 index 5a757304..00000000 --- a/resources/original/preview2-shim/browser/io.js +++ /dev/null @@ -1,60 +0,0 @@ -export const streams = { - read(s, len) { - console.log(`[streams] Original Read ${s} ${len}`); - }, - blockingRead(s, len) { - console.log(`[streams] Blocking read ${s} ${len}`); - }, - skip(s, _len) { - console.log(`[streams] Skip ${s}`); - }, - blockingSkip(s, _len) { - console.log(`[streams] Blocking skip ${s}`); - }, - subscribeToInputStream(s) { - console.log(`[streams] Subscribe to input stream ${s}`); - }, - dropInputStream(s) { - console.log(`[streams] Drop input stream ${s}`); - }, - write(s, buf) { - streams.blockingWrite(s, buf); - }, - blockingWrite(s, buf) { - switch (s) { - case 0: - throw new Error(`TODO: write stdin`); - case 1: { - process.stdout.write(buf); - return [BigInt(buf.byteLength), 'ended']; - } - case 2: { - process.stderr.write(buf); - return [BigInt(buf.byteLength), 'ended']; - } - default: - throw new Error(`TODO: write ${s}`); - } - }, - writeZeroes(s, _len) { - console.log(`[streams] Write zeroes ${s}`); - }, - blockingWriteZeroes(s, _len) { - console.log(`[streams] Blocking write zeroes ${s}`); - }, - splice(s, _src, _len) { - console.log(`[streams] Splice ${s}`); - }, - blockingSplice(s, _src, _len) { - console.log(`[streams] Blocking splice ${s}`); - }, - forward(s, _src) { - console.log(`[streams] Forward ${s}`); - }, - subscribeToOutputStream(s) { - console.log(`[streams] Subscribe to output stream ${s}`); - }, - dropOutputStream(s) { - console.log(`[streams] Drop output stream ${s}`); - } -}; diff --git a/resources/original/preview2-shim/browser/logging.js b/resources/original/preview2-shim/browser/logging.js deleted file mode 100644 index 9c963ac7..00000000 --- a/resources/original/preview2-shim/browser/logging.js +++ /dev/null @@ -1,14 +0,0 @@ -const levels = ["trace", "debug", "info", "warn", "error", "critical"]; - -let logLevel = levels.indexOf("warn"); - -export const logging = { - log(level, context, msg) { - if (logLevel > levels.indexOf(level)) return; - console[level](`(${context}) ${msg}\n`); - } -}; - -export function setLevel(level) { - logLevel = levels.indexOf(level); -} diff --git a/resources/original/preview2-shim/browser/poll.js b/resources/original/preview2-shim/browser/poll.js deleted file mode 100644 index 52d2fe36..00000000 --- a/resources/original/preview2-shim/browser/poll.js +++ /dev/null @@ -1,9 +0,0 @@ -export const poll = { - dropPollable (pollable) { - console.log(`[poll] Drop (${pollable})`); - }, - pollOneoff (input) { - console.log(`[poll] Oneoff (${input})`); - return []; - } -}; diff --git a/resources/original/preview2-shim/browser/random.js b/resources/original/preview2-shim/browser/random.js deleted file mode 100644 index 5ec1d7c5..00000000 --- a/resources/original/preview2-shim/browser/random.js +++ /dev/null @@ -1,56 +0,0 @@ -const MAX_BYTES = 65536; - -let insecureRandomValue1, insecureRandomValue2; - -export const insecure = { - getInsecureRandomBytes (len) { - return random.getRandomBytes(len); - }, - getInsecureRandomU64 () { - return random.getRandomU64(); - } -}; - -let insecureSeedValue1, insecureSeedValue2; - -export const insecureSeed = { - insecureSeed () { - if (insecureSeedValue1 === undefined) { - insecureSeedValue1 = random.getRandomU64(); - insecureSeedValue2 = random.getRandomU64(); - } - return [insecureSeedValue1, insecureSeedValue2]; - } -}; - -export const random = { - getRandomBytes(len) { - const bytes = new Uint8Array(Number(len)); - - if (len > MAX_BYTES) { - // this is the max bytes crypto.getRandomValues - // can do at once see https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues - for (var generated = 0; generated < len; generated += MAX_BYTES) { - // buffer.slice automatically checks if the end is past the end of - // the buffer so we don't have to here - crypto.getRandomValues(bytes.slice(generated, generated + MAX_BYTES)); - } - } else { - crypto.getRandomValues(bytes); - } - - return bytes; - }, - - getRandomU64 () { - return crypto.getRandomValues(new BigUint64Array(1))[0]; - }, - - insecureRandom () { - if (insecureRandomValue1 === undefined) { - insecureRandomValue1 = random.getRandomU64(); - insecureRandomValue2 = random.getRandomU64(); - } - return [insecureRandomValue1, insecureRandomValue2]; - } -}; diff --git a/resources/original/preview2-shim/browser/sockets.js b/resources/original/preview2-shim/browser/sockets.js deleted file mode 100644 index 19aae42a..00000000 --- a/resources/original/preview2-shim/browser/sockets.js +++ /dev/null @@ -1,200 +0,0 @@ -export const instanceNetwork = { - instanceNetwork () { - console.log(`[sockets] instance network`); - } -}; - -export const ipNameLookup = { - dropResolveAddressStream () { - - }, - subscribe () { - - }, - resolveAddresses () { - - }, - resolveNextAddress () { - - }, - nonBlocking () { - - }, - setNonBlocking () { - - }, -}; - -export const network = { - dropNetwork () { - - } -}; - -export const tcpCreateSocket = { - createTcpSocket () { - - } -}; - -export const tcp = { - subscribe () { - - }, - dropTcpSocket() { - - }, - bind() { - - }, - connect() { - - }, - listen() { - - }, - accept() { - - }, - localAddress() { - - }, - remoteAddress() { - - }, - addressFamily() { - - }, - ipv6Only() { - - }, - setIpv6Only() { - - }, - setListenBacklogSize() { - - }, - keepAlive() { - - }, - setKeepAlive() { - - }, - noDelay() { - - }, - setNoDelay() { - - }, - unicastHopLimit() { - - }, - setUnicastHopLimit() { - - }, - receiveBufferSize() { - - }, - setReceiveBufferSize() { - - }, - sendBufferSize() { - - }, - setSendBufferSize() { - - }, - nonBlocking() { - - }, - setNonBlocking() { - - }, - shutdown() { - - } -}; - -export const udp = { - subscribe () { - - }, - - dropUdpSocket () { - - }, - - bind () { - - }, - - connect () { - - }, - - receive () { - - }, - - send () { - - }, - - localAddress () { - - }, - - remoteAddress () { - - }, - - addressFamily () { - - }, - - ipv6Only () { - - }, - - setIpv6Only () { - - }, - - unicastHopLimit () { - - }, - - setUnicastHopLimit () { - - }, - - receiveBufferSize () { - - }, - - setReceiveBufferSize () { - - }, - - sendBufferSize () { - - }, - - setSendBufferSize () { - - }, - - nonBlocking () { - - }, - - setNonBlocking () { - - } -}; - -export const udpCreateSocket = { - createUdpSocket () { - - } -}; diff --git a/resources/original/preview2-shim/http/error.js b/resources/original/preview2-shim/http/error.js deleted file mode 100644 index 748f20cb..00000000 --- a/resources/original/preview2-shim/http/error.js +++ /dev/null @@ -1,11 +0,0 @@ -export class UnexpectedError extends Error { - /** @type { import("../../types/imports/wasi-http-types").ErrorUnexpectedError } */ - payload; - constructor(message = "unexpected-error") { - super(message); - this.payload = { - tag: "unexpected-error", - val: message, - }; - } -} diff --git a/resources/original/preview2-shim/http/make-request.js b/resources/original/preview2-shim/http/make-request.js deleted file mode 100644 index ee743244..00000000 --- a/resources/original/preview2-shim/http/make-request.js +++ /dev/null @@ -1,30 +0,0 @@ -import { runAsWorker } from "./synckit/index.js"; - -/** - * @param {import("../../types/imports/wasi-http-types").Request} req - * @returns {Promise} - */ -async function makeRequest(req) { - try { - let headers = new Headers(req.headers); - const resp = await fetch(req.uri, { - method: req.method.toString(), - headers, - body: req.body && req.body.length > 0 ? req.body : undefined, - redirect: "manual", - }); - let arrayBuffer = await resp.arrayBuffer(); - return JSON.stringify({ - status: resp.status, - headers: Array.from(resp.headers.entries()), - body: - arrayBuffer.byteLength > 0 - ? Buffer.from(arrayBuffer).toString("base64") - : undefined, - }); - } catch (err) { - return JSON.stringify({ message: err.toString() }); - } -} - -runAsWorker(makeRequest); diff --git a/resources/original/preview2-shim/http/synckit/index.d.ts b/resources/original/preview2-shim/http/synckit/index.d.ts deleted file mode 100644 index 73e2e8f9..00000000 --- a/resources/original/preview2-shim/http/synckit/index.d.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* -MIT License - -Copyright (c) 2021 UnTS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -/// -import { MessagePort } from "node:worker_threads"; -export type AnyFn = (...args: T) => R; -export type AnyPromise = Promise; -export type AnyAsyncFn = AnyFn>; -export type Syncify = T extends ( - ...args: infer Args -) => Promise - ? (...args: Args) => R - : never; -export type PromiseType = T extends Promise - ? R - : never; -export interface MainToWorkerMessage { - sharedBuffer: SharedArrayBuffer; - id: number; - args: T; -} -export interface WorkerData { - workerPort: MessagePort; -} -export interface DataMessage { - result?: T; - error?: unknown; - properties?: unknown; -} -export interface WorkerToMainMessage extends DataMessage { - id: number; -} -export interface SyncifyOptions { - bufferSize?: number; - timeout?: number; - execArgv?: string[]; -} -export declare function createSyncFn( - workerPath: string, - bufferSize?: number, - timeout?: number -): Syncify; -export declare function createSyncFn( - workerPath: string, - options?: SyncifyOptions -): Syncify; -export declare function runAsWorker< - R = unknown, - T extends AnyAsyncFn = AnyAsyncFn ->(fn: T): void; diff --git a/resources/original/preview2-shim/http/synckit/index.js b/resources/original/preview2-shim/http/synckit/index.js deleted file mode 100644 index 22ce198e..00000000 --- a/resources/original/preview2-shim/http/synckit/index.js +++ /dev/null @@ -1,141 +0,0 @@ -// Based on: https://github.com/un-ts/synckit -/* -MIT License - -Copyright (c) 2021 UnTS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -import path from "node:path"; -import { - MessageChannel, - Worker, - receiveMessageOnPort, - workerData, - parentPort, -} from "node:worker_threads"; - -const DEFAULT_WORKER_BUFFER_SIZE = 1024; -const syncFnCache = new Map(); - -function extractProperties(object) { - if (object && typeof object === "object") { - const properties = {}; - for (const key in object) { - properties[key] = object[key]; - } - return properties; - } -} - -export function createSyncFn(workerPath, bufferSizeOrOptions, timeout) { - if (!path.isAbsolute(workerPath)) { - throw new Error("`workerPath` must be absolute"); - } - const cachedSyncFn = syncFnCache.get(workerPath); - if (cachedSyncFn) { - return cachedSyncFn; - } - const syncFn = startWorkerThread( - workerPath, - typeof bufferSizeOrOptions === "number" - ? { bufferSize: bufferSizeOrOptions, timeout } - : bufferSizeOrOptions - ); - syncFnCache.set(workerPath, syncFn); - return syncFn; -} - -function startWorkerThread( - workerPath, - { - bufferSize = DEFAULT_WORKER_BUFFER_SIZE, - timeout = undefined, - execArgv = [], - } = {} -) { - const { port1: mainPort, port2: workerPort } = new MessageChannel(); - const worker = new Worker(workerPath, { - workerData: { workerPort }, - transferList: [workerPort], - execArgv: execArgv, - }); - let nextID = 0; - const syncFn = (...args) => { - const id = nextID++; - const sharedBuffer = new SharedArrayBuffer(bufferSize); - const sharedBufferView = new Int32Array(sharedBuffer); - const msg = { sharedBuffer, id, args }; - worker.postMessage(msg); - const status = Atomics.wait(sharedBufferView, 0, 0, timeout); - if (!["ok", "not-equal"].includes(status)) { - throw new Error("Internal error: Atomics.wait() failed: " + status); - } - const { - id: id2, - result, - error, - properties, - } = receiveMessageOnPort(mainPort).message; - if (id !== id2) { - throw new Error(`Internal error: Expected id ${id} but got id ${id2}`); - } - if (error) { - throw Object.assign(error, properties); - } - return result; - }; - worker.unref(); - return syncFn; -} - -export function runAsWorker(fn) { - if (!workerData) { - return; - } - const { workerPort } = workerData; - try { - parentPort.on("message", ({ sharedBuffer, id, args }) => { - (async () => { - const sharedBufferView = new Int32Array(sharedBuffer); - let msg; - try { - msg = { id, result: await fn(...args) }; - } catch (error) { - msg = { id, error, properties: extractProperties(error) }; - } - workerPort.postMessage(msg); - Atomics.add(sharedBufferView, 0, 1); - Atomics.notify(sharedBufferView, 0); - })(); - }); - } catch (error) { - parentPort.on("message", ({ sharedBuffer, id }) => { - const sharedBufferView = new Int32Array(sharedBuffer); - workerPort.postMessage({ - id, - error, - properties: extractProperties(error), - }); - Atomics.add(sharedBufferView, 0, 1); - Atomics.notify(sharedBufferView, 0); - }); - } -} diff --git a/resources/original/preview2-shim/http/wasi-http.js b/resources/original/preview2-shim/http/wasi-http.js deleted file mode 100644 index 76947b9d..00000000 --- a/resources/original/preview2-shim/http/wasi-http.js +++ /dev/null @@ -1,347 +0,0 @@ -// Based on: -// https://github.com/bytecodealliance/wasmtime/blob/8efcb9851602287fd07a1a1e91501f51f2653d7e/crates/wasi-http/ - -/** - * @typedef {import("../../types/imports/wasi-http-types").Fields} Fields - * @typedef {import("../../types/imports/wasi-http-types").FutureIncomingResponse} FutureIncomingResponse - * @typedef {import("../../types/imports/wasi-http-types").Headers} Headers - * @typedef {import("../../types/imports/wasi-http-types").IncomingResponse} IncomingResponse - * @typedef {import("../../types/imports/wasi-http-types").IncomingStream} IncomingStream - * @typedef {import("../../types/imports/wasi-http-types").Method} Method - * @typedef {import("../../types/imports/wasi-http-types").OutgoingRequest} OutgoingRequest - * @typedef {import("../../types/imports/wasi-http-types").RequestOptions} RequestOptions - * @typedef {import("../../types/imports/wasi-http-types").Result} Result - * @typedef {import("../../types/imports/wasi-http-types").Scheme} Scheme - * @typedef {import("../../types/imports/wasi-http-types").StatusCode} StatusCode - * @typedef {import("../../types/imports/wasi-io-streams").StreamStatus} StreamStatus -*/ - -import * as io from '@bytecodealliance/preview2-shim/io'; -import * as http from '@bytecodealliance/preview2-shim/http'; -import { UnexpectedError } from './error.js'; - -export class WasiHttp { - requestIdBase = 1; - responseIdBase = 1; - fieldsIdBase = 1; - streamIdBase = 3; - futureIdBase = 1; - /** @type {Map} */ requests = new Map(); - /** @type {Map} */ responses = new Map(); - /** @type {Map>} */ fields = new Map(); - /** @type {Map} */ streams = new Map(); - /** @type {Map} */ futures = new Map(); - - constructor() {} - - /** - * @param {OutgoingRequest} requestId - * @param {RequestOptions | null} options - * @returns {FutureIncomingResponse} - */ - handle = (requestId, _options) => { - const request = this.requests.get(requestId); - if (!request) throw Error("not found!"); - - const responseId = this.responseIdBase; - this.responseIdBase += 1; - const response = new ActiveResponse(responseId); - - const scheme = request.scheme.tag === "HTTP" ? "http://" : "https://"; - - const url = scheme + request.authority + request.pathWithQuery; - const headers = { - "host": request.authority, - }; - if (request.headers && request.headers.size > 0) { - for (const [key, value] of request.headers.entries()) { - headers[key] = Array.isArray(value) ? value.join(",") : value; - } - } - const body = this.streams.get(request.body); - - const res = http.send({ - method: request.method.tag, - uri: url, - headers: headers, - params: [], - body: body && body.length > 0 ? body : undefined, - }); - - response.status = res.status; - if (res.headers && res.headers.size > 0) { - for (const [key, value] of res.headers) { - response.responseHeaders.set(key, [value]); - } - } - const buf = res.body; - response.body = this.streamIdBase; - this.streamIdBase += 1; - this.streams.set(response.body, buf); - this.responses.set(responseId, response); - - const futureId = this.futureIdBase; - this.futureIdBase += 1; - const future = new ActiveFuture(futureId, responseId); - this.futures.set(futureId, future); - return futureId; - } - - read = (stream, len) => { - return this.blockingRead(stream, len); - } - - /** - * @param {InputStream} stream - * @param {bigint} len - * @returns {[Uint8Array | ArrayBuffer, StreamStatus]} - */ - blockingRead = (stream, len) => { - if (stream < 3) { - return io.streams.blockingRead(stream); - } - const s = this.streams.get(stream); - if (!s) throw Error(`stream not found: ${stream}`); - const position = Number(len); - if (position === 0) { - return [new Uint8Array(), s.byteLength > 0 ? 'open' : 'ended']; - } else if (s.byteLength > position) { - this.streams.set(stream, s.slice(position, s.byteLength)); - return [s.slice(0, position), 'open']; - } else { - return [s.slice(0, position), 'ended']; - } - } - - /** - * @param {InputStream} stream - * @returns {Pollable} - */ - subscribeToInputStream = (stream) => { - // TODO: not implemented yet - console.log(`[streams] Subscribe to input stream ${stream}`); - } - - /** - * @param {InputStream} stream - */ - dropInputStream = (stream) => { - const s = this.streams.get(stream); - if (!s) throw Error(`no such input stream ${stream}`); - s.set([]); - } - - write = (stream, buf) => { - return this.blockingWrite(stream, buf); - } - - /** - * @param {OutputStream} stream - * @param {Uint8Array} buf - * @returns {[bigint, StreamStatus]} - */ - blockingWrite = (stream, buf) => { - if (stream < 3) { - return io.streams.blockingWrite(stream, buf); - } - this.streams.set(stream, buf); - return [BigInt(buf.byteLength), 'ended']; - } - - /** - * @param {OutputStream} stream - * @returns {Pollable} - */ - subscribeToOutputStream = (stream) => { - // TODO: not implemented yet - console.log(`[streams] Subscribe to output stream ${stream}`); - } - - /** - * @param {OutputStream} stream - */ - dropOutputStream = (stream) => { - const s = this.streams.get(stream); - if (!s) throw Error(`no such output stream ${stream}`); - s.set([]); - } - - /** - * @param {Fields} fields - */ - dropFields = (fields) => { - this.fields.delete(fields); - } - - /** - * @param {[string, string][]} entries - * @returns {Fields} - */ - newFields = (entries) => { - const map = new Map(entries); - - const id = this.fieldsIdBase; - this.fieldsIdBase += 1; - this.fields.set(id, map); - - return id; - } - - /** - * @param {Fields} fields - * @returns {[string, string][]} - */ - fieldsEntries = (fields) => { - return this.fields.get(fields) ?? []; - } - - /** - * @param {OutgoingRequest} request - */ - dropOutgoingRequest = (request) => { - this.requests.delete(request); - } - - /** - * @param {Method} method - * @param {string | null} pathWithQuery - * @param {Scheme | null} scheme - * @param {string | null} authority - * @param {Headers} headers - * @returns {number} - */ - newOutgoingRequest = (method, pathWithQuery, scheme, authority, headers) => { - const id = this.requestIdBase; - this.requestIdBase += 1; - - const req = new ActiveRequest(id); - req.pathWithQuery = pathWithQuery; - req.authority = authority; - req.method = method; - req.headers = this.fields.get(headers); - req.scheme = scheme; - this.requests.set(id, req); - return id; - } - - /** - * @param {OutgoingRequest} request - * @returns {OutgoingStream} - */ - outgoingRequestWrite = (request) => { - const req = this.requests.get(request); - req.body = this.streamIdBase; - this.streamIdBase += 1; - return req.body; - } - - /** - * @param {IncomingResponse} response - */ - dropIncomingResponse = (response) => { - this.responses.delete(response); - } - - /** - * @param {IncomingResponse} response - * @returns {StatusCode} - */ - incomingResponseStatus = (response) => { - const r = this.responses.get(response); - return r.status; - } - - /** - * @param {IncomingResponse} response - * @returns {Headers} - */ - incomingResponseHeaders = (response) => { - const r = this.responses.get(response); - const id = this.fieldsIdBase; - this.fieldsIdBase += 1; - - this.fields.set(id, r.responseHeaders); - return id; - } - - /** - * @param {IncomingResponse} response - * @returns {IncomingStream} - */ - incomingResponseConsume = (response) => { - const r = this.responses.get(response); - return r.body; - } - - /** - * @param {FutureIncomingResponse} future - */ - dropFutureIncomingResponse = (future) => { - return this.futures.delete(future); - } - - /** - * @param {FutureIncomingResponse} future - * @returns {Result | null} - */ - futureIncomingResponseGet = (future) => { - const f = this.futures.get(future); - if (!f) { - return { - tag: "err", - val: UnexpectedError(`no such future ${f}`), - }; - } - // For now this will assume the future will return - // the response immediately - const response = f.responseId; - const r = this.responses.get(response); - if (!r) { - return { - tag: "err", - val: UnexpectedError(`no such response ${response}`), - }; - } - return { - tag: "ok", - val: response, - }; - } -} - -class ActiveRequest { - /** @type {number} */ id; - activeRequest = false; - /** @type {Method} */ method = { tag: 'get' }; - /** @type {Scheme | null} */ scheme = { tag: 'HTTP' }; - pathWithQuery = null; - authority = null; - /** @type {Map} */ headers = new Map(); - body = 3; - - constructor(id) { - this.id = id; - } -} - -class ActiveResponse { - /** @type {number} */ id; - activeResponse = false; - status = 0; - body = 3; - /** @type {Map} */ responseHeaders = new Map(); - - constructor(id) { - this.id = id; - } -} - -class ActiveFuture { - /** @type {number} */ id; - /** @type {number} */ responseId; - - constructor(id, responseId) { - this.id = id; - this.responseId = responseId; - } -} diff --git a/resources/transformed/README.md b/resources/transformed/README.md deleted file mode 100644 index 906ddd26..00000000 --- a/resources/transformed/README.md +++ /dev/null @@ -1,4 +0,0 @@ -### Source - -The folders in this repo are "forked" from the [jco repo](https://github.com/bytecodealliance/jco), -and come with their "Apache-2.0 WITH LLVM-exception" license. diff --git a/resources/transformed/preview2-shim/LICENSE b/resources/transformed/preview2-shim/LICENSE deleted file mode 100644 index f9d81955..00000000 --- a/resources/transformed/preview2-shim/LICENSE +++ /dev/null @@ -1,220 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - ---- LLVM Exceptions to the Apache 2.0 License ---- - -As an exception, if, as a result of your compiling your source code, portions -of this Software are embedded into an Object form of such source code, you -may redistribute such embedded portions in such Object form without complying -with the conditions of Sections 4(a), 4(b) and 4(d) of the License. - -In addition, if you combine or link compiled forms of this Software with -software that is licensed under the GPLv2 ("Combined Software") and if a -court of competent jurisdiction determines that the patent provision (Section -3), the indemnity provision (Section 9) or other Section of the License -conflicts with the conditions of the GPLv2, you may retroactively and -prospectively choose to deem waived or otherwise exclude such Section(s) of -the License, but only in their entirety and only with respect to the Combined -Software. - diff --git a/resources/transformed/preview2-shim/README.md b/resources/transformed/preview2-shim/README.md deleted file mode 100644 index 6c69811b..00000000 --- a/resources/transformed/preview2-shim/README.md +++ /dev/null @@ -1,17 +0,0 @@ -### Source - -This folder is a "fork" of the -[`packages/preview2-shim/lib`](https://github.com/bytecodealliance/jco/tree/main/packages/preview2-shim/lib) -folder in jco. - -### License - -The code in this folder is licensed under the "Apache-2.0 WITH LLVM-exception" license, -see [LICENSE](./LICENSE). - -### Changes - -- Replaced import path in `/http/wasi-http.js` -- Added the `index.js` file -- Added the `bundled.js` file -- Replaced `/browser/random.js` file with a "dummy" replacement diff --git a/resources/transformed/preview2-shim/browser/cli-base.js b/resources/transformed/preview2-shim/browser/cli-base.js deleted file mode 100644 index 34a44a16..00000000 --- a/resources/transformed/preview2-shim/browser/cli-base.js +++ /dev/null @@ -1,48 +0,0 @@ -let _env; -export function _setEnv (envObj) { - _env = Object.entries(envObj); -} - -export const environment = { - getEnvironment () { - if (!_env) _env = []; - return _env; - } -}; - -class ComponentExit extends Error { - constructor(code) { - super(`Component exited ${code === 0 ? 'successfully' : 'with error'}`); - this.code = code; - } -} - -export const exit = { - exit (status) { - throw new ComponentExit(status.tag === 'err' ? 1 : 0); - } -}; - -export const preopens = { - getDirectories () { - return []; - } -} - -export const stdin = { - getStdin () { - return 0; - } -}; - -export const stdout = { - getStdout () { - return 1; - } -}; - -export const stderr = { - getStderr () { - return 2; - } -}; diff --git a/resources/transformed/preview2-shim/browser/cli.js b/resources/transformed/preview2-shim/browser/cli.js deleted file mode 100644 index 4d9acebf..00000000 --- a/resources/transformed/preview2-shim/browser/cli.js +++ /dev/null @@ -1,86 +0,0 @@ -let _env, _args = [], _cwd = null; -export function _setEnv (envObj) { - _env = Object.entries(envObj); -} - -export function _setArgs (args) { - _args = args; -} - -export function _setCwd (cwd) { - _cwd = cwd; -} - -export const environment = { - getEnvironment () { - if (!_env) _setEnv(process.env); - return _env; - }, - getArguments () { - return _args; - }, - initialCwd () { - return _cwd; - } -}; - -class ComponentExit extends Error { - constructor(code) { - super(`Component exited ${code === 0 ? 'successfully' : 'with error'}`); - this.code = code; - } -} - -export const exit = { - exit (status) { - throw new ComponentExit(status.tag === 'err' ? 1 : 0); - } -}; - -export const stdin = { - getStdin () { - return 0; - } -}; - -export const stdout = { - getStdout () { - return 1; - } -}; - -export const stderr = { - getStderr () { - return 2; - } -}; - -export const terminalInput = { - dropTerminalInput () { - - } -}; - -export const terminalOutput = { - dropTerminalOutput () { - - } -}; - -export const terminalStderr = { - getTerminalStderr () { - return 0; - } -}; - -export const terminalStdin = { - getTerminalStdin () { - return 1; - } -}; - -export const terminalStdout = { - getTerminalStdout () { - return 2; - } -}; diff --git a/resources/transformed/preview2-shim/browser/clocks.js b/resources/transformed/preview2-shim/browser/clocks.js deleted file mode 100644 index 1500a420..00000000 --- a/resources/transformed/preview2-shim/browser/clocks.js +++ /dev/null @@ -1,46 +0,0 @@ -function _hrtimeBigint () { - // performance.now() is in milliseconds, but we want nanoseconds - return BigInt(Math.floor(performance.now() * 1e6)); -} - -let _hrStart = _hrtimeBigint(); - -export const monotonicClock = { - resolution() { - return 1n; - }, - now () { - return _hrtimeBigint() - _hrStart; - }, - subscribe (_when, _absolute) { - console.log(`[monotonic-clock] Subscribe`); - } -}; - -export const timezone = { - display (timezone, when) { - console.log(`[timezone] DISPLAY ${timezone} ${when}`); - }, - - utcOffset (timezone, when) { - console.log(`[timezone] UTC OFFSET ${timezone} ${when}`); - return 0; - }, - - dropTimezone (timezone) { - console.log(`[timezone] DROP ${timezone}`); - } -}; - -export const wallClock = { - now() { - let now = Date.now(); // in milliseconds - const seconds = BigInt(Math.floor(now / 1e3)); - const nanoseconds = (now % 1e3) * 1e6; - return { seconds, nanoseconds }; - }, - - resolution() { - console.log(`[wall-clock] Wall clock resolution`); - } -}; diff --git a/resources/transformed/preview2-shim/browser/filesystem.js b/resources/transformed/preview2-shim/browser/filesystem.js deleted file mode 100644 index d0a1e4ab..00000000 --- a/resources/transformed/preview2-shim/browser/filesystem.js +++ /dev/null @@ -1,157 +0,0 @@ -export const preopens = { - getDirectories () { - return []; - } -} - -export const types = { - readViaStream(fd, offset) { - console.log(`[filesystem] READ STREAM ${fd} ${offset}`); - }, - - writeViaStream(fd, offset) { - console.log(`[filesystem] WRITE STREAM ${fd} ${offset}`); - }, - - appendViaStream(fd) { - console.log(`[filesystem] APPEND STREAM ${fd}`); - }, - - advise(fd, offset, length, advice) { - console.log(`[filesystem] ADVISE`, fd, offset, length, advice); - }, - - syncData(fd) { - console.log(`[filesystem] SYNC DATA ${fd}`); - }, - - getFlags(fd) { - console.log(`[filesystem] FLAGS FOR ${fd}`); - }, - - getType(fd) { - console.log(`[filesystem] GET TYPE ${fd}`); - }, - - setFlags(fd, flags) { - console.log(`[filesystem] SET FLAGS ${fd} ${JSON.stringify(flags)}`); - }, - - setSize(fd, size) { - console.log(`[filesystem] SET SIZE`, fd, size); - }, - - setTimes(fd, dataAccessTimestamp, dataModificationTimestamp) { - console.log(`[filesystem] SET TIMES`, fd, dataAccessTimestamp, dataModificationTimestamp); - }, - - read(fd, length, offset) { - console.log(`[filesystem] READ`, fd, length, offset); - }, - - write(fd, buffer, offset) { - console.log(`[filesystem] WRITE`, fd, buffer, offset); - }, - - readDirectory(fd) { - console.log(`[filesystem] READ DIR`, fd); - }, - - sync(fd) { - console.log(`[filesystem] SYNC`, fd); - }, - - createDirectoryAt(fd, path) { - console.log(`[filesystem] CREATE DIRECTORY`, fd, path); - }, - - stat(fd) { - console.log(`[filesystem] STAT`, fd); - }, - - statAt(fd, pathFlags, path) { - console.log(`[filesystem] STAT`, fd, pathFlags, path); - }, - - setTimesAt(fd) { - console.log(`[filesystem] SET TIMES AT`, fd); - }, - - linkAt(fd) { - console.log(`[filesystem] LINK AT`, fd); - }, - - openAt(fd) { - console.log(`[filesystem] OPEN AT ${fd}`); - }, - - readlinkAt(fd) { - console.log(`[filesystem] READLINK AT`, fd); - }, - - removeDirectoryAt(fd) { - console.log(`[filesystem] REMOVE DIR AT`, fd); - }, - - renameAt(fd) { - console.log(`[filesystem] RENAME AT`, fd); - }, - - symlinkAt(fd) { - console.log(`[filesystem] SYMLINK AT`, fd); - }, - - unlinkFileAt(fd) { - console.log(`[filesystem] UNLINK FILE AT`, fd); - }, - - changeFilePermissionsAt(fd) { - console.log(`[filesystem] CHANGE FILE PERMISSIONS AT`, fd); - }, - - changeDirectoryPermissionsAt(fd) { - console.log(`[filesystem] CHANGE DIR PERMISSIONS AT`, fd); - }, - - lockShared(fd) { - console.log(`[filesystem] LOCK SHARED`, fd); - }, - - lockExclusive(fd) { - console.log(`[filesystem] LOCK EXCLUSIVE`, fd); - }, - - tryLockShared(fd) { - console.log(`[filesystem] TRY LOCK SHARED`, fd); - }, - - tryLockExclusive(fd) { - console.log(`[filesystem] TRY LOCK EXCLUSIVE`, fd); - }, - - unlock(fd) { - console.log(`[filesystem] UNLOCK`, fd); - }, - - dropDescriptor(fd) { - console.log(`[filesystem] DROP DESCRIPTOR`, fd); - }, - - readDirectoryEntry(stream) { - console.log(`[filesystem] READ DIRECTRY ENTRY`, stream); - }, - - dropDirectoryEntryStream(stream) { - console.log(`[filesystem] DROP DIRECTORY ENTRY`, stream); - }, - - metadataHash(fd) { - console.log(`[filesystem] METADATA HASH`, fd); - }, - - metadataHashAt(fd, pathFlags, path) { - console.log(`[filesystem] METADATA HASH AT `, fd, pathFlags, path); - } -}; - -export { types as filesystemTypes } diff --git a/resources/transformed/preview2-shim/browser/http.js b/resources/transformed/preview2-shim/browser/http.js deleted file mode 100644 index 592b3ad4..00000000 --- a/resources/transformed/preview2-shim/browser/http.js +++ /dev/null @@ -1,146 +0,0 @@ -import { UnexpectedError } from "../http/error.js"; - -/** - * @param {import("../../types/imports/wasi-http-types").Request} req - * @returns {string} - */ -export function send(req) { - console.log(`[http] Send (browser) ${req.uri}`); - try { - const xhr = new XMLHttpRequest(); - xhr.open(req.method.toString(), req.uri, false); - const requestHeaders = new Headers(req.headers); - for (let [name, value] of requestHeaders.entries()) { - if (name !== "user-agent" && name !== "host") { - xhr.setRequestHeader(name, value); - } - } - xhr.send(req.body && req.body.length > 0 ? req.body : null); - const body = xhr.response ? new TextEncoder().encode(xhr.response) : undefined; - const headers = []; - xhr.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach((line) => { - var parts = line.split(': '); - var key = parts.shift(); - var value = parts.join(': '); - headers.push([key, value]); - }); - return { - status: xhr.status, - headers, - body, - }; - } catch (err) { - throw new UnexpectedError(err.message); - } -} - -export const incomingHandler = { - handle () { - - } -}; - -export const outgoingHandler = { - handle () { - - } -}; - -export const types = { - dropFields(_fields) { - console.log("[types] Drop fields"); - }, - newFields(_entries) { - console.log("[types] New fields"); - }, - fieldsGet(_fields, _name) { - console.log("[types] Fields get"); - }, - fieldsSet(_fields, _name, _value) { - console.log("[types] Fields set"); - }, - fieldsDelete(_fields, _name) { - console.log("[types] Fields delete"); - }, - fieldsAppend(_fields, _name, _value) { - console.log("[types] Fields append"); - }, - fieldsEntries(_fields) { - console.log("[types] Fields entries"); - }, - fieldsClone(_fields) { - console.log("[types] Fields clone"); - }, - finishIncomingStream(s) { - console.log(`[types] Finish incoming stream ${s}`); - }, - finishOutgoingStream(s, _trailers) { - console.log(`[types] Finish outgoing stream ${s}`); - }, - dropIncomingRequest(_req) { - console.log("[types] Drop incoming request"); - }, - dropOutgoingRequest(_req) { - console.log("[types] Drop outgoing request"); - }, - incomingRequestMethod(_req) { - console.log("[types] Incoming request method"); - }, - incomingRequestPathWithQuery(_req) { - console.log("[types] Incoming request path with query"); - }, - incomingRequestScheme(_req) { - console.log("[types] Incoming request scheme"); - }, - incomingRequestAuthority(_req) { - console.log("[types] Incoming request authority"); - }, - incomingRequestHeaders(_req) { - console.log("[types] Incoming request headers"); - }, - incomingRequestConsume(_req) { - console.log("[types] Incoming request consume"); - }, - newOutgoingRequest(_method, _pathWithQuery, _scheme, _authority, _headers) { - console.log("[types] New outgoing request"); - }, - outgoingRequestWrite(_req) { - console.log("[types] Outgoing request write"); - }, - dropResponseOutparam(_res) { - console.log("[types] Drop response outparam"); - }, - setResponseOutparam(_response) { - console.log("[types] Drop fields"); - }, - dropIncomingResponse(_res) { - console.log("[types] Drop incoming response"); - }, - dropOutgoingResponse(_res) { - console.log("[types] Drop outgoing response"); - }, - incomingResponseStatus(_res) { - console.log("[types] Incoming response status"); - }, - incomingResponseHeaders(_res) { - console.log("[types] Incoming response headers"); - }, - incomingResponseConsume(_res) { - console.log("[types] Incoming response consume"); - }, - newOutgoingResponse(_statusCode, _headers) { - console.log("[types] New outgoing response"); - }, - outgoingResponseWrite(_res) { - console.log("[types] Outgoing response write"); - }, - dropFutureIncomingResponse(_f) { - console.log("[types] Drop future incoming response"); - }, - futureIncomingResponseGet(_f) { - console.log("[types] Future incoming response get"); - }, - listenToFutureIncomingResponse(_f) { - console.log("[types] Listen to future incoming response"); - } -}; diff --git a/resources/transformed/preview2-shim/browser/index.js b/resources/transformed/preview2-shim/browser/index.js deleted file mode 100644 index 11add6fa..00000000 --- a/resources/transformed/preview2-shim/browser/index.js +++ /dev/null @@ -1,25 +0,0 @@ -import * as clocks from "./clocks.js"; -import * as filesystem from "./filesystem.js"; -import * as http from "./http.js"; -import * as io from "./io.js"; -import * as logging from "./logging.js"; -import * as poll from "./poll.js"; -import * as random from "./random.js"; -import * as sockets from "./sockets.js"; -import * as cli from "./cli.js"; - -export const importObject = { - clocks, - filesystem, - http, - io, - logging, - poll, - random, - sockets, - cli, -}; - -export { WasiHttp } from "../http/wasi-http.js"; - -export default importObject; diff --git a/resources/transformed/preview2-shim/browser/io.js b/resources/transformed/preview2-shim/browser/io.js deleted file mode 100644 index 5a757304..00000000 --- a/resources/transformed/preview2-shim/browser/io.js +++ /dev/null @@ -1,60 +0,0 @@ -export const streams = { - read(s, len) { - console.log(`[streams] Original Read ${s} ${len}`); - }, - blockingRead(s, len) { - console.log(`[streams] Blocking read ${s} ${len}`); - }, - skip(s, _len) { - console.log(`[streams] Skip ${s}`); - }, - blockingSkip(s, _len) { - console.log(`[streams] Blocking skip ${s}`); - }, - subscribeToInputStream(s) { - console.log(`[streams] Subscribe to input stream ${s}`); - }, - dropInputStream(s) { - console.log(`[streams] Drop input stream ${s}`); - }, - write(s, buf) { - streams.blockingWrite(s, buf); - }, - blockingWrite(s, buf) { - switch (s) { - case 0: - throw new Error(`TODO: write stdin`); - case 1: { - process.stdout.write(buf); - return [BigInt(buf.byteLength), 'ended']; - } - case 2: { - process.stderr.write(buf); - return [BigInt(buf.byteLength), 'ended']; - } - default: - throw new Error(`TODO: write ${s}`); - } - }, - writeZeroes(s, _len) { - console.log(`[streams] Write zeroes ${s}`); - }, - blockingWriteZeroes(s, _len) { - console.log(`[streams] Blocking write zeroes ${s}`); - }, - splice(s, _src, _len) { - console.log(`[streams] Splice ${s}`); - }, - blockingSplice(s, _src, _len) { - console.log(`[streams] Blocking splice ${s}`); - }, - forward(s, _src) { - console.log(`[streams] Forward ${s}`); - }, - subscribeToOutputStream(s) { - console.log(`[streams] Subscribe to output stream ${s}`); - }, - dropOutputStream(s) { - console.log(`[streams] Drop output stream ${s}`); - } -}; diff --git a/resources/transformed/preview2-shim/browser/logging.js b/resources/transformed/preview2-shim/browser/logging.js deleted file mode 100644 index 9c963ac7..00000000 --- a/resources/transformed/preview2-shim/browser/logging.js +++ /dev/null @@ -1,14 +0,0 @@ -const levels = ["trace", "debug", "info", "warn", "error", "critical"]; - -let logLevel = levels.indexOf("warn"); - -export const logging = { - log(level, context, msg) { - if (logLevel > levels.indexOf(level)) return; - console[level](`(${context}) ${msg}\n`); - } -}; - -export function setLevel(level) { - logLevel = levels.indexOf(level); -} diff --git a/resources/transformed/preview2-shim/browser/poll.js b/resources/transformed/preview2-shim/browser/poll.js deleted file mode 100644 index 52d2fe36..00000000 --- a/resources/transformed/preview2-shim/browser/poll.js +++ /dev/null @@ -1,9 +0,0 @@ -export const poll = { - dropPollable (pollable) { - console.log(`[poll] Drop (${pollable})`); - }, - pollOneoff (input) { - console.log(`[poll] Oneoff (${input})`); - return []; - } -}; diff --git a/resources/transformed/preview2-shim/browser/random.js b/resources/transformed/preview2-shim/browser/random.js deleted file mode 100644 index cd9a3f91..00000000 --- a/resources/transformed/preview2-shim/browser/random.js +++ /dev/null @@ -1,41 +0,0 @@ -export const insecure = { - getInsecureRandomBytes(len) { - return random.getRandomBytes(len); - }, - getInsecureRandomU64() { - return random.getRandomU64(); - }, -}; - -let insecureSeedValue1, insecureSeedValue2; - -export const insecureSeed = { - insecureSeed() { - if (insecureSeedValue1 === undefined) { - insecureSeedValue1 = random.getRandomU64(); - insecureSeedValue2 = random.getRandomU64(); - } - return [insecureSeedValue1, insecureSeedValue2]; - }, -}; - -export const random = { - getRandomBytes(len) { - // We don't really care about this impl, it will be overridden anyway - const bytes = new Uint8Array(Number(len)); - return bytes; - }, - - getRandomU64() { - // We don't really care about this impl, it will be overridden anyway - return 0n; - }, - - insecureRandom() { - if (insecureRandomValue1 === undefined) { - insecureRandomValue1 = random.getRandomU64(); - insecureRandomValue2 = random.getRandomU64(); - } - return [insecureRandomValue1, insecureRandomValue2]; - }, -}; diff --git a/resources/transformed/preview2-shim/browser/sockets.js b/resources/transformed/preview2-shim/browser/sockets.js deleted file mode 100644 index 19aae42a..00000000 --- a/resources/transformed/preview2-shim/browser/sockets.js +++ /dev/null @@ -1,200 +0,0 @@ -export const instanceNetwork = { - instanceNetwork () { - console.log(`[sockets] instance network`); - } -}; - -export const ipNameLookup = { - dropResolveAddressStream () { - - }, - subscribe () { - - }, - resolveAddresses () { - - }, - resolveNextAddress () { - - }, - nonBlocking () { - - }, - setNonBlocking () { - - }, -}; - -export const network = { - dropNetwork () { - - } -}; - -export const tcpCreateSocket = { - createTcpSocket () { - - } -}; - -export const tcp = { - subscribe () { - - }, - dropTcpSocket() { - - }, - bind() { - - }, - connect() { - - }, - listen() { - - }, - accept() { - - }, - localAddress() { - - }, - remoteAddress() { - - }, - addressFamily() { - - }, - ipv6Only() { - - }, - setIpv6Only() { - - }, - setListenBacklogSize() { - - }, - keepAlive() { - - }, - setKeepAlive() { - - }, - noDelay() { - - }, - setNoDelay() { - - }, - unicastHopLimit() { - - }, - setUnicastHopLimit() { - - }, - receiveBufferSize() { - - }, - setReceiveBufferSize() { - - }, - sendBufferSize() { - - }, - setSendBufferSize() { - - }, - nonBlocking() { - - }, - setNonBlocking() { - - }, - shutdown() { - - } -}; - -export const udp = { - subscribe () { - - }, - - dropUdpSocket () { - - }, - - bind () { - - }, - - connect () { - - }, - - receive () { - - }, - - send () { - - }, - - localAddress () { - - }, - - remoteAddress () { - - }, - - addressFamily () { - - }, - - ipv6Only () { - - }, - - setIpv6Only () { - - }, - - unicastHopLimit () { - - }, - - setUnicastHopLimit () { - - }, - - receiveBufferSize () { - - }, - - setReceiveBufferSize () { - - }, - - sendBufferSize () { - - }, - - setSendBufferSize () { - - }, - - nonBlocking () { - - }, - - setNonBlocking () { - - } -}; - -export const udpCreateSocket = { - createUdpSocket () { - - } -}; diff --git a/resources/transformed/preview2-shim/bundled.js b/resources/transformed/preview2-shim/bundled.js deleted file mode 100644 index 1860eeb3..00000000 --- a/resources/transformed/preview2-shim/bundled.js +++ /dev/null @@ -1,750 +0,0 @@ -(() => { - var __defProp = Object.defineProperty; - var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); - }; - - // browser/clocks.js - var clocks_exports = {}; - __export(clocks_exports, { - monotonicClock: () => monotonicClock, - timezone: () => timezone, - wallClock: () => wallClock - }); - function _hrtimeBigint() { - return BigInt(Math.floor(performance.now() * 1e6)); - } - var _hrStart = _hrtimeBigint(); - var monotonicClock = { - resolution() { - return 1n; - }, - now() { - return _hrtimeBigint() - _hrStart; - }, - subscribe(_when, _absolute) { - console.log(`[monotonic-clock] Subscribe`); - } - }; - var timezone = { - display(timezone2, when) { - console.log(`[timezone] DISPLAY ${timezone2} ${when}`); - }, - utcOffset(timezone2, when) { - console.log(`[timezone] UTC OFFSET ${timezone2} ${when}`); - return 0; - }, - dropTimezone(timezone2) { - console.log(`[timezone] DROP ${timezone2}`); - } - }; - var wallClock = { - now() { - let now = Date.now(); - const seconds = BigInt(Math.floor(now / 1e3)); - const nanoseconds = now % 1e3 * 1e6; - return { seconds, nanoseconds }; - }, - resolution() { - console.log(`[wall-clock] Wall clock resolution`); - } - }; - - // browser/filesystem.js - var filesystem_exports = {}; - __export(filesystem_exports, { - filesystemTypes: () => types, - preopens: () => preopens, - types: () => types - }); - var preopens = { - getDirectories() { - return []; - } - }; - var types = { - readViaStream(fd, offset) { - console.log(`[filesystem] READ STREAM ${fd} ${offset}`); - }, - writeViaStream(fd, offset) { - console.log(`[filesystem] WRITE STREAM ${fd} ${offset}`); - }, - appendViaStream(fd) { - console.log(`[filesystem] APPEND STREAM ${fd}`); - }, - advise(fd, offset, length, advice) { - console.log(`[filesystem] ADVISE`, fd, offset, length, advice); - }, - syncData(fd) { - console.log(`[filesystem] SYNC DATA ${fd}`); - }, - getFlags(fd) { - console.log(`[filesystem] FLAGS FOR ${fd}`); - }, - getType(fd) { - console.log(`[filesystem] GET TYPE ${fd}`); - }, - setFlags(fd, flags) { - console.log(`[filesystem] SET FLAGS ${fd} ${JSON.stringify(flags)}`); - }, - setSize(fd, size) { - console.log(`[filesystem] SET SIZE`, fd, size); - }, - setTimes(fd, dataAccessTimestamp, dataModificationTimestamp) { - console.log(`[filesystem] SET TIMES`, fd, dataAccessTimestamp, dataModificationTimestamp); - }, - read(fd, length, offset) { - console.log(`[filesystem] READ`, fd, length, offset); - }, - write(fd, buffer, offset) { - console.log(`[filesystem] WRITE`, fd, buffer, offset); - }, - readDirectory(fd) { - console.log(`[filesystem] READ DIR`, fd); - }, - sync(fd) { - console.log(`[filesystem] SYNC`, fd); - }, - createDirectoryAt(fd, path) { - console.log(`[filesystem] CREATE DIRECTORY`, fd, path); - }, - stat(fd) { - console.log(`[filesystem] STAT`, fd); - }, - statAt(fd, pathFlags, path) { - console.log(`[filesystem] STAT`, fd, pathFlags, path); - }, - setTimesAt(fd) { - console.log(`[filesystem] SET TIMES AT`, fd); - }, - linkAt(fd) { - console.log(`[filesystem] LINK AT`, fd); - }, - openAt(fd) { - console.log(`[filesystem] OPEN AT ${fd}`); - }, - readlinkAt(fd) { - console.log(`[filesystem] READLINK AT`, fd); - }, - removeDirectoryAt(fd) { - console.log(`[filesystem] REMOVE DIR AT`, fd); - }, - renameAt(fd) { - console.log(`[filesystem] RENAME AT`, fd); - }, - symlinkAt(fd) { - console.log(`[filesystem] SYMLINK AT`, fd); - }, - unlinkFileAt(fd) { - console.log(`[filesystem] UNLINK FILE AT`, fd); - }, - changeFilePermissionsAt(fd) { - console.log(`[filesystem] CHANGE FILE PERMISSIONS AT`, fd); - }, - changeDirectoryPermissionsAt(fd) { - console.log(`[filesystem] CHANGE DIR PERMISSIONS AT`, fd); - }, - lockShared(fd) { - console.log(`[filesystem] LOCK SHARED`, fd); - }, - lockExclusive(fd) { - console.log(`[filesystem] LOCK EXCLUSIVE`, fd); - }, - tryLockShared(fd) { - console.log(`[filesystem] TRY LOCK SHARED`, fd); - }, - tryLockExclusive(fd) { - console.log(`[filesystem] TRY LOCK EXCLUSIVE`, fd); - }, - unlock(fd) { - console.log(`[filesystem] UNLOCK`, fd); - }, - dropDescriptor(fd) { - console.log(`[filesystem] DROP DESCRIPTOR`, fd); - }, - readDirectoryEntry(stream) { - console.log(`[filesystem] READ DIRECTRY ENTRY`, stream); - }, - dropDirectoryEntryStream(stream) { - console.log(`[filesystem] DROP DIRECTORY ENTRY`, stream); - }, - metadataHash(fd) { - console.log(`[filesystem] METADATA HASH`, fd); - }, - metadataHashAt(fd, pathFlags, path) { - console.log(`[filesystem] METADATA HASH AT `, fd, pathFlags, path); - } - }; - - // browser/http.js - var http_exports = {}; - __export(http_exports, { - incomingHandler: () => incomingHandler, - outgoingHandler: () => outgoingHandler, - send: () => send, - types: () => types2 - }); - - // http/error.js - var UnexpectedError = class extends Error { - /** @type { import("../../types/imports/wasi-http-types").ErrorUnexpectedError } */ - payload; - constructor(message = "unexpected-error") { - super(message); - this.payload = { - tag: "unexpected-error", - val: message - }; - } - }; - - // browser/http.js - function send(req) { - console.log(`[http] Send (browser) ${req.uri}`); - try { - const xhr = new XMLHttpRequest(); - xhr.open(req.method.toString(), req.uri, false); - const requestHeaders = new Headers(req.headers); - for (let [name, value] of requestHeaders.entries()) { - if (name !== "user-agent" && name !== "host") { - xhr.setRequestHeader(name, value); - } - } - xhr.send(req.body && req.body.length > 0 ? req.body : null); - const body = xhr.response ? new TextEncoder().encode(xhr.response) : void 0; - const headers = []; - xhr.getAllResponseHeaders().trim().split(/[\r\n]+/).forEach((line) => { - var parts = line.split(": "); - var key = parts.shift(); - var value = parts.join(": "); - headers.push([key, value]); - }); - return { - status: xhr.status, - headers, - body - }; - } catch (err) { - throw new UnexpectedError(err.message); - } - } - var incomingHandler = { - handle() { - } - }; - var outgoingHandler = { - handle() { - } - }; - var types2 = { - dropFields(_fields) { - console.log("[types] Drop fields"); - }, - newFields(_entries) { - console.log("[types] New fields"); - }, - fieldsGet(_fields, _name) { - console.log("[types] Fields get"); - }, - fieldsSet(_fields, _name, _value) { - console.log("[types] Fields set"); - }, - fieldsDelete(_fields, _name) { - console.log("[types] Fields delete"); - }, - fieldsAppend(_fields, _name, _value) { - console.log("[types] Fields append"); - }, - fieldsEntries(_fields) { - console.log("[types] Fields entries"); - }, - fieldsClone(_fields) { - console.log("[types] Fields clone"); - }, - finishIncomingStream(s) { - console.log(`[types] Finish incoming stream ${s}`); - }, - finishOutgoingStream(s, _trailers) { - console.log(`[types] Finish outgoing stream ${s}`); - }, - dropIncomingRequest(_req) { - console.log("[types] Drop incoming request"); - }, - dropOutgoingRequest(_req) { - console.log("[types] Drop outgoing request"); - }, - incomingRequestMethod(_req) { - console.log("[types] Incoming request method"); - }, - incomingRequestPathWithQuery(_req) { - console.log("[types] Incoming request path with query"); - }, - incomingRequestScheme(_req) { - console.log("[types] Incoming request scheme"); - }, - incomingRequestAuthority(_req) { - console.log("[types] Incoming request authority"); - }, - incomingRequestHeaders(_req) { - console.log("[types] Incoming request headers"); - }, - incomingRequestConsume(_req) { - console.log("[types] Incoming request consume"); - }, - newOutgoingRequest(_method, _pathWithQuery, _scheme, _authority, _headers) { - console.log("[types] New outgoing request"); - }, - outgoingRequestWrite(_req) { - console.log("[types] Outgoing request write"); - }, - dropResponseOutparam(_res) { - console.log("[types] Drop response outparam"); - }, - setResponseOutparam(_response) { - console.log("[types] Drop fields"); - }, - dropIncomingResponse(_res) { - console.log("[types] Drop incoming response"); - }, - dropOutgoingResponse(_res) { - console.log("[types] Drop outgoing response"); - }, - incomingResponseStatus(_res) { - console.log("[types] Incoming response status"); - }, - incomingResponseHeaders(_res) { - console.log("[types] Incoming response headers"); - }, - incomingResponseConsume(_res) { - console.log("[types] Incoming response consume"); - }, - newOutgoingResponse(_statusCode, _headers) { - console.log("[types] New outgoing response"); - }, - outgoingResponseWrite(_res) { - console.log("[types] Outgoing response write"); - }, - dropFutureIncomingResponse(_f) { - console.log("[types] Drop future incoming response"); - }, - futureIncomingResponseGet(_f) { - console.log("[types] Future incoming response get"); - }, - listenToFutureIncomingResponse(_f) { - console.log("[types] Listen to future incoming response"); - } - }; - - // browser/io.js - var io_exports = {}; - __export(io_exports, { - streams: () => streams - }); - var streams = { - read(s, len) { - console.log(`[streams] Original Read ${s} ${len}`); - }, - blockingRead(s, len) { - console.log(`[streams] Blocking read ${s} ${len}`); - }, - skip(s, _len) { - console.log(`[streams] Skip ${s}`); - }, - blockingSkip(s, _len) { - console.log(`[streams] Blocking skip ${s}`); - }, - subscribeToInputStream(s) { - console.log(`[streams] Subscribe to input stream ${s}`); - }, - dropInputStream(s) { - console.log(`[streams] Drop input stream ${s}`); - }, - write(s, buf) { - streams.blockingWrite(s, buf); - }, - blockingWrite(s, buf) { - switch (s) { - case 0: - throw new Error(`TODO: write stdin`); - case 1: { - process.stdout.write(buf); - return [BigInt(buf.byteLength), "ended"]; - } - case 2: { - process.stderr.write(buf); - return [BigInt(buf.byteLength), "ended"]; - } - default: - throw new Error(`TODO: write ${s}`); - } - }, - writeZeroes(s, _len) { - console.log(`[streams] Write zeroes ${s}`); - }, - blockingWriteZeroes(s, _len) { - console.log(`[streams] Blocking write zeroes ${s}`); - }, - splice(s, _src, _len) { - console.log(`[streams] Splice ${s}`); - }, - blockingSplice(s, _src, _len) { - console.log(`[streams] Blocking splice ${s}`); - }, - forward(s, _src) { - console.log(`[streams] Forward ${s}`); - }, - subscribeToOutputStream(s) { - console.log(`[streams] Subscribe to output stream ${s}`); - }, - dropOutputStream(s) { - console.log(`[streams] Drop output stream ${s}`); - } - }; - - // browser/logging.js - var logging_exports = {}; - __export(logging_exports, { - logging: () => logging, - setLevel: () => setLevel - }); - var levels = ["trace", "debug", "info", "warn", "error", "critical"]; - var logLevel = levels.indexOf("warn"); - var logging = { - log(level, context, msg) { - if (logLevel > levels.indexOf(level)) - return; - console[level](`(${context}) ${msg} -`); - } - }; - function setLevel(level) { - logLevel = levels.indexOf(level); - } - - // browser/poll.js - var poll_exports = {}; - __export(poll_exports, { - poll: () => poll - }); - var poll = { - dropPollable(pollable) { - console.log(`[poll] Drop (${pollable})`); - }, - pollOneoff(input) { - console.log(`[poll] Oneoff (${input})`); - return []; - } - }; - - // browser/random.js - var random_exports = {}; - __export(random_exports, { - insecure: () => insecure, - insecureSeed: () => insecureSeed, - random: () => random - }); - var insecure = { - getInsecureRandomBytes(len) { - return random.getRandomBytes(len); - }, - getInsecureRandomU64() { - return random.getRandomU64(); - } - }; - var insecureSeedValue1; - var insecureSeedValue2; - var insecureSeed = { - insecureSeed() { - if (insecureSeedValue1 === void 0) { - insecureSeedValue1 = random.getRandomU64(); - insecureSeedValue2 = random.getRandomU64(); - } - return [insecureSeedValue1, insecureSeedValue2]; - } - }; - var random = { - getRandomBytes(len) { - const bytes = new Uint8Array(Number(len)); - return bytes; - }, - getRandomU64() { - return 0n; - }, - insecureRandom() { - if (insecureRandomValue1 === void 0) { - insecureRandomValue1 = random.getRandomU64(); - insecureRandomValue2 = random.getRandomU64(); - } - return [insecureRandomValue1, insecureRandomValue2]; - } - }; - - // browser/sockets.js - var sockets_exports = {}; - __export(sockets_exports, { - instanceNetwork: () => instanceNetwork, - ipNameLookup: () => ipNameLookup, - network: () => network, - tcp: () => tcp, - tcpCreateSocket: () => tcpCreateSocket, - udp: () => udp, - udpCreateSocket: () => udpCreateSocket - }); - var instanceNetwork = { - instanceNetwork() { - console.log(`[sockets] instance network`); - } - }; - var ipNameLookup = { - dropResolveAddressStream() { - }, - subscribe() { - }, - resolveAddresses() { - }, - resolveNextAddress() { - }, - nonBlocking() { - }, - setNonBlocking() { - } - }; - var network = { - dropNetwork() { - } - }; - var tcpCreateSocket = { - createTcpSocket() { - } - }; - var tcp = { - subscribe() { - }, - dropTcpSocket() { - }, - bind() { - }, - connect() { - }, - listen() { - }, - accept() { - }, - localAddress() { - }, - remoteAddress() { - }, - addressFamily() { - }, - ipv6Only() { - }, - setIpv6Only() { - }, - setListenBacklogSize() { - }, - keepAlive() { - }, - setKeepAlive() { - }, - noDelay() { - }, - setNoDelay() { - }, - unicastHopLimit() { - }, - setUnicastHopLimit() { - }, - receiveBufferSize() { - }, - setReceiveBufferSize() { - }, - sendBufferSize() { - }, - setSendBufferSize() { - }, - nonBlocking() { - }, - setNonBlocking() { - }, - shutdown() { - } - }; - var udp = { - subscribe() { - }, - dropUdpSocket() { - }, - bind() { - }, - connect() { - }, - receive() { - }, - send() { - }, - localAddress() { - }, - remoteAddress() { - }, - addressFamily() { - }, - ipv6Only() { - }, - setIpv6Only() { - }, - unicastHopLimit() { - }, - setUnicastHopLimit() { - }, - receiveBufferSize() { - }, - setReceiveBufferSize() { - }, - sendBufferSize() { - }, - setSendBufferSize() { - }, - nonBlocking() { - }, - setNonBlocking() { - } - }; - var udpCreateSocket = { - createUdpSocket() { - } - }; - - // browser/cli.js - var cli_exports = {}; - __export(cli_exports, { - _setArgs: () => _setArgs, - _setCwd: () => _setCwd, - _setEnv: () => _setEnv, - environment: () => environment, - exit: () => exit, - stderr: () => stderr, - stdin: () => stdin, - stdout: () => stdout, - terminalInput: () => terminalInput, - terminalOutput: () => terminalOutput, - terminalStderr: () => terminalStderr, - terminalStdin: () => terminalStdin, - terminalStdout: () => terminalStdout - }); - var _env; - var _args = []; - var _cwd = null; - function _setEnv(envObj) { - _env = Object.entries(envObj); - } - function _setArgs(args) { - _args = args; - } - function _setCwd(cwd) { - _cwd = cwd; - } - var environment = { - getEnvironment() { - if (!_env) - _setEnv(process.env); - return _env; - }, - getArguments() { - return _args; - }, - initialCwd() { - return _cwd; - } - }; - var ComponentExit = class extends Error { - constructor(code) { - super(`Component exited ${code === 0 ? "successfully" : "with error"}`); - this.code = code; - } - }; - var exit = { - exit(status) { - throw new ComponentExit(status.tag === "err" ? 1 : 0); - } - }; - var stdin = { - getStdin() { - return 0; - } - }; - var stdout = { - getStdout() { - return 1; - } - }; - var stderr = { - getStderr() { - return 2; - } - }; - var terminalInput = { - dropTerminalInput() { - } - }; - var terminalOutput = { - dropTerminalOutput() { - } - }; - var terminalStderr = { - getTerminalStderr() { - return 0; - } - }; - var terminalStdin = { - getTerminalStdin() { - return 1; - } - }; - var terminalStdout = { - getTerminalStdout() { - return 2; - } - }; - - // browser/index.js - var importObject = { - clocks: clocks_exports, - filesystem: filesystem_exports, - http: http_exports, - io: io_exports, - logging: logging_exports, - poll: poll_exports, - random: random_exports, - sockets: sockets_exports, - cli: cli_exports - }; - var browser_default = importObject; - - // index.js - function getWasiImports() { - let exports = { ...browser_default, "cli-base": browser_default.cliBase }; - let wasiExports = {}; - for (let package_name in exports) { - for (let export_name in exports[package_name]) { - let export_name_tr = export_name; - if (export_name == "monotonicClock") { - export_name_tr = "monotonic-clock"; - } - if (export_name == "wallClock") { - export_name_tr = "wall-clock"; - } - let funcs = Object.entries( - exports[package_name][export_name] - ).map(([key, _]) => { - return key; - }).join(", "); - console.log(`export wasi:${package_name}/${export_name_tr} as ${export_name} ${funcs}`); - wasiExports[`wasi:${package_name}/${export_name_tr}`] = exports[package_name][export_name]; - } - } - return wasiExports; - } - - return getWasiImports(); -})(); diff --git a/resources/transformed/preview2-shim/http/error.js b/resources/transformed/preview2-shim/http/error.js deleted file mode 100644 index 748f20cb..00000000 --- a/resources/transformed/preview2-shim/http/error.js +++ /dev/null @@ -1,11 +0,0 @@ -export class UnexpectedError extends Error { - /** @type { import("../../types/imports/wasi-http-types").ErrorUnexpectedError } */ - payload; - constructor(message = "unexpected-error") { - super(message); - this.payload = { - tag: "unexpected-error", - val: message, - }; - } -} diff --git a/resources/transformed/preview2-shim/http/make-request.js b/resources/transformed/preview2-shim/http/make-request.js deleted file mode 100644 index ee743244..00000000 --- a/resources/transformed/preview2-shim/http/make-request.js +++ /dev/null @@ -1,30 +0,0 @@ -import { runAsWorker } from "./synckit/index.js"; - -/** - * @param {import("../../types/imports/wasi-http-types").Request} req - * @returns {Promise} - */ -async function makeRequest(req) { - try { - let headers = new Headers(req.headers); - const resp = await fetch(req.uri, { - method: req.method.toString(), - headers, - body: req.body && req.body.length > 0 ? req.body : undefined, - redirect: "manual", - }); - let arrayBuffer = await resp.arrayBuffer(); - return JSON.stringify({ - status: resp.status, - headers: Array.from(resp.headers.entries()), - body: - arrayBuffer.byteLength > 0 - ? Buffer.from(arrayBuffer).toString("base64") - : undefined, - }); - } catch (err) { - return JSON.stringify({ message: err.toString() }); - } -} - -runAsWorker(makeRequest); diff --git a/resources/transformed/preview2-shim/http/synckit/index.d.ts b/resources/transformed/preview2-shim/http/synckit/index.d.ts deleted file mode 100644 index 73e2e8f9..00000000 --- a/resources/transformed/preview2-shim/http/synckit/index.d.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* -MIT License - -Copyright (c) 2021 UnTS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -/// -import { MessagePort } from "node:worker_threads"; -export type AnyFn = (...args: T) => R; -export type AnyPromise = Promise; -export type AnyAsyncFn = AnyFn>; -export type Syncify = T extends ( - ...args: infer Args -) => Promise - ? (...args: Args) => R - : never; -export type PromiseType = T extends Promise - ? R - : never; -export interface MainToWorkerMessage { - sharedBuffer: SharedArrayBuffer; - id: number; - args: T; -} -export interface WorkerData { - workerPort: MessagePort; -} -export interface DataMessage { - result?: T; - error?: unknown; - properties?: unknown; -} -export interface WorkerToMainMessage extends DataMessage { - id: number; -} -export interface SyncifyOptions { - bufferSize?: number; - timeout?: number; - execArgv?: string[]; -} -export declare function createSyncFn( - workerPath: string, - bufferSize?: number, - timeout?: number -): Syncify; -export declare function createSyncFn( - workerPath: string, - options?: SyncifyOptions -): Syncify; -export declare function runAsWorker< - R = unknown, - T extends AnyAsyncFn = AnyAsyncFn ->(fn: T): void; diff --git a/resources/transformed/preview2-shim/http/synckit/index.js b/resources/transformed/preview2-shim/http/synckit/index.js deleted file mode 100644 index 22ce198e..00000000 --- a/resources/transformed/preview2-shim/http/synckit/index.js +++ /dev/null @@ -1,141 +0,0 @@ -// Based on: https://github.com/un-ts/synckit -/* -MIT License - -Copyright (c) 2021 UnTS - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -import path from "node:path"; -import { - MessageChannel, - Worker, - receiveMessageOnPort, - workerData, - parentPort, -} from "node:worker_threads"; - -const DEFAULT_WORKER_BUFFER_SIZE = 1024; -const syncFnCache = new Map(); - -function extractProperties(object) { - if (object && typeof object === "object") { - const properties = {}; - for (const key in object) { - properties[key] = object[key]; - } - return properties; - } -} - -export function createSyncFn(workerPath, bufferSizeOrOptions, timeout) { - if (!path.isAbsolute(workerPath)) { - throw new Error("`workerPath` must be absolute"); - } - const cachedSyncFn = syncFnCache.get(workerPath); - if (cachedSyncFn) { - return cachedSyncFn; - } - const syncFn = startWorkerThread( - workerPath, - typeof bufferSizeOrOptions === "number" - ? { bufferSize: bufferSizeOrOptions, timeout } - : bufferSizeOrOptions - ); - syncFnCache.set(workerPath, syncFn); - return syncFn; -} - -function startWorkerThread( - workerPath, - { - bufferSize = DEFAULT_WORKER_BUFFER_SIZE, - timeout = undefined, - execArgv = [], - } = {} -) { - const { port1: mainPort, port2: workerPort } = new MessageChannel(); - const worker = new Worker(workerPath, { - workerData: { workerPort }, - transferList: [workerPort], - execArgv: execArgv, - }); - let nextID = 0; - const syncFn = (...args) => { - const id = nextID++; - const sharedBuffer = new SharedArrayBuffer(bufferSize); - const sharedBufferView = new Int32Array(sharedBuffer); - const msg = { sharedBuffer, id, args }; - worker.postMessage(msg); - const status = Atomics.wait(sharedBufferView, 0, 0, timeout); - if (!["ok", "not-equal"].includes(status)) { - throw new Error("Internal error: Atomics.wait() failed: " + status); - } - const { - id: id2, - result, - error, - properties, - } = receiveMessageOnPort(mainPort).message; - if (id !== id2) { - throw new Error(`Internal error: Expected id ${id} but got id ${id2}`); - } - if (error) { - throw Object.assign(error, properties); - } - return result; - }; - worker.unref(); - return syncFn; -} - -export function runAsWorker(fn) { - if (!workerData) { - return; - } - const { workerPort } = workerData; - try { - parentPort.on("message", ({ sharedBuffer, id, args }) => { - (async () => { - const sharedBufferView = new Int32Array(sharedBuffer); - let msg; - try { - msg = { id, result: await fn(...args) }; - } catch (error) { - msg = { id, error, properties: extractProperties(error) }; - } - workerPort.postMessage(msg); - Atomics.add(sharedBufferView, 0, 1); - Atomics.notify(sharedBufferView, 0); - })(); - }); - } catch (error) { - parentPort.on("message", ({ sharedBuffer, id }) => { - const sharedBufferView = new Int32Array(sharedBuffer); - workerPort.postMessage({ - id, - error, - properties: extractProperties(error), - }); - Atomics.add(sharedBufferView, 0, 1); - Atomics.notify(sharedBufferView, 0); - }); - } -} diff --git a/resources/transformed/preview2-shim/http/wasi-http.js b/resources/transformed/preview2-shim/http/wasi-http.js deleted file mode 100644 index 170f85fe..00000000 --- a/resources/transformed/preview2-shim/http/wasi-http.js +++ /dev/null @@ -1,347 +0,0 @@ -// Based on: -// https://github.com/bytecodealliance/wasmtime/blob/8efcb9851602287fd07a1a1e91501f51f2653d7e/crates/wasi-http/ - -/** - * @typedef {import("../../types/imports/wasi-http-types").Fields} Fields - * @typedef {import("../../types/imports/wasi-http-types").FutureIncomingResponse} FutureIncomingResponse - * @typedef {import("../../types/imports/wasi-http-types").Headers} Headers - * @typedef {import("../../types/imports/wasi-http-types").IncomingResponse} IncomingResponse - * @typedef {import("../../types/imports/wasi-http-types").IncomingStream} IncomingStream - * @typedef {import("../../types/imports/wasi-http-types").Method} Method - * @typedef {import("../../types/imports/wasi-http-types").OutgoingRequest} OutgoingRequest - * @typedef {import("../../types/imports/wasi-http-types").RequestOptions} RequestOptions - * @typedef {import("../../types/imports/wasi-http-types").Result} Result - * @typedef {import("../../types/imports/wasi-http-types").Scheme} Scheme - * @typedef {import("../../types/imports/wasi-http-types").StatusCode} StatusCode - * @typedef {import("../../types/imports/wasi-io-streams").StreamStatus} StreamStatus -*/ - -import * as io from '../browser//io'; -import * as http from '../browser//http'; -import { UnexpectedError } from './error.js'; - -export class WasiHttp { - requestIdBase = 1; - responseIdBase = 1; - fieldsIdBase = 1; - streamIdBase = 3; - futureIdBase = 1; - /** @type {Map} */ requests = new Map(); - /** @type {Map} */ responses = new Map(); - /** @type {Map>} */ fields = new Map(); - /** @type {Map} */ streams = new Map(); - /** @type {Map} */ futures = new Map(); - - constructor() {} - - /** - * @param {OutgoingRequest} requestId - * @param {RequestOptions | null} options - * @returns {FutureIncomingResponse} - */ - handle = (requestId, _options) => { - const request = this.requests.get(requestId); - if (!request) throw Error("not found!"); - - const responseId = this.responseIdBase; - this.responseIdBase += 1; - const response = new ActiveResponse(responseId); - - const scheme = request.scheme.tag === "HTTP" ? "http://" : "https://"; - - const url = scheme + request.authority + request.pathWithQuery; - const headers = { - "host": request.authority, - }; - if (request.headers && request.headers.size > 0) { - for (const [key, value] of request.headers.entries()) { - headers[key] = Array.isArray(value) ? value.join(",") : value; - } - } - const body = this.streams.get(request.body); - - const res = http.send({ - method: request.method.tag, - uri: url, - headers: headers, - params: [], - body: body && body.length > 0 ? body : undefined, - }); - - response.status = res.status; - if (res.headers && res.headers.size > 0) { - for (const [key, value] of res.headers) { - response.responseHeaders.set(key, [value]); - } - } - const buf = res.body; - response.body = this.streamIdBase; - this.streamIdBase += 1; - this.streams.set(response.body, buf); - this.responses.set(responseId, response); - - const futureId = this.futureIdBase; - this.futureIdBase += 1; - const future = new ActiveFuture(futureId, responseId); - this.futures.set(futureId, future); - return futureId; - } - - read = (stream, len) => { - return this.blockingRead(stream, len); - } - - /** - * @param {InputStream} stream - * @param {bigint} len - * @returns {[Uint8Array | ArrayBuffer, StreamStatus]} - */ - blockingRead = (stream, len) => { - if (stream < 3) { - return io.streams.blockingRead(stream); - } - const s = this.streams.get(stream); - if (!s) throw Error(`stream not found: ${stream}`); - const position = Number(len); - if (position === 0) { - return [new Uint8Array(), s.byteLength > 0 ? 'open' : 'ended']; - } else if (s.byteLength > position) { - this.streams.set(stream, s.slice(position, s.byteLength)); - return [s.slice(0, position), 'open']; - } else { - return [s.slice(0, position), 'ended']; - } - } - - /** - * @param {InputStream} stream - * @returns {Pollable} - */ - subscribeToInputStream = (stream) => { - // TODO: not implemented yet - console.log(`[streams] Subscribe to input stream ${stream}`); - } - - /** - * @param {InputStream} stream - */ - dropInputStream = (stream) => { - const s = this.streams.get(stream); - if (!s) throw Error(`no such input stream ${stream}`); - s.set([]); - } - - write = (stream, buf) => { - return this.blockingWrite(stream, buf); - } - - /** - * @param {OutputStream} stream - * @param {Uint8Array} buf - * @returns {[bigint, StreamStatus]} - */ - blockingWrite = (stream, buf) => { - if (stream < 3) { - return io.streams.blockingWrite(stream, buf); - } - this.streams.set(stream, buf); - return [BigInt(buf.byteLength), 'ended']; - } - - /** - * @param {OutputStream} stream - * @returns {Pollable} - */ - subscribeToOutputStream = (stream) => { - // TODO: not implemented yet - console.log(`[streams] Subscribe to output stream ${stream}`); - } - - /** - * @param {OutputStream} stream - */ - dropOutputStream = (stream) => { - const s = this.streams.get(stream); - if (!s) throw Error(`no such output stream ${stream}`); - s.set([]); - } - - /** - * @param {Fields} fields - */ - dropFields = (fields) => { - this.fields.delete(fields); - } - - /** - * @param {[string, string][]} entries - * @returns {Fields} - */ - newFields = (entries) => { - const map = new Map(entries); - - const id = this.fieldsIdBase; - this.fieldsIdBase += 1; - this.fields.set(id, map); - - return id; - } - - /** - * @param {Fields} fields - * @returns {[string, string][]} - */ - fieldsEntries = (fields) => { - return this.fields.get(fields) ?? []; - } - - /** - * @param {OutgoingRequest} request - */ - dropOutgoingRequest = (request) => { - this.requests.delete(request); - } - - /** - * @param {Method} method - * @param {string | null} pathWithQuery - * @param {Scheme | null} scheme - * @param {string | null} authority - * @param {Headers} headers - * @returns {number} - */ - newOutgoingRequest = (method, pathWithQuery, scheme, authority, headers) => { - const id = this.requestIdBase; - this.requestIdBase += 1; - - const req = new ActiveRequest(id); - req.pathWithQuery = pathWithQuery; - req.authority = authority; - req.method = method; - req.headers = this.fields.get(headers); - req.scheme = scheme; - this.requests.set(id, req); - return id; - } - - /** - * @param {OutgoingRequest} request - * @returns {OutgoingStream} - */ - outgoingRequestWrite = (request) => { - const req = this.requests.get(request); - req.body = this.streamIdBase; - this.streamIdBase += 1; - return req.body; - } - - /** - * @param {IncomingResponse} response - */ - dropIncomingResponse = (response) => { - this.responses.delete(response); - } - - /** - * @param {IncomingResponse} response - * @returns {StatusCode} - */ - incomingResponseStatus = (response) => { - const r = this.responses.get(response); - return r.status; - } - - /** - * @param {IncomingResponse} response - * @returns {Headers} - */ - incomingResponseHeaders = (response) => { - const r = this.responses.get(response); - const id = this.fieldsIdBase; - this.fieldsIdBase += 1; - - this.fields.set(id, r.responseHeaders); - return id; - } - - /** - * @param {IncomingResponse} response - * @returns {IncomingStream} - */ - incomingResponseConsume = (response) => { - const r = this.responses.get(response); - return r.body; - } - - /** - * @param {FutureIncomingResponse} future - */ - dropFutureIncomingResponse = (future) => { - return this.futures.delete(future); - } - - /** - * @param {FutureIncomingResponse} future - * @returns {Result | null} - */ - futureIncomingResponseGet = (future) => { - const f = this.futures.get(future); - if (!f) { - return { - tag: "err", - val: UnexpectedError(`no such future ${f}`), - }; - } - // For now this will assume the future will return - // the response immediately - const response = f.responseId; - const r = this.responses.get(response); - if (!r) { - return { - tag: "err", - val: UnexpectedError(`no such response ${response}`), - }; - } - return { - tag: "ok", - val: response, - }; - } -} - -class ActiveRequest { - /** @type {number} */ id; - activeRequest = false; - /** @type {Method} */ method = { tag: 'get' }; - /** @type {Scheme | null} */ scheme = { tag: 'HTTP' }; - pathWithQuery = null; - authority = null; - /** @type {Map} */ headers = new Map(); - body = 3; - - constructor(id) { - this.id = id; - } -} - -class ActiveResponse { - /** @type {number} */ id; - activeResponse = false; - status = 0; - body = 3; - /** @type {Map} */ responseHeaders = new Map(); - - constructor(id) { - this.id = id; - } -} - -class ActiveFuture { - /** @type {number} */ id; - /** @type {number} */ responseId; - - constructor(id, responseId) { - this.id = id; - this.responseId = responseId; - } -} diff --git a/resources/transformed/preview2-shim/http/wasi-http.js-E b/resources/transformed/preview2-shim/http/wasi-http.js-E deleted file mode 100644 index 76947b9d..00000000 --- a/resources/transformed/preview2-shim/http/wasi-http.js-E +++ /dev/null @@ -1,347 +0,0 @@ -// Based on: -// https://github.com/bytecodealliance/wasmtime/blob/8efcb9851602287fd07a1a1e91501f51f2653d7e/crates/wasi-http/ - -/** - * @typedef {import("../../types/imports/wasi-http-types").Fields} Fields - * @typedef {import("../../types/imports/wasi-http-types").FutureIncomingResponse} FutureIncomingResponse - * @typedef {import("../../types/imports/wasi-http-types").Headers} Headers - * @typedef {import("../../types/imports/wasi-http-types").IncomingResponse} IncomingResponse - * @typedef {import("../../types/imports/wasi-http-types").IncomingStream} IncomingStream - * @typedef {import("../../types/imports/wasi-http-types").Method} Method - * @typedef {import("../../types/imports/wasi-http-types").OutgoingRequest} OutgoingRequest - * @typedef {import("../../types/imports/wasi-http-types").RequestOptions} RequestOptions - * @typedef {import("../../types/imports/wasi-http-types").Result} Result - * @typedef {import("../../types/imports/wasi-http-types").Scheme} Scheme - * @typedef {import("../../types/imports/wasi-http-types").StatusCode} StatusCode - * @typedef {import("../../types/imports/wasi-io-streams").StreamStatus} StreamStatus -*/ - -import * as io from '@bytecodealliance/preview2-shim/io'; -import * as http from '@bytecodealliance/preview2-shim/http'; -import { UnexpectedError } from './error.js'; - -export class WasiHttp { - requestIdBase = 1; - responseIdBase = 1; - fieldsIdBase = 1; - streamIdBase = 3; - futureIdBase = 1; - /** @type {Map} */ requests = new Map(); - /** @type {Map} */ responses = new Map(); - /** @type {Map>} */ fields = new Map(); - /** @type {Map} */ streams = new Map(); - /** @type {Map} */ futures = new Map(); - - constructor() {} - - /** - * @param {OutgoingRequest} requestId - * @param {RequestOptions | null} options - * @returns {FutureIncomingResponse} - */ - handle = (requestId, _options) => { - const request = this.requests.get(requestId); - if (!request) throw Error("not found!"); - - const responseId = this.responseIdBase; - this.responseIdBase += 1; - const response = new ActiveResponse(responseId); - - const scheme = request.scheme.tag === "HTTP" ? "http://" : "https://"; - - const url = scheme + request.authority + request.pathWithQuery; - const headers = { - "host": request.authority, - }; - if (request.headers && request.headers.size > 0) { - for (const [key, value] of request.headers.entries()) { - headers[key] = Array.isArray(value) ? value.join(",") : value; - } - } - const body = this.streams.get(request.body); - - const res = http.send({ - method: request.method.tag, - uri: url, - headers: headers, - params: [], - body: body && body.length > 0 ? body : undefined, - }); - - response.status = res.status; - if (res.headers && res.headers.size > 0) { - for (const [key, value] of res.headers) { - response.responseHeaders.set(key, [value]); - } - } - const buf = res.body; - response.body = this.streamIdBase; - this.streamIdBase += 1; - this.streams.set(response.body, buf); - this.responses.set(responseId, response); - - const futureId = this.futureIdBase; - this.futureIdBase += 1; - const future = new ActiveFuture(futureId, responseId); - this.futures.set(futureId, future); - return futureId; - } - - read = (stream, len) => { - return this.blockingRead(stream, len); - } - - /** - * @param {InputStream} stream - * @param {bigint} len - * @returns {[Uint8Array | ArrayBuffer, StreamStatus]} - */ - blockingRead = (stream, len) => { - if (stream < 3) { - return io.streams.blockingRead(stream); - } - const s = this.streams.get(stream); - if (!s) throw Error(`stream not found: ${stream}`); - const position = Number(len); - if (position === 0) { - return [new Uint8Array(), s.byteLength > 0 ? 'open' : 'ended']; - } else if (s.byteLength > position) { - this.streams.set(stream, s.slice(position, s.byteLength)); - return [s.slice(0, position), 'open']; - } else { - return [s.slice(0, position), 'ended']; - } - } - - /** - * @param {InputStream} stream - * @returns {Pollable} - */ - subscribeToInputStream = (stream) => { - // TODO: not implemented yet - console.log(`[streams] Subscribe to input stream ${stream}`); - } - - /** - * @param {InputStream} stream - */ - dropInputStream = (stream) => { - const s = this.streams.get(stream); - if (!s) throw Error(`no such input stream ${stream}`); - s.set([]); - } - - write = (stream, buf) => { - return this.blockingWrite(stream, buf); - } - - /** - * @param {OutputStream} stream - * @param {Uint8Array} buf - * @returns {[bigint, StreamStatus]} - */ - blockingWrite = (stream, buf) => { - if (stream < 3) { - return io.streams.blockingWrite(stream, buf); - } - this.streams.set(stream, buf); - return [BigInt(buf.byteLength), 'ended']; - } - - /** - * @param {OutputStream} stream - * @returns {Pollable} - */ - subscribeToOutputStream = (stream) => { - // TODO: not implemented yet - console.log(`[streams] Subscribe to output stream ${stream}`); - } - - /** - * @param {OutputStream} stream - */ - dropOutputStream = (stream) => { - const s = this.streams.get(stream); - if (!s) throw Error(`no such output stream ${stream}`); - s.set([]); - } - - /** - * @param {Fields} fields - */ - dropFields = (fields) => { - this.fields.delete(fields); - } - - /** - * @param {[string, string][]} entries - * @returns {Fields} - */ - newFields = (entries) => { - const map = new Map(entries); - - const id = this.fieldsIdBase; - this.fieldsIdBase += 1; - this.fields.set(id, map); - - return id; - } - - /** - * @param {Fields} fields - * @returns {[string, string][]} - */ - fieldsEntries = (fields) => { - return this.fields.get(fields) ?? []; - } - - /** - * @param {OutgoingRequest} request - */ - dropOutgoingRequest = (request) => { - this.requests.delete(request); - } - - /** - * @param {Method} method - * @param {string | null} pathWithQuery - * @param {Scheme | null} scheme - * @param {string | null} authority - * @param {Headers} headers - * @returns {number} - */ - newOutgoingRequest = (method, pathWithQuery, scheme, authority, headers) => { - const id = this.requestIdBase; - this.requestIdBase += 1; - - const req = new ActiveRequest(id); - req.pathWithQuery = pathWithQuery; - req.authority = authority; - req.method = method; - req.headers = this.fields.get(headers); - req.scheme = scheme; - this.requests.set(id, req); - return id; - } - - /** - * @param {OutgoingRequest} request - * @returns {OutgoingStream} - */ - outgoingRequestWrite = (request) => { - const req = this.requests.get(request); - req.body = this.streamIdBase; - this.streamIdBase += 1; - return req.body; - } - - /** - * @param {IncomingResponse} response - */ - dropIncomingResponse = (response) => { - this.responses.delete(response); - } - - /** - * @param {IncomingResponse} response - * @returns {StatusCode} - */ - incomingResponseStatus = (response) => { - const r = this.responses.get(response); - return r.status; - } - - /** - * @param {IncomingResponse} response - * @returns {Headers} - */ - incomingResponseHeaders = (response) => { - const r = this.responses.get(response); - const id = this.fieldsIdBase; - this.fieldsIdBase += 1; - - this.fields.set(id, r.responseHeaders); - return id; - } - - /** - * @param {IncomingResponse} response - * @returns {IncomingStream} - */ - incomingResponseConsume = (response) => { - const r = this.responses.get(response); - return r.body; - } - - /** - * @param {FutureIncomingResponse} future - */ - dropFutureIncomingResponse = (future) => { - return this.futures.delete(future); - } - - /** - * @param {FutureIncomingResponse} future - * @returns {Result | null} - */ - futureIncomingResponseGet = (future) => { - const f = this.futures.get(future); - if (!f) { - return { - tag: "err", - val: UnexpectedError(`no such future ${f}`), - }; - } - // For now this will assume the future will return - // the response immediately - const response = f.responseId; - const r = this.responses.get(response); - if (!r) { - return { - tag: "err", - val: UnexpectedError(`no such response ${response}`), - }; - } - return { - tag: "ok", - val: response, - }; - } -} - -class ActiveRequest { - /** @type {number} */ id; - activeRequest = false; - /** @type {Method} */ method = { tag: 'get' }; - /** @type {Scheme | null} */ scheme = { tag: 'HTTP' }; - pathWithQuery = null; - authority = null; - /** @type {Map} */ headers = new Map(); - body = 3; - - constructor(id) { - this.id = id; - } -} - -class ActiveResponse { - /** @type {number} */ id; - activeResponse = false; - status = 0; - body = 3; - /** @type {Map} */ responseHeaders = new Map(); - - constructor(id) { - this.id = id; - } -} - -class ActiveFuture { - /** @type {number} */ id; - /** @type {number} */ responseId; - - constructor(id, responseId) { - this.id = id; - this.responseId = responseId; - } -} diff --git a/resources/transformed/preview2-shim/index.js b/resources/transformed/preview2-shim/index.js deleted file mode 100644 index 0066c7cc..00000000 --- a/resources/transformed/preview2-shim/index.js +++ /dev/null @@ -1,36 +0,0 @@ -import importObject from "./browser"; - -function to_kebab_case(str) { - return str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(); -} - -export function getWasiImports() { - let exports = { ...importObject, "cli-base": importObject.cliBase }; - - let wasiExports = {}; - - for (let package_name in exports) { - for (let export_name in exports[package_name]) { - let export_name_tr = export_name; - if (export_name == "monotonicClock") { - export_name_tr = "monotonic-clock"; - } - if (export_name == "wallClock") { - export_name_tr = "wall-clock"; - } - - let funcs = - Object.entries( - exports[package_name][export_name] - ).map(([key, _]) => { - return key - }).join(", "); - - console.log(`export wasi:${package_name}/${export_name_tr} as ${export_name} ${funcs}`) - wasiExports[`wasi:${package_name}/${export_name_tr}`] = - exports[package_name][export_name]; - } - } - - return wasiExports; -} diff --git a/resources/transformed/random.js b/resources/transformed/random.js deleted file mode 100644 index cd9a3f91..00000000 --- a/resources/transformed/random.js +++ /dev/null @@ -1,41 +0,0 @@ -export const insecure = { - getInsecureRandomBytes(len) { - return random.getRandomBytes(len); - }, - getInsecureRandomU64() { - return random.getRandomU64(); - }, -}; - -let insecureSeedValue1, insecureSeedValue2; - -export const insecureSeed = { - insecureSeed() { - if (insecureSeedValue1 === undefined) { - insecureSeedValue1 = random.getRandomU64(); - insecureSeedValue2 = random.getRandomU64(); - } - return [insecureSeedValue1, insecureSeedValue2]; - }, -}; - -export const random = { - getRandomBytes(len) { - // We don't really care about this impl, it will be overridden anyway - const bytes = new Uint8Array(Number(len)); - return bytes; - }, - - getRandomU64() { - // We don't really care about this impl, it will be overridden anyway - return 0n; - }, - - insecureRandom() { - if (insecureRandomValue1 === undefined) { - insecureRandomValue1 = random.getRandomU64(); - insecureRandomValue2 = random.getRandomU64(); - } - return [insecureRandomValue1, insecureRandomValue2]; - }, -}; diff --git a/resources/transformed/transform.sh b/resources/transformed/transform.sh deleted file mode 100755 index 240fb1c5..00000000 --- a/resources/transformed/transform.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/sh -set -e - -## Wasi shim - -# copy the files -rm -rf /browser -rm -rf preview2-shim/http - -cp -r ../original/preview2-shim/browser preview2-shim -cp -r ../original/preview2-shim/http preview2-shim - -# change the import path -cd preview2-shim -sed -i -E 's#@bytecodealliance/preview2-shim#../browser/#' http/wasi-http.js - -# TODO: Crypto is not defined ... -cp ../random.js browser/random.js - -# bundle the files into a single file -esbuild index.js --bundle --outfile=bundled.js - -# return the import object from the bundle -tail -r bundled.js | tail +2 | tail -r > bundled_new.js -echo >> bundled_new.js -echo ' return getWasiImports();' >> bundled_new.js -echo '})();' >> bundled_new.js -mv bundled_new.js bundled.js - -cd .. From af7d1fb0daddf5ad8c8bd63f4cab10004357f00f Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Tue, 5 Sep 2023 11:01:38 +0200 Subject: [PATCH 22/26] fix: cli-base aliased as cli --- crates/wasm-bridge-js/src/component/linker.rs | 21 +++++++++++----- .../src/wasi/preview2/environment.rs | 24 ++++++++----------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/crates/wasm-bridge-js/src/component/linker.rs b/crates/wasm-bridge-js/src/component/linker.rs index 57752225..d0e3bdb7 100644 --- a/crates/wasm-bridge-js/src/component/linker.rs +++ b/crates/wasm-bridge-js/src/component/linker.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, rc::Rc}; +use std::{collections::HashMap, iter::once, rc::Rc}; use convert_case::Casing; use js_sys::{Object, Reflect}; @@ -9,6 +9,7 @@ use crate::{AsContextMut, DataHandle, DropHandle, Engine, Result}; use super::*; pub struct Linker { + aliases: Vec, fns: Vec>, instances: HashMap>, wasi_imports: Option, @@ -20,6 +21,7 @@ impl Linker { fns: vec![], instances: HashMap::new(), wasi_imports: None, + aliases: vec![], } } @@ -50,13 +52,15 @@ impl Linker { let _span = tracing::debug_span!("link instance", instance_name).entered(); let instance_obj = Object::new(); - for function in instance_linker.fns.iter() { - tracing::debug!(function = function.name.as_str(), "link instance func"); + for instance_name in once(instance_name).chain(&instance_linker.aliases) { + for function in instance_linker.fns.iter() { + tracing::debug!(function = function.name.as_str(), "link instance func"); - let drop_handle = - function.add_to_instance_imports(&instance_obj, data_handle.clone()); + let drop_handle = + function.add_to_instance_imports(&instance_obj, data_handle.clone()); - closures.push(drop_handle); + closures.push(drop_handle); + } } Reflect::set(&import_object, &instance_name.into(), &instance_obj).unwrap(); @@ -111,6 +115,11 @@ impl Linker { pub(crate) fn set_wasi_imports(&mut self, imports: Object) { self.wasi_imports = Some(imports); } + + pub(crate) fn alias(&mut self, dst: &str) -> &mut Self { + self.aliases.push(dst.into()); + self + } } struct PreparedFn { diff --git a/crates/wasm-bridge-js/src/wasi/preview2/environment.rs b/crates/wasm-bridge-js/src/wasi/preview2/environment.rs index 930885ae..ffdd5684 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/environment.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/environment.rs @@ -8,28 +8,24 @@ use super::WasiView; /// Adds environment integration to the linker pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { - linker.instance("wasi:cli-base/environment")?.func_wrap( - "get-environment", - |data: StoreContextMut, (): ()| { + linker + .instance("wasi:cli-base/environment")? + .func_wrap("get-environment", |data: StoreContextMut, (): ()| { Ok(data .ctx() .environment() .iter() .map(|(k, v)| (k.to_owned(), v.to_owned())) .collect::>()) - }, - )?; - - linker.instance("wasi:cli-base/environment")?.func_wrap( - "get-arguments", - |_data: StoreContextMut, (): ()| -> Result { unimplemented!() }, - )?; - - linker - .instance("wasi:cli-base/environment")? + })? + .func_wrap( + "get-arguments", + |_data: StoreContextMut, (): ()| -> Result { unimplemented!() }, + )? .func_wrap("initial-cwd", |_data: StoreContextMut, (): ()| { Ok(String::from(".")) - })?; + })? + .alias("cli"); Ok(()) } From d8cd04dd73705f0ec76cd23bdf63db6bce546c3a Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Tue, 5 Sep 2023 11:40:02 +0200 Subject: [PATCH 23/26] fix: cargo component shenanigans --- crates/wasm-bridge-js/src/component/linker.rs | 18 ++++++++++-------- .../src/wasi/preview2/command.rs | 2 +- .../src/wasi/preview2/environment.rs | 5 ++--- .../src/wasi/preview2/filesystem.rs | 2 +- .../src/wasi/preview2/preopens.rs | 2 +- .../wasm-bridge-js/src/wasi/preview2/stdio.rs | 6 +++--- 6 files changed, 18 insertions(+), 17 deletions(-) diff --git a/crates/wasm-bridge-js/src/component/linker.rs b/crates/wasm-bridge-js/src/component/linker.rs index d0e3bdb7..7b5bbfff 100644 --- a/crates/wasm-bridge-js/src/component/linker.rs +++ b/crates/wasm-bridge-js/src/component/linker.rs @@ -50,20 +50,22 @@ impl Linker { // JCO makes instance functions use camel case for (instance_name, instance_linker) in self.instances.iter() { let _span = tracing::debug_span!("link instance", instance_name).entered(); + let instance_obj = Object::new(); - for instance_name in once(instance_name).chain(&instance_linker.aliases) { - for function in instance_linker.fns.iter() { - tracing::debug!(function = function.name.as_str(), "link instance func"); + for function in instance_linker.fns.iter() { + tracing::debug!(function = function.name.as_str(), "link instance func"); - let drop_handle = - function.add_to_instance_imports(&instance_obj, data_handle.clone()); + let drop_handle = + function.add_to_instance_imports(&instance_obj, data_handle.clone()); - closures.push(drop_handle); - } + closures.push(drop_handle); } - Reflect::set(&import_object, &instance_name.into(), &instance_obj).unwrap(); + for instance_name in once(instance_name).chain(&instance_linker.aliases) { + tracing::debug!(instance_name, "assign instance"); + Reflect::set(&import_object, &instance_name.into(), &instance_obj).unwrap(); + } } let closures = Rc::from(closures); diff --git a/crates/wasm-bridge-js/src/wasi/preview2/command.rs b/crates/wasm-bridge-js/src/wasi/preview2/command.rs index 7d7ff7bc..5c0a9187 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/command.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/command.rs @@ -56,7 +56,7 @@ pub fn add_to_linker(linker: &mut Linker) -> Result<() Ok(data.ctx_mut().random().next_u64()) })?; - linker.instance("wasi:cli-base/exit")?.func_wrap( + linker.instance("wasi:cli/exit")?.func_wrap( "exit", |_data: StoreContextMut, (_status,): (std::result::Result<(), ()>,)| diff --git a/crates/wasm-bridge-js/src/wasi/preview2/environment.rs b/crates/wasm-bridge-js/src/wasi/preview2/environment.rs index ffdd5684..d0d3f238 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/environment.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/environment.rs @@ -9,7 +9,7 @@ use super::WasiView; /// Adds environment integration to the linker pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { linker - .instance("wasi:cli-base/environment")? + .instance("wasi:cli/environment")? .func_wrap("get-environment", |data: StoreContextMut, (): ()| { Ok(data .ctx() @@ -24,8 +24,7 @@ pub(crate) fn add_to_linker(linker: &mut Linker) -> Re )? .func_wrap("initial-cwd", |_data: StoreContextMut, (): ()| { Ok(String::from(".")) - })? - .alias("cli"); + })?; Ok(()) } diff --git a/crates/wasm-bridge-js/src/wasi/preview2/filesystem.rs b/crates/wasm-bridge-js/src/wasi/preview2/filesystem.rs index 668f19d2..cec39a05 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/filesystem.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/filesystem.rs @@ -10,7 +10,7 @@ pub type InputStream = u32; pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { linker - .instance("wasi:filesystem/filesystem")? + .instance("wasi:filesystem/types")? .func_wrap( "append-via-stream", |_data: StoreContextMut, (_this,): (Descriptor,)| -> Result { diff --git a/crates/wasm-bridge-js/src/wasi/preview2/preopens.rs b/crates/wasm-bridge-js/src/wasi/preview2/preopens.rs index e1532412..95275d3d 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/preopens.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/preopens.rs @@ -3,7 +3,7 @@ use crate::{component::Linker, Result, StoreContextMut}; use super::WasiView; pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { - linker.instance("wasi:cli-base/preopens")?.func_wrap( + linker.instance("wasi:filesystem/preopens")?.func_wrap( "get-directories", |_data: StoreContextMut, (): ()| -> Result> { Ok(vec![]) }, )?; diff --git a/crates/wasm-bridge-js/src/wasi/preview2/stdio.rs b/crates/wasm-bridge-js/src/wasi/preview2/stdio.rs index d8aface7..a7a55663 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/stdio.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/stdio.rs @@ -7,19 +7,19 @@ pub(crate) const STDOUT_IDENT: u32 = 1; pub(crate) const STDERR_IDENT: u32 = 2; pub(crate) fn add_to_linker(linker: &mut Linker) -> Result<()> { linker - .instance("wasi:cli-base/stdout")? + .instance("wasi:cli/stdout")? .func_wrap("get-stdout", |_data: StoreContextMut, (): ()| { Ok(STDOUT_IDENT) })?; linker - .instance("wasi:cli-base/stderr")? + .instance("wasi:cli/stderr")? .func_wrap("get-stderr", |_data: StoreContextMut, (): ()| { Ok(STDERR_IDENT) })?; linker - .instance("wasi:cli-base/stdin")? + .instance("wasi:cli/stdin")? .func_wrap("get-stdin", |_data: StoreContextMut, (): ()| { Ok(STDIN_IDENT) })?; From 59553457621803503afc43cd7630e9a854438dc1 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Tue, 5 Sep 2023 12:30:22 +0200 Subject: [PATCH 24/26] fix: remove no longer needed instance aliasing --- crates/wasm-bridge-js/src/component/linker.rs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/crates/wasm-bridge-js/src/component/linker.rs b/crates/wasm-bridge-js/src/component/linker.rs index 7b5bbfff..27dae771 100644 --- a/crates/wasm-bridge-js/src/component/linker.rs +++ b/crates/wasm-bridge-js/src/component/linker.rs @@ -9,7 +9,6 @@ use crate::{AsContextMut, DataHandle, DropHandle, Engine, Result}; use super::*; pub struct Linker { - aliases: Vec, fns: Vec>, instances: HashMap>, wasi_imports: Option, @@ -21,7 +20,6 @@ impl Linker { fns: vec![], instances: HashMap::new(), wasi_imports: None, - aliases: vec![], } } @@ -62,10 +60,8 @@ impl Linker { closures.push(drop_handle); } - for instance_name in once(instance_name).chain(&instance_linker.aliases) { - tracing::debug!(instance_name, "assign instance"); - Reflect::set(&import_object, &instance_name.into(), &instance_obj).unwrap(); - } + tracing::debug!(instance_name, "assign instance"); + Reflect::set(&import_object, &instance_name.into(), &instance_obj).unwrap(); } let closures = Rc::from(closures); @@ -112,16 +108,6 @@ impl Linker { .entry(name.to_owned()) .or_insert_with(|| Linker::new(&Engine {}))) // TODO: engine re-creation } - - #[cfg(feature = "wasi")] - pub(crate) fn set_wasi_imports(&mut self, imports: Object) { - self.wasi_imports = Some(imports); - } - - pub(crate) fn alias(&mut self, dst: &str) -> &mut Self { - self.aliases.push(dst.into()); - self - } } struct PreparedFn { From 831157ac49d71cb3558f392e4acfd9784783c6f4 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Thu, 7 Sep 2023 09:53:28 +0200 Subject: [PATCH 25/26] chore: update wasmtime --- crates/wasm-bridge/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/wasm-bridge/Cargo.toml b/crates/wasm-bridge/Cargo.toml index a5908d00..a4a35246 100644 --- a/crates/wasm-bridge/Cargo.toml +++ b/crates/wasm-bridge/Cargo.toml @@ -10,8 +10,8 @@ categories.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -wasmtime = { version = "13.0.0", git = "https://github.com/bytecodealliance/wasmtime", default-features = false, features = ["cranelift"] } -wasmtime-wasi = { version = "13.0.0", git = "https://github.com/bytecodealliance/wasmtime", optional = true } +wasmtime = { version = "14.0.0", git = "https://github.com/bytecodealliance/wasmtime", default-features = false, features = ["cranelift"] } +wasmtime-wasi = { version = "14.0.0", git = "https://github.com/bytecodealliance/wasmtime", optional = true } wasm-bridge-macros = { path = "../wasm-bridge-macros", version = "0.2.2", optional = true } async-trait = { version = "0.1.73", optional = true } From 526bb141bbb6999174f51b1236b631d6dc84e866 Mon Sep 17 00:00:00 2001 From: Tei Leelo Roberts Date: Thu, 7 Sep 2023 11:07:21 +0200 Subject: [PATCH 26/26] Squashed commit of the following: commit 2b9a00a38d09f52f9fd0cd21f0a73cb66854e69a Author: Tei Leelo Roberts Date: Fri Sep 1 10:12:19 2023 +0200 feat: expose sync feature commit 60a9adfbc93ccf31f742758d9d221e7c51fa084b Author: Tei Leelo Roberts Date: Fri Sep 1 10:04:43 2023 +0200 wip: sync streams commit 7563ec0c364522c8b89b45888dffb3705867fff7 Author: Tei Leelo Roberts Date: Thu Aug 31 18:14:02 2023 +0200 fix: update streams to newest wit commit c85d53e385928a7de867f6dd25d8b1321f99dac7 Author: Tei Leelo Roberts Date: Thu Aug 31 17:36:53 2023 +0200 feat: implement filesystem stream support commit b1d8fc858af70fe1ca0f099d1675ce344dcfee7b Author: Tei Leelo Roberts Date: Thu Aug 31 17:12:22 2023 +0200 feat: stdio commit f5e3311690a28fb05866cd8daf7416d981669426 Author: Tei Leelo Roberts Date: Thu Aug 31 15:19:02 2023 +0200 feat: wasi:cli-base/environment commit 49f35d8807efb53397704e664885352a9dfec65c Author: Tei Leelo Roberts Date: Thu Aug 31 11:58:03 2023 +0200 fix: negative head not supported on MacOS commit d6f52bcec0a5e0559ede96707437473572056244 Author: Tei Leelo Roberts Date: Thu Aug 31 10:59:08 2023 +0200 fix: module hierarchy mismatch wasm-bridge-js and wasmtime commit e8d1875d0ca95867f2baea5fbd00a95ee5ecb943 Author: Tei Leelo Roberts Date: Wed Aug 30 17:44:18 2023 +0200 chore: move guest examples into dedicated directory commit 0ea2a25da8b767e96719607f2c3b3d3d6f7ce6de Author: Tei Leelo Roberts Date: Wed Aug 30 17:33:50 2023 +0200 feat: flatten io redirect test commit 451cf325c98e631c262fbeae4dbffd85150e1cc5 Author: Tei Leelo Roberts Date: Wed Aug 30 16:22:38 2023 +0200 wip: flattened test structure --- crates/wasm-bridge-js/src/component/component_loader.rs | 3 +-- crates/wasm-bridge-js/src/wasi/preview2/streams.rs | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/wasm-bridge-js/src/component/component_loader.rs b/crates/wasm-bridge-js/src/component/component_loader.rs index cc76f7c3..d6601514 100644 --- a/crates/wasm-bridge-js/src/component/component_loader.rs +++ b/crates/wasm-bridge-js/src/component/component_loader.rs @@ -31,8 +31,7 @@ impl ComponentLoader { if name.ends_with(".wasm") { wasm_cores.push((name, bytes)); } else if name.ends_with(".js") { - let s = String::from_utf8_lossy(&bytes); - tracing::debug!(s = %&*s, "js loader"); + tracing::debug!(s = %&*String::from_utf8_lossy(&bytes), "js loader"); // panic!("{}", String::from_utf8_lossy(&bytes)); // TODO: test that instantiate is not already Some? instantiate = Some(load_instantiate_fn(&bytes)?); diff --git a/crates/wasm-bridge-js/src/wasi/preview2/streams.rs b/crates/wasm-bridge-js/src/wasi/preview2/streams.rs index d805d5a6..30bc603e 100644 --- a/crates/wasm-bridge-js/src/wasi/preview2/streams.rs +++ b/crates/wasm-bridge-js/src/wasi/preview2/streams.rs @@ -24,7 +24,6 @@ pub(crate) fn add_to_linker(linker: &mut Linker) -> Re let mut bytes = vec![0u8; max_bytes as usize]; let (count, status) = data.ctx_mut().stdin().read(&mut bytes)?; - // tracing::debug!(?count, "bytes read"); bytes.truncate(count as _); @@ -55,7 +54,6 @@ pub(crate) fn add_to_linker(linker: &mut Linker) -> Re |data: StoreContextMut, (id, buffer): (u32, Vec)| -> Result> { - tracing::debug!(?id, "write"); let (bytes_written, status) = match id { STDOUT_IDENT => data.ctx_mut().stdout().write(&buffer)?,