Skip to main content

capsule_core/wasm/
runtime.rs

1use std::fmt;
2use std::path::PathBuf;
3use std::sync::Arc;
4
5use tokio::sync::{Mutex, RwLock};
6use wasmtime::component::Component;
7use wasmtime::{Config, Engine};
8
9use crate::config::log::{Log, LogError};
10use crate::config::manifest::CapsuleToml;
11use crate::wasm::utilities::task_reporter::TaskReporter;
12
13pub enum WasmRuntimeError {
14    WasmtimeError(wasmtime::Error),
15    LogError(LogError),
16    ConfigError(String),
17    FilesystemError(String),
18    SerializationError(String),
19    Timeout,
20}
21
22impl fmt::Display for WasmRuntimeError {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        match self {
25            WasmRuntimeError::WasmtimeError(msg) => {
26                write!(f, "{}", msg)
27            }
28            WasmRuntimeError::LogError(msg) => write!(f, "{}", msg),
29            WasmRuntimeError::ConfigError(msg) => write!(f, "{}", msg),
30            WasmRuntimeError::FilesystemError(msg) => {
31                write!(f, "{}", msg)
32            }
33            WasmRuntimeError::SerializationError(msg) => {
34                write!(f, "{}", msg)
35            }
36            WasmRuntimeError::Timeout => write!(f, "Timeout"),
37        }
38    }
39}
40
41impl From<wasmtime::Error> for WasmRuntimeError {
42    fn from(err: wasmtime::Error) -> Self {
43        WasmRuntimeError::WasmtimeError(err)
44    }
45}
46
47impl From<LogError> for WasmRuntimeError {
48    fn from(err: LogError) -> Self {
49        WasmRuntimeError::LogError(err)
50    }
51}
52
53pub trait RuntimeCommand {
54    type Output;
55    fn execute(
56        self,
57        runtime: Arc<Runtime>,
58    ) -> impl Future<Output = Result<Self::Output, WasmRuntimeError>> + Send;
59}
60
61pub struct RuntimeConfig {
62    pub cache_dir: PathBuf,
63    pub verbose: bool,
64}
65
66impl Default for RuntimeConfig {
67    fn default() -> Self {
68        Self {
69            cache_dir: PathBuf::from(".capsule"),
70            verbose: false,
71        }
72    }
73}
74
75pub struct Runtime {
76    pub(crate) engine: Engine,
77    pub(crate) log: Log,
78
79    #[allow(dead_code)]
80    pub(crate) cache_dir: PathBuf,
81
82    pub verbose: bool,
83
84    component: RwLock<Option<Component>>,
85    pub task_reporter: Arc<Mutex<TaskReporter>>,
86    pub capsule_toml: CapsuleToml,
87}
88
89impl Runtime {
90    pub fn new(
91        config: RuntimeConfig,
92        capsule_toml: CapsuleToml,
93    ) -> Result<Arc<Self>, WasmRuntimeError> {
94        let mut engine_config = Config::new();
95        let db_path = config.cache_dir.join("trace.db");
96        let log = Log::new(
97            Some(
98                db_path
99                    .parent()
100                    .expect("Cache dir is empty")
101                    .to_str()
102                    .expect("failed to get cache dir"),
103            ),
104            db_path
105                .file_name()
106                .expect("Cache dir is empty")
107                .to_str()
108                .expect("failed to get cache dir"),
109        )?;
110
111        engine_config.wasm_component_model(true);
112        engine_config.async_support(true);
113        engine_config.consume_fuel(true);
114
115        let task_reporter = Arc::new(Mutex::new(TaskReporter::new(config.verbose)));
116
117        Ok(Arc::new(Self {
118            engine: Engine::new(&engine_config)?,
119            log,
120            cache_dir: config.cache_dir,
121            verbose: config.verbose,
122            component: RwLock::new(None),
123            task_reporter,
124            capsule_toml,
125        }))
126    }
127
128    pub async fn execute<C: RuntimeCommand>(
129        self: &Arc<Self>,
130        command: C,
131    ) -> Result<C::Output, WasmRuntimeError> {
132        command.execute(Arc::clone(self)).await
133    }
134
135    pub async fn get_component(&self) -> Option<Component> {
136        self.component.read().await.clone()
137    }
138
139    pub async fn set_component(&self, component: Component) {
140        *self.component.write().await = Some(component);
141    }
142}