Skip to main content

jsdet_core/
persistent.rs

1use std::sync::Arc;
2
3use crate::{Bridge, CompiledModule, ExecutionResult, Observation, Result, SandboxConfig};
4
5/// Reusable sandbox wrapper that keeps a loaded script set and re-executes it
6/// with appended probe code.
7///
8/// This preserves the public API expected by Soleno and jsdet consumers while
9/// keeping the execution model explicit and deterministic.
10pub struct PersistentSandbox {
11    module: Arc<CompiledModule>,
12    bridge: Arc<dyn Bridge>,
13    config: SandboxConfig,
14    loaded_scripts: Vec<String>,
15}
16
17impl PersistentSandbox {
18    /// Create a new reusable sandbox.
19    pub fn new(
20        module: &CompiledModule,
21        bridge: Arc<dyn Bridge>,
22        config: &SandboxConfig,
23    ) -> Result<Self> {
24        let serialized = module.serialize()?;
25        let module = CompiledModule::load_cached(&serialized)?;
26        Ok(Self {
27            module: Arc::new(module),
28            bridge,
29            config: config.clone(),
30            loaded_scripts: Vec::new(),
31        })
32    }
33
34    /// Load the baseline scripts that should run before every probe.
35    pub fn load(&mut self, scripts: &[String]) -> Result<()> {
36        self.loaded_scripts = scripts.to_vec();
37        let _ = self.execute(&[])?;
38        Ok(())
39    }
40
41    /// Execute probe code against the currently loaded script set.
42    #[must_use]
43    pub fn eval_only(&mut self, script: &str) -> Vec<Observation> {
44        self.execute(&[script.to_string()])
45            .map(|result| result.observations)
46            .unwrap_or_default()
47    }
48
49    /// Return the currently configured store fuel.
50    pub fn store_fuel(&self) -> Result<u64> {
51        Ok(self.config.max_fuel)
52    }
53
54    /// Update the configured store fuel for future executions.
55    pub fn set_store_fuel(&mut self, fuel: u64) {
56        self.config.max_fuel = fuel;
57    }
58
59    fn execute(&self, extra_scripts: &[String]) -> Result<ExecutionResult> {
60        let mut scripts = self.loaded_scripts.clone();
61        scripts.extend(extra_scripts.iter().cloned());
62        self.module
63            .execute(&scripts, Arc::clone(&self.bridge), &self.config)
64    }
65}