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