diff --git a/daemon/src/config.rs b/daemon/src/config.rs new file mode 100644 index 0000000000..de01d9a1af --- /dev/null +++ b/daemon/src/config.rs @@ -0,0 +1,112 @@ +/* + * Copyright 2019 Cargill Incorporated + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ----------------------------------------------------------------------------- + */ + +use log::Level; + +use crate::error::ConfigurationError; + +pub struct GridConfig { + validator_endpoint: String, + log_level: Level, +} + +impl GridConfig { + pub fn validator_endpoint(&self) -> &str { + &self.validator_endpoint + } + + pub fn log_level(&self) -> Level { + self.log_level + } +} + +pub struct GridConfigBuilder { + validator_endpoint: Option, + log_level: Option, +} + +impl Default for GridConfigBuilder { + fn default() -> Self { + Self { + validator_endpoint: Some("localhost:4004".to_owned()), + log_level: Some(Level::Warn), + } + } +} + +impl GridConfigBuilder { + pub fn with_cli_args(&mut self, matches: &clap::ArgMatches<'_>) -> Self { + Self { + validator_endpoint: matches + .value_of("connect") + .map(ToOwned::to_owned) + .or_else(|| self.validator_endpoint.take()), + log_level: (match matches.occurrences_of("verbose") { + 0 => Some(Level::Warn), + 1 => Some(Level::Info), + _ => Some(Level::Debug), + }) + .or_else(|| self.log_level.take()), + } + } + + pub fn build(mut self) -> Result { + Ok(GridConfig { + validator_endpoint: self + .validator_endpoint + .take() + .ok_or_else(|| ConfigurationError::MissingValue("validator_endpoint".to_owned()))?, + log_level: self + .log_level + .take() + .ok_or_else(|| ConfigurationError::MissingValue("log_level".to_owned()))?, + }) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn build_with_args() { + let matches = clap::App::new("testapp") + .arg(clap::Arg::with_name("connect").short("C").takes_value(true)) + .get_matches_from(vec!["testapp", "-C", "validator:4004"]); + + let config = GridConfigBuilder::default() + .with_cli_args(&matches) + .build() + .expect("Unable to build configuration"); + + assert_eq!("validator:4004", config.validator_endpoint()); + } + + #[test] + fn build_with_missing_args() { + let matches = clap::App::new("testapp") + .arg(clap::Arg::with_name("connect").short("C").takes_value(true)) + .get_matches_from(vec!["testapp"]); + + let config = GridConfigBuilder::default() + .with_cli_args(&matches) + .build() + .expect("Unable to build configuration"); + + assert_eq!("localhost:4004", config.validator_endpoint()); + } +} diff --git a/daemon/src/error.rs b/daemon/src/error.rs index de11cdd48f..8f5c690566 100644 --- a/daemon/src/error.rs +++ b/daemon/src/error.rs @@ -1,4 +1,5 @@ // Copyright 2019 Bitwise IO, Inc. +// Copyright 2019 Cargill Incorporated // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,12 +21,14 @@ use log; #[derive(Debug)] pub enum DaemonError { LoggingInitializationError(Box), + ConfigurationError(Box), } impl Error for DaemonError { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { DaemonError::LoggingInitializationError(err) => Some(err), + DaemonError::ConfigurationError(err) => Some(err), } } } @@ -36,6 +39,7 @@ impl fmt::Display for DaemonError { DaemonError::LoggingInitializationError(e) => { write!(f, "Logging initialization error: {}", e) } + DaemonError::ConfigurationError(e) => write!(f, "Configuration error: {}", e), } } } @@ -45,3 +49,26 @@ impl From for DaemonError { DaemonError::LoggingInitializationError(Box::new(err)) } } + +#[derive(Debug, PartialEq)] +pub enum ConfigurationError { + MissingValue(String), +} + +impl Error for ConfigurationError {} + +impl fmt::Display for ConfigurationError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + ConfigurationError::MissingValue(config_field_name) => { + write!(f, "Missing configuration for {}", config_field_name) + } + } + } +} + +impl From for DaemonError { + fn from(err: ConfigurationError) -> Self { + DaemonError::ConfigurationError(Box::new(err)) + } +} diff --git a/daemon/src/main.rs b/daemon/src/main.rs index 414334fc3e..8fb21de62b 100644 --- a/daemon/src/main.rs +++ b/daemon/src/main.rs @@ -20,11 +20,14 @@ extern crate clap; #[macro_use] extern crate log; +mod config; mod error; -use crate::error::DaemonError; use simple_logger; +use crate::config::GridConfigBuilder; +use crate::error::DaemonError; + const APP_NAME: &str = env!("CARGO_PKG_NAME"); const VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -34,15 +37,18 @@ fn run() -> Result<(), DaemonError> { (version: VERSION) (author: "Contributors to Hyperledger Grid") (about: "Daemon Package for Hyperledger Grid") + (@arg connect: -C --connect +takes_value "connection endpoint for validator") (@arg verbose: -v +multiple "Log verbosely") ) .get_matches(); - match matches.occurrences_of("verbose") { - 0 => simple_logger::init_with_level(log::Level::Warn), - 1 => simple_logger::init_with_level(log::Level::Info), - _ => simple_logger::init_with_level(log::Level::Debug), - }?; + let config = GridConfigBuilder::default() + .with_cli_args(&matches) + .build()?; + + simple_logger::init_with_level(config.log_level())?; + + info!("Connecting to validator at {}", config.validator_endpoint()); Ok(()) }