use std::{any::Any, collections::HashMap, sync::Arc};
use wasmtime::component::ResourceTable;
use wasmtime_wasi::{IoView, WasiCtx, WasiCtxBuilder, WasiView};
use wasmtime_wasi_http::{WasiHttpCtx, WasiHttpView};
use crate::plugin::HostPlugin;
pub struct Ctx {
pub id: String,
pub component_id: Arc<str>,
pub workload_id: Arc<str>,
pub table: wasmtime::component::ResourceTable,
pub ctx: WasiCtx,
pub http: WasiHttpCtx,
plugins: HashMap<&'static str, Arc<dyn Any + Send + Sync>>,
}
impl Ctx {
pub fn get_plugin<T: HostPlugin + 'static>(&self, plugin_id: &str) -> Option<Arc<T>> {
self.plugins.get(plugin_id)?.clone().downcast().ok()
}
pub fn builder(
workload_id: impl Into<Arc<str>>,
component_id: impl Into<Arc<str>>,
) -> CtxBuilder {
CtxBuilder::new(workload_id, component_id)
}
}
impl std::fmt::Debug for Ctx {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Ctx")
.field("id", &self.id)
.field("workload_id", &self.workload_id.as_ref())
.field("table", &self.table)
.finish()
}
}
impl IoView for Ctx {
fn table(&mut self) -> &mut ResourceTable {
&mut self.table
}
}
impl WasiView for Ctx {
fn ctx(&mut self) -> &mut WasiCtx {
&mut self.ctx
}
}
impl WasiHttpView for Ctx {
fn ctx(&mut self) -> &mut WasiHttpCtx {
&mut self.http
}
}
pub struct CtxBuilder {
id: String,
workload_id: Arc<str>,
component_id: Arc<str>,
ctx: Option<WasiCtx>,
plugins: HashMap<&'static str, Arc<dyn HostPlugin + Send + Sync>>,
}
impl CtxBuilder {
pub fn new(workload_id: impl Into<Arc<str>>, component_id: impl Into<Arc<str>>) -> Self {
Self {
id: uuid::Uuid::new_v4().to_string(),
component_id: component_id.into(),
workload_id: workload_id.into(),
ctx: None,
plugins: HashMap::new(),
}
}
pub fn with_wasi_ctx(mut self, ctx: WasiCtx) -> Self {
self.ctx = Some(ctx);
self
}
pub fn with_plugins(
mut self,
plugins: HashMap<&'static str, Arc<dyn HostPlugin + Send + Sync>>,
) -> Self {
self.plugins.extend(plugins);
self
}
pub fn build(self) -> Ctx {
let plugins = self
.plugins
.into_iter()
.map(|(k, v)| (k, v as Arc<dyn Any + Send + Sync>))
.collect();
Ctx {
id: self.id,
ctx: self.ctx.unwrap_or_else(|| {
WasiCtxBuilder::new()
.args(&["main.wasm"])
.inherit_stderr()
.build()
}),
workload_id: self.workload_id,
component_id: self.component_id,
http: WasiHttpCtx::new(),
table: ResourceTable::new(),
plugins,
}
}
}