From 7da593acbc3edfc6846f9bd2ffc54a01522bb43d Mon Sep 17 00:00:00 2001 From: Adam Lock Date: Thu, 23 Jan 2020 20:58:14 +0000 Subject: [PATCH] Move mqtt-client to pico-args, show usage if parse_args() returns an error --- Cargo.lock | 8 +- samples/discovery-client/src/main.rs | 5 +- samples/modbus-server/src/main.rs | 5 +- samples/mqtt-client/Cargo.toml | 2 +- samples/mqtt-client/src/main.rs | 147 +++++++++++++++------------ samples/simple-client/src/main.rs | 5 +- samples/web-client/src/main.rs | 5 +- 7 files changed, 98 insertions(+), 79 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b12a47635..39c5e0cc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1169,9 +1169,9 @@ dependencies = [ name = "opcua-discovery-client" version = "0.8.0" dependencies = [ - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "opcua-client 0.8.0", "opcua-console-logging 0.8.0", + "pico-args 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1191,10 +1191,10 @@ dependencies = [ name = "opcua-modbus-server" version = "0.8.0" dependencies = [ - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "opcua-console-logging 0.8.0", "opcua-server 0.8.0", + "pico-args 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1209,9 +1209,9 @@ dependencies = [ name = "opcua-mqtt-client" version = "0.8.0" dependencies = [ - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "opcua-client 0.8.0", "opcua-console-logging 0.8.0", + "pico-args 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rumqtt 0.30.0 (git+https://github.com/AtherEnergy/rumqtt.git?rev=83b4694525061e2ccef617c0ac867db2044cc4e7)", ] @@ -1287,9 +1287,9 @@ version = "0.8.0" dependencies = [ "actix 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", "actix-web 0.7.19 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "opcua-client 0.8.0", "opcua-console-logging 0.8.0", + "pico-args 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/samples/discovery-client/src/main.rs b/samples/discovery-client/src/main.rs index 2f1478c03..7db59bc6c 100644 --- a/samples/discovery-client/src/main.rs +++ b/samples/discovery-client/src/main.rs @@ -27,8 +27,9 @@ Usage: discovery-client --config [config] --run-demo-slave const DEFAULT_DISCOVERY_URL: &str = "opc.tcp://localhost:4840/"; -fn main() -> Result<(), Box> { - let args = Args::parse_args()?; +fn main() -> Result<(), ()> { + let args = Args::parse_args() + .map_err(|_| Args::usage())?; if args.help { Args::usage(); } else { diff --git a/samples/modbus-server/src/main.rs b/samples/modbus-server/src/main.rs index 25ac90c84..78b46c2dc 100644 --- a/samples/modbus-server/src/main.rs +++ b/samples/modbus-server/src/main.rs @@ -86,9 +86,10 @@ Usage: modbus-server --config [config] --run-demo-slave const DEFAULT_CONFIG: &str = "./modbus.conf"; -fn main() -> Result<(), Box> { +fn main() -> Result<(), ()> { // Read command line arguments - let args = Args::parse_args()?; + let args = Args::parse_args() + .map_err(|_| Args::usage())?; if args.help { Args::usage(); } else { diff --git a/samples/mqtt-client/Cargo.toml b/samples/mqtt-client/Cargo.toml index bbe85924a..41ea33d40 100644 --- a/samples/mqtt-client/Cargo.toml +++ b/samples/mqtt-client/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Adam Lock "] edition = "2018" [dependencies] -clap = "2.33" +pico-args = "0.3" # This is a completely arbitrary snapshot of rumqtt that happens to work rumqtt = { git = "https://github.com/AtherEnergy/rumqtt.git", rev = "83b4694525061e2ccef617c0ac867db2044cc4e7" } diff --git a/samples/mqtt-client/src/main.rs b/samples/mqtt-client/src/main.rs index 9cc73ceb2..174e1fbdb 100644 --- a/samples/mqtt-client/src/main.rs +++ b/samples/mqtt-client/src/main.rs @@ -2,15 +2,51 @@ //! values before exiting. use std::{ path::PathBuf, - sync::{Arc, Mutex, RwLock, mpsc}, + sync::{Arc, mpsc, Mutex, RwLock}, thread, }; use rumqtt::{MqttClient, MqttOptions, QoS}; -use clap::{App, Arg, value_t_or_exit}; use opcua_client::prelude::*; +struct Args { + help: bool, + config: String, + endpoint_id: String, + host: String, + port: u16, +} + +impl Args { + pub fn parse_args() -> Result> { + let mut args = pico_args::Arguments::from_env(); + Ok(Args { + help: args.contains(["-h", "--help"]), + config: args.opt_value_from_str("--config")?.unwrap_or(String::from(DEFAULT_CONFIG_FILE)), + endpoint_id: args.opt_value_from_str("--config")?.unwrap_or(String::from("")), + host: args.opt_value_from_str("--host")?.unwrap_or(String::from(DEFAULT_MQTT_HOST)), + port: args.opt_value_from_str("--port")?.unwrap_or(DEFAULT_MQTT_PORT), + }) + } + + pub fn usage() { + println!(r#"MQTT client +Usage: discovery-client --config [config] --run-demo-slave + -h, --help Show help + --config file Sets the configuration file to read settings and endpoints from (default: {}) + --endpoint-id id Sets the endpoint id from the config file to connect to + --host host Address or name of the MQTT server to connect with (default: {}) + --port port Port number of MQTT server to connect with (default: {})"#, + DEFAULT_CONFIG_FILE, DEFAULT_MQTT_HOST, DEFAULT_MQTT_PORT); + } +} + +const DEFAULT_CONFIG_FILE: &str = "../client.conf/"; +const DEFAULT_MQTT_HOST: &str = "broker.hivemq.com"; +const DEFAULT_MQTT_PORT: u16 = 1883; + + // This client will do the following: // // 1. Read a configuration file (either default or the one specified using --config) @@ -19,72 +55,51 @@ use opcua_client::prelude::*; // 4. Publish those values to an MQTT broker (default broker.hivemq.com:1883) // 5. User can observe result on the broker (e.g. http://www.mqtt-dashboard.com/) -fn main() { - // Read command line arguments - let m = App::new("Simple OPC UA Client") - .arg(Arg::with_name("config") - .long("config") - .help("Sets the configuration file to read settings and endpoints from") - .takes_value(true) - .default_value("../client.conf") - .required(false)) - .arg(Arg::with_name("id") - .long("endpoint-id") - .help("Sets the endpoint id from the config file to connect to") - .takes_value(true) - .default_value("") - .required(false)) - .arg(Arg::with_name("host") - .long("host") - .help("Address or name of the MQTT server to connect with") - .default_value("broker.hivemq.com") - .takes_value(true) - .required(true)) - .arg(Arg::with_name("port") - .long("port") - .help("Port number of MQTT server to connect with") - .default_value("1883") - .takes_value(true) - .required(true)) - .get_matches(); - - let mqtt_host = m.value_of("host").unwrap().to_string(); - let mqtt_port = value_t_or_exit!(m, "port", u16); - let config_file = m.value_of("config").unwrap().to_string(); - let endpoint_id = m.value_of("id").unwrap().to_string(); - - // Optional - enable OPC UA logging - opcua_console_logging::init(); - - // The way this will work is the mqtt connection will live in its own thread, listening for - // events that are sent to it. - let (tx, rx) = mpsc::channel::<(NodeId, DataValue)>(); - let _ = thread::spawn(move || { - let mqtt_options = MqttOptions::new("test-id", mqtt_host, mqtt_port).set_keep_alive(10); - let (mut mqtt_client, _) = MqttClient::start(mqtt_options).unwrap(); - - loop { - let (node_id, data_value) = rx.recv().unwrap(); - let topic = format!("opcua-rust/mqtt-client/{}/{}", node_id.namespace, node_id.identifier); - let value = if let Some(ref value) = data_value.value { - format!("{:?}", value) - } else { - "null".to_string() - }; - println!("Publishing {} = {}", topic, value); - mqtt_client.publish(topic, QoS::AtLeastOnce, value).unwrap(); - } - }); - - // Use the sample client config to set up a client. The sample config has a number of named - // endpoints one of which is marked as the default. - let mut client = Client::new(ClientConfig::load(&PathBuf::from(config_file)).unwrap()); - let endpoint_id: Option<&str> = if !endpoint_id.is_empty() { Some(&endpoint_id) } else { None }; - if let Ok(session) = client.connect_to_endpoint_id(endpoint_id) { - let _ = subscription_loop(session, tx).map_err(|err| { - println!("ERROR: Got an error while performing action - {}", err); +fn main() -> Result<(), ()> { + let args = Args::parse_args() + .map_err(|_| Args::usage())?; + if args.help { + Args::usage(); + } else { + let mqtt_host = args.host; + let mqtt_port = args.port; + let config_file = args.config; + let endpoint_id = args.endpoint_id; + + // Optional - enable OPC UA logging + opcua_console_logging::init(); + + // The way this will work is the mqtt connection will live in its own thread, listening for + // events that are sent to it. + let (tx, rx) = mpsc::channel::<(NodeId, DataValue)>(); + let _ = thread::spawn(move || { + let mqtt_options = MqttOptions::new("test-id", mqtt_host, mqtt_port).set_keep_alive(10); + let (mut mqtt_client, _) = MqttClient::start(mqtt_options).unwrap(); + + loop { + let (node_id, data_value) = rx.recv().unwrap(); + let topic = format!("opcua-rust/mqtt-client/{}/{}", node_id.namespace, node_id.identifier); + let value = if let Some(ref value) = data_value.value { + format!("{:?}", value) + } else { + "null".to_string() + }; + println!("Publishing {} = {}", topic, value); + mqtt_client.publish(topic, QoS::AtLeastOnce, value).unwrap(); + } }); + + // Use the sample client config to set up a client. The sample config has a number of named + // endpoints one of which is marked as the default. + let mut client = Client::new(ClientConfig::load(&PathBuf::from(config_file)).unwrap()); + let endpoint_id: Option<&str> = if !endpoint_id.is_empty() { Some(&endpoint_id) } else { None }; + if let Ok(session) = client.connect_to_endpoint_id(endpoint_id) { + let _ = subscription_loop(session, tx).map_err(|err| { + println!("ERROR: Got an error while performing action - {}", err); + }); + } } + Ok(()) } fn subscription_loop(session: Arc>, tx: mpsc::Sender<(NodeId, DataValue)>) -> Result<(), StatusCode> { diff --git a/samples/simple-client/src/main.rs b/samples/simple-client/src/main.rs index a81b03dc8..da29e1640 100644 --- a/samples/simple-client/src/main.rs +++ b/samples/simple-client/src/main.rs @@ -31,9 +31,10 @@ Usage: simple-client --url [url] const DEFAULT_URL: &str = "opc.tcp://localhost:4855"; -fn main() -> Result<(), Box> { +fn main() -> Result<(), ()> { // Read command line arguments - let args = Args::parse_args()?; + let args = Args::parse_args() + .map_err(|_| Args::usage())?; if args.help { Args::usage(); } else { diff --git a/samples/web-client/src/main.rs b/samples/web-client/src/main.rs index 139a2d54d..188686265 100644 --- a/samples/web-client/src/main.rs +++ b/samples/web-client/src/main.rs @@ -43,8 +43,9 @@ Usage: web-client --config [config] --run-demo-slave const DEFAULT_HTTP_PORT: u16 = 8686; -fn main() -> Result<(), Box> { - let args = Args::parse_args()?; +fn main() -> Result<(), ()> { + let args = Args::parse_args() + .map_err(|_| Args::usage())?; if args.help { Args::usage(); } else {