feat: 实时通信与高级功能
This commit is contained in:
@@ -0,0 +1,277 @@
|
||||
//! 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(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user