58 lines
1.7 KiB
Rust
58 lines
1.7 KiB
Rust
use std::collections::HashMap;
|
|
use std::sync::OnceLock;
|
|
|
|
pub static GLOBAL_CONFIG: OnceLock<AppConfig> = OnceLock::new();
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct AppConfig {
|
|
pub env: HashMap<String, String>,
|
|
}
|
|
|
|
impl AppConfig {
|
|
const ENV_FILES: &'static [&'static str] = &[".env", ".env.local"];
|
|
pub fn load() -> AppConfig {
|
|
let mut env = HashMap::new();
|
|
for env_file in AppConfig::ENV_FILES {
|
|
if let Err(e) = dotenvy::from_path(env_file) {
|
|
tracing::debug!(file = %env_file, error = %e, "dotenv load skipped");
|
|
}
|
|
if let Ok(env_file_content) = std::fs::read_to_string(env_file) {
|
|
for line in env_file_content.lines() {
|
|
if let Some((key, value)) = line.split_once('=') {
|
|
env.insert(key.to_string(), value.to_string());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Environment variables (e.g. K8s injected APP_DOMAIN_URL) take precedence over .env files
|
|
env = std::env::vars().chain(env).collect();
|
|
let this = AppConfig { env };
|
|
// Handle the race condition: if another thread already set the global, return it.
|
|
// This is safe because config is immutable after load.
|
|
if GLOBAL_CONFIG.get().is_some() {
|
|
GLOBAL_CONFIG.get().unwrap().clone()
|
|
} else {
|
|
let _ = GLOBAL_CONFIG.set(this);
|
|
GLOBAL_CONFIG
|
|
.get()
|
|
.expect("global config should be set after load")
|
|
.clone()
|
|
}
|
|
}
|
|
}
|
|
|
|
pub mod ai;
|
|
pub mod app;
|
|
pub mod avatar;
|
|
pub mod database;
|
|
pub mod domain;
|
|
pub mod embed;
|
|
pub mod hook;
|
|
pub mod logs;
|
|
pub mod nats;
|
|
pub mod qdrant;
|
|
pub mod redis;
|
|
pub mod smtp;
|
|
pub mod ssh;
|
|
pub mod storage;
|