Files
mixvideo-v2/apps/desktop/src-tauri/src/business/services/tauri_event_emitter.rs

278 lines
9.5 KiB
Rust

//! Tauri 事件发射器
//! 将实时事件发送到前端的服务
use anyhow::Result;
use std::sync::Arc;
use tauri::{AppHandle, Manager};
use tokio::sync::broadcast;
use tracing::{info, warn, error, debug};
use serde::{Serialize, Deserialize};
use crate::business::services::realtime_monitor_v2::{RealtimeEventV2, EventSubscriber};
/// Tauri 事件名称常量
pub mod events {
pub const COMFYUI_CONNECTION_CHANGED: &str = "comfyui://connection-changed";
pub const COMFYUI_EXECUTION_STARTED: &str = "comfyui://execution-started";
pub const COMFYUI_EXECUTION_PROGRESS: &str = "comfyui://execution-progress";
pub const COMFYUI_NODE_EXECUTING: &str = "comfyui://node-executing";
pub const COMFYUI_EXECUTION_COMPLETED: &str = "comfyui://execution-completed";
pub const COMFYUI_EXECUTION_FAILED: &str = "comfyui://execution-failed";
pub const COMFYUI_QUEUE_UPDATED: &str = "comfyui://queue-updated";
pub const COMFYUI_SYSTEM_STATUS_UPDATED: &str = "comfyui://system-status-updated";
}
/// 前端事件数据结构
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FrontendEvent {
pub event_type: String,
pub data: serde_json::Value,
pub timestamp: String,
}
/// Tauri 事件发射器
pub struct TauriEventEmitter {
app_handle: AppHandle,
event_receiver: Option<broadcast::Receiver<RealtimeEventV2>>,
is_running: Arc<tokio::sync::RwLock<bool>>,
task_handle: Arc<tokio::sync::RwLock<Option<tokio::task::JoinHandle<()>>>>,
}
impl TauriEventEmitter {
/// 创建新的事件发射器
pub fn new(app_handle: AppHandle) -> Self {
Self {
app_handle,
event_receiver: None,
is_running: Arc::new(tokio::sync::RwLock::new(false)),
task_handle: Arc::new(tokio::sync::RwLock::new(None)),
}
}
/// 启动事件发射器
pub async fn start(&mut self, mut event_receiver: broadcast::Receiver<RealtimeEventV2>) -> Result<()> {
info!("启动 Tauri 事件发射器");
// 检查是否已经在运行
{
let running = self.is_running.read().await;
if *running {
return Ok(());
}
}
let app_handle = self.app_handle.clone();
let is_running = Arc::clone(&self.is_running);
// 启动事件处理任务
let handle = tokio::spawn(async move {
{
let mut running = is_running.write().await;
*running = true;
}
info!("Tauri 事件发射器已启动");
while let Ok(event) = event_receiver.recv().await {
if let Err(e) = Self::emit_to_frontend(&app_handle, &event).await {
error!("发送事件到前端失败: {}", e);
}
}
{
let mut running = is_running.write().await;
*running = false;
}
info!("Tauri 事件发射器已停止");
});
{
let mut task_handle = self.task_handle.write().await;
*task_handle = Some(handle);
}
Ok(())
}
/// 停止事件发射器
pub async fn stop(&self) -> Result<()> {
info!("停止 Tauri 事件发射器");
let handle = {
let mut task_handle = self.task_handle.write().await;
task_handle.take()
};
if let Some(handle) = handle {
handle.abort();
}
{
let mut running = self.is_running.write().await;
*running = false;
}
Ok(())
}
/// 检查是否正在运行
pub async fn is_running(&self) -> bool {
*self.is_running.read().await
}
/// 发送事件到前端
async fn emit_to_frontend(app_handle: &AppHandle, event: &RealtimeEventV2) -> Result<()> {
let (event_name, event_data) = Self::convert_event_for_frontend(event);
let frontend_event = FrontendEvent {
event_type: event_name.clone(),
data: event_data,
timestamp: chrono::Utc::now().to_rfc3339(),
};
// 发送到前端
app_handle.emit_all(&event_name, &frontend_event)
.map_err(|e| anyhow::anyhow!("发送事件失败: {}", e))?;
debug!("已发送事件到前端: {}", event_name);
Ok(())
}
/// 转换事件为前端格式
fn convert_event_for_frontend(event: &RealtimeEventV2) -> (String, serde_json::Value) {
match event {
RealtimeEventV2::ConnectionChanged { connected, message, timestamp } => (
events::COMFYUI_CONNECTION_CHANGED.to_string(),
serde_json::json!({
"connected": connected,
"message": message,
"timestamp": timestamp
})
),
RealtimeEventV2::ExecutionStarted { prompt_id, execution_id, node_id, timestamp } => (
events::COMFYUI_EXECUTION_STARTED.to_string(),
serde_json::json!({
"prompt_id": prompt_id,
"execution_id": execution_id,
"node_id": node_id,
"timestamp": timestamp
})
),
RealtimeEventV2::ExecutionProgress { prompt_id, execution_id, node_id, progress, max_progress, percentage, timestamp } => (
events::COMFYUI_EXECUTION_PROGRESS.to_string(),
serde_json::json!({
"prompt_id": prompt_id,
"execution_id": execution_id,
"node_id": node_id,
"progress": progress,
"max_progress": max_progress,
"percentage": percentage,
"timestamp": timestamp
})
),
RealtimeEventV2::NodeExecuting { prompt_id, execution_id, node_id, node_title, timestamp } => (
events::COMFYUI_NODE_EXECUTING.to_string(),
serde_json::json!({
"prompt_id": prompt_id,
"execution_id": execution_id,
"node_id": node_id,
"node_title": node_title,
"timestamp": timestamp
})
),
RealtimeEventV2::ExecutionCompleted { prompt_id, execution_id, outputs, output_urls, execution_time, timestamp } => (
events::COMFYUI_EXECUTION_COMPLETED.to_string(),
serde_json::json!({
"prompt_id": prompt_id,
"execution_id": execution_id,
"outputs": outputs,
"output_urls": output_urls,
"execution_time": execution_time,
"timestamp": timestamp
})
),
RealtimeEventV2::ExecutionFailed { prompt_id, execution_id, node_id, error, details, timestamp } => (
events::COMFYUI_EXECUTION_FAILED.to_string(),
serde_json::json!({
"prompt_id": prompt_id,
"execution_id": execution_id,
"node_id": node_id,
"error": error,
"details": details,
"timestamp": timestamp
})
),
RealtimeEventV2::QueueUpdated { running_count, pending_count, timestamp } => (
events::COMFYUI_QUEUE_UPDATED.to_string(),
serde_json::json!({
"running_count": running_count,
"pending_count": pending_count,
"timestamp": timestamp
})
),
RealtimeEventV2::SystemStatusUpdated { memory_usage, gpu_usage, active_connections, timestamp } => (
events::COMFYUI_SYSTEM_STATUS_UPDATED.to_string(),
serde_json::json!({
"memory_usage": memory_usage,
"gpu_usage": gpu_usage,
"active_connections": active_connections,
"timestamp": timestamp
})
),
}
}
}
impl EventSubscriber for TauriEventEmitter {
fn handle_event(&self, event: &RealtimeEventV2) {
let app_handle = self.app_handle.clone();
let event = event.clone();
// 异步发送事件
tokio::spawn(async move {
if let Err(e) = Self::emit_to_frontend(&app_handle, &event).await {
error!("发送事件到前端失败: {}", e);
}
});
}
}
/// 事件发射器管理器
pub struct EventEmitterManager {
emitters: Vec<Arc<TauriEventEmitter>>,
}
impl EventEmitterManager {
/// 创建新的管理器
pub fn new() -> Self {
Self {
emitters: Vec::new(),
}
}
/// 添加发射器
pub fn add_emitter(&mut self, emitter: Arc<TauriEventEmitter>) {
self.emitters.push(emitter);
}
/// 启动所有发射器
pub async fn start_all(&mut self, event_receiver: broadcast::Receiver<RealtimeEventV2>) -> Result<()> {
for emitter in &mut self.emitters {
// 为每个发射器创建独立的接收器
let receiver = event_receiver.resubscribe();
// 注意:这里需要获取可变引用,但 Arc 不允许
// 实际实现中可能需要重新设计架构
}
Ok(())
}
/// 停止所有发射器
pub async fn stop_all(&self) -> Result<()> {
for emitter in &self.emitters {
emitter.stop().await?;
}
Ok(())
}
}