From a781f8e1ba34b708e323659d7afe93dfaef78f59 Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Fri, 25 Sep 2026 15:13:30 +0800 Subject: [PATCH] =?UTF-8?q?fix(gui):=20=E8=AE=BE=E5=A4=87=E6=A1=A5=20bind?= =?UTF-8?q?=20=E7=BB=93=E6=9E=9C=E5=88=A4=20ok=20+=20=E6=9A=B4=E9=9C=B2?= =?UTF-8?q?=E7=99=BB=E8=AE=B0=E7=8A=B6=E6=80=81=EF=BC=8C=E4=B8=8E=E9=B8=BF?= =?UTF-8?q?=E8=92=99=E7=AB=AF=E5=AF=B9=E9=BD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GUI 主进程与 Go 客户端同病: 只打日志、不看 ok。 服务端 bind 被拒时回 {"ok":false,"error":"bind rejected"} 并关闭连接, GUI 既不报错也不重连 ⇒ 设备静默失联(TCP/WS 通但从未登记进网关)。 另:成功时服务端不含 device 字段,原日志用 `msg.device || deviceBridgeId` 兜底才显得像成功,掩盖了「从未真的读 ok」。 鸿蒙端 DeviceBridge.ets:209 本来就是正确实现(检查 ok、区分 connected 与 bound),本次把 GUI 与 Go 客户端对齐到同一语义: 新增 deviceBridgeBound / deviceBridgeBindError,bind 被拒打 error 级日志 并说明常见原因(令牌不匹配 / 设备未授权)。 --- cmd/gui/main.js | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/cmd/gui/main.js b/cmd/gui/main.js index 042b83f..ee5729f 100644 --- a/cmd/gui/main.js +++ b/cmd/gui/main.js @@ -810,6 +810,11 @@ const devOs = require("os"); let deviceBridge = null; // 当前活动设备桥 let deviceBridgeId = ""; // 设备 meta device_id(hello 后可用于 cmd_result) let deviceBridgeAddr = ""; // 设备桥网关地址 + +// 设备桥的**登记**状态(与"连接已建立"是两件事)。 +// 连接成功但 bind 被拒时设备是失联的,只看 connected 会给出假阳性。 +let deviceBridgeBound = false; +let deviceBridgeBindError = ""; // 音频/媒体接收聚合缓冲(服务端分块推送二进制→聚合→播放) let speechAccum = null; @@ -1252,9 +1257,33 @@ function onDeviceMsg(msg) { } catch (e) { console.log("[device-bridge] exec error: " + e.message); } - } else if (op === "hello_ack" || op === "bind_ack") { + } else if (op === "bind_ack") { + // ★ bind 结果必须判 ok —— 与鸿蒙端(DeviceBridge.ets:209)对齐。 + // + // 原实现与 Go 客户端同病:只打一行日志、不看 ok。服务端 bind 被拒时回 + // {"ok":false,"error":"bind rejected"} 并**关闭连接**,GUI 却既不报错也 + // 不重连,设备静默失联 —— TCP/WS 通但从未登记进网关,命令永远下发不到。 + // + // 另:成功时服务端**不含 device 字段**,原日志靠 `msg.device || deviceBridgeId` + // 兜底才显示得像成功,掩盖了「没有真的读 ok」这件事。 + const accepted = msg.ok === true; + deviceBridgeBound = accepted; + if (accepted) { + console.log("[device-bridge] bind_ok device=" + deviceBridgeId); + } else { + deviceBridgeBindError = String(msg.error || "bind rejected"); + console.error( + "[device-bridge] bind rejected: " + + deviceBridgeBindError + + "(设备令牌不匹配或设备未授权)", + ); + } + try { + rebuildTrayMenu(); + } catch (e) {} + } else if (op === "hello_ack") { console.log( - "[device-bridge] " + op + " device=" + (msg.device || deviceBridgeId), + "[device-bridge] hello_ack device=" + (msg.device || deviceBridgeId) + " online=" + msg.online, ); try { rebuildTrayMenu(); @@ -2080,6 +2109,8 @@ function argsSafe(cmd) { // url 可为 ws(s)://完整端点(含路径),token 为网关 ws_token。 async function startDeviceBridge(cfg) { if (!cfg) return; + deviceBridgeBound = false; + deviceBridgeBindError = ""; const url = cfg.url || cfg.gateway || ""; const token = cfg.apiKey || cfg.token || ""; if (!url || !token) {