cardinal_wasm_plugins/
runner.rs1use crate::instance::WasmInstance;
2use crate::plugin::WasmPlugin;
3use crate::{ExecutionContext, SharedExecutionContext};
4use bytes::Bytes;
5use cardinal_errors::internal::CardinalInternalError;
6use cardinal_errors::CardinalError;
7use std::collections::HashMap;
8use std::sync::Arc;
9use wasmer::TypedFunction;
10use wasmer::{Function, FunctionEnv, Store};
11
12#[derive(Debug)]
13pub struct ExecutionResult {
14 pub should_continue: bool,
15 pub execution_context: ExecutionContext,
16}
17
18pub type HostFunctionBuilder =
19 Arc<dyn Fn(&mut Store, &FunctionEnv<SharedExecutionContext>) -> Function + Send + Sync>;
20pub type HostFunctionMap = HashMap<String, Vec<(String, HostFunctionBuilder)>>;
21
22pub struct WasmRunner<'a> {
23 pub plugin: &'a WasmPlugin,
24 host_imports: Option<&'a HostFunctionMap>,
25}
26
27impl<'a> WasmRunner<'a> {
28 pub fn new(plugin: &'a WasmPlugin, host_imports: Option<&'a HostFunctionMap>) -> Self {
29 Self {
30 plugin,
31 host_imports,
32 }
33 }
34
35 pub fn run(
36 &self,
37 shared_ctx: SharedExecutionContext,
38 ) -> Result<ExecutionResult, CardinalError> {
39 let mut instance =
41 WasmInstance::from_plugin(self.plugin, self.host_imports, shared_ctx.clone())?;
42
43 let handle: TypedFunction<(i32, i32), i32> = instance
53 .instance
54 .exports
55 .get_typed_function(&instance.store, "handle")
56 .map_err(|e| {
57 CardinalError::InternalError(CardinalInternalError::InvalidWasmModule(format!(
58 "missing `handle` export {e}"
59 )))
60 })?;
61
62 let alloc: TypedFunction<(i32, i32), i32> = instance
63 .instance
64 .exports
65 .get_typed_function(&instance.store, "__new")
66 .map_err(|e| {
67 CardinalError::InternalError(CardinalInternalError::InvalidWasmModule(format!(
68 "missing `alloc` export {e}"
69 )))
70 })?;
71
72 let body_opt: Option<Bytes> = {
73 let ctx_ref = instance.env.as_ref(&instance.store);
74 ctx_ref.read().body().clone()
75 };
76
77 let (ptr, len) = if let Some(body) = body_opt.filter(|b| !b.is_empty()) {
78 let len = body.len() as i32;
79
80 let p = alloc.call(&mut instance.store, len, 0).map_err(|e| {
81 CardinalError::InternalError(CardinalInternalError::InvalidWasmModule(format!(
82 "Alloc failed {e}"
83 )))
84 })?;
85
86 {
87 let view = instance.memory.view(&instance.store);
88 view.write(p as u64, &body).map_err(|e| {
89 CardinalError::InternalError(CardinalInternalError::InvalidWasmModule(format!(
90 "Writing Body failed {e}"
91 )))
92 })?;
93 }
94
95 (p, len)
96 } else {
97 (0, 0)
98 };
99
100 let decision = handle.call(&mut instance.store, ptr, len).map_err(|e| {
101 CardinalError::InternalError(CardinalInternalError::InvalidWasmModule(format!(
102 "WASM Handle call failed {e}"
103 )))
104 })?;
105
106 let exec_ctx_clone = shared_ctx.read().clone();
107
108 Ok(ExecutionResult {
109 should_continue: decision == 1,
110 execution_context: exec_ctx_clone,
111 })
112 }
113}