use std::time::Duration;
#[derive(Debug, Clone)]
pub struct Config {
pub base_url: String,
pub timeout: Duration,
pub retries: u32,
pub log_level: String,
pub deploy_strategy: DeployStrategy,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DeployStrategy {
Remote,
Local,
Mock,
}
#[derive(Debug, Clone, Default)]
pub struct ConfigBuilder {
base_url: Option<String>,
timeout: Option<Duration>,
retries: Option<u32>,
log_level: Option<String>,
deploy_strategy: Option<DeployStrategy>,
}
impl ConfigBuilder {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn base_url(mut self, base_url: impl Into<String>) -> Self {
self.base_url = Some(base_url.into());
self
}
#[must_use]
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
#[must_use]
pub fn retries(mut self, retries: u32) -> Self {
self.retries = Some(retries);
self
}
#[must_use]
pub fn log_level(mut self, log_level: impl Into<String>) -> Self {
self.log_level = Some(log_level.into());
self
}
#[must_use]
pub fn deploy_strategy(mut self, strategy: DeployStrategy) -> Self {
self.deploy_strategy = Some(strategy);
self
}
#[must_use]
pub fn build(self) -> Config {
Config {
base_url: self.base_url.unwrap_or_else(|| {
std::env::var("SERVERLESS_BASE_URL")
.unwrap_or_else(|_| "http://localhost:3000".to_string())
}),
timeout: self.timeout.unwrap_or_else(|| {
Duration::from_millis(
std::env::var("SERVERLESS_TIMEOUT")
.unwrap_or_else(|_| "30000".to_string())
.parse()
.unwrap_or(30_000),
)
}),
retries: self.retries.unwrap_or_else(|| {
std::env::var("SERVERLESS_RETRIES")
.unwrap_or_else(|_| "3".to_string())
.parse()
.unwrap_or(3)
}),
log_level: self.log_level.unwrap_or_else(|| {
std::env::var("SERVERLESS_LOG_LEVEL").unwrap_or_else(|_| "info".to_string())
}),
deploy_strategy: self
.deploy_strategy
.unwrap_or_else(Config::determine_deploy_strategy),
}
}
}
impl Config {
#[must_use]
pub fn builder() -> ConfigBuilder {
ConfigBuilder::new()
}
#[must_use]
pub fn from_env() -> Self {
let deploy_strategy = Self::determine_deploy_strategy();
Self {
base_url: std::env::var("SERVERLESS_BASE_URL")
.unwrap_or_else(|_| "http://localhost:3000".to_string()),
timeout: Duration::from_millis(
std::env::var("SERVERLESS_TIMEOUT")
.unwrap_or_else(|_| "30000".to_string())
.parse()
.unwrap_or(30_000),
),
retries: std::env::var("SERVERLESS_RETRIES")
.unwrap_or_else(|_| "3".to_string())
.parse()
.unwrap_or(3),
log_level: std::env::var("SERVERLESS_LOG_LEVEL").unwrap_or_else(|_| "info".to_string()),
deploy_strategy,
}
}
fn determine_deploy_strategy() -> DeployStrategy {
if cfg!(feature = "mock_server") {
DeployStrategy::Mock
} else if cfg!(feature = "local_call") {
DeployStrategy::Local
} else {
DeployStrategy::Remote
}
}
#[must_use]
pub fn deploy_strategy(&self) -> &DeployStrategy {
&self.deploy_strategy
}
#[must_use]
pub fn base_url(&self) -> &str {
&self.base_url
}
#[must_use]
pub fn timeout(&self) -> Duration {
self.timeout
}
#[must_use]
pub fn retries(&self) -> u32 {
self.retries
}
#[must_use]
pub fn log_level(&self) -> &str {
&self.log_level
}
pub fn init_logging(&self) {
use tracing_subscriber::{EnvFilter, fmt};
let env_filter =
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(&self.log_level));
fmt().with_env_filter(env_filter).init();
}
}
impl Default for Config {
fn default() -> Self {
Self::from_env()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_config_default() {
let config = Config::default();
assert_eq!(config.base_url, "http://localhost:3000");
assert_eq!(config.timeout, Duration::from_millis(30_000));
assert_eq!(config.retries, 3);
assert_eq!(config.log_level, "info");
}
#[test]
fn test_deploy_strategy_remote() {
if !cfg!(feature = "mock_server") && !cfg!(feature = "local_call") {
let config = Config::default();
assert_eq!(*config.deploy_strategy(), DeployStrategy::Remote);
}
}
#[test]
fn test_config_builder() {
let config = Config::builder()
.base_url("http://localhost:8080")
.timeout(Duration::from_secs(60))
.retries(5)
.log_level("debug")
.build();
assert_eq!(config.base_url, "http://localhost:8080");
assert_eq!(config.timeout, Duration::from_secs(60));
assert_eq!(config.retries, 5);
assert_eq!(config.log_level, "debug");
}
}