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