1use std::path::{Path, PathBuf};
2
3use anyhow::{Context, Result};
4use serde::Deserialize;
5
6#[derive(Deserialize, Debug, Clone)]
9pub struct AgentConfig {
10 pub agent: AgentSection,
11 pub log: LogSection,
12}
13
14#[derive(Deserialize, Debug, Clone)]
15pub struct AgentSection {
16 pub id: String,
17 pub nats_url: String,
18 #[serde(default)]
25 pub groups: Vec<String>,
26}
27
28#[derive(Deserialize, Debug, Clone)]
29pub struct LogSection {
30 pub path: String,
31 pub level: String,
32 #[serde(default = "default_keep_days")]
37 pub keep_days: usize,
38}
39
40fn default_keep_days() -> usize {
41 14
42}
43
44#[derive(Deserialize, Debug, Clone)]
47pub struct BackendConfig {
48 pub server: ServerSection,
49 pub nats: NatsSection,
50 pub db: DbSection,
51 pub log: LogSection,
52}
53
54#[derive(Deserialize, Debug, Clone)]
55pub struct ServerSection {
56 pub bind: String,
57}
58
59#[derive(Deserialize, Debug, Clone)]
60pub struct NatsSection {
61 pub url: String,
62}
63
64#[derive(Deserialize, Debug, Clone)]
65pub struct DbSection {
66 pub sqlite_path: String,
67}
68
69fn load_typed<T: serde::de::DeserializeOwned>(path: &Path) -> Result<T> {
72 let mut engine = teravars::Engine::new();
73 let ctx = teravars::system_context();
74 let paths: Vec<PathBuf> = vec![path.to_path_buf()];
75 let merged = teravars::load_merged(&paths, &mut engine, &ctx)
76 .with_context(|| format!("teravars load_merged: {path:?}"))?;
77 let cfg: T = toml::Value::Table(merged.config)
78 .try_into()
79 .with_context(|| format!("decode config from {path:?}"))?;
80 Ok(cfg)
81}
82
83pub fn load_agent_config(path: &Path) -> Result<AgentConfig> {
84 load_typed(path)
85}
86
87pub fn load_backend_config(path: &Path) -> Result<BackendConfig> {
88 load_typed(path)
89}