diff --git a/crates/churn-agent/src/main.rs b/crates/churn-agent/src/main.rs index 97e09f6..c7b89f7 100644 --- a/crates/churn-agent/src/main.rs +++ b/crates/churn-agent/src/main.rs @@ -14,7 +14,7 @@ use axum::{ use churn_domain::AgentEnrollReq; use clap::{Parser, Subcommand}; use serde_json::json; -use wasmtime::{Caller, Engine, Linker, Module, Store}; +use wasmtime::{Caller, Engine, Extern, Func, Linker, Module, Store}; #[derive(Parser)] #[command(author, version, about, long_about = None, subcommand_required = true)] @@ -102,20 +102,42 @@ async fn handle_command(cmd: Command) -> anyhow::Result<()> { let engine = Engine::default(); let module = Module::from_file(&engine, exe)?; - // Create a `Linker` which will be later used to instantiate this module. - // Host functionality is defined by name within the `Linker`. let mut linker = Linker::new(&engine); - linker.func_wrap("print", "print", |caller: Caller<'_, u32>, param: i32| { - println!("Got {} from WebAssembly", param); - println!("my host state is: {}", caller.data()); - })?; + linker.func_wrap( + "$root", + "print", + |mut caller: Caller<'_, ()>, ptr: i32, len: i32| { + // Use our `caller` context to learn about the memory export of the + // module which called this host function. + let mem = match caller.get_export("memory") { + Some(Extern::Memory(mem)) => mem, + _ => panic!("failed to find host memory"), + }; + + // Use the `ptr` and `len` values to get a subslice of the wasm-memory + // which we'll attempt to interpret as utf-8. + let data = mem + .data(&caller) + .get(ptr as u32 as usize..) + .and_then(|arr| arr.get(..len as u32 as usize)); + let string = match data { + Some(data) => match std::str::from_utf8(data) { + Ok(s) => s, + Err(_) => panic!("invalid utf-8"), + }, + None => panic!("pointer/length out of bounds"), + }; + + println!("Got {} from WebAssembly", string); + }, + )?; // All wasm objects operate within the context of a "store". Each // `Store` has a type parameter to store host-specific data, which in // this case we're using `4` for. - let mut store = Store::new(&engine, 4); + let mut store = Store::new(&engine, ()); let instance = linker.instantiate(&mut store, &module)?; - let hello = instance.get_typed_func::<(), ()>(&mut store, "hello")?; + let hello = instance.get_typed_func::<(), ()>(&mut store, "run")?; // And finally we can call the wasm! hello.call(&mut store, ())?;