feat(daemon): add configuration via config crate with TOML + env vars

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Christian Mueller 2026-03-19 22:51:52 +01:00
parent 48d93321a3
commit 6d7409b156
3 changed files with 118 additions and 3 deletions

View File

@ -0,0 +1,69 @@
// backend/daemon/src/config.rs
use config::{Config, Environment, File};
use serde::Deserialize;
#[derive(Debug, Deserialize, Clone)]
pub struct AppConfig {
pub http: HttpConfig,
pub influx: InfluxConfig,
pub database: DatabaseConfig,
pub alarm: AlarmConfig,
}
#[derive(Debug, Deserialize, Clone)]
pub struct HttpConfig {
#[serde(default = "default_bind")]
pub bind: String,
#[serde(default = "default_port")]
pub port: u16,
}
#[derive(Debug, Deserialize, Clone)]
pub struct InfluxConfig {
#[serde(default = "default_influx_url")]
pub url: String,
#[serde(default)]
pub token: String,
#[serde(default = "default_org")]
pub org: String,
#[serde(default = "default_bucket")]
pub bucket: String,
}
#[derive(Debug, Deserialize, Clone)]
pub struct DatabaseConfig {
#[serde(default = "default_db_path")]
pub path: String,
}
#[derive(Debug, Deserialize, Clone)]
pub struct AlarmConfig {
#[serde(default = "default_warning")]
pub warning_threshold_hours: f64,
#[serde(default = "default_alarm")]
pub alarm_threshold_hours: f64,
#[serde(default = "default_interval")]
pub check_interval_secs: u64,
}
fn default_bind() -> String { "0.0.0.0".into() }
fn default_port() -> u16 { 8080 }
fn default_influx_url() -> String { "http://localhost:8086".into() }
fn default_org() -> String { "loraweb".into() }
fn default_bucket() -> String { "sensors".into() }
fn default_db_path() -> String { "loraweb.db".into() }
fn default_warning() -> f64 { 2.0 }
fn default_alarm() -> f64 { 6.0 }
fn default_interval() -> u64 { 60 }
impl AppConfig {
pub fn load() -> Result<Self, config::ConfigError> {
let config_path = std::env::var("CONFIG_PATH")
.unwrap_or_else(|_| "daemon-config".into());
let cfg = Config::builder()
.add_source(File::with_name(&config_path).required(false))
.add_source(Environment::with_prefix("LORAWEB").separator("__"))
.build()?;
cfg.try_deserialize()
}
}

View File

@ -1,7 +1,35 @@
mod config;
mod db;
use crate::config::AppConfig;
use sqlx::sqlite::SqlitePoolOptions;
#[tokio::main] #[tokio::main]
async fn main() { async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt() tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) .with_env_filter(
tracing_subscriber::EnvFilter::from_default_env()
.add_directive("loraweb_daemon=info".parse()?)
)
.init(); .init();
tracing::info!("loraweb-daemon starting...");
let cfg = AppConfig::load()?;
tracing::info!("Configuration loaded");
let pool = SqlitePoolOptions::new()
.max_connections(5)
.connect(&format!("sqlite:{}?mode=rwc", cfg.database.path))
.await?;
db::init_db(&pool).await?;
tracing::info!(
"LoRaWAN Daemon ready — Ingest: http://{}:{}/",
cfg.http.bind, cfg.http.port
);
tracing::info!(
"Configure ChirpStack HTTP Integration: POST http://<this-server>:{}/",
cfg.http.port
);
Ok(())
} }

View File

@ -0,0 +1,18 @@
# deploy/daemon-config.toml
[http]
bind = "0.0.0.0"
port = 8080
[influx]
url = "http://localhost:8086"
token = ""
org = "loraweb"
bucket = "sensors"
[database]
path = "loraweb.db"
[alarm]
warning_threshold_hours = 2.0
alarm_threshold_hours = 6.0
check_interval_secs = 60