Skip to main content

spin_factor_variables/
lib.rs

1mod host;
2pub mod runtime_config;
3
4use std::sync::Arc;
5
6use runtime_config::RuntimeConfig;
7use spin_expressions::{ProviderResolver as ExpressionResolver, Template};
8use spin_factor_otel::OtelFactorState;
9use spin_factors::{
10    anyhow, ConfigureAppContext, Factor, FactorData, InitContext, PrepareContext, RuntimeFactors,
11    SelfInstanceBuilder,
12};
13
14/// A factor for providing variables to components.
15#[derive(Default)]
16pub struct VariablesFactor {
17    _priv: (),
18}
19
20impl VariablesFactor {
21    /// Creates a new `VariablesFactor`.
22    pub fn new() -> Self {
23        Default::default()
24    }
25}
26
27impl Factor for VariablesFactor {
28    type RuntimeConfig = RuntimeConfig;
29    type AppState = AppState;
30    type InstanceBuilder = InstanceState;
31
32    fn init(&mut self, ctx: &mut impl InitContext<Self>) -> anyhow::Result<()> {
33        ctx.link_bindings(spin_world::v1::config::add_to_linker::<_, FactorData<Self>>)?;
34        ctx.link_bindings(spin_world::v2::variables::add_to_linker::<_, FactorData<Self>>)?;
35        ctx.link_bindings(spin_world::wasi::config::store::add_to_linker::<_, FactorData<Self>>)?;
36        Ok(())
37    }
38
39    fn configure_app<T: RuntimeFactors>(
40        &self,
41        mut ctx: ConfigureAppContext<T, Self>,
42    ) -> anyhow::Result<Self::AppState> {
43        let app = ctx.app();
44        let mut expression_resolver =
45            ExpressionResolver::new(app.variables().map(|(key, val)| (key.clone(), val.clone())))?;
46
47        for component in app.components() {
48            expression_resolver.add_component_variables(
49                component.id(),
50                component.config().map(|(k, v)| (k.into(), v.into())),
51            )?;
52        }
53
54        let providers = ctx.take_runtime_config().unwrap_or_default();
55        for provider in providers {
56            expression_resolver.add_provider(provider);
57        }
58
59        Ok(AppState {
60            expression_resolver: Arc::new(expression_resolver),
61        })
62    }
63
64    fn prepare<T: RuntimeFactors>(
65        &self,
66        mut ctx: PrepareContext<T, Self>,
67    ) -> anyhow::Result<InstanceState> {
68        let component_id = ctx.app_component().id().to_string();
69        let expression_resolver = ctx.app_state().expression_resolver.clone();
70        let otel = OtelFactorState::from_prepare_context(&mut ctx)?;
71        Ok(InstanceState {
72            component_id,
73            expression_resolver,
74            otel,
75        })
76    }
77}
78
79pub struct AppState {
80    expression_resolver: Arc<ExpressionResolver>,
81}
82
83impl AppState {
84    pub async fn resolve_expression(
85        &self,
86        expr: impl Into<Box<str>>,
87    ) -> spin_expressions::Result<String> {
88        let template = Template::new(expr)?;
89        self.expression_resolver.resolve_template(&template).await
90    }
91
92    pub fn expression_resolver(&self) -> &Arc<ExpressionResolver> {
93        &self.expression_resolver
94    }
95}
96
97pub struct InstanceState {
98    component_id: String,
99    expression_resolver: Arc<ExpressionResolver>,
100    otel: OtelFactorState,
101}
102
103impl InstanceState {
104    pub fn expression_resolver(&self) -> &Arc<ExpressionResolver> {
105        &self.expression_resolver
106    }
107}
108
109impl SelfInstanceBuilder for InstanceState {}