Skip to content
Clone
e478cc4
108 lines 2.7 KB Rust
use std::path::PathBuf;
use crate::app::AppConfig;
use crate::error::{ConfigError, ConfigResult};
#[derive(Debug, Clone)]
pub struct ConfigLoader {
config_file: Option<PathBuf>,
local_config_file: Option<PathBuf>,
env_prefix: String,
use_env: bool,
use_dotenv: bool,
validate: bool,
}
impl Default for ConfigLoader {
fn default() -> Self {
Self::new()
}
}
impl ConfigLoader {
pub fn new() -> Self {
Self {
config_file: Some(PathBuf::from("config/default.yaml")),
local_config_file: Some(PathBuf::from("config/local.yaml")),
env_prefix: "APP".to_string(),
use_env: true,
use_dotenv: true,
validate: true,
}
}
pub fn config_file(mut self, path: impl Into<PathBuf>) -> Self {
self.config_file = Some(path.into());
self
}
pub fn local_config_file(mut self, path: impl Into<PathBuf>) -> Self {
self.local_config_file = Some(path.into());
self
}
pub fn no_config_file(mut self) -> Self {
self.config_file = None;
self
}
pub fn no_local_config_file(mut self) -> Self {
self.local_config_file = None;
self
}
pub fn env_prefix(mut self, prefix: impl Into<String>) -> Self {
self.env_prefix = prefix.into();
self
}
pub fn no_env(mut self) -> Self {
self.use_env = false;
self
}
pub fn no_dotenv(mut self) -> Self {
self.use_dotenv = false;
self
}
pub fn validate(mut self, on: bool) -> Self {
self.validate = on;
self
}
pub fn load(self) -> ConfigResult<AppConfig> {
if self.use_dotenv {
let _ = dotenvy::dotenv();
}
let mut builder = config_rs::Config::builder();
if let Some(path) = self.config_file {
builder = builder
.add_source(config_rs::File::with_name(&path.to_string_lossy()).required(false));
}
if let Some(path) = self.local_config_file {
builder = builder
.add_source(config_rs::File::with_name(&path.to_string_lossy()).required(false));
}
if self.use_env {
builder = builder.add_source(
config_rs::Environment::with_prefix(&self.env_prefix)
.prefix_separator("_")
.separator("__")
.try_parsing(true),
);
}
let conf = builder.build()?;
let app: AppConfig = conf.try_deserialize()?;
if self.validate {
app.validate().map_err(ConfigError::Validation)?;
}
Ok(app)
}
}
pub fn load() -> ConfigResult<AppConfig> {
ConfigLoader::new().load()
}