use std::sync::Arc;
use tokio::time::Duration;
use wasmtime::Error;
use wasmtime::{Config, Engine, Linker, Module, Store};
use wasmtime_wasi::{WasiCtx, p1::WasiP1Ctx};
#[tokio::main]
async fn main() -> Result<(), Error> {
let env = Environment::new()?;
let inputs1 = Inputs::new(env.clone(), "Gussie");
let inputs2 = Inputs::new(env.clone(), "Willa");
let inputs3 = Inputs::new(env, "Sparky");
let join1 = tokio::task::spawn(async move { run_wasm(inputs1).await });
let join2 = tokio::task::spawn(async move {
tokio::time::sleep(Duration::from_millis(750)).await;
run_wasm(inputs2).await
});
let join3 = tokio::task::spawn(async move {
tokio::time::sleep(Duration::from_millis(1250)).await;
run_wasm(inputs3).await
});
join1.await??;
join2.await??;
join3.await??;
Ok(())
}
#[derive(Clone)]
struct Environment {
engine: Engine,
module: Module,
linker: Arc<Linker<WasiP1Ctx>>,
}
impl Environment {
pub fn new() -> Result<Self, Error> {
let mut config = Config::new();
config.consume_fuel(true);
let engine = Engine::new(&config)?;
let module = Module::from_file(&engine, "target/wasm32-wasip1/debug/tokio-wasi.wasm")?;
let mut linker = Linker::new(&engine);
wasmtime_wasi::p1::add_to_linker_async(&mut linker, |cx| cx)?;
Ok(Self {
engine,
module,
linker: Arc::new(linker),
})
}
}
struct Inputs {
env: Environment,
name: String,
}
impl Inputs {
fn new(env: Environment, name: &str) -> Self {
Self {
env,
name: name.to_owned(),
}
}
}
async fn run_wasm(inputs: Inputs) -> Result<(), Error> {
let wasi = WasiCtx::builder()
.inherit_stdout()
.env("NAME", &inputs.name)
.build_p1();
let mut store = Store::new(&inputs.env.engine, wasi);
store.set_fuel(u64::MAX)?;
store.fuel_async_yield_interval(Some(10000))?;
let instance = inputs
.env
.linker
.instantiate_async(&mut store, &inputs.env.module)
.await?;
instance
.get_typed_func::<(), ()>(&mut store, "_start")?
.call_async(&mut store, ())
.await?;
Ok(())
}