mixvideo-v2/apps/desktop/src-tauri/src/app_state.rs

214 lines
9.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use std::sync::{Arc, Mutex};
use crate::data::repositories::project_repository::ProjectRepository;
use crate::data::repositories::material_repository::MaterialRepository;
use crate::data::repositories::model_repository::ModelRepository;
use crate::data::repositories::model_dynamic_repository::ModelDynamicRepository;
use crate::data::repositories::video_generation_repository::VideoGenerationRepository;
use crate::data::repositories::conversation_repository::ConversationRepository;
use crate::data::repositories::outfit_photo_generation_repository::OutfitPhotoGenerationRepository;
use crate::infrastructure::database::Database;
use crate::infrastructure::performance::PerformanceMonitor;
use crate::infrastructure::event_bus::EventBusManager;
/// 应用全局状态管理
/// 遵循 Tauri 开发规范的状态管理模式
pub struct AppState {
pub database: Mutex<Option<Arc<Database>>>,
pub project_repository: Mutex<Option<ProjectRepository>>,
pub material_repository: Mutex<Option<MaterialRepository>>,
pub model_repository: Mutex<Option<ModelRepository>>,
pub model_dynamic_repository: Mutex<Option<ModelDynamicRepository>>,
pub video_generation_repository: Mutex<Option<VideoGenerationRepository>>,
pub conversation_repository: Mutex<Option<Arc<ConversationRepository>>>,
pub outfit_photo_generation_repository: Mutex<Option<OutfitPhotoGenerationRepository>>,
pub performance_monitor: Mutex<PerformanceMonitor>,
pub event_bus_manager: Arc<EventBusManager>,
}
impl AppState {
pub fn new() -> Self {
Self {
database: Mutex::new(None),
project_repository: Mutex::new(None),
material_repository: Mutex::new(None),
model_repository: Mutex::new(None),
model_dynamic_repository: Mutex::new(None),
video_generation_repository: Mutex::new(None),
conversation_repository: Mutex::new(None),
outfit_photo_generation_repository: Mutex::new(None),
performance_monitor: Mutex::new(PerformanceMonitor::new()),
event_bus_manager: Arc::new(EventBusManager::new()),
}
}
/// 初始化数据库连接
/// 遵循安全第一原则,确保数据库初始化的安全性
/// 默认使用连接池模式以提高并发性能
pub fn initialize_database(&self) -> anyhow::Result<()> {
println!("开始初始化数据库连接...");
// 暂时使用单连接模式,避免锁竞争问题
// TODO: 在解决 SQLite 锁问题后重新启用连接池
let database = Arc::new(Database::new()?);
println!("使用单连接模式初始化数据库");
// 连接池模式代码(暂时注释)
/*
let database = match Database::new_with_pool() {
Ok(db) => {
println!("连接池模式初始化成功");
Arc::new(db)
},
Err(e) => {
eprintln!("连接池模式初始化失败: {}, 回退到单连接模式", e);
Arc::new(Database::new()?)
}
};
*/
let project_repository = ProjectRepository::new(database.clone())?;
let material_repository = MaterialRepository::new(database.clone())?;
let model_repository = ModelRepository::new(database.clone());
let model_dynamic_repository = ModelDynamicRepository::new(database.clone());
let video_generation_repository = VideoGenerationRepository::new(database.clone());
let conversation_repository = Arc::new(ConversationRepository::new(database.clone()));
// 初始化数据库表
model_dynamic_repository.init_tables()?;
video_generation_repository.init_tables()?;
conversation_repository.initialize_tables()?;
// 初始化穿搭图片相关表
let outfit_image_repository = crate::data::repositories::outfit_image_repository::OutfitImageRepository::new(database.clone());
outfit_image_repository.init_tables()?;
// 初始化穿搭照片生成相关表
let outfit_photo_generation_repository = OutfitPhotoGenerationRepository::new(database.clone())?;
*self.database.lock().unwrap() = Some(database.clone());
*self.project_repository.lock().unwrap() = Some(project_repository);
*self.material_repository.lock().unwrap() = Some(material_repository);
*self.model_repository.lock().unwrap() = Some(model_repository);
*self.model_dynamic_repository.lock().unwrap() = Some(model_dynamic_repository);
*self.video_generation_repository.lock().unwrap() = Some(video_generation_repository);
*self.conversation_repository.lock().unwrap() = Some(conversation_repository);
*self.outfit_photo_generation_repository.lock().unwrap() = Some(outfit_photo_generation_repository);
println!("数据库初始化完成,连接池状态: {}",
if database.has_pool() { "已启用" } else { "未启用" });
Ok(())
}
/// 初始化数据库连接(单连接模式,用于测试或特殊场景)
pub fn initialize_database_single_mode(&self) -> anyhow::Result<()> {
let database = Arc::new(Database::new()?);
let project_repository = ProjectRepository::new(database.clone())?;
let material_repository = MaterialRepository::new(database.clone())?;
let model_repository = ModelRepository::new(database.clone());
let model_dynamic_repository = ModelDynamicRepository::new(database.clone());
let video_generation_repository = VideoGenerationRepository::new(database.clone());
let conversation_repository = Arc::new(ConversationRepository::new(database.clone()));
// 初始化数据库表
model_dynamic_repository.init_tables()?;
video_generation_repository.init_tables()?;
conversation_repository.initialize_tables()?;
// 初始化穿搭图片相关表
let outfit_image_repository = crate::data::repositories::outfit_image_repository::OutfitImageRepository::new(database.clone());
outfit_image_repository.init_tables()?;
// 初始化穿搭照片生成相关表
let outfit_photo_generation_repository = OutfitPhotoGenerationRepository::new(database.clone())?;
*self.database.lock().unwrap() = Some(database.clone());
*self.project_repository.lock().unwrap() = Some(project_repository);
*self.material_repository.lock().unwrap() = Some(material_repository);
*self.model_repository.lock().unwrap() = Some(model_repository);
*self.model_dynamic_repository.lock().unwrap() = Some(model_dynamic_repository);
*self.video_generation_repository.lock().unwrap() = Some(video_generation_repository);
*self.conversation_repository.lock().unwrap() = Some(conversation_repository);
*self.outfit_photo_generation_repository.lock().unwrap() = Some(outfit_photo_generation_repository);
println!("数据库初始化完成,使用单连接模式");
Ok(())
}
/// 获取项目仓库实例
pub fn get_project_repository(&self) -> anyhow::Result<std::sync::MutexGuard<Option<ProjectRepository>>> {
Ok(self.project_repository.lock().unwrap())
}
/// 获取素材仓库实例
pub fn get_material_repository(&self) -> anyhow::Result<std::sync::MutexGuard<Option<MaterialRepository>>> {
Ok(self.material_repository.lock().unwrap())
}
/// 获取模特仓库实例
pub fn get_model_repository(&self) -> anyhow::Result<std::sync::MutexGuard<Option<ModelRepository>>> {
Ok(self.model_repository.lock().unwrap())
}
/// 获取模特动态仓库实例
pub fn get_model_dynamic_repository(&self) -> anyhow::Result<std::sync::MutexGuard<Option<ModelDynamicRepository>>> {
Ok(self.model_dynamic_repository.lock().unwrap())
}
/// 获取视频生成仓库实例
pub fn get_video_generation_repository(&self) -> anyhow::Result<std::sync::MutexGuard<Option<VideoGenerationRepository>>> {
Ok(self.video_generation_repository.lock().unwrap())
}
/// 获取会话仓库实例
pub fn get_conversation_repository(&self) -> anyhow::Result<Arc<ConversationRepository>> {
let repo_guard = self.conversation_repository.lock().unwrap();
repo_guard.as_ref()
.ok_or_else(|| anyhow::anyhow!("会话仓库未初始化"))
.map(|repo| repo.clone())
}
/// 获取数据库实例
pub fn get_database(&self) -> Arc<Database> {
// 使用全局静态数据库实例,确保整个应用只有一个数据库实例
use std::sync::OnceLock;
static DATABASE_INSTANCE: OnceLock<Arc<Database>> = OnceLock::new();
DATABASE_INSTANCE.get_or_init(|| {
// 只在第一次调用时初始化数据库
Arc::new(Database::new().unwrap())
}).clone()
}
/// 获取数据库连接
pub fn get_connection(&self) -> anyhow::Result<std::sync::Arc<std::sync::Mutex<rusqlite::Connection>>> {
let database = self.get_database();
Ok(database.get_connection())
}
/// 用于测试的构造函数
#[cfg(test)]
pub fn new_with_database(_database: Arc<Database>) -> Self {
let state = Self {
database: Mutex::new(None),
project_repository: Mutex::new(None),
material_repository: Mutex::new(None),
model_repository: Mutex::new(None),
model_dynamic_repository: Mutex::new(None),
video_generation_repository: Mutex::new(None),
conversation_repository: Mutex::new(None),
outfit_photo_generation_repository: Mutex::new(None),
performance_monitor: Mutex::new(PerformanceMonitor::new()),
event_bus_manager: Arc::new(EventBusManager::new()),
};
// 不直接存储database而是在需要时返回传入的database
state
}
}
impl Default for AppState {
fn default() -> Self {
Self::new()
}
}