feat: init

This commit is contained in:
zhenyi
2026-06-07 11:30:56 +08:00
commit 563381c1ca
361 changed files with 41327 additions and 0 deletions
+90
View File
@@ -0,0 +1,90 @@
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 {
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()
.expect("global config should be set after load")
.clone()
}
}
}
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;