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