use premortem::prelude::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, DeriveValidate)]
struct AppConfig {
#[validate(non_empty)]
#[serde(default = "default_host")]
host: String,
#[validate(range(1..=65535))]
#[serde(default = "default_port")]
port: u16,
#[serde(default)]
debug: bool,
#[serde(default = "default_log_level")]
log_level: String,
#[serde(default = "default_max_connections")]
max_connections: u32,
}
fn default_host() -> String {
"0.0.0.0".to_string()
}
fn default_port() -> u16 {
8080
}
fn default_log_level() -> String {
"info".to_string()
}
fn default_max_connections() -> u32 {
100
}
impl Default for AppConfig {
fn default() -> Self {
Self {
host: default_host(),
port: default_port(),
debug: false,
log_level: default_log_level(),
max_connections: default_max_connections(),
}
}
}
fn main() {
let environment = std::env::var("APP_ENV").unwrap_or_else(|_| "development".to_string());
println!("Loading configuration for environment: {}", environment);
println!();
let config = Config::<AppConfig>::builder()
.source(Defaults::from(AppConfig::default()))
.source(Toml::file("config/base.toml").optional())
.source(Toml::file(format!("config/{}.toml", environment)).optional())
.source(Env::prefix("APP_"))
.build()
.unwrap_or_else(|errors| {
eprintln!("Configuration errors ({}):", errors.len());
for error in errors.iter() {
eprintln!(" - {}", error);
}
std::process::exit(1);
});
println!("Final configuration:");
println!(" Host: {}", config.host);
println!(" Port: {}", config.port);
println!(" Debug: {}", config.debug);
println!(" Log Level: {}", config.log_level);
println!(" Max Connections: {}", config.max_connections);
println!();
match environment.as_str() {
"development" => {
println!("Running in DEVELOPMENT mode");
if config.debug {
println!(" Debug mode enabled - verbose logging active");
}
}
"production" => {
println!("Running in PRODUCTION mode");
if config.debug {
println!(" WARNING: Debug mode enabled in production!");
}
}
_ => {
println!("Running in {} mode", environment.to_uppercase());
}
}
}