extern crate core; use std::time::SystemTime; use anyhow::Result; use serde_json::Value; use wasmtime::{Config, Engine, Instance, Linker, Module, Store}; use crate::fn_common::FnResult; mod fn_common; mod fn_fetch; wit_bindgen_wasmtime::export!("../container.wit"); #[derive(Default)] pub struct MyContainer { fetch_invoked_count: u32, } impl container::Container for MyContainer { fn fetch(&mut self, params: &str) -> String { let t1 = SystemTime::now(); if self.fetch_invoked_count > 10 { return FnResult::fail("Fetch invoke count cannot more than 10").to_json(); } self.fetch_invoked_count += 1; let result = fn_fetch::do_fetch(params).to_json(); let t2 = SystemTime::now(); let e = t2.duration_since(t1).expect("get duration error"); println!("+ fetch: {}, time cost: {}ms", params, e.as_millis()); result } fn log(&mut self, level: &str, message: &str) { println!("[{}] {}", level, message); } } wit_bindgen_wasmtime::import!("../exports.wit"); fn main() -> Result<()> { let main_t1 = SystemTime::now(); 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 eval_t1 = SystemTime::now(); let a = exports.eval_javascript(&mut store, r##" function hi(name) { return "hi: " + name; } console.log('hello', 1, true); let a = []; // a.push(console); console.log('query: ' + 'print_request.action'); a.push(fetch('https://hatter.ink/util/print_request.action', { headers: { 'Test-Header': 'this is a test header', } })); // a.push(fetch('https://hatter.ink/ip.action')); console.log('query: ' + 'ip.jsonp'); a.push(fetch('https://hatter.ink/ip/ip.jsonp')); // a.push(fetch('https://hatter.ink/ip2.action')); a.push({ userId: 'id001', name: 'Test', }); JSON.stringify(a) // a "##); let eval_e = SystemTime::now().duration_since(eval_t1).expect("get duration error"); println!("+ eval cost: {}ms", eval_e.as_millis()); let a = match a { Ok(a) => a, Err(a) => { let e = format!("{}", a); if e.contains("all fuel consumed by WebAssembly") { println!("all fuel consumed by WebAssembly"); } else { println!("{}", a); } return Ok(()); } }; // let a = a.expect("error"); let a: Value = match serde_json::from_str(&a) { Ok(a) => a, Err(e) => panic!("ERROR: {}", e), }; let a = match a { Value::String(a) => a, _ => panic!("error: {}", a), }; let v: Value = match serde_json::from_str(&a) { Ok(v) => v, Err(e) => panic!("Parse json1 failed: {}, raw json:\n - {}", e, a), }; let p = serde_json::to_string_pretty(&v).expect("error"); // println!("------- {}", v); println!("{}", p); let main_e = SystemTime::now().duration_since(main_t1).expect("get duration error"); println!("+ total cost (-eval): {}ms", main_e.as_millis() - eval_e.as_millis()); println!("+ total cost: {}ms", main_e.as_millis()); 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(), }, ); store.add_fuel(1_000_000_000_u64).ok(); // FUEL 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.consume_fuel(true); // FUEL // config.debug_info(true); config.wasm_backtrace_details(wasmtime::WasmBacktraceDetails::Enable); Ok(config) }