refactor: 添加 EventEmit trait 到 proxycast-core

- 新增 event_emit 模块:EventEmit trait、DynEmitter、NoOpEmitter
- 解耦 Tauri 事件发射,供独立 crate 使用
- app/types.rs 添加 TauriEventEmitter 实现
This commit is contained in:
coso
2026-02-08 22:40:48 +08:00
parent 146db0d110
commit f169e93e6e
2 changed files with 65 additions and 1 deletions
+47
View File
@@ -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<dyn EventEmit>` 实现可克隆的动态分发。
#[derive(Clone)]
pub struct DynEmitter(pub Arc<dyn EventEmit>);
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(())
}
}
+18 -1
View File
@@ -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<TokenCacheService>);
/// TrayManager 状态封装
pub struct TrayManagerState<R: Runtime>(pub Arc<tokio::sync::RwLock<Option<TrayManager<R>>>>);
/// 通用 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::*;