Skip to main content

greentic_component_runtime/
loader.rs

1use std::collections::HashMap;
2use std::sync::{Arc, Mutex};
3
4use component_manifest::{ComponentInfo, ManifestValidator};
5use greentic_interfaces_host::component::v0_4::exports::greentic::component::node::GuestIndices;
6use jsonschema::{Validator, validator_for};
7use serde_json::Value;
8use wasmtime::component::{Component as WasmComponent, InstancePre};
9use wasmtime::{Config, Engine};
10
11use crate::error::CompError;
12use crate::host_imports::{HostState, build_linker};
13use crate::policy::LoadPolicy;
14
15#[derive(Debug, Clone)]
16pub struct ComponentRef {
17    pub name: String,
18    pub locator: String,
19}
20
21pub struct Loader;
22
23impl Default for Loader {
24    fn default() -> Self {
25        Self
26    }
27}
28
29impl Loader {
30    pub fn load(
31        &self,
32        cref: &ComponentRef,
33        policy: &LoadPolicy,
34    ) -> Result<ComponentHandle, CompError> {
35        let artifact = policy
36            .store
37            .fetch_from_str(&cref.locator, &policy.verification)?;
38
39        let engine = create_engine()?;
40        let component = WasmComponent::from_binary(&engine, &artifact.bytes)?;
41
42        let linker = build_linker(&engine, &policy.host)?;
43        let instance_pre = linker.instantiate_pre(&component)?;
44        let guest_indices = GuestIndices::new(&instance_pre)?;
45        let host_state = HostState::empty(policy.host.clone());
46        let mut store = wasmtime::Store::new(&engine, host_state);
47
48        let instance = instance_pre.instantiate(&mut store)?;
49        let guest = guest_indices.load(&mut store, &instance)?;
50        let manifest_json = guest.call_get_manifest(&mut store)?;
51        let manifest_value: Value = serde_json::from_str(&manifest_json)?;
52        let validator = ManifestValidator::new();
53        let info = validator.validate_value(manifest_value.clone())?;
54
55        let config_schema_value = manifest_value
56            .get("config_schema")
57            .ok_or(CompError::InvalidManifest("config_schema"))?;
58        let config_schema = validator_for(config_schema_value)
59            .map_err(|err| CompError::SchemaValidation(err.to_string()))?;
60
61        Ok(ComponentHandle {
62            inner: Arc::new(ComponentInner {
63                cref: cref.clone(),
64                info,
65                config_schema: Arc::new(config_schema),
66                engine,
67                instance_pre,
68                guest_indices,
69                host_policy: policy.host.clone(),
70                bindings: Mutex::new(HashMap::new()),
71            }),
72        })
73    }
74
75    pub fn describe(&self, handle: &ComponentHandle) -> Result<ComponentInfo, CompError> {
76        Ok(handle.inner.info.clone())
77    }
78}
79
80fn create_engine() -> Result<Engine, CompError> {
81    let mut config = Config::new();
82    config.wasm_component_model(true);
83    config.wasm_backtrace_details(wasmtime::WasmBacktraceDetails::Enable);
84    Engine::new(&config).map_err(|err| CompError::Runtime(err.to_string()))
85}
86
87pub struct ComponentHandle {
88    pub(crate) inner: Arc<ComponentInner>,
89}
90
91pub(crate) struct ComponentInner {
92    pub(crate) cref: ComponentRef,
93    pub(crate) info: ComponentInfo,
94    pub(crate) config_schema: Arc<Validator>,
95    pub(crate) engine: Engine,
96    pub(crate) instance_pre: InstancePre<HostState>,
97    pub(crate) guest_indices: GuestIndices,
98    pub(crate) host_policy: crate::policy::HostPolicy,
99    pub(crate) bindings: Mutex<HashMap<String, TenantBinding>>,
100}
101
102#[derive(Debug, Clone)]
103pub(crate) struct TenantBinding {
104    pub config: Value,
105    pub secrets: HashMap<String, Vec<u8>>,
106}
107
108impl ComponentHandle {
109    pub fn info(&self) -> &ComponentInfo {
110        &self.inner.info
111    }
112
113    pub fn cref(&self) -> &ComponentRef {
114        &self.inner.cref
115    }
116}
117
118impl Clone for ComponentHandle {
119    fn clone(&self) -> Self {
120        Self {
121            inner: Arc::clone(&self.inner),
122        }
123    }
124}