Files
mixvideo-v2/apps/desktop/src-tauri/src/business/services/config_manager.rs
2025-08-08 15:09:25 +08:00

316 lines
10 KiB
Rust

//! 配置管理服务
//! 统一管理应用配置,支持配置验证和环境适配
use anyhow::{Result, anyhow};
use std::sync::Arc;
use tokio::sync::RwLock;
use tracing::{info, warn, error, debug};
use crate::config::{AppConfig, ComfyUISettings};
use crate::data::models::comfyui::{ComfyUIConfig, ValidationResult};
/// 环境类型
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum Environment {
/// 开发环境
Development,
/// 测试环境
Testing,
/// 生产环境
Production,
}
impl Environment {
/// 从环境变量获取环境类型
pub fn from_env() -> Self {
match std::env::var("MIXVIDEO_ENV").as_deref() {
Ok("production") | Ok("prod") => Environment::Production,
Ok("testing") | Ok("test") => Environment::Testing,
_ => Environment::Development,
}
}
/// 获取环境名称
pub fn name(&self) -> &'static str {
match self {
Environment::Development => "development",
Environment::Testing => "testing",
Environment::Production => "production",
}
}
}
/// 配置管理器
pub struct ConfigManager {
/// 应用配置
app_config: Arc<RwLock<AppConfig>>,
/// 当前环境
environment: Environment,
/// 配置文件路径
config_path: Option<String>,
}
impl ConfigManager {
/// 创建新的配置管理器
pub fn new(app_config: AppConfig, config_path: Option<String>) -> Self {
let environment = Environment::from_env();
info!("配置管理器初始化,环境: {}", environment.name());
Self {
app_config: Arc::new(RwLock::new(app_config)),
environment,
config_path,
}
}
/// 获取当前环境
pub fn get_environment(&self) -> &Environment {
&self.environment
}
/// 获取应用配置
pub async fn get_app_config(&self) -> AppConfig {
self.app_config.read().await.clone()
}
/// 更新应用配置
pub async fn update_app_config(&self, config: AppConfig) -> Result<()> {
// 验证配置
let validation = self.validate_app_config(&config).await?;
if !validation.valid {
return Err(anyhow!("配置验证失败: {:?}", validation.errors));
}
// 更新配置
*self.app_config.write().await = config;
// 保存到文件
self.save_config().await?;
info!("应用配置已更新");
Ok(())
}
/// 获取 ComfyUI 配置
pub async fn get_comfyui_config(&self) -> ComfyUIConfig {
let app_config = self.app_config.read().await;
let mut config = app_config.comfyui_settings.to_comfyui_config();
// 根据环境调整配置
self.apply_environment_config(&mut config);
config
}
/// 更新 ComfyUI 配置
pub async fn update_comfyui_config(&self, config: ComfyUIConfig) -> Result<()> {
// 验证配置
let validation = config.validate();
if !validation.valid {
return Err(anyhow!("ComfyUI 配置验证失败: {:?}", validation.errors));
}
// 更新应用配置中的 ComfyUI 设置
{
let mut app_config = self.app_config.write().await;
app_config.comfyui_settings.update_from_comfyui_config(&config);
}
// 保存到文件
self.save_config().await?;
info!("ComfyUI 配置已更新");
Ok(())
}
/// 获取 ComfyUI 设置
pub async fn get_comfyui_settings(&self) -> ComfyUISettings {
let app_config = self.app_config.read().await;
app_config.comfyui_settings.clone()
}
/// 更新 ComfyUI 设置
pub async fn update_comfyui_settings(&self, settings: ComfyUISettings) -> Result<()> {
// 验证设置
let validation = settings.validate();
if !validation.valid {
return Err(anyhow!("ComfyUI 设置验证失败: {:?}", validation.errors));
}
// 更新配置
{
let mut app_config = self.app_config.write().await;
app_config.comfyui_settings = settings;
}
// 保存到文件
self.save_config().await?;
info!("ComfyUI 设置已更新");
Ok(())
}
/// 重置 ComfyUI 配置为默认值
pub async fn reset_comfyui_config(&self) -> Result<()> {
let default_settings = ComfyUISettings::default();
self.update_comfyui_settings(default_settings).await
}
/// 验证应用配置
async fn validate_app_config(&self, config: &AppConfig) -> Result<ValidationResult> {
use crate::data::models::comfyui::{ValidationResult, SDKValidationError as ValidationError};
let mut result = ValidationResult::success();
// 验证主题
if !["light", "dark", "auto"].contains(&config.theme.as_str()) {
result.add_error(ValidationError::new("theme", "无效的主题设置"));
}
// 验证语言
if !["zh-CN", "en-US"].contains(&config.language.as_str()) {
result.add_error(ValidationError::new("language", "无效的语言设置"));
}
// 验证窗口大小
if config.window_size.width <= 0.0 || config.window_size.height <= 0.0 {
result.add_error(ValidationError::new("window_size", "窗口大小必须大于 0"));
}
// 验证 ComfyUI 设置
let comfyui_validation = config.comfyui_settings.validate();
for error in comfyui_validation.errors {
result.add_error(error);
}
Ok(result)
}
/// 根据环境调整配置
fn apply_environment_config(&self, config: &mut ComfyUIConfig) {
match self.environment {
Environment::Development => {
// 开发环境:启用详细日志,较短超时
config.timeout_seconds = std::cmp::min(config.timeout_seconds, 120);
config.retry_attempts = std::cmp::min(config.retry_attempts, 2);
debug!("应用开发环境配置");
}
Environment::Testing => {
// 测试环境:中等超时,适中重试
config.timeout_seconds = std::cmp::min(config.timeout_seconds, 180);
config.retry_attempts = std::cmp::min(config.retry_attempts, 3);
debug!("应用测试环境配置");
}
Environment::Production => {
// 生产环境:较长超时,更多重试
config.timeout_seconds = std::cmp::max(config.timeout_seconds, 300);
config.retry_attempts = std::cmp::max(config.retry_attempts, 3);
debug!("应用生产环境配置");
}
}
}
/// 保存配置到文件
async fn save_config(&self) -> Result<()> {
if let Some(config_path) = &self.config_path {
let app_config = self.app_config.read().await;
let config_json = serde_json::to_string_pretty(&*app_config)?;
tokio::fs::write(config_path, config_json).await
.map_err(|e| anyhow!("保存配置文件失败: {}", e))?;
debug!("配置已保存到: {}", config_path);
}
Ok(())
}
/// 从文件加载配置
pub async fn load_config(config_path: &str) -> Result<AppConfig> {
match tokio::fs::read_to_string(config_path).await {
Ok(content) => {
let config: AppConfig = serde_json::from_str(&content)
.map_err(|e| anyhow!("解析配置文件失败: {}", e))?;
info!("从文件加载配置: {}", config_path);
Ok(config)
}
Err(_) => {
warn!("配置文件不存在,使用默认配置: {}", config_path);
Ok(AppConfig::default())
}
}
}
/// 导出配置
pub async fn export_config(&self) -> Result<String> {
let app_config = self.app_config.read().await;
serde_json::to_string_pretty(&*app_config)
.map_err(|e| anyhow!("导出配置失败: {}", e))
}
/// 导入配置
pub async fn import_config(&self, config_json: &str) -> Result<()> {
let config: AppConfig = serde_json::from_str(config_json)
.map_err(|e| anyhow!("解析配置失败: {}", e))?;
self.update_app_config(config).await
}
/// 获取配置统计信息
pub async fn get_config_stats(&self) -> ConfigStats {
let app_config = self.app_config.read().await;
ConfigStats {
environment: self.environment.clone(),
config_path: self.config_path.clone(),
comfyui_enabled: app_config.comfyui_settings.enabled,
sdk_enabled: app_config.comfyui_settings.is_sdk_enabled(),
recent_projects_count: app_config.recent_projects.len(),
}
}
/// 检查配置健康状态
pub async fn health_check(&self) -> Result<ConfigHealthStatus> {
let app_config = self.app_config.read().await;
let validation = self.validate_app_config(&*app_config).await?;
let status = if validation.valid {
ConfigHealthStatus::Healthy
} else {
ConfigHealthStatus::Unhealthy(validation.errors)
};
Ok(status)
}
}
/// 配置统计信息
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ConfigStats {
pub environment: Environment,
pub config_path: Option<String>,
pub comfyui_enabled: bool,
pub sdk_enabled: bool,
pub recent_projects_count: usize,
}
/// 配置健康状态
#[derive(Debug, Clone)]
pub enum ConfigHealthStatus {
/// 健康
Healthy,
/// 不健康
Unhealthy(Vec<crate::data::models::comfyui::ValidationError>),
}
impl std::fmt::Display for ConfigHealthStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ConfigHealthStatus::Healthy => write!(f, "健康"),
ConfigHealthStatus::Unhealthy(errors) => {
write!(f, "不健康 ({} 个错误)", errors.len())
}
}
}
}