use std::env;
use std::path::{Path, PathBuf};
use anyhow::{Context, Result};
use omnia_otel::Telemetry;
use tracing::instrument;
use wasmtime::component::{Component, InstancePre, Linker};
use wasmtime::{Config, Engine};
use wasmtime_wasi::WasiView;
use crate::traits::Host;
#[instrument]
pub fn create<T: WasiView + 'static>(wasm: &PathBuf) -> Result<Compiled<T>> {
init_env(wasm)?;
tracing::info!("initializing runtime");
let mut config = Config::new();
config.wasm_component_model_async(true);
let engine = Engine::new(&config)?;
let component = unsafe { Component::deserialize_file(&engine, wasm) }.or_else(|e| {
if cfg!(feature = "jit") {
Component::from_file(&engine, wasm)
} else {
Err(wasmtime::Error::msg(format!(
"Issue loading component: {e}. Enable `jit` feature to load wasm32 files."
)))
}
})?;
let mut linker = Linker::new(&engine);
wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;
wasmtime_wasi::p3::add_to_linker(&mut linker)?;
tracing::info!("runtime initialized");
Ok(Compiled { component, linker })
}
pub struct Compiled<T: WasiView + 'static> {
component: Component,
linker: Linker<T>,
}
impl<T: WasiView> Compiled<T> {
pub fn link<H: Host<T>>(&mut self, _: H) -> Result<()> {
H::add_to_linker(&mut self.linker)
}
pub fn pre_instantiate(&mut self) -> Result<InstancePre<T>> {
self.linker.instantiate_pre(&self.component).map_err(anyhow::Error::from)
}
}
fn init_env(wasm: &Path) -> Result<()> {
let name = wasm.file_stem().and_then(|s| s.to_str()).unwrap_or("unknown");
if env::var("COMPONENT").is_err() {
unsafe {
env::set_var("COMPONENT", name);
};
}
let mut builder = Telemetry::new(name);
if let Ok(endpoint) = env::var("OTEL_GRPC_URL") {
builder = builder.endpoint(endpoint);
}
builder.build().context("initializing telemetry")
}