wasm_sandbox/runtime/
component.rs1use std::sync::Arc;
13use std::path::Path;
14use uuid::Uuid;
15
16use wasmtime::component::{Component, Instance, Linker};
17use wasmtime::{Engine, Store};
18
19use crate::error::{Error, Result};
20use crate::runtime::{WasmModule, WasmInstance, WasmRuntime, WasmFunctionCaller, WasmInstanceState, ModuleId, RuntimeConfig, RuntimeMetrics};
21use crate::security::{Capabilities, ResourceLimits};
22
23pub struct ComponentModule {
25 id: ModuleId,
27
28 component: Component,
30
31 name: Option<String>,
33
34 metadata: serde_json::Value,
36}
37
38impl ComponentModule {
39 pub fn new(engine: &Engine, bytes: &[u8]) -> Result<Self> {
41 let component = Component::new(engine, bytes)
42 .map_err(|e| Error::ModuleLoad { message: e.to_string() })?;
43
44 Ok(Self {
45 id: ModuleId::new(),
46 component,
47 name: None,
48 metadata: serde_json::Value::Null,
49 })
50 }
51
52 pub fn component(&self) -> &Component {
54 &self.component
55 }
56
57 pub fn with_name(mut self, name: impl Into<String>) -> Self {
59 self.name = Some(name.into());
60 self
61 }
62
63 pub fn with_metadata(mut self, metadata: serde_json::Value) -> Self {
65 self.metadata = metadata;
66 self
67 }
68}
69
70impl WasmModule for ComponentModule {
71 fn id(&self) -> ModuleId {
72 self.id
73 }
74
75 fn name(&self) -> Option<&str> {
76 self.name.as_deref()
77 }
78
79 fn size(&self) -> usize {
80 0
82 }
83
84 fn exports(&self) -> Vec<String> {
85 Vec::new()
88 }
89
90 fn clone_module(&self) -> Box<dyn WasmModule> {
91 Box::new(ComponentModule {
92 id: self.id,
93 component: self.component.clone(),
94 name: self.name.clone(),
95 metadata: self.metadata.clone(),
96 })
97 }
98
99 fn as_any(&self) -> &dyn std::any::Any {
100 self
101 }
102}
103
104pub struct ComponentInstance<T: 'static> {
106 #[allow(dead_code)]
108 id: Uuid,
109
110 #[allow(dead_code)]
112 module_id: Uuid,
113
114 instance: Instance,
116
117 store: Store<T>,
119
120 #[allow(dead_code)]
122 capabilities: Capabilities,
123
124 #[allow(dead_code)]
126 resource_limits: ResourceLimits,
127}
128
129impl<T: Send + 'static> ComponentInstance<T> {
130 pub fn new(
132 module: &ComponentModule,
133 mut store: Store<T>,
134 linker: &Linker<T>,
135 capabilities: Capabilities,
136 resource_limits: ResourceLimits
137 ) -> Result<Self> {
138 let instance = linker.instantiate(&mut store, &module.component)
139 .map_err(|e| Error::InstanceCreation { reason: e.to_string(), instance_id: None })?;
140
141 Ok(Self {
142 id: Uuid::new_v4(),
143 module_id: module.id.as_uuid(),
144 instance,
145 store,
146 capabilities,
147 resource_limits,
148 })
149 }
150
151 pub fn store(&self) -> &Store<T> {
153 &self.store
154 }
155
156 pub fn store_mut(&mut self) -> &mut Store<T> {
158 &mut self.store
159 }
160
161 pub fn instance(&self) -> &Instance {
163 &self.instance
164 }
165}
166
167impl<T: Send + Sync + 'static> WasmInstance for ComponentInstance<T> {
168 fn state(&self) -> WasmInstanceState {
169 WasmInstanceState::Running }
171
172 fn memory_usage(&self) -> usize {
173 0
175 }
176
177 fn fuel_usage(&self) -> Option<u64> {
178 None
180 }
181
182 fn reset_fuel(&self) -> Result<()> {
183 Ok(())
185 }
186
187 fn add_fuel(&self, _fuel: u64) -> Result<()> {
188 Ok(())
190 }
191
192 unsafe fn memory_ptr(&self) -> Result<*mut u8> {
193 Err(Error::UnsupportedOperation { message: "Direct memory access not supported for components".to_string() })
195 }
196
197 fn memory_size(&self) -> usize {
198 0
200 }
201
202 fn function_caller(&self) -> Box<dyn WasmFunctionCaller> {
203 Box::new(ComponentFunctionCaller {})
204 }
205
206 fn call_simple_function(&self, _function_name: &str, _params: &[i32]) -> Result<i32> {
207 Err(Error::UnsupportedOperation { message: "Simple function calls not supported for components".to_string() })
209 }
210}
211
212pub struct ComponentFunctionCaller {}
214
215impl WasmFunctionCaller for ComponentFunctionCaller {
216 fn call_function_json(
217 &self,
218 _function_name: &str,
219 _params_json: &str,
220 ) -> Result<String> {
221 Err(Error::UnsupportedOperation { message: "Component function calling not yet implemented".to_string() })
222 }
223
224 fn call_function_msgpack(
225 &self,
226 _function_name: &str,
227 _params_msgpack: &[u8],
228 ) -> Result<Vec<u8>> {
229 Err(Error::UnsupportedOperation { message: "Component function calling not yet implemented".to_string() })
230 }
231
232 fn as_any(&self) -> &dyn std::any::Any {
233 self
234 }
235}
236
237pub struct ComponentRuntime {
239 engine: Engine,
241
242 #[allow(dead_code)]
244 default_capabilities: Capabilities,
245
246 #[allow(dead_code)]
248 default_resource_limits: ResourceLimits,
249}
250
251impl ComponentRuntime {
252 pub fn new(
254 default_capabilities: Capabilities,
255 default_resource_limits: ResourceLimits,
256 ) -> Result<Self> {
257 let mut config = wasmtime::Config::new();
258
259 config.wasm_component_model(true);
261
262 if default_resource_limits.memory.max_memory_pages > 0 {
264 config.max_wasm_stack(default_resource_limits.memory.max_memory_pages as usize * 65536);
265 }
266
267 let engine = Engine::new(&config)
268 .map_err(|e| Error::RuntimeInitialization { message: e.to_string() })?;
269
270 Ok(Self {
271 engine,
272 default_capabilities,
273 default_resource_limits,
274 })
275 }
276
277 pub fn create_component_module(&self, bytes: &[u8]) -> Result<ComponentModule> {
279 ComponentModule::new(&self.engine, bytes)
280 }
281
282 pub fn create_component_module_from_file(&self, path: impl AsRef<Path>) -> Result<ComponentModule> {
284 let bytes = std::fs::read(path)
285 .map_err(|e| Error::IoError { message: e.to_string() })?;
286 self.create_component_module(&bytes)
287 }
288
289 pub fn create_store<T>(&self, data: T) -> Store<T> {
291 Store::new(&self.engine, data)
292 }
293
294 pub fn create_linker<T>(&self) -> Linker<T> {
296 Linker::new(&self.engine)
297 }
298}
299
300impl WasmRuntime for ComponentRuntime {
301 fn initialize(&mut self, _config: RuntimeConfig) -> Result<()> {
302 Ok(())
304 }
305
306 fn load_module(&self, bytes: &[u8]) -> Result<Box<dyn WasmModule>> {
307 let module = self.create_component_module(bytes)?;
308 Ok(Box::new(module))
309 }
310
311 fn get_module(&self, _id: ModuleId) -> Result<Arc<dyn WasmModule>> {
312 Err(Error::UnsupportedOperation { message: "Module retrieval not implemented for components yet".to_string() })
314 }
315
316 fn get_module_ids(&self) -> Vec<ModuleId> {
317 Vec::new()
319 }
320
321 fn create_instance(
322 &self,
323 _module: &dyn WasmModule,
324 _resources: ResourceLimits,
325 _capabilities: Capabilities,
326 ) -> Result<Box<dyn WasmInstance>> {
327 Err(Error::UnsupportedOperation { message: "Instance creation interface not implemented for components yet".to_string() })
328 }
329
330 fn get_metrics(&self) -> RuntimeMetrics {
331 RuntimeMetrics {
332 compiled_modules: 0,
333 active_instances: 0,
334 total_memory_usage: 0,
335 peak_memory_usage: 0,
336 fuel_consumption_rate: None,
337 cache_hit_rate: None,
338 last_compilation_time_ms: None,
339 }
340 }
341
342 fn shutdown(&self) -> Result<()> {
343 Ok(())
345 }
346}