From 57c4a5251c30d3dc2b78059fd208d8948d999056 Mon Sep 17 00:00:00 2001 From: rtkay123 Date: Sun, 29 Mar 2026 16:15:54 +0200 Subject: refactor: move config to core --- lib/warden-core/src/config/cli/database.rs | 136 +++++++++++++++++++++++++++++ lib/warden-core/src/config/cli/mod.rs | 85 ++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 lib/warden-core/src/config/cli/database.rs create mode 100644 lib/warden-core/src/config/cli/mod.rs (limited to 'lib/warden-core/src/config/cli') diff --git a/lib/warden-core/src/config/cli/database.rs b/lib/warden-core/src/config/cli/database.rs new file mode 100644 index 0000000..31ba930 --- /dev/null +++ b/lib/warden-core/src/config/cli/database.rs @@ -0,0 +1,136 @@ +use clap::Parser; +use serde::{Deserialize, Serialize}; +use url::Url; + +use crate::WardenError; + +#[derive(Parser, Clone, Deserialize, Serialize, Debug)] +#[serde(rename_all = "kebab-case")] +pub struct Database { + /// Full database URL (if provided, overrides individual components) + #[arg(long, env = "DATABASE_URL")] + pub database_url: Option, + + #[arg(long, env = "DB_USER")] + /// Database username + #[serde(rename = "username")] + pub database_username: Option, + + /// Database password + #[arg(long, env = "DB_PASSWORD")] + #[serde(rename = "password")] + pub database_password: Option, + + /// Database host + #[arg(long, env = "DB_HOST", default_value = "localhost")] + #[serde(rename = "host")] + pub database_host: Option, + + /// Database port + #[arg(long, env = "DB_PORT")] + #[serde(rename = "port")] + pub database_port: Option, + + /// Database name + #[arg(long, env = "DB_NAME")] + #[serde(rename = "name")] + pub database_name: Option, + + /// Database pool size + #[arg(long, env = "DATABASE_POOL_SIZE", default_value = "10")] + #[serde(rename = "pool-size")] + pub database_pool_size: Option, +} + +impl Default for Database { + fn default() -> Self { + Self { + database_url: Default::default(), + database_username: Some(String::from("postgres")), + database_password: Some(String::from("password")), + database_host: Some(String::from("localhost")), + database_port: Some(5432), + database_name: Some(String::from("warden")), + database_pool_size: Some(10), + } + } +} + +impl Database { + pub fn merge(cli: &Self, file: &Self) -> Result { + let url = cli.database_url.clone().or(file.database_url.clone()); + + let pool_size = cli + .database_pool_size + .or(file.database_pool_size) + .unwrap_or(10); + + let final_url = match url { + Some(u) => u, + None => { + let host = cli + .database_host + .clone() + .or(file.database_host.clone()) + .unwrap_or_else(|| "localhost".to_string()); + + let mut u = Url::parse(&format!("postgresql://{}", host))?; + + let user = cli + .database_username + .as_ref() + .or(file.database_username.as_ref()); + let pass = cli + .database_password + .as_ref() + .or(file.database_password.as_ref()); + let port = cli.database_port.or(file.database_port); + let name = cli.database_name.as_ref().or(file.database_name.as_ref()); + + if let Some(user) = user { + u.set_username(user).ok(); + } + if let Some(pass) = pass { + u.set_password(Some(pass)).ok(); + } + if let Some(port) = port { + u.set_port(Some(port)).ok(); + } + if let Some(name) = name { + u.set_path(name); + } + + u + } + }; + + Ok(Self { + database_url: Some(final_url), + database_pool_size: Some(pool_size), + ..cli.clone() + }) + } + + pub fn get_url(&self) -> Result { + if let Some(ref url) = self.database_url { + return Ok(url.clone()); + } + + let host = "localhost".to_owned(); + let host = self.database_host.as_ref().unwrap_or_else(|| &host); + let mut url = Url::parse(&format!("postgres://{host}"))?; + + if let Some(ref u) = self.database_username { + url.set_username(u).ok(); + } + if let Some(ref p) = self.database_password { + url.set_password(Some(p)).ok(); + } + url.set_port(self.database_port).ok(); + if let Some(ref name) = self.database_name { + url.set_path(name); + } + + Ok(url) + } +} diff --git a/lib/warden-core/src/config/cli/mod.rs b/lib/warden-core/src/config/cli/mod.rs new file mode 100644 index 0000000..36f6bf0 --- /dev/null +++ b/lib/warden-core/src/config/cli/mod.rs @@ -0,0 +1,85 @@ +pub mod database; +use std::path::PathBuf; + +use clap::{Parser, Subcommand, ValueEnum}; +use serde::{Deserialize, Serialize}; + +use crate::config::cli::database::Database; + +#[derive(Parser, Serialize, Deserialize, Default, Debug)] +#[command(version, about, long_about = None)] +/// Real-time transaction monitoring +pub struct Cli { + /// Sets a custom config file + #[arg(short, long, value_name = "FILE")] + #[serde(skip)] + pub config: Option, + #[command(flatten)] + pub server: Server, + #[command(subcommand)] + #[serde(skip)] + pub command: Option, + #[command(flatten)] + pub database: Database, +} + +#[derive(Subcommand, Debug)] +pub enum Commands { + /// Generates a default configuration file + Init { + /// Path to save the config + #[arg(short, long, default_value = "warden.toml")] + path: String, + }, +} + +#[derive(Parser, Deserialize, Serialize, Debug)] +#[serde(rename_all = "kebab-case")] +pub struct Server { + /// Sets the port that the server listens to + #[arg(short, long, value_name = "PORT", env = "PORT", default_value = "2210")] + #[arg(value_parser = clap::value_parser!(u16).range(1..=65535))] + pub port: Option, + /// Runtime environment + #[arg(short, long, value_name = "ENV", default_value = "prod", env = "ENV")] + pub environment: Option, + /// Log Level + #[arg(long, value_name = "LOG_LEVEL", env = "LOG_LEVEL")] + pub log_level: Option, + /// Log file directory (defaults to temp_dir) + #[arg(long, value_name = "DIR", env = "LOGS_DIR")] + pub log_dir: Option, + /// Request timeout duration in seconds + #[arg( + long, + value_name = "TIMEOUT_DURATION", + env = "TIMEOUT_DURATION_SECS", + default_value = "5" + )] + pub timeout_secs: Option, +} + +impl Default for Server { + fn default() -> Self { + Self { + port: Some(2210), + environment: Default::default(), + log_level: Some(format!( + "{}=debug,tower_http=debug,axum::rejection=trace", + env!("CARGO_CRATE_NAME") + )), + log_dir: Some(std::env::temp_dir()), + timeout_secs: Some(5), + } + } +} + +#[derive(Deserialize, ValueEnum, Serialize, Clone, Copy, Default, Debug)] +#[serde(rename_all = "lowercase")] +pub enum CliEnvironment { + #[default] + Dev, + Development, + Prod, + Production, +} -- cgit v1.2.3