b83a842c6f
- 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
92 lines
2.6 KiB
Rust
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;
|