Skip to main content

rns_hooks/
program.rs

1use crate::builtin::BuiltinProgram;
2#[cfg(feature = "native")]
3use crate::native::NativeProgram;
4#[cfg(feature = "wasm")]
5use crate::runtime::StoreData;
6#[cfg(feature = "wasm")]
7use wasmtime::{Instance, Module, Store};
8
9pub enum ProgramBackend {
10    Builtin(BuiltinProgram),
11    #[cfg(feature = "wasm")]
12    Wasm(WasmProgram),
13    #[cfg(feature = "native")]
14    Native(NativeProgram),
15}
16
17#[cfg(feature = "wasm")]
18pub struct WasmProgram {
19    pub module: Module,
20    pub export_name: String,
21    /// Cached store and instance for cross-call state persistence.
22    pub cached: Option<(Store<StoreData>, Instance)>,
23}
24
25/// A loaded hook program ready for execution.
26pub struct LoadedProgram {
27    pub name: String,
28    pub priority: i32,
29    pub consecutive_traps: u32,
30    pub enabled: bool,
31    pub max_consecutive_traps: u32,
32    pub backend: ProgramBackend,
33}
34
35impl LoadedProgram {
36    pub fn new_builtin(name: String, builtin: BuiltinProgram, priority: i32) -> Self {
37        LoadedProgram {
38            name,
39            priority,
40            consecutive_traps: 0,
41            enabled: true,
42            max_consecutive_traps: 10,
43            backend: ProgramBackend::Builtin(builtin),
44        }
45    }
46
47    #[cfg(feature = "wasm")]
48    pub fn new(name: String, module: Module, priority: i32) -> Self {
49        LoadedProgram {
50            name,
51            priority,
52            consecutive_traps: 0,
53            enabled: true,
54            max_consecutive_traps: 10,
55            backend: ProgramBackend::Wasm(WasmProgram {
56                module,
57                export_name: "on_hook".to_string(),
58                cached: None,
59            }),
60        }
61    }
62
63    #[cfg(feature = "native")]
64    pub fn new_native(name: String, native: NativeProgram, priority: i32) -> Self {
65        LoadedProgram {
66            name,
67            priority,
68            consecutive_traps: 0,
69            enabled: true,
70            max_consecutive_traps: 10,
71            backend: ProgramBackend::Native(native),
72        }
73    }
74
75    /// Reset the consecutive trap counter after a successful execution.
76    pub fn record_success(&mut self) {
77        self.consecutive_traps = 0;
78    }
79
80    /// Drop the cached store/instance (e.g. on reload).
81    pub fn drop_cache(&mut self) {
82        match &mut self.backend {
83            ProgramBackend::Builtin(_) => {}
84            #[cfg(feature = "wasm")]
85            ProgramBackend::Wasm(wasm) => {
86                wasm.cached = None;
87            }
88            #[cfg(feature = "native")]
89            ProgramBackend::Native(_) => {}
90        }
91    }
92
93    pub fn backend_name(&self) -> &'static str {
94        match &self.backend {
95            ProgramBackend::Builtin(_) => "builtin",
96            #[cfg(feature = "wasm")]
97            ProgramBackend::Wasm(_) => "wasm",
98            #[cfg(feature = "native")]
99            ProgramBackend::Native(_) => "native",
100        }
101    }
102
103    /// Increment the trap counter. Returns `true` if the program was auto-disabled.
104    pub fn record_trap(&mut self) -> bool {
105        self.consecutive_traps += 1;
106        if self.consecutive_traps >= self.max_consecutive_traps {
107            self.enabled = false;
108            true
109        } else {
110            false
111        }
112    }
113}