diff options
Diffstat (limited to 'lib/warden-core/src/config/mod.rs')
| -rw-r--r-- | lib/warden-core/src/config/mod.rs | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/lib/warden-core/src/config/mod.rs b/lib/warden-core/src/config/mod.rs new file mode 100644 index 0000000..9d0c937 --- /dev/null +++ b/lib/warden-core/src/config/mod.rs @@ -0,0 +1,120 @@ +pub mod cli; +mod log_level; + +use std::path::PathBuf; + +use clap::ValueEnum; +pub use cli::Cli; +pub use cli::Commands; +use serde::Deserialize; +use tracing_subscriber::EnvFilter; + +use crate::WardenError; +use crate::config::cli::CliEnvironment; +use crate::config::cli::database::Database; + +#[derive(Deserialize, Default, Debug, ValueEnum, Clone, Copy)] +#[serde(rename_all = "lowercase")] +pub enum Environment { + Development, + #[default] + Production, +} + +impl From<CliEnvironment> for Environment { + fn from(value: CliEnvironment) -> Self { + match value { + CliEnvironment::Dev | CliEnvironment::Development => Self::Development, + CliEnvironment::Prod | CliEnvironment::Production => Self::Production, + } + } +} + +#[derive(Debug, Clone)] +pub struct Configuration { + pub server: Server, + pub database: Database, +} + +#[derive(Debug, Clone)] +pub struct Server { + pub port: u16, + pub environment: Environment, + pub log_level: EnvFilter, + pub log_dir: PathBuf, + pub timeout_secs: u64, +} + +impl Server { + fn merge(cli: &Cli, file: &Cli, missing: &mut Vec<&str>) -> Result<Self, WardenError> { + let port = cli.server.port.or(file.server.port); + + if port.is_none() { + missing.push("server.port"); + } + + let timeout = cli.server.timeout_secs.or(file.server.timeout_secs); + + if timeout.is_none() { + missing.push("server.timeout"); + } + + let log_dir = cli.server.log_dir.clone().or(file.server.log_dir.clone()); + + if log_dir.is_none() { + missing.push("server.log_dir"); + } + + let log_level = cli + .server + .log_level + .as_ref() + .or(file.server.log_level.as_ref()) + .map(ToOwned::to_owned); + + if log_level.is_none() { + missing.push("server.log_level"); + } + + let environment = cli.server.environment.or(file.server.environment); + + if environment.is_none() { + missing.push("server.environment"); + } + + if !missing.is_empty() { + let err = missing + .iter() + .map(|f| format!(" - {}", f)) + .collect::<Vec<_>>() + .join("\n"); + return Err(WardenError::Config(err)); + } + + let log_level = + tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| { + // axum logs rejections from built-in extractors with the `axum::rejection` + // target, at `TRACE` level. `axum::rejection=trace` enables showing those events + log_level.unwrap().into() + }); + + Ok(Self { + port: port.unwrap(), + environment: environment.unwrap().into(), + log_dir: log_dir.unwrap(), + timeout_secs: timeout.unwrap(), + log_level, + }) + } +} + +impl Configuration { + pub fn merge(cli: &Cli, file: &Cli) -> Result<Self, WardenError> { + let mut missing = Vec::new(); + + let server = Server::merge(cli, file, &mut missing)?; + let database = Database::merge(&cli.database, &file.database)?; + + Ok(Self { server, database }) + } +} |
