Stream: wasmtime

Topic: Implementing custom HTTP Outgoing Handler?


view this post on Zulip Claire Smith (Mar 06 2025 at 03:00):

I'd like to work on a demo where I can run this wstd http client example using a custom implementation of the WASI http interface.

I'd like to have a runtime that provides implementations using both quiche and arti.

image.png

This is what I have for the client program, I am wondering where to start on this?

I saw a wasmtime http example similar to this but also allowing http access, I can't seem to find it again?

//! Example of instantiating a wasm module which uses WASI imports.

/*
You can execute this example with:
    cmake examples/
    cargo run --example wasip2
*/

use wasmtime::component::{Component, Linker, ResourceTable};
use wasmtime::*;
use wasmtime_wasi::bindings::sync::Command;
use wasmtime_wasi::{IoView, WasiCtx, WasiCtxBuilder, WasiView};

pub struct ComponentRunStates {
    // These two are required basically as a standard way to enable the impl of IoView and
    // WasiView.
    // impl of WasiView is required by [`wasmtime_wasi::add_to_linker_sync`]
    pub wasi_ctx: WasiCtx,
    pub resource_table: ResourceTable,
    // You can add other custom host states if needed
}

impl IoView for ComponentRunStates {
    fn table(&mut self) -> &mut ResourceTable {
        &mut self.resource_table
    }
}
impl WasiView for ComponentRunStates {
    fn ctx(&mut self) -> &mut WasiCtx {
        &mut self.wasi_ctx
    }
}

fn main() -> Result<()> {
    // Define the WASI functions globally on the `Config`.
    let engine = Engine::default();
    let mut linker = Linker::new(&engine);
    wasmtime_wasi::add_to_linker_sync(&mut linker)?;

    // Create a WASI context and put it in a Store; all instances in the store
    // share this context. `WasiCtxBuilder` provides a number of ways to
    // configure what the target program will have access to.
    let wasi = WasiCtxBuilder::new().inherit_stdio().inherit_args().build();
    let state = ComponentRunStates {
        wasi_ctx: wasi,
        resource_table: ResourceTable::new(),
    };
    let mut store = Store::new(&engine, state);

    // Instantiate our component with the imports we've created, and run it.
    let component = Component::from_file(&engine, "target/wasm32-wasip2/debug/wasi.wasm")?;
    let command = Command::instantiate(&mut store, &component, &linker)?;
    let program_result = command.wasi_cli_run().call_run(&mut store)?;
    if program_result.is_err() {
        std::process::exit(1)
    }

    // Alternatively, instead of using `Command`, just instantiate it as a normal component
    // New states
    let wasi = WasiCtxBuilder::new().inherit_stdio().inherit_args().build();
    let state = ComponentRunStates {
        wasi_ctx: wasi,
        resource_table: ResourceTable::new(),
    };
    let mut store = Store::new(&engine, state);
    // Instantiate it as a normal component
    let instance = linker.instantiate(&mut store, &component)?;
    // Get the index for the exported interface
    let interface_idx = instance
        .get_export(&mut store, None, "wasi:cli/run@0.2.0")
        .expect("Cannot get `wasi:cli/run@0.2.0` interface");
    // Get the index for the exported function in the exported interface
    let parent_export_idx = Some(&interface_idx);
    let func_idx = instance
        .get_export(&mut store, parent_export_idx, "run")
        .expect("Cannot get `run` function in `wasi:cli/run@0.2.0` interface");
    let func = instance
        .get_func(&mut store, func_idx)
        .expect("Unreachable since we've got func_idx");
    // As the `run` function in `wasi:cli/run@0.2.0` takes no argument and return a WASI result that correspond to a `Result<(), ()>`
    // Reference:
    // * https://github.com/WebAssembly/wasi-cli/blob/main/wit/run.wit
    // * Documentation for [Func::typed](https://docs.rs/wasmtime/latest/wasmtime/component/struct.Func.html#method.typed) and [ComponentNamedList](https://docs.rs/wasmtime/latest/wasmtime/component/trait.ComponentNamedList.html)
    let typed = func.typed::<(), (Result<(), ()>,)>(&store)?;
    let (result,) = typed.call(&mut store, ())?;
    // Required, see documentation of TypedFunc::call
    typed.post_return(&mut store)?;
    result.map_err(|_| anyhow::anyhow!("error"))
}
A WebAssembly-native stdlib. Contribute to yoshuawuyts/wstd development by creating an account on GitHub.

view this post on Zulip Claire Smith (Mar 06 2025 at 03:04):

Once I have a runtime that can successfully provide http capabilities then I can wade through the standard implementation and see what I have to do to

view this post on Zulip Alex Crichton (Mar 06 2025 at 05:40):

Do the examples here help with what you're looking to achieve?


Last updated: Apr 07 2025 at 10:03 UTC