Lines
97.69 %
Functions
5.88 %
Branches
100 %
//! Program configurations.
use std::env;
use clap::{builder::RangedU64ValueParser, Arg, ArgMatches, Command};
use serde::Deserialize;
use sylvia_iot_corelib::constants::DbEngine;
/// Configuration file object.
#[derive(Default, Deserialize)]
pub struct Config {
/// **sylvia-iot-auth** API base path with host. For example: `http://localhost:1080/auth`.
pub auth: Option<String>,
/// **sylvia-iot-broker** API base path with host. For example: `http://localhost:2080/broker`.
pub broker: Option<String>,
pub db: Option<Db>,
#[serde(rename = "mqChannels")]
pub mq_channels: Option<MqChannels>,
}
/// Database configuration object.
pub struct Db {
/// Select the model implementation.
/// - `mongodb`: pure MongoDB.
/// - `sqlite`: pure SQLite.
pub engine: Option<String>,
pub mongodb: Option<MongoDb>,
pub sqlite: Option<Sqlite>,
/// MongoDB configuration object.
pub struct MongoDb {
/// Use `mongodb://username:password@host:port` format.
pub url: Option<String>,
pub database: Option<String>,
#[serde(rename = "poolSize")]
pub pool_size: Option<u32>,
/// SQLite configuration object.
pub struct Sqlite {
/// Use absolute/relative path.
pub path: Option<String>,
/// Message channels configuration object.
pub struct MqChannels {
pub broker: Option<DataData>,
pub coremgr: Option<DataData>,
/// Channel `broker.data` `coremgr.data` configuration object.
pub struct DataData {
/// Queue connection URL of the data channel.
/// AMQP QoS prefetch from **1** to **65535**. None or zero use default value **100**.
pub prefetch: Option<u16>,
/// MQTT shared subscription topic prefix.
#[serde(rename = "sharedPrefix")]
pub shared_prefix: Option<String>,
pub const DEF_AUTH: &'static str = "http://localhost:1080/auth";
pub const DEF_BROKER: &'static str = "http://localhost:2080/broker";
pub const DEF_ENGINE: &'static str = DbEngine::SQLITE;
pub const DEF_MONGODB_URL: &'static str = "mongodb://localhost:27017";
pub const DEF_MONGODB_DB: &'static str = "data";
pub const DEF_SQLITE_PATH: &'static str = "data.db";
pub const DEF_MQ_PREFETCH: u16 = 100;
pub const DEF_MQ_SHAREDPREFIX: &'static str = "$share/sylvia-iot-data/";
pub const DEF_MQ_CHANNEL_URL: &'static str = "amqp://localhost";
/// To register Clap arguments.
pub fn reg_args(cmd: Command) -> Command {
cmd.arg(
Arg::new("data.auth")
.long("data.auth")
.help("sylvia-iot-auth host (ex: http://localhost:1080/auth)")
.num_args(1),
)
.arg(
Arg::new("data.broker")
.long("data.broker")
.help("sylvia-iot-broker host (ex: http://localhost:2080/broker)")
Arg::new("data.db.engine")
.long("data.db.engine")
.help("database engine")
.num_args(1)
.value_parser([DbEngine::MONGODB, DbEngine::SQLITE]),
Arg::new("data.db.mongodb.url")
.long("data.db.mongodb.url")
.help("MongoDB URL (scheme://[username][:password][@][host][:port]")
Arg::new("data.db.mongodb.database")
.long("data.db.mongodb.database")
.help("database nane")
Arg::new("data.db.mongodb.poolsize")
.long("data.db.mongodb.poolsize")
.help("connection pool size")
.value_parser(RangedU64ValueParser::<u64>::new().range(1..=u32::MAX as u64)),
Arg::new("data.db.sqlite.path")
.long("data.db.sqlite.path")
.help("SQLite path")
Arg::new("data.mq-channels.broker.url")
.long("data.mq-channels.broker.url")
.help("URL of `broker.data` channel")
Arg::new("data.mq-channels.broker.prefetch")
.long("data.mq-channels.broker.prefetch")
.help("AMQP prefetch for `broker.data` channel")
.value_parser(RangedU64ValueParser::<u64>::new().range(1..=u16::MAX as u64)),
Arg::new("data.mq-channels.broker.sharedprefix")
.long("data.mq-channels.broker.sharedprefix")
.help("MQTT shared subscription prefix of `broker.data` channel")
Arg::new("data.mq-channels.coremgr.url")
.long("data.mq-channels.coremgr.url")
.help("URL of `coremgr.data` channel")
Arg::new("data.mq-channels.coremgr.prefetch")
.long("data.mq-channels.coremgr.prefetch")
.help("AMQP prefetch for `coremgr.data` channel")
Arg::new("data.mq-channels.coremgr.sharedprefix")
.long("data.mq-channels.coremgr.sharedprefix")
.help("MQTT shared subscription prefix of `coremgr.data` channel")
/// To read input arguments from command-line arguments and environment variables.
///
/// This function will call [`apply_default()`] to fill missing values so you do not need call it
/// again.
pub fn read_args(args: &ArgMatches) -> Config {
apply_default(&Config {
auth: match args.get_one::<String>("data.auth") {
None => match env::var("DATA_AUTH") {
Err(_) => None,
Ok(v) => Some(v),
},
Some(v) => Some(v.clone()),
broker: match args.get_one::<String>("data.broker") {
None => match env::var("DATA_BROKER") {
db: Some(Db {
engine: match args.get_one::<String>("data.db.engine") {
None => match env::var("DATA_DB_ENGINE") {
mongodb: Some(MongoDb {
url: match args.get_one::<String>("data.db.mongodb.url") {
None => match env::var("DATA_DB_MONGODB_URL") {
database: match args.get_one::<String>("data.db.mongodb.database") {
None => match env::var("DATA_DB_MONGODB_DATABASE") {
pool_size: match args.get_one::<u64>("data.db.mongodb.poolsize") {
None => match env::var("DATA_DB_MONGODB_POOLSIZE") {
Ok(v) => match v.parse::<u32>() {
Some(v) => Some(*v as u32),
}),
sqlite: Some(Sqlite {
path: match args.get_one::<String>("data.db.sqlite.path") {
None => match env::var("DATA_DB_SQLITE_PATH") {
mq_channels: Some(MqChannels {
broker: Some(DataData {
url: match args.get_one::<String>("data.mq-channels.broker.url") {
None => match env::var("DATA_MQCHANNELS_BROKER_URL") {
prefetch: match args.get_one::<u64>("data.mq-channels.broker.prefetch") {
None => match env::var("DATA_MQCHANNELS_BROKER_PREFETCH") {
Ok(v) => match v.parse::<u16>() {
Some(v) => Some(*v as u16),
shared_prefix: match args.get_one::<String>("data.mq-channels.broker.sharedprefix")
{
None => match env::var("DATA_MQCHANNELS_BROKER_SHAREDPREFIX") {
coremgr: Some(DataData {
url: match args.get_one::<String>("data.mq-channels.coremgr.url") {
None => match env::var("DATA_MQCHANNELS_COREMGR_URL") {
prefetch: match args.get_one::<u64>("data.mq-channels.coremgr.prefetch") {
None => match env::var("DATA_MQCHANNELS_COREMGR_PREFETCH") {
shared_prefix: match args.get_one::<String>("data.mq-channels.coremgr.sharedprefix")
None => match env::var("DATA_MQCHANNELS_COREMGR_SHAREDPREFIX") {
})
/// Fill missing configuration with default values.
pub fn apply_default(config: &Config) -> Config {
Config {
auth: match config.auth.as_ref() {
None => Some(DEF_AUTH.to_string()),
Some(auth) => Some(auth.clone()),
broker: match config.broker.as_ref() {
None => Some(DEF_BROKER.to_string()),
Some(broker) => Some(broker.clone()),
db: match config.db.as_ref() {
None => Some(Db {
engine: Some(DEF_ENGINE.to_string()),
url: Some(DEF_MONGODB_URL.to_string()),
database: Some(DEF_MONGODB_DB.to_string()),
pool_size: None,
path: Some(DEF_SQLITE_PATH.to_string()),
Some(db) => Some(Db {
engine: match db.engine.as_ref() {
None => Some(DEF_ENGINE.to_string()),
Some(engine) => match engine.as_str() {
DbEngine::MONGODB => Some(DbEngine::MONGODB.to_string()),
DbEngine::SQLITE => Some(DbEngine::SQLITE.to_string()),
_ => Some(DEF_ENGINE.to_string()),
mongodb: match db.mongodb.as_ref() {
None => Some(MongoDb {
Some(mongodb) => Some(MongoDb {
url: match mongodb.url.as_ref() {
None => Some(DEF_MONGODB_URL.to_string()),
Some(url) => Some(url.to_string()),
database: match mongodb.database.as_ref() {
None => Some(DEF_MONGODB_DB.to_string()),
Some(database) => Some(database.to_string()),
pool_size: mongodb.pool_size,
sqlite: match db.sqlite.as_ref() {
None => Some(Sqlite {
Some(sqlite) => Some(Sqlite {
path: match sqlite.path.as_ref() {
None => Some(DEF_SQLITE_PATH.to_string()),
Some(path) => Some(path.to_string()),
mq_channels: match config.mq_channels.as_ref() {
None => Some(MqChannels {
url: Some(DEF_MQ_CHANNEL_URL.to_string()),
prefetch: Some(DEF_MQ_PREFETCH),
shared_prefix: Some(DEF_MQ_SHAREDPREFIX.to_string()),
Some(mq_channels) => Some(MqChannels {
broker: match mq_channels.broker.as_ref() {
None => Some(DataData {
Some(channel) => Some(DataData {
url: match channel.url.as_ref() {
None => Some(DEF_MQ_CHANNEL_URL.to_string()),
prefetch: match channel.prefetch {
None => Some(DEF_MQ_PREFETCH),
Some(prefetch) => Some(prefetch),
shared_prefix: match channel.shared_prefix.as_ref() {
None => Some(DEF_MQ_SHAREDPREFIX.to_string()),
Some(shared_prefix) => Some(shared_prefix.to_string()),
coremgr: match mq_channels.coremgr.as_ref() {