I am trying to wrap my head around using WASI with the component model and have some questions. Lets say I have a component written in Rust like:
package wasm-version-tests:component;
interface clients {
resource wasm-version-tests-client {
constructor();
hello-world: func() -> string;
}
}
world wasm-version-tests {
export clients;
}
wit_bindgen::generate!({
world: "wasm-version-tests",
exports: {
"wasm-version-tests:component/clients/wasm-version-tests-client": WasmVersionTestsClients,
},
use exports::wasm_version_tests::component::clients::GuestWasmVersionTestsClient;
pub struct WasmVersionTestsClients;
impl GuestWasmVersionTestsClient for WasmVersionTestsClients {
fn fetch_url(&self, url: String) -> String {
//Pretend fetch is doing an http call
let data = fetch(url);
return "Hello World".to_string();
}
fn new() -> Self {
WasmVersionTestsClients
}
}
This component performs an http
call. If I compile this to wasm32-wasi
and use jco transpile
on the resulting binary, will the wasi:http
shim automatically be included? Or do I need to specify an import wasi:http
statement in my .wit
file and use the imported wasi:http
functions to handle all http
traffic? I know in the wasm-bindgen
era several crates (http ones specifically) had special compilation flags for wasm32
targets that let them work directly with the bindings, but as far as I can tell that doesn't seem to be a thing yet for wit
and the component model.
@Landon James in order to depend on HTTP in WASI, you do indeed need to directly specify you depend on it.
What we did in the surf
crate (one of the HTTP crates from the wasm-bindgen
era) was to just assume that if you compiled with the bindgen flag on, that the js-sys
/web-sys
APIs would be present. This really wasn't great.
Actually, let me walk back my earlier statement a little bit perhaps
if you want to use wasi:http
in Rust, you do need to import it directly. jco
knows how to provide that interface, so you'll generally be fine if you do that.
A different way of doing this could be to just use the Rust stdlib's TCP abstraction, and bring your own HTTP stack. Doing this natively for WASI Preview 2 is likely going to be some work because afaik there are no async Rust runtimes which directly support it yet (the stdlib doesn't either). But it is possible to support it by targeting WASI Preview 1 and using the compat shim to allow it to work on Preview 2.
wrt jco
: targeting Node.js should give you access to TCP sockets (though I think we might still be missing the TCP bind syscall in the implementation) - while targeting the browser will only give you access to the high-level HTTP interfaces (but the browser impl has been temporarily de-prioritized in favor of getting Node.js over the finish line first)
Does that... make sense?
Yes I think that (mostly) makes sense, thank you! My one clarifying question would be around:
if you want to use wasi:http in Rust, you do need to import it directly. jco knows how to provide that interface, so you'll generally be fine if you do that.
I am assuming that this means importing the wasmtime-wasi-http
crate and using the functions from there to make my http
calls? But I would not need to import the wasi:http
wit definitions from https://github.com/WebAssembly/wasi-http unless I wanted to include those types in my component's public API?
Non-jco related sidenote: importing wasmtime-wasi-http
to my project and building for wasm32-wasi
causes several build failures via the wasmtime-fiber
crate:
error: fibers are not supported on this platform
--> /Users/lnj/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wasmtime-fiber-16.0.0/src/lib.rs:17:9
|
17 | compile_error!("fibers are not supported on this platform");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0433]: failed to resolve: use of undeclared crate or module `imp`
--> /Users/lnj/.cargo/registry/src/index.crates.io-6f17d22bba15001f/wasmtime-fiber-16.0.0/src/lib.rs:27:17
|
27 | Ok(Self(imp::FiberStack::new(size)?))
| ^^^ use of undeclared crate or module `imp`
wasmtime-wasi-http depends on wasmtime, so it will only build for the platforms wasmtime builds for
it is a host implementation of wasi-http
if you are trying to use wasi-http interfaces from webassembly, you should use wit-bindgen in your crate
with the wasi-http wits
Got this all figured out and documented in this repo. Thanks for all the help!
Funnily enough, I happen to be doing something similar and ended up with a codebase very similar to yours -- one thing I wanted to ask is how you built those generated typescript bindings? I used only incoming-handler
so I just wrote the minimal required type declarations by hand.
I did a tiny bit of searching around jco
and componentize-js
underneath to see if there was something for that (generating type declarations) but didn't find anything.
Thankfully thats one of the easier steps, you can look through the build
script in that repo's package.json
for the full steps, but the gist of it is:
wasm-tools component new
on that binary to get the component metadata in therejco
via your package manager and run something along the lines of :npx jco transpile ./path/to/your/componentized/binary -o ./path/to/output --no-namespaced-exports
And it will output the typescript definitions. In my repo that is everything in this directory. Note that the --no-namespaced-exports
flag is required because jco
by default generates some code that is just barely not typescript compatible.
Thanks for the tips and spelling it out in detail, I'll see if I can work that into my flow!
@Landon James if I already have a 12_05 component, I should just be able to use this directly, yes? In other words, I should just be able to jco transpile and directly use it.
Oh hey @Landon James if you're interested in the code that I ended up with, it's up here after a bunch of polishing:
https://github.com/wasmCloud/wasmCloud/pull/1300/files
hopefully it's pretty easy to follow -- I ended up copying type definitions from jco
explicitly, the ones in there are pretty complete so I didn't have to work too hard -- just some typescript type declaration wrangling
Ralph said:
Landon James if I already have a 12_05 component, I should just be able to use this directly, yes? In other words, I should just be able to jco transpile and directly use it.
Yep that is my understanding! jco
makes it pretty easy to transpile the js bindings from any wasm (component) binary.
Last updated: Dec 23 2024 at 12:05 UTC