Environment variables can now be used directly inside the config instead of requiring special handling
This commit is contained in:
parent
82859d8e46
commit
d06c0b6980
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -2,6 +2,15 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "0.7.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.68"
|
version = "1.0.68"
|
||||||
|
@ -37,6 +46,7 @@ dependencies = [
|
||||||
"impl_cast",
|
"impl_cast",
|
||||||
"paste",
|
"paste",
|
||||||
"pollster",
|
"pollster",
|
||||||
|
"regex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rumqttc",
|
"rumqttc",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -784,6 +794,8 @@ version = "1.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
|
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
"regex-syntax",
|
"regex-syntax",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ tracing = "0.1.37"
|
||||||
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
|
||||||
bytes = "1.3.0"
|
bytes = "1.3.0"
|
||||||
pollster = "0.2.5"
|
pollster = "0.2.5"
|
||||||
|
regex = "1.7.0"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto=true
|
lto=true
|
||||||
|
|
|
@ -5,6 +5,10 @@ base_url = "https://login.huizinga.dev/api/oidc"
|
||||||
host="olympus.lan.huizinga.dev"
|
host="olympus.lan.huizinga.dev"
|
||||||
port=8883
|
port=8883
|
||||||
username="mqtt"
|
username="mqtt"
|
||||||
|
password="${MQTT_PASSWORD}"
|
||||||
|
|
||||||
|
[ntfy]
|
||||||
|
topic = "${NTFY_TOPIC}"
|
||||||
|
|
||||||
[presence]
|
[presence]
|
||||||
topic = "automation_dev/presence"
|
topic = "automation_dev/presence"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use std::{fs, error::Error, collections::HashMap, net::{Ipv4Addr, SocketAddr}};
|
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 rumqttc::AsyncClient;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
@ -14,7 +15,6 @@ pub struct Config {
|
||||||
pub mqtt: MqttConfig,
|
pub mqtt: MqttConfig,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub fullfillment: FullfillmentConfig,
|
pub fullfillment: FullfillmentConfig,
|
||||||
#[serde(default)]
|
|
||||||
pub ntfy: NtfyConfig,
|
pub ntfy: NtfyConfig,
|
||||||
pub presence: MqttDeviceConfig,
|
pub presence: MqttDeviceConfig,
|
||||||
pub light_sensor: LightSensorConfig,
|
pub light_sensor: LightSensorConfig,
|
||||||
|
@ -33,7 +33,7 @@ pub struct MqttConfig {
|
||||||
pub host: String,
|
pub host: String,
|
||||||
pub port: u16,
|
pub port: u16,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
pub password: Option<String>,
|
pub password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
@ -68,19 +68,13 @@ fn default_fullfillment_port() -> u16 {
|
||||||
pub struct NtfyConfig {
|
pub struct NtfyConfig {
|
||||||
#[serde(default = "default_ntfy_url")]
|
#[serde(default = "default_ntfy_url")]
|
||||||
pub url: String,
|
pub url: String,
|
||||||
pub topic: Option<String>,
|
pub topic: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_ntfy_url() -> String {
|
fn default_ntfy_url() -> String {
|
||||||
"https://ntfy.sh".into()
|
"https://ntfy.sh".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for NtfyConfig {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self { url: default_ntfy_url(), topic: None }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct LightSensorConfig {
|
pub struct LightSensorConfig {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
|
@ -161,11 +155,23 @@ impl Config {
|
||||||
pub fn build(filename: &str) -> Result<Self, Box<dyn Error>> {
|
pub fn build(filename: &str) -> Result<Self, Box<dyn Error>> {
|
||||||
debug!("Loading config: {filename}");
|
debug!("Loading config: {filename}");
|
||||||
let file = fs::read_to_string(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]"))?);
|
// Substitute in environment variables
|
||||||
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]!"))?);
|
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)
|
Ok(config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#![feature(async_closure)]
|
#![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};
|
use axum::{Router, Json, routing::post, http::StatusCode, extract::FromRef};
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ async fn main() {
|
||||||
|
|
||||||
// Configure MQTT
|
// Configure MQTT
|
||||||
let mut mqttoptions = MqttOptions::new("rust-test", config.mqtt.host, config.mqtt.port);
|
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_keep_alive(Duration::from_secs(5));
|
||||||
mqttoptions.set_transport(Transport::tls_with_default_config());
|
mqttoptions.set_transport(Transport::tls_with_default_config());
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ impl Notification {
|
||||||
|
|
||||||
impl Ntfy {
|
impl Ntfy {
|
||||||
pub fn new(config: NtfyConfig) -> Self {
|
pub fn new(config: NtfyConfig) -> Self {
|
||||||
Self { base_url: config.url, topic: config.topic.unwrap() }
|
Self { base_url: config.url, topic: config.topic }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user