use anyhow::Result; use serde::{Deserialize, Serialize}; use wasmtime::{Config, Engine, Instance, Linker, Module, Store}; wit_bindgen_wasmtime::export!("../container.wit"); #[derive(Clone, Debug, Serialize, Deserialize)] struct FetchResult { error: Option, result: Option, } #[derive(Clone, Debug, Serialize, Deserialize)] struct JsResult { message: String, } #[derive(Default)] pub struct MyContainer; impl container::Container for MyContainer { fn fetch(&mut self, s: &str) -> String { println!("fetch arguments: {}", s); let url: String = s.chars().skip(1).take(s.len() - 2).collect(); println!("fetch arguments URL: {}", url); let r = match reqwest::blocking::get(&url) { Err(e) => return serde_json::to_string(&FetchResult { error: Some(serde_json::to_string(&JsResult { message: format!("failed: {}", e) }).expect("to json failed.4")), result: None, }).expect("to json failed.3"), Ok(r) => r, }; serde_json::to_string(&FetchResult { error: None, result: Some(serde_json::to_string(&JsResult { message: format!("fetched: {:?}", r.text()), }).expect("to json failed.1")), }).expect("to json failed.2") } } wit_bindgen_wasmtime::import!("../exports.wit"); fn main() -> Result<()> { use exports::*; let wasm = "../engine/target/wasm32-unknown-unknown/debug/engine.wasm"; let (exports, mut store) = instantiate( wasm, |linker| container::add_to_linker(linker, |cx| -> &mut MyContainer { &mut cx.imports }), |store, module, linker| Exports::instantiate(store, module, linker, |cx| &mut cx.exports), )?; let a = exports.eval_javascript(&mut store, r##" function hi(name) { return "hi: " + name; } let a = []; a.push(fetch('https://hatter.ink/ip.action')); for (let i = 0; i < 3; i++) { a.push(i); } a.push({ id: 1, name: 'hatter' }); a.push(hi('001')); a.push(hi('002')); // JSON.stringify(a) a "##); match a { Ok(a) => println!("Hello, world! {:?}", a), Err(e) => println!("ERROR: {}", e), } Ok(()) } struct Context { imports: I, exports: E, } fn instantiate( wasm: &str, add_imports: impl FnOnce(&mut Linker>) -> Result<()>, mk_exports: impl FnOnce( &mut Store>, &Module, &mut Linker>, ) -> Result<(T, Instance)>, ) -> Result<(T, Store>)> { let engine = Engine::new(&default_config()?)?; let module = Module::from_file(&engine, wasm)?; let mut linker = Linker::new(&engine); add_imports(&mut linker)?; let mut store = Store::new( &engine, Context { imports: I::default(), exports: E::default(), }, ); let (exports, _instance) = mk_exports(&mut store, &module, &mut linker)?; Ok((exports, store)) } fn default_config() -> Result { // Create an engine with caching enabled to assist with iteration in this project. let mut config = Config::new(); config.cache_config_load_default()?; config.wasm_backtrace_details(wasmtime::WasmBacktraceDetails::Enable); Ok(config) }