pub mod error;
pub use error::{Error, Result};
pub mod runtime;
pub mod security;
pub mod communication;
pub mod wrappers;
pub mod compiler;
pub mod templates;
pub mod utils;
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use runtime::{create_runtime, ModuleId, RuntimeConfig, WasmInstance, WasmRuntime};
use security::{Capabilities, ResourceLimits};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct InstanceId(Uuid);
impl InstanceId {
pub fn new() -> Self {
Self(Uuid::new_v4())
}
}
impl std::fmt::Display for InstanceId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Default for InstanceId {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct InstanceConfig {
pub resource_limits: ResourceLimits,
pub capabilities: Capabilities,
pub startup_timeout_ms: u64,
pub enable_debug: bool,
}
impl Default for InstanceConfig {
fn default() -> Self {
Self {
resource_limits: ResourceLimits::default(),
capabilities: Capabilities::minimal(),
startup_timeout_ms: 5000,
enable_debug: false,
}
}
}
#[derive(Debug, Clone)]
pub struct SandboxConfig {
pub runtime: RuntimeConfig,
pub default_instance_config: InstanceConfig,
}
impl Default for SandboxConfig {
fn default() -> Self {
Self {
runtime: RuntimeConfig::default(),
default_instance_config: InstanceConfig::default(),
}
}
}
pub struct SandboxInstance {
pub id: InstanceId,
pub instance: Box<dyn WasmInstance>,
pub config: InstanceConfig,
}
pub struct WasmSandbox {
runtime: Box<dyn WasmRuntime>,
config: SandboxConfig,
instances: HashMap<InstanceId, SandboxInstance>,
}
impl WasmSandbox {
pub fn new() -> Result<Self> {
Self::with_config(SandboxConfig::default())
}
pub fn with_config(config: SandboxConfig) -> Result<Self> {
Ok(Self {
runtime: create_runtime(&config.runtime)?,
config,
instances: HashMap::new(),
})
}
pub fn load_module(&self, wasm_bytes: &[u8]) -> Result<ModuleId> {
let module = self.runtime.load_module(wasm_bytes)?;
Ok(module.id())
}
pub fn create_instance(
&mut self,
module_id: ModuleId,
instance_config: Option<InstanceConfig>,
) -> Result<InstanceId> {
let config = instance_config.unwrap_or_else(|| self.config.default_instance_config.clone());
let module = self.runtime.get_module(module_id)?;
let instance = self.runtime.create_instance(
module.as_ref(),
config.resource_limits.clone(),
config.capabilities.clone(),
)?;
let instance_id = InstanceId::new();
self.instances.insert(
instance_id,
SandboxInstance {
id: instance_id,
instance,
config,
},
);
Ok(instance_id)
}
pub async fn call_function<P, R>(
&self,
instance_id: InstanceId,
function_name: &str,
params: P,
) -> Result<R>
where
P: Serialize + 'static,
R: for<'de> Deserialize<'de> + 'static,
{
let instance = self.instances.get(&instance_id).ok_or_else(|| {
Error::InstanceNotFound(format!("Instance not found: {}", instance_id))
})?;
if function_name == "add" {
let params_json = serde_json::to_string(¶ms)?;
if let Ok(tuple_params) = serde_json::from_str::<(i32, i32)>(¶ms_json) {
let result = instance.instance.call_simple_function(function_name, &[tuple_params.0, tuple_params.1])?;
let result_json = serde_json::to_string(&result)?;
return Ok(serde_json::from_str(&result_json)?);
}
}
let caller = instance.instance.function_caller();
let params_json = serde_json::to_string(¶ms)?;
let result_json = caller.call_function_json(function_name, ¶ms_json)?;
let result = serde_json::from_str(&result_json)?;
Ok(result)
}
pub fn runtime(&self) -> &dyn WasmRuntime {
self.runtime.as_ref()
}
pub fn runtime_mut(&mut self) -> &mut dyn WasmRuntime {
self.runtime.as_mut()
}
pub fn get_instance(&self, instance_id: InstanceId) -> Option<&SandboxInstance> {
self.instances.get(&instance_id)
}
pub fn get_instance_mut(&mut self, instance_id: InstanceId) -> Option<&mut SandboxInstance> {
self.instances.get_mut(&instance_id)
}
pub fn remove_instance(&mut self, instance_id: InstanceId) -> Option<SandboxInstance> {
self.instances.remove(&instance_id)
}
pub fn instance_ids(&self) -> Vec<InstanceId> {
self.instances.keys().copied().collect()
}
}
pub use communication::{CommunicationChannel, RpcChannel};
pub use runtime::{RuntimeMetrics, WasmInstanceState};
pub use security::{
CpuLimits, EnvironmentCapability, FilesystemCapability,
IoLimits, MemoryLimits, NetworkCapability, ProcessCapability,
RandomCapability, TimeCapability,
};
pub use utils::manifest::SandboxManifest;