Simplify config generation from cfg file

Signed-off-by: Sayan Nandan <nandansayan@outlook.com>
next
Sayan Nandan 3 years ago
parent 788b3073c0
commit 43bef62a9e
No known key found for this signature in database
GPG Key ID: 5EDED89A1ADA6273

@ -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 <ohsayan@outlook.com>
*
* 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 <https://www.gnu.org/licenses/>.
*
*/
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;
}
};
}

@ -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<T, U> {
Custom(T, Option<U>),
}
#[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<ParsedConfig>`
///
/// 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<ConfigType<ParsedConfig, String
Ok(ConfigType::Def(ParsedConfig::default(), restorefile))
}
}
mod cfgerror {
use std::fmt;
#[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),
}
}
}
}

Loading…
Cancel
Save