olai_stack_runtime/
source.rs1use std::collections::BTreeMap;
4use std::fmt;
5use std::time::SystemTime;
6
7use async_trait::async_trait;
8use olai_stack_state::{InstanceId, VarSet};
9
10use crate::secrets::SecretValue;
11
12#[derive(Clone, Default)]
14pub struct Overlay {
15 pub vars: BTreeMap<String, String>,
17 pub endpoints: BTreeMap<String, String>,
19 pub credentials: BTreeMap<String, SecretValue>,
22 pub expires_at: Option<SystemTime>,
24}
25
26impl fmt::Debug for Overlay {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 f.debug_struct("Overlay")
29 .field("vars", &self.vars)
30 .field("endpoints", &self.endpoints)
31 .field("credentials", &self.credentials.keys().collect::<Vec<_>>())
32 .field("expires_at", &self.expires_at)
33 .finish()
34 }
35}
36
37impl Overlay {
38 pub fn is_expired(&self, now: SystemTime) -> bool {
40 self.expires_at.is_some_and(|t| t <= now)
41 }
42}
43
44#[derive(Clone, Debug)]
46pub struct SourceCtx {
47 pub instance: InstanceId,
49 pub workspace: String,
51 pub environment: String,
53 pub revision: u32,
55 pub config: serde_json::Value,
58}
59
60#[derive(Debug, thiserror::Error)]
62#[error("source `{source_name}`: {reason}")]
63pub struct SourceError {
64 pub source_name: String,
66 pub reason: String,
68}
69
70#[async_trait]
75pub trait Source: Send + Sync {
76 fn name(&self) -> &str;
78
79 async fn overlay(&self, ctx: &SourceCtx) -> Result<Overlay, SourceError>;
81
82 async fn refresh(&self, ctx: &SourceCtx, current: &Overlay) -> Result<Overlay, SourceError> {
84 let _ = current;
85 self.overlay(ctx).await
86 }
87}
88
89#[derive(Clone, Debug, Default)]
92pub struct UserVars {
93 vars: BTreeMap<String, String>,
94}
95
96impl UserVars {
97 pub fn new(vars: BTreeMap<String, String>) -> Self {
99 UserVars { vars }
100 }
101
102 pub fn from_var_set(set: &VarSet) -> Self {
104 UserVars::new(
105 set.0
106 .iter()
107 .filter_map(|(k, v)| match v {
108 olai_stack_state::VarValue::Literal(l) => Some((k.clone(), l.clone())),
109 olai_stack_state::VarValue::Secret(_) => None,
110 })
111 .collect(),
112 )
113 }
114}
115
116#[async_trait]
117impl Source for UserVars {
118 fn name(&self) -> &str {
119 "user"
120 }
121
122 async fn overlay(&self, _ctx: &SourceCtx) -> Result<Overlay, SourceError> {
123 Ok(Overlay {
124 vars: self.vars.clone(),
125 ..Overlay::default()
126 })
127 }
128}