diff --git a/src-tauri/crates/core/src/event_emit.rs b/src-tauri/crates/core/src/event_emit.rs new file mode 100644 index 000000000..54d69c767 --- /dev/null +++ b/src-tauri/crates/core/src/event_emit.rs @@ -0,0 +1,47 @@ +//! 通用事件发射 trait +//! +//! 提供与 Tauri 解耦的事件发射抽象,供独立 crate 使用。 +//! 主 crate 通过实现 `EventEmit` trait 注入 Tauri 的 `AppHandle.emit()`。 + +use std::sync::Arc; + +/// 事件发射 trait +/// +/// 所有需要向前端发送事件的 crate 都通过此 trait 抽象, +/// 避免直接依赖 Tauri。 +pub trait EventEmit: Send + Sync + 'static { + /// 发送事件 + /// + /// # Arguments + /// * `event` - 事件名称(如 "mcp:server_started") + /// * `payload` - JSON 格式的事件数据 + fn emit_event(&self, event: &str, payload: &serde_json::Value) -> Result<(), String>; +} + +/// 动态事件发射器包装 +/// +/// 使用 `Arc` 实现可克隆的动态分发。 +#[derive(Clone)] +pub struct DynEmitter(pub Arc); + +impl DynEmitter { + /// 创建新的动态发射器 + pub fn new(emitter: impl EventEmit) -> Self { + Self(Arc::new(emitter)) + } + + /// 发送事件 + pub fn emit_event(&self, event: &str, payload: &serde_json::Value) -> Result<(), String> { + self.0.emit_event(event, payload) + } +} + +/// 空操作发射器(用于测试或不需要事件的场景) +#[derive(Debug, Clone)] +pub struct NoOpEmitter; + +impl EventEmit for NoOpEmitter { + fn emit_event(&self, _event: &str, _payload: &serde_json::Value) -> Result<(), String> { + Ok(()) + } +} diff --git a/src-tauri/src/app/types.rs b/src-tauri/src/app/types.rs index 03b14fa70..fcd63b649 100644 --- a/src-tauri/src/app/types.rs +++ b/src-tauri/src/app/types.rs @@ -3,7 +3,7 @@ //! 包含应用状态类型和相关实现。 use std::sync::Arc; -use tauri::Runtime; +use tauri::{Emitter, Runtime}; use tokio::sync::RwLock; use crate::logger; @@ -11,6 +11,8 @@ use crate::server; use crate::services::token_cache_service::TokenCacheService; use crate::tray::TrayManager; +use proxycast_core::event_emit::EventEmit; + // 重新导出 core crate 的 ProviderType pub use proxycast_core::ProviderType; @@ -26,6 +28,21 @@ pub struct TokenCacheServiceState(pub Arc); /// TrayManager 状态封装 pub struct TrayManagerState(pub Arc>>>); +/// 通用 Tauri 事件发射器 +/// +/// 实现 `proxycast_core::EventEmit` trait, +/// 供所有独立 crate(MCP、Agent 等)通过 DynEmitter 使用。 +#[derive(Clone)] +pub struct TauriEventEmitter(pub tauri::AppHandle); + +impl EventEmit for TauriEventEmitter { + fn emit_event(&self, event: &str, payload: &serde_json::Value) -> Result<(), String> { + self.0 + .emit(event, payload.clone()) + .map_err(|e| format!("Tauri emit 失败: {e}")) + } +} + #[cfg(test)] mod tests { use super::*;