witmproxy 0.0.1-alpha

A WASM-in-the-middle proxy
use crate::wasm::{Host, WitmProxyCtxView, bindgen::Plugin};
use anyhow::Result;
use wasmtime::{
    Config, Engine, Store,
    component::{Component, Linker},
};
use wasmtime_wasi::p3::bindings::LinkOptions;

pub struct Runtime {
    pub engine: Engine,
    pub config: Config,
    pub linker: Linker<Host>,
}

impl Runtime {
    pub fn try_default() -> Result<Self> {
        let mut config = Config::new();
        config.wasm_component_model(true);
        config.wasm_component_model_async(true);
        config.async_support(true);

        let engine = Engine::new(&config)?;

        let mut linker: Linker<Host> = Linker::new(&engine);

        // TODO: fix this
        // Add WASI CLI support (needed by the component)
        wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;

        // Add WASI HTTP support
        let options = LinkOptions::default();
        wasmtime_wasi::p3::add_to_linker_with_options(&mut linker, &options)?;

        // Add WASI HTTP support
        wasmtime_wasi_http::p3::add_to_linker(&mut linker)?;

        // Add our custom host capabilities using the wrapper pattern
        crate::wasm::add_to_linker(&mut linker, |host: &mut Host| {
            WitmProxyCtxView::new(&host.witmproxy_ctx, &mut host.table)
        })?;

        Ok(Self {
            engine,
            config,
            linker,
        })
    }

    pub fn new_store(&self) -> Store<Host> {
        Store::new(&self.engine, Host::default())
    }

    pub async fn instantiate_plugin_component(
        &self,
        component: &Component,
    ) -> Result<(Plugin, Store<Host>)> {
        let mut store = self.new_store();
        let instance = self.linker.instantiate_async(&mut store, component).await?;
        let plugin = Plugin::new(&mut store, &instance)?;
        Ok((plugin, store))
    }
}