新增: 跨端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:
2026-06-22 01:24:01 +08:00
parent 566bbcb394
commit 5d1749a58f
11 changed files with 818 additions and 0 deletions

View 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),
}