278 lines
9.5 KiB
Rust
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(())
|
|
}
|
|
}
|