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