Files
appks/config/mod.rs
T
zhenyi b83a842c6f fix(core): remove unwrap/expect in non-test code
- cache/lru.rs: replace lock().unwrap() with if let Ok guard,
  consistent with other lock acquisitions in the same file
- service/repo/core.rs: replace try_into().unwrap() with
  copy_from_slice which is infallible for fixed-size slices
- service/auth/rsa.rs: replace 3 expect() calls with map_err()
  for ChaCha20Poly1305 key init and session key retrieval
- config/mod.rs: replace GLOBAL_CONFIG.get().expect() with
  unwrap_or_else fallback to empty config
2026-06-10 18:48:49 +08:00

92 lines
2.6 KiB
Rust

use crate::error::{AppError, AppResult};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::str::FromStr;
use tokio::sync::OnceCell;
pub static GLOBAL_CONFIG: OnceCell<AppConfig> = OnceCell::const_new();
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct AppConfig {
pub env: HashMap<String, String>,
}
impl AppConfig {
pub fn main_domain(&self) -> AppResult<String> {
self.get_env::<String>("APP_MAIN_DOMAIN")?
.filter(|s| !s.is_empty())
.ok_or_else(|| AppError::Config("APP_MAIN_DOMAIN is not set".into()))
}
pub const ENV_FILES: &'static [&'static str] = &[
".env",
".env.local",
".env.development",
".env.development.local",
".env.test",
".env.test.local",
".env.production",
".env.production.local",
];
pub fn get_env<T: FromStr>(&self, key: &str) -> AppResult<Option<T>>
where
<T as FromStr>::Err: std::fmt::Display,
{
match self.env.get(key) {
Some(v) if !v.is_empty() => Ok(Some(
v.parse::<T>().map_err(|e| AppError::Parse(e.to_string()))?,
)),
Some(_) => Ok(None),
None => Ok(None),
}
}
pub fn get_env_or<T: FromStr>(&self, key: &str, default: T) -> AppResult<T>
where
<T as FromStr>::Err: std::fmt::Display,
{
Ok(self.get_env(key)?.unwrap_or(default))
}
pub fn load() -> AppConfig {
dotenvy::dotenv().ok();
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());
}
}
}
}
env = env.into_iter().chain(std::env::vars()).collect();
let this = AppConfig { env };
if let Some(config) = GLOBAL_CONFIG.get() {
config.clone()
} else {
let _ = GLOBAL_CONFIG.set(this);
GLOBAL_CONFIG
.get()
.cloned()
.unwrap_or_else(|| AppConfig { env: HashMap::new() })
}
}
}
pub mod aiprovider;
pub mod app;
pub mod channelaiprovider;
pub mod database;
pub mod embedaiprovider;
pub mod etcd;
pub mod lru;
pub mod nats;
pub mod qdrant;
pub mod redis;
pub mod rpc;
pub mod s3;