Environment variables can now be used directly inside the config instead of requiring special handling

This commit is contained in:
2023-01-06 04:06:36 +01:00
parent 82859d8e46
commit d06c0b6980
6 changed files with 39 additions and 16 deletions

View File

@@ -1,6 +1,7 @@
use std::{fs, error::Error, collections::HashMap, net::{Ipv4Addr, SocketAddr}};
use tracing::{debug, trace};
use regex::{Regex, Captures};
use tracing::{debug, trace, warn};
use rumqttc::AsyncClient;
use serde::Deserialize;
@@ -14,7 +15,6 @@ pub struct Config {
pub mqtt: MqttConfig,
#[serde(default)]
pub fullfillment: FullfillmentConfig,
#[serde(default)]
pub ntfy: NtfyConfig,
pub presence: MqttDeviceConfig,
pub light_sensor: LightSensorConfig,
@@ -33,7 +33,7 @@ pub struct MqttConfig {
pub host: String,
pub port: u16,
pub username: String,
pub password: Option<String>,
pub password: String,
}
#[derive(Debug, Deserialize)]
@@ -68,19 +68,13 @@ fn default_fullfillment_port() -> u16 {
pub struct NtfyConfig {
#[serde(default = "default_ntfy_url")]
pub url: String,
pub topic: Option<String>,
pub topic: String,
}
fn default_ntfy_url() -> String {
"https://ntfy.sh".into()
}
impl Default for NtfyConfig {
fn default() -> Self {
Self { url: default_ntfy_url(), topic: None }
}
}
#[derive(Debug, Deserialize)]
pub struct LightSensorConfig {
#[serde(flatten)]
@@ -161,11 +155,23 @@ impl Config {
pub fn build(filename: &str) -> Result<Self, Box<dyn Error>> {
debug!("Loading config: {filename}");
let file = fs::read_to_string(filename)?;
let mut config: Self = toml::from_str(&file)?;
config.mqtt.password = Some(std::env::var("MQTT_PASSWORD").or(config.mqtt.password.ok_or("MQTT password needs to be set in either config [mqtt.password] or the environment [MQTT_PASSWORD]"))?);
config.ntfy.topic = Some(std::env::var("NTFY_TOPIC").or(config.ntfy.topic.ok_or("ntfy.sh topic needs to be set in either config [ntfy.url] or the environment [NTFY_TOPIC]!"))?);
// Substitute in environment variables
let re = Regex::new(r"\$\{(.*)\}").unwrap();
let file = re.replace_all(&file, |caps: &Captures| {
let key = caps.get(1).unwrap().as_str();
debug!("Substituting '{key}' in config");
match std::env::var(key) {
Ok(value) => value,
Err(_) => {
// @TODO Would be nice if we could propagate this error upwards
warn!("Environment variable '{key}' is not set, using empty string as default");
"".to_string()
}
}
});
let config = toml::from_str(&file)?;
Ok(config)
}
}

View File

@@ -1,5 +1,5 @@
#![feature(async_closure)]
use std::{time::Duration, sync::{Arc, RwLock}, process, net::SocketAddr};
use std::{time::Duration, sync::{Arc, RwLock}, process};
use axum::{Router, Json, routing::post, http::StatusCode, extract::FromRef};
@@ -45,7 +45,7 @@ async fn main() {
// Configure MQTT
let mut mqttoptions = MqttOptions::new("rust-test", config.mqtt.host, config.mqtt.port);
mqttoptions.set_credentials(config.mqtt.username, config.mqtt.password.unwrap());
mqttoptions.set_credentials(config.mqtt.username, config.mqtt.password);
mqttoptions.set_keep_alive(Duration::from_secs(5));
mqttoptions.set_transport(Transport::tls_with_default_config());

View File

@@ -89,7 +89,7 @@ impl Notification {
impl Ntfy {
pub fn new(config: NtfyConfig) -> Self {
Self { base_url: config.url, topic: config.topic.unwrap() }
Self { base_url: config.url, topic: config.topic }
}
}