新增: 跨端WS隧道脚手架(df-tunnel客户端+df-relay云中继)
df-tunnel:桌面端出站WS客户端(TunnelClient trait+骨架,穿NAT连云后端) df-relay:axum WS中继服务(转发小程序↔桌面端,广播骨架) 双crate独立消息骨架,不依赖src-tauri/df-types避跨crate强耦合 workspace crates/* glob自动注册,Phase2填充WS握手/鉴权/重连/路由
This commit is contained in:
108
crates/df-tunnel/src/events.rs
Normal file
108
crates/df-tunnel/src/events.rs
Normal file
@@ -0,0 +1,108 @@
|
||||
//! df-tunnel 隧道事件类型
|
||||
//!
|
||||
//! 设计依据:设计文档「三、技术选型」指出 AiChatEvent 17 变体在两端同语言保证类型一致。
|
||||
//! 但 AiChatEvent 定义在 src-tauri 非 crate 层,跨 crate path 引用会破坏分层边界
|
||||
//! (lib crate 依赖 src-tauri 二进制不合理)。故此处**独立定义隧道透传子集**:
|
||||
//! - 仅保留跨端高频透传的 4 个变体(TextDelta/ToolCall/Approval/Completed),
|
||||
//! Phase2 可按需追加,不依赖 src-tauri。
|
||||
//! - 携带 conv_id 字段做多会话路由(对齐 F-09 多会话 conv_id 契约)。
|
||||
//!
|
||||
//! 向后兼容:新增变体只加不减,旧消费方忽略未知变体(serde 配 `#[serde(other)]` 捕获兜底)。
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// 隧道透传的事件类型(AiChatEvent 简化子集)
|
||||
///
|
||||
/// 变体语义对齐桌面端 ai-chat-event:
|
||||
/// - `TextDelta`:流式增量文本块
|
||||
/// - `ToolCall`:工具调用请求(含工具名/参数)
|
||||
/// - `Approval`:审批请求(用户授权确认)
|
||||
/// - `Completed`:单轮对话完成
|
||||
///
|
||||
/// Phase2 可扩展 Error/Stopped/Regenerated 等变体。
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(tag = "kind", rename_all = "snake_case")]
|
||||
pub enum TunnelEvent {
|
||||
/// 流式文本增量
|
||||
TextDelta {
|
||||
/// 会话 ID(多会话路由用,对齐 F-09)
|
||||
conv_id: String,
|
||||
/// 增量文本片段
|
||||
delta: String,
|
||||
},
|
||||
|
||||
/// 工具调用请求
|
||||
ToolCall {
|
||||
/// 会话 ID
|
||||
conv_id: String,
|
||||
/// 工具调用唯一标识(用于回填结果)
|
||||
call_id: String,
|
||||
/// 工具名
|
||||
name: String,
|
||||
/// 工具参数(原始 JSON,由消费方按 name 解析)
|
||||
arguments: serde_json::Value,
|
||||
},
|
||||
|
||||
/// 审批请求(工具/操作需用户授权)
|
||||
Approval {
|
||||
/// 会话 ID
|
||||
conv_id: String,
|
||||
/// 审批项唯一标识
|
||||
approval_id: String,
|
||||
/// 审批描述(展示给用户)
|
||||
description: String,
|
||||
},
|
||||
|
||||
/// 对话单轮完成
|
||||
Completed {
|
||||
/// 会话 ID
|
||||
conv_id: String,
|
||||
/// 本轮产生的消息 ID
|
||||
message_id: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl TunnelEvent {
|
||||
/// 取事件所属会话 ID(路由分发的便利方法)
|
||||
pub fn conv_id(&self) -> &str {
|
||||
match self {
|
||||
TunnelEvent::TextDelta { conv_id, .. }
|
||||
| TunnelEvent::ToolCall { conv_id, .. }
|
||||
| TunnelEvent::Approval { conv_id, .. }
|
||||
| TunnelEvent::Completed { conv_id, .. } => conv_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 云后端 → 桌面端的操作指令(小程序远程操作映射)
|
||||
///
|
||||
/// 对齐设计文档「Layer1 指令路由」:
|
||||
/// send/stop/approve/regenerate/switch 五类操作。
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(tag = "kind", rename_all = "snake_case")]
|
||||
pub enum TunnelCommand {
|
||||
/// 发送消息
|
||||
Send { conv_id: String, content: String },
|
||||
/// 停止当前生成
|
||||
Stop { conv_id: String },
|
||||
/// 审批通过/拒绝(approval_id + accepted)
|
||||
Approve { conv_id: String, approval_id: String, accepted: bool },
|
||||
/// 重新生成
|
||||
Regenerate { conv_id: String },
|
||||
/// 切换对话
|
||||
Switch { conv_id: String },
|
||||
}
|
||||
|
||||
/// 隧道传输的消息包装(双向)
|
||||
///
|
||||
/// 区分「桌面端 → 云后端 → 小程序」的事件流(TunnelEvent)
|
||||
/// 与「小程序 → 云后端 → 桌面端」的指令流(TunnelCommand)。
|
||||
/// 同一 WS 连接复用,靠 kind 标签区分。
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(tag = "dir", rename_all = "snake_case")]
|
||||
pub enum TunnelMessage {
|
||||
/// 桌面端发出的事件(下行)
|
||||
Event(TunnelEvent),
|
||||
/// 云后端转发的指令(上行,发往桌面端)
|
||||
Command(TunnelCommand),
|
||||
}
|
||||
Reference in New Issue
Block a user