diff --git a/Cargo.lock b/Cargo.lock index 5ff6f48..8cb7ee1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -108,6 +108,15 @@ dependencies = [ "syn 2.0.65", ] +[[package]] +name = "atomic" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" +dependencies = [ + "bytemuck", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -307,6 +316,12 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +[[package]] +name = "bytemuck" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" + [[package]] name = "bytes" version = "1.6.0" @@ -608,6 +623,20 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +[[package]] +name = "figment" +version = "0.10.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3" +dependencies = [ + "atomic", + "pear", + "serde", + "toml", + "uncased", + "version_check", +] + [[package]] name = "flume" version = "0.11.0" @@ -990,6 +1019,12 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "inlinable_string" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" + [[package]] name = "ipnet" version = "2.9.0" @@ -1322,6 +1357,29 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +[[package]] +name = "pear" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdeeaa00ce488657faba8ebf44ab9361f9365a97bd39ffb8a60663f57ff4b467" +dependencies = [ + "inlinable_string", + "pear_codegen", + "yansi", +] + +[[package]] +name = "pear_codegen" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bab5b985dc082b345f812b7df84e1bef27e7207b39e448439ba8bd69c93f147" +dependencies = [ + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn 2.0.65", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1436,6 +1494,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.65", + "version_check", + "yansi", +] + [[package]] name = "quote" version = "1.0.36" @@ -1801,15 +1872,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-toml-merge" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e75a6b6c577215161d30ba4e13fb493c435a8b4140c442e590b61b4b2a27a226" -dependencies = [ - "toml", -] - [[package]] name = "serde_derive" version = "1.0.203" @@ -2007,6 +2069,7 @@ dependencies = [ "config", "dotenvy_macro", "env_logger", + "figment", "home", "log", "mockito", @@ -2020,7 +2083,6 @@ dependencies = [ "serde_json", "tokio", "tokio-rustls 0.26.0", - "toml-env", ] [[package]] @@ -2188,18 +2250,6 @@ dependencies = [ "toml_edit", ] -[[package]] -name = "toml-env" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a740df0c7ded7632d527f5e4015c28c19803c9b8d6e87cc7ae72ae4d68d6f4b0" -dependencies = [ - "serde", - "serde-toml-merge", - "thiserror", - "toml", -] - [[package]] name = "toml_datetime" version = "0.6.6" @@ -2288,6 +2338,15 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" +[[package]] +name = "uncased" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.15" @@ -2629,6 +2688,12 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + [[package]] name = "zeroize" version = "1.7.0" diff --git a/Cargo.toml b/Cargo.toml index 21d6dc3..56a252f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,4 +26,4 @@ serde = "1.0.203" serde_json = "1.0.117" tokio = {version = "1.37.0", features = ["full", "rt-multi-thread"]} tokio-rustls = "0.26.0" -toml-env = "1.2.0" \ No newline at end of file +figment = { version = "0.10", features = ["toml", "env"] } \ No newline at end of file diff --git a/README.md b/README.md index d4a0dd0..262bfc1 100644 --- a/README.md +++ b/README.md @@ -183,8 +183,7 @@ export TAGOIO__RELAY__MQTT__BROKER_TLS_CERT="" export TAGOIO__RELAY__MQTT__BROKER_TLS_KEY="" # Subscribe to multiple topics -export TAGOIO__RELAY__MQTT__SUBSCRIBE__1="/tago/#" -export TAGOIO__RELAY__MQTT__SUBSCRIBE__2="/topic/+" +export TAGOIO__RELAY__MQTT__SUBSCRIBE=["/tago/#"] # Change the path to the configuration file export TAGOIO__RELAY__CONFIG_PATH="/root/.config/.tagoio-mqtt-relay.toml" diff --git a/examples/basic-docker-compose/docker-compose.yml b/examples/basic-docker-compose/docker-compose.yml index fdf6251..d6ad82b 100644 --- a/examples/basic-docker-compose/docker-compose.yml +++ b/examples/basic-docker-compose/docker-compose.yml @@ -19,7 +19,7 @@ services: # - TAGOIO__RELAY__MQTT__TLS_ENABLED="false" # - TAGOIO__RELAY__MQTT__ADDRESS="localhost" # - TAGOIO__RELAY__MQTT__PORT="1883" - # - TAGOIO__RELAY__MQTT__SUBSCRIBE__1="/device/#" + # - TAGOIO__RELAY__MQTT__SUBSCRIBE=["/device/#"] # - TAGOIO__RELAY__MQTT__USERNAME="my-username" # - TAGOIO__RELAY__MQTT__PASSWORD="my-password" # - TAGOIO__RELAY__MQTT__BROKER_TLS_CA="" diff --git a/examples/mosquitto-relay-setup/docker-compose.yml b/examples/mosquitto-relay-setup/docker-compose.yml index ba99f1c..8ad64b6 100644 --- a/examples/mosquitto-relay-setup/docker-compose.yml +++ b/examples/mosquitto-relay-setup/docker-compose.yml @@ -19,13 +19,12 @@ services: # Mosquitto Broker Settings for the Relay to connect to - TAGOIO__RELAY__MQTT__ADDRESS=mosquitto-broker - - TAGOIO__RELAY__MQTT__TLS_ENABLED=false + - TAGOIO__RELAY__MQTT__PORT=1883 - TAGOIO__RELAY__MQTT__CLIENT_ID=tagoio-relay - TAGOIO__RELAY__MQTT__USERNAME=my-username - TAGOIO__RELAY__MQTT__PASSWORD=my-password - - TAGOIO__RELAY__MQTT__SUBSCRIBE__1="/tago/#" - - # - TAGOIO__RELAY__MQTT__PORT=1883 + - TAGOIO__RELAY__MQTT__SUBSCRIBE=["/device/#"] + - TAGOIO__RELAY__MQTT__TLS_ENABLED=false # - TAGOIO__RELAY__MQTT__BROKER_TLS_CA="" # - TAGOIO__RELAY__MQTT__BROKER_TLS_CERT="" # - TAGOIO__RELAY__MQTT__BROKER_TLS_KEY="" diff --git a/src/default_config.toml b/src/default_config.toml index f572ecb..e19b4bf 100644 --- a/src/default_config.toml +++ b/src/default_config.toml @@ -2,13 +2,13 @@ network_token="Your-Network-Token" # Generate a Network Token under your TagoIO Network Settings authorization_token="Your-Authorization-Token" # Generate an Authorization Token under your TagoIO > Devices > Authorizations tagoio_url="https://api.tago.io" # Default -downlink_port="3001" # Default is 3000 +downlink_port=3001 # Default is 3000 [relay.mqtt] client_id="tagoio-relay" # Default is tagoio-relay tls_enabled=false address="localhost" -port="1883" +port=1883 subscribe=["/tago/#", "/tago/+"] # MQTT topics to subscribe to username="my-username" password="my-passowrd" diff --git a/src/relay.rs b/src/relay.rs index 4abe74d..27a3dff 100644 --- a/src/relay.rs +++ b/src/relay.rs @@ -96,12 +96,7 @@ pub async fn start_relay() -> Result<()> { let api_port = { let config_file = CONFIG_FILE.read().unwrap(); - config_file - .as_ref() - .unwrap() - .downlink_port - .clone() - .unwrap_or("3000".to_string()) + config_file.as_ref().unwrap().downlink_port.unwrap_or(3000) }; let test = create_ssl_acceptor().unwrap(); @@ -115,10 +110,7 @@ pub async fn start_relay() -> Result<()> { // } // }; - let addr = SocketAddr::from(( - HOST_ADDRESS.parse::().unwrap(), - api_port.parse::().unwrap(), - )); + let addr = SocketAddr::from((HOST_ADDRESS.parse::().unwrap(), api_port)); tokio::spawn(async move { log::info!(target: "info", "Starting Publish API on: {}", addr); diff --git a/src/schema/mod.rs b/src/schema/mod.rs index fe337b4..61d1f0f 100644 --- a/src/schema/mod.rs +++ b/src/schema/mod.rs @@ -10,8 +10,8 @@ pub struct RelayConfig { pub struct ConfigFile { pub network_token: String, pub authorization_token: String, - pub tagoio_url: Option, // Default is "https://api.tago.io" - pub downlink_port: Option, // Default is "3000" + pub tagoio_url: Option, // Default is "https://api.tago.io" + pub downlink_port: Option, // Default is "3000" pub mqtt: Mqtt, } @@ -20,7 +20,7 @@ pub struct Mqtt { pub client_id: Option, // Default is "tagoio-relay" pub tls_enabled: bool, pub address: String, - pub port: String, + pub port: u16, pub subscribe: Vec, // Default is ["/tago/#", "/device/+"] pub username: Option, // Default is "my-username" pub password: Option, // Default is "my-password" @@ -53,7 +53,7 @@ impl ConfigFile { self.tagoio_url = Some("https://api.tago.io".to_string()); } if self.downlink_port.is_none() { - self.downlink_port = Some("3000".to_string()); + self.downlink_port = Option::from(3000); } self.mqtt = self.mqtt.with_defaults()?; Ok(self) @@ -94,7 +94,7 @@ mod tests { client_id: None, tls_enabled: false, address: "localhost".to_string(), - port: "1883".to_string(), + port: 1883, subscribe: vec![], username: None, password: None, @@ -110,7 +110,7 @@ mod tests { assert_eq!(relay_config.profile_id.unwrap(), "self-hosted"); // assert_eq!(relay_config.state.unwrap(), InitiatedState::Stopped); assert_eq!(relay_config.config.tagoio_url.unwrap(), "https://api.tago.io"); - assert_eq!(relay_config.config.downlink_port.unwrap(), "3000"); + assert_eq!(relay_config.config.downlink_port.unwrap(), 3000); assert_eq!(relay_config.config.mqtt.client_id.unwrap(), "tagoio-relay"); // assert_eq!( // relay_config.config.mqtt.authentication_certificate_file.unwrap(), @@ -129,7 +129,7 @@ mod tests { client_id: None, tls_enabled: false, address: "localhost".to_string(), - port: "1883".to_string(), + port: 1883, subscribe: vec![], username: None, password: None, @@ -142,7 +142,7 @@ mod tests { let config_with_defaults = config.with_defaults().unwrap(); assert_eq!(config_with_defaults.tagoio_url.unwrap(), "https://api.tago.io"); - assert_eq!(config_with_defaults.downlink_port.unwrap(), "3000"); + assert_eq!(config_with_defaults.downlink_port.unwrap(), 3000); assert_eq!(config_with_defaults.mqtt.client_id.unwrap(), "tagoio-relay"); } @@ -152,7 +152,7 @@ mod tests { client_id: None, tls_enabled: false, address: "localhost".to_string(), - port: "1883".to_string(), + port: 1883, subscribe: vec!["/tago/#".to_string(), "/device/+".to_string()], username: None, password: None, diff --git a/src/services/mqttrelay.rs b/src/services/mqttrelay.rs index d0075e5..de6cd00 100644 --- a/src/services/mqttrelay.rs +++ b/src/services/mqttrelay.rs @@ -76,15 +76,7 @@ fn initialize_mqtt_options(relay_cfg: &RelayConfig) -> MqttOptions { let crt_file = &relay_cfg.config.mqtt.broker_tls_cert; let key_file = &relay_cfg.config.mqtt.broker_tls_key; - let port: u16 = match relay_cfg.config.mqtt.port.parse() { - Ok(port) => port, - Err(e) => { - log::error!(target: "mqtt", "Invalid Broker Port number: {}. Error: {:?}", relay_cfg.config.mqtt.port, e); - std::process::exit(1); - } - }; - - let mut mqttoptions = MqttOptions::new(client_id, &relay_cfg.config.mqtt.address, port); + let mut mqttoptions = MqttOptions::new(client_id, &relay_cfg.config.mqtt.address, relay_cfg.config.mqtt.port); mqttoptions.set_keep_alive(Duration::from_secs(30)); mqttoptions.set_max_packet_size(1024 * 1024, 1024 * 1024); // 1mb in/out diff --git a/src/services/tagoio.rs b/src/services/tagoio.rs index 383c41d..10a788d 100644 --- a/src/services/tagoio.rs +++ b/src/services/tagoio.rs @@ -183,12 +183,12 @@ mod tests { network_token: "test_network_token".to_string(), authorization_token: "test_authorization_token".to_string(), tagoio_url: Some(server.url()), - downlink_port: Some("3000".to_string()), + downlink_port: Some(3000), mqtt: Mqtt { client_id: Some("test_client_id".to_string()), tls_enabled: false, address: "localhost".to_string(), - port: "1883".to_string(), + port: 1883, subscribe: vec!["/tago/#".to_string(), "/device/+".to_string()], username: Some("test_username".to_string()), password: Some("test_password".to_string()), diff --git a/src/utils.rs b/src/utils.rs index fb9cfab..c7a4e7a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,6 +1,9 @@ +use figment::{ + providers::{Env, Format, Toml}, + Figment, +}; use home::home_dir; use std::time::Duration; -use toml_env::{initialize, Args, AutoMapEnvArgs}; use crate::schema::ConfigFile; @@ -75,27 +78,18 @@ pub fn fetch_config_file(user_path: Option) -> Option { std::process::exit(1); } - let config: Option = initialize(Args { - auto_map_env: Some(AutoMapEnvArgs { - divider: "__", - prefix: Some("TAGOIO"), // Prefix for environment variables - transform: Box::new(|name| name.to_lowercase()), - }), - // logging: Logging::StdOut, - config_path: Some(&config_path), - ..Args::default() - }) - .unwrap_or_else(|err| { + let figment = Figment::new() + .merge(Toml::file(&config_path)) + .merge(Env::prefixed("TAGOIO__").split("__")); + + let config: ConfigFileResponse = figment.extract().unwrap_or_else(|err| { log::error!(target: "error", "Failed to initialize configuration: {}", err); std::process::exit(1); }); - config - .unwrap_or_else(|| { - log::error!(target: "error", "Configuration file is missing or invalid."); - std::process::exit(1); - }) - .relay + println!("{:?}", config.relay); + + config.relay } pub fn calculate_backoff(attempt: u32) -> Duration {