use crate::{Result, configuration_error, validation_error, with_context};
use openlark_core::config::{Config, ConfigSummary};
use openlark_core::error::ErrorTrait;
use std::env;
pub struct EnvConfig {
pub app_id: String,
pub app_secret: String,
}
pub fn check_env_config() -> Result<EnvConfig> {
let app_id = env::var("OPENLARK_APP_ID")
.map_err(|_| configuration_error("环境变量检查失败 [variable: OPENLARK_APP_ID]"))?;
if app_id.is_empty() {
return with_context(
Err(validation_error(
"OPENLARK_APP_ID",
"应用ID环境变量不能为空",
)),
"validation",
"env_config",
);
}
let app_secret = env::var("OPENLARK_APP_SECRET")
.map_err(|_| configuration_error("环境变量检查失败 [variable: OPENLARK_APP_SECRET]"))?;
if app_secret.is_empty() {
return with_context(
Err(validation_error(
"OPENLARK_APP_SECRET",
"应用密钥环境变量不能为空",
)),
"validation",
"env_config",
);
}
if let Ok(base_url) = env::var("OPENLARK_BASE_URL")
&& !base_url.starts_with("http://")
&& !base_url.starts_with("https://")
{
return with_context(
Err(validation_error(
"OPENLARK_BASE_URL",
"基础URL必须以http://或https://开头",
)),
"validation",
"env_config",
);
}
if let Ok(timeout_str) = env::var("OPENLARK_TIMEOUT")
&& timeout_str.parse::<u64>().is_err()
{
return with_context(
Err(validation_error(
"OPENLARK_TIMEOUT",
"超时设置必须是有效的数字(秒数)",
)),
"validation",
"env_config",
);
}
Ok(EnvConfig { app_id, app_secret })
}
pub fn create_config_from_env() -> Result<Config> {
check_env_config()?;
Ok(Config::from_env())
}
pub fn get_config_summary(config: &Config) -> ConfigSummary {
config.summary()
}
pub fn get_enabled_features() -> Vec<&'static str> {
#[allow(unused_mut)]
let mut features = vec!["auth"];
#[cfg(feature = "communication")]
features.push("communication");
#[cfg(feature = "docs")]
features.push("docs");
#[cfg(feature = "security")]
features.push("security");
#[cfg(feature = "hr")]
features.push("hr");
#[cfg(feature = "ai")]
features.push("ai");
features
}
pub fn validate_feature_dependencies() -> Result<Vec<String>> {
let enabled_features = get_enabled_features();
let mut issues = Vec::new();
if enabled_features.contains(&"communication") && !enabled_features.contains(&"auth") {
issues.push("通讯服务 (communication) 需要启用认证服务 (auth)".to_string());
}
if enabled_features.contains(&"docs") && !enabled_features.contains(&"auth") {
issues.push("文档服务 (docs) 需要启用认证服务 (auth)".to_string());
}
if enabled_features.contains(&"hr") && !enabled_features.contains(&"auth") {
issues.push("人力资源服务 (hr) 需要启用认证服务 (auth)".to_string());
}
if enabled_features.contains(&"ai") && !enabled_features.contains(&"auth") {
issues.push("AI服务 (ai) 需要启用认证服务 (auth)".to_string());
}
if enabled_features.contains(&"calendar") && !enabled_features.contains(&"auth") {
issues.push("日历服务 (calendar) 需要启用认证服务 (auth)".to_string());
}
if enabled_features.contains(&"admin") && !enabled_features.contains(&"hr") {
issues.push("管理服务 (admin) 建议启用人力资源服务 (hr) 以获得完整功能".to_string());
}
if enabled_features.contains(&"approval") && !enabled_features.contains(&"auth") {
issues.push("审批服务 (approval) 需要启用认证服务 (auth)".to_string());
}
if issues.is_empty() {
Ok(issues)
} else {
with_context(
Err(configuration_error(format!(
"发现 {} 个功能依赖问题: {}",
issues.len(),
issues.join("; ")
))),
"validation",
"feature_dependencies",
)
}
}
pub fn diagnose_system() -> SystemDiagnostics {
let mut diagnostics = SystemDiagnostics::new();
match check_env_config() {
Ok(_) => {
diagnostics.env_config_status = "✅ 正常".to_string();
}
Err(error) => {
diagnostics.env_config_status =
format!("❌ {}", error.user_message().unwrap_or("未知错误"));
diagnostics.add_issue("环境变量", error.user_message().unwrap_or("未知错误"));
}
}
match validate_feature_dependencies() {
Ok(_) => {
diagnostics.feature_deps_status = "✅ 正常".to_string();
}
Err(error) => {
diagnostics.feature_deps_status =
format!("❌ {}", error.user_message().unwrap_or("未知错误"));
diagnostics.add_issue("功能依赖", error.user_message().unwrap_or("未知错误"));
}
}
diagnostics.enabled_features = get_enabled_features()
.into_iter()
.map(|s| s.to_string())
.collect();
diagnostics
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct SystemDiagnostics {
pub env_config_status: String,
pub feature_deps_status: String,
pub enabled_features: Vec<String>,
pub issues: Vec<DiagnosticIssue>,
}
impl SystemDiagnostics {
pub fn new() -> Self {
Self {
env_config_status: "未检查".to_string(),
feature_deps_status: "未检查".to_string(),
enabled_features: Vec::new(),
issues: Vec::new(),
}
}
pub fn add_issue(&mut self, category: &str, description: &str) {
self.issues.push(DiagnosticIssue {
category: category.to_string(),
description: description.to_string(),
});
}
pub fn health_summary(&self) -> String {
let healthy_count = self.issues.len();
if healthy_count == 0 {
"🟢 系统配置健康".to_string()
} else {
format!("🟡 发现 {healthy_count} 个配置问题")
}
}
pub fn has_critical_issues(&self) -> bool {
self.issues
.iter()
.any(|issue| issue.category.contains("环境变量") || issue.category.contains("功能依赖"))
}
}
impl Default for SystemDiagnostics {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct DiagnosticIssue {
pub category: String,
pub description: String,
}