新增: df-tunnel send_raw_event 出站透传
Phase3 阶段2(D2 全19变体透传):trait TunnelClient 加 send_raw_event(Value) + WsTunnelClient 实现;OutFrame::Event 改持 String(send_event/send_raw_event 预序列化,run_loop 只写 socket DRY)。cargo check + 5 测试过。
This commit is contained in:
@@ -81,6 +81,13 @@ pub trait TunnelClient: Send + Sync {
|
|||||||
///
|
///
|
||||||
/// 非阻塞入队,实际 socket 写入异步完成。连接断开时返回 NotConnected。
|
/// 非阻塞入队,实际 socket 写入异步完成。连接断开时返回 NotConnected。
|
||||||
async fn send_event(&self, event: TunnelEvent) -> Result<()>;
|
async fn send_event(&self, event: TunnelEvent) -> Result<()>;
|
||||||
|
|
||||||
|
/// 发送原始事件(桌面端 → 云后端 → 小程序),payload 为 AiChatEvent 序列化 JSON Value
|
||||||
|
///
|
||||||
|
/// Phase3 阶段2(D2 全 19 变体透传):EventBus subscriber 把 AiChatEvent Value 经此方法
|
||||||
|
/// 透传(不经 TunnelEvent 强类型子集)。与 [`send_event`](TunnelClient::send_event) 伴行,
|
||||||
|
/// 后者保留作高频子集快捷方式(D5 强类型保留)。非阻塞入队,连接断开返 NotConnected。
|
||||||
|
async fn send_raw_event(&self, payload: serde_json::Value) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 握手探测窗口(relay 校验通过后静默进入收发循环,无 ack 帧;
|
/// 握手探测窗口(relay 校验通过后静默进入收发循环,无 ack 帧;
|
||||||
@@ -105,8 +112,11 @@ struct ConnState {
|
|||||||
|
|
||||||
/// 收发循环出站帧(SendLoop 内部消费)
|
/// 收发循环出站帧(SendLoop 内部消费)
|
||||||
enum OutFrame {
|
enum OutFrame {
|
||||||
/// 业务事件(序列化后写 socket)
|
/// 业务事件(已序列化 JSON 字符串,run_loop 直接写 socket)
|
||||||
Event(TunnelEvent),
|
///
|
||||||
|
/// send_event(TunnelEvent) 与 send_raw_event(Value) 各自预序列化为 String 入队,
|
||||||
|
/// 统一经此变体写 socket(DRY:序列化在调用侧,run_loop 只负责写)。
|
||||||
|
Event(String),
|
||||||
/// 优雅关闭
|
/// 优雅关闭
|
||||||
Close,
|
Close,
|
||||||
}
|
}
|
||||||
@@ -260,13 +270,29 @@ impl TunnelClient for WsTunnelClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn send_event(&self, event: TunnelEvent) -> Result<()> {
|
async fn send_event(&self, event: TunnelEvent) -> Result<()> {
|
||||||
|
// 序列化提前(OutFrame::Event 持 String),失败返 Serde 错给调用方
|
||||||
|
let json = serde_json::to_string(&event)?;
|
||||||
let conn = self.conn.lock().await;
|
let conn = self.conn.lock().await;
|
||||||
let Some(state) = conn.as_ref() else {
|
let Some(state) = conn.as_ref() else {
|
||||||
return Err(TunnelError::NotConnected);
|
return Err(TunnelError::NotConnected);
|
||||||
};
|
};
|
||||||
state
|
state
|
||||||
.tx
|
.tx
|
||||||
.send(OutFrame::Event(event))
|
.send(OutFrame::Event(json))
|
||||||
|
.map_err(|_| TunnelError::NotConnected)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn send_raw_event(&self, payload: serde_json::Value) -> Result<()> {
|
||||||
|
// AiChatEvent Value 序列化为 JSON 字符串入队(与 send_event 共用 OutFrame::Event(String))
|
||||||
|
let json = serde_json::to_string(&payload)?;
|
||||||
|
let conn = self.conn.lock().await;
|
||||||
|
let Some(state) = conn.as_ref() else {
|
||||||
|
return Err(TunnelError::NotConnected);
|
||||||
|
};
|
||||||
|
state
|
||||||
|
.tx
|
||||||
|
.send(OutFrame::Event(json))
|
||||||
.map_err(|_| TunnelError::NotConnected)?;
|
.map_err(|_| TunnelError::NotConnected)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -358,14 +384,8 @@ async fn run_loop(
|
|||||||
// 出站队列
|
// 出站队列
|
||||||
maybe_out = rx.recv() => {
|
maybe_out = rx.recv() => {
|
||||||
match maybe_out {
|
match maybe_out {
|
||||||
Some(OutFrame::Event(ev)) => {
|
// OutFrame::Event 持已序列化 JSON 字符串(send_event/send_raw_event 预序列化)
|
||||||
let json = match serde_json::to_string(&ev) {
|
Some(OutFrame::Event(json)) => {
|
||||||
Ok(j) => j,
|
|
||||||
Err(e) => {
|
|
||||||
tracing::warn!(error = %e, "事件序列化失败,跳过");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if let Err(e) = sink.send(WsMessage::Text(json)).await {
|
if let Err(e) = sink.send(WsMessage::Text(json)).await {
|
||||||
tracing::warn!(error = %e, "socket 写入失败,收发循环退出");
|
tracing::warn!(error = %e, "socket 写入失败,收发循环退出");
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user