fix(gui): 设备桥 gateway 自动发现回写主进程

## 要判的是什么

2026-10-05 实测故障:GUI 面板里能看到设备通道地址,但设备桥连不上。
日志只有一行 `ws cookie len=0` + 401,没有任何「地址来自发现」的痕迹。

根因不是配置错,是**发现结果与实际连接配置从不联通**:

- 渲染进程 app.js 的 loadDiscoveredGateway() 调 /device/gateway,
  拿到的地址只写进 **state.discoveredGateway**(UI 展示用);
- 主进程 startDeviceBridge() 读的是 **gui-prefs.deviceBridge.gateway**;
- 两边从未交换过 —— state 是渲染进程内存,prefs 是主进程文件。

于是服务端明明已经通过 /device/gateway 告诉了客户端正确地址
(proxy.go:1078 生成的 url_portal),GUI 却仍在用用户几个月前手填的旧地址,
且永远 401/ECONNREFUSED、不重试。

## 修复

发现成功后回写 deviceBridge.set({gateway}),让主进程真正用上。

两个刻意的约束:

1. **仅当本地 gateway 为空才写**(!cur.gateway)—— 手填值优先。
   用户可能故意指向内网直连或灰度实例,发现只做缺省补全。
2. **只传 gateway,不传 token** —— /device/gateway 不返回设备令牌
   (ws_token),写了反而会写坏已有的正确 token。

deviceBridge.set 会 stop+start 桥,改完立即生效,无需重启进程。

## 顺带记下一个实测坑(已写进门禁)

设备桥 WS 的认证**不走 cookie**。registry.go ServeWS 只认三种来源:
?token= / X-API-Key / Sec-WebSocket-Protocol: homeagent.<token>,
cookie 完全不参与 acceptBind。

排查时曾误以为「发 cookie 就能过」—— 实测服务端仍 401。
cookie 那条路是错的,已还原 connections.json。

## 门禁(cmd/gui/device-gateway-discovery.test.mjs)

9 条判据,文本扫描(自动回写由 refreshAll 的 15s 定时器驱动,
构造那个时序需真 Electron + 真后端 + 会话 cookie,CI 里没有)。

覆盖:发现调用存在、回写接通、本地非空则不覆盖、只传 gateway、
preload 暴露 set、主进程注册 handler、get 返回明文 token、
set 会重启桥、connectDeviceWS 把 token 放进 query。

变异测试验证非假红:
- 删掉回写块(复现本次故障形态)⇒ 第 2、3、4 条转红;
- 去掉「本地为空才写」改成无条件覆盖 ⇒ 第 3 条转红。

排障过程中判据自身报过 3 次假红(正则窗口不足、字符串切片后仍按
match 数组用 setHandler[0]),均已修正并记在注释里。
This commit is contained in:
JianFeeeee
2026-10-05 13:05:18 +08:00
parent 2bbbb6b830
commit bca791a14b
2 changed files with 192 additions and 0 deletions

View File

@ -761,6 +761,29 @@ async function loadDiscoveredGateway() {
(d && d.available && (d.url_portal || d.url)) || "";
if (state.discoveredGateway) {
console.log("[device-bridge] discovered gateway: " + state.discoveredGateway);
// ★ 回写到主进程,让设备桥**真的**用上发现结果。
//
// 此前发现只停在state.discoveredGateway(UI 展示用),而主进程的
// startDeviceBridge 读的是 gui-prefs.deviceBridge.gateway ——
// 两者从不联通。症状:GUI 面板里能看到设备通道地址,但设备桥连不上,
// 而日志只有一行 ws cookie len=0,没有任何“地址来自发现”的痕迹。
//
// 仅当本地未配置 gateway 时才写:手填的值优先(用户可能故意指向
// 内网直连或灰度实例),发现只做**缺省补全**。
if (window.homeagent && window.homeagent.deviceBridge) {
try {
var cur = await window.homeagent.deviceBridge.get();
if (cur && !cur.gateway && state.discoveredGateway) {
await window.homeagent.deviceBridge.set({ gateway: state.discoveredGateway });
console.log(
"[device-bridge] gateway auto-configured from discovery: " +
state.discoveredGateway,
);
}
} catch (e2) {
console.log("[device-bridge] auto-config skipped: " + e2.message);
}
}
}
} catch (e) {
state.discoveredGateway = "";