greentic_component_runtime/
loader.rs1use 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}