diff --git a/server/src/config/macros.rs b/server/src/config/macros.rs new file mode 100644 index 00000000..1be6f597 --- /dev/null +++ b/server/src/config/macros.rs @@ -0,0 +1,43 @@ +/* + * Created on Sat Oct 02 2021 + * + * This file is a part of Skytable + * Skytable (formerly known as TerrabaseDB or Skybase) is a free and open-source + * NoSQL database written by Sayan Nandan ("the Author") with the + * vision to provide flexibility in data modelling without compromising + * on performance, queryability or scalability. + * + * Copyright (c) 2021, Sayan Nandan + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * +*/ + +macro_rules! cli_parse_or_default_or_err { + ($parsewhat:expr, $default:expr, $except:expr $(,)?) => { + match $parsewhat.map(|v| v.parse()) { + Some(Ok(v)) => v, + Some(Err(_)) => return Err(self::cfgerror::ConfigError::CliArgErr($except)), + None => $default, + } + }; +} + +macro_rules! set_if_exists { + ($testwhat:expr, $trywhat:expr) => { + if let Some(testwhat) = $testwhat { + $trywhat = testwhat; + } + }; +} diff --git a/server/src/config/mod.rs b/server/src/config/mod.rs index 2b5eab77..d6e2d3d3 100644 --- a/server/src/config/mod.rs +++ b/server/src/config/mod.rs @@ -27,28 +27,22 @@ //! This module provides tools to handle configuration files and settings use crate::dbnet::MAXIMUM_CONNECTION_LIMIT; +use clap::{load_yaml, App}; use serde::Deserialize; -use std::fmt; use std::fs; use std::net::{IpAddr, Ipv4Addr}; // modules +#[macro_use] +mod macros; mod cfgfile; #[cfg(test)] mod tests; +// self imports +use self::cfgerror::ConfigError; const DEFAULT_IPV4: IpAddr = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); const DEFAULT_SSL_PORT: u16 = 2004; -macro_rules! cli_parse_or_default_or_err { - ($parsewhat:expr, $default:expr, $except:expr $(,)?) => { - match $parsewhat.map(|v| v.parse()) { - Some(Ok(v)) => v, - Some(Err(_)) => return Err(ConfigError::CliArgErr($except)), - None => $default, - } - }; -} - /// The BGSAVE configuration /// /// If BGSAVE is enabled, then the duration (corresponding to `every`) is wrapped in the `Enabled` @@ -230,60 +224,52 @@ impl ParsedConfig { /// Create a `ParsedConfig` instance from a `Config` object, which is a parsed /// TOML file (represented as an object) fn from_config(cfg_info: cfgfile::Config) -> Self { - ParsedConfig { - noart: option_unwrap_or!(cfg_info.server.noart, false), - bgsave: if let Some(bgsave) = cfg_info.bgsave { - match (bgsave.enabled, bgsave.every) { - // TODO: Show a warning that there are unused keys - (Some(enabled), Some(every)) => BGSave::new(enabled, every), - (Some(enabled), None) => BGSave::new(enabled, 120), - (None, Some(every)) => BGSave::new(true, every), - (None, None) => BGSave::default(), - } - } else { - BGSave::default() - }, - snapshot: cfg_info - .snapshot - .map(|snapshot| { - SnapshotConfig::Enabled(SnapshotPref::new( - snapshot.every, - snapshot.atmost, - option_unwrap_or!(snapshot.failsafe, true), - )) - }) - .unwrap_or_else(SnapshotConfig::default), - ports: if let Some(sslopts) = cfg_info.ssl { - if option_unwrap_or!(sslopts.only, false) { - PortConfig::SecureOnly { - ssl: SslOpts { - key: sslopts.key, - chain: sslopts.chain, - port: sslopts.port, - passfile: sslopts.passin, - }, - host: cfg_info.server.host, - } - } else { - PortConfig::Multi { - ssl: SslOpts { - key: sslopts.key, - chain: sslopts.chain, - port: sslopts.port, - passfile: sslopts.passin, - }, - host: cfg_info.server.host, - port: cfg_info.server.port, - } + let mut cfg = Self::default(); + set_if_exists!(cfg_info.server.noart, cfg.noart); + if let Some(bgsave) = cfg_info.bgsave { + let bgsave_ret = match (bgsave.enabled, bgsave.every) { + // TODO: Show a warning that there are unused keys + (Some(enabled), Some(every)) => BGSave::new(enabled, every), + (Some(enabled), None) => BGSave::new(enabled, 120), + (None, Some(every)) => BGSave::new(true, every), + (None, None) => BGSave::default(), + }; + cfg.bgsave = bgsave_ret; + } + if let Some(snapshot) = cfg_info.snapshot { + cfg.snapshot = SnapshotConfig::Enabled(SnapshotPref::new( + snapshot.every, + snapshot.atmost, + option_unwrap_or!(snapshot.failsafe, true), + )); + } + if let Some(sslopts) = cfg_info.ssl { + let portcfg = if option_unwrap_or!(sslopts.only, false) { + PortConfig::SecureOnly { + ssl: SslOpts { + key: sslopts.key, + chain: sslopts.chain, + port: sslopts.port, + passfile: sslopts.passin, + }, + host: cfg_info.server.host, } } else { - PortConfig::InsecureOnly { + PortConfig::Multi { + ssl: SslOpts { + key: sslopts.key, + chain: sslopts.chain, + port: sslopts.port, + passfile: sslopts.passin, + }, host: cfg_info.server.host, port: cfg_info.server.port, } - }, - maxcon: option_unwrap_or!(cfg_info.server.maxclient, MAXIMUM_CONNECTION_LIMIT), + }; + cfg.ports = portcfg; } + set_if_exists!(cfg_info.server.maxclient, cfg.maxcon); + cfg } #[cfg(test)] /// Create a new `ParsedConfig` from a `TOML` string @@ -328,8 +314,6 @@ impl ParsedConfig { } } -use clap::{load_yaml, App}; - /// The type of configuration: /// - We either used a custom configuration file given to us by the user (`Custom`) OR /// - We used the default configuration (`Def`) @@ -338,31 +322,6 @@ pub enum ConfigType { Custom(T, Option), } -#[derive(Debug)] -/// Type of configuration error: -/// - The config file was not found (`OSError`) -/// - The config file was invalid (`SyntaxError`) -/// - The config file has an invalid value, which is syntatically correct -/// but logically incorrect (`CfgError`) -/// - The command line arguments have an invalid value/invalid values (`CliArgError`) -pub enum ConfigError { - OSError(std::io::Error), - SyntaxError(toml::de::Error), - CfgError(&'static str), - CliArgErr(&'static str), -} - -impl fmt::Display for ConfigError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ConfigError::OSError(e) => writeln!(f, "error: {}", e), - ConfigError::SyntaxError(e) => writeln!(f, "syntax error in configuration file: {}", e), - ConfigError::CfgError(e) => write!(f, "Configuration error: {}", e), - ConfigError::CliArgErr(e) => write!(f, "Argument error: {}", e), - } - } -} - /// This function returns a `ConfigType` /// /// This parses a configuration file if it is supplied as a command line argument @@ -571,3 +530,33 @@ pub fn get_config_file_or_return_cfg() -> Result) -> fmt::Result { + match self { + ConfigError::OSError(e) => writeln!(f, "error: {}", e), + ConfigError::SyntaxError(e) => { + writeln!(f, "syntax error in configuration file: {}", e) + } + ConfigError::CfgError(e) => write!(f, "Configuration error: {}", e), + ConfigError::CliArgErr(e) => write!(f, "Argument error: {}", e), + } + } + } +}