docs(bridge): 光湖桥聊天双壳集成开发链 DEV-20260812-002(Electron PASS / Tauri ACL 未闭合 + 踩坑因果链 + 未决清单)
This commit is contained in:
parent
21aec6f504
commit
7f257364d2
1 changed files with 97 additions and 0 deletions
97
development/GHB-DEV-CHAIN-20260812-002.md
Executable file
97
development/GHB-DEV-CHAIN-20260812-002.md
Executable file
|
|
@ -0,0 +1,97 @@
|
|||
# 光湖桥聊天工具 · 双壳集成开发链 · DEV-20260812-002
|
||||
|
||||
- 登记号:GHB-DEV-CHAIN-20260812-002
|
||||
- 日期:2026-08-12
|
||||
- 执行人:铸渊 ICE-P-ZY001(QoderCN 实例)
|
||||
- 指令源:冰朔——"光湖桥,就是给人类在光湖世界里做一个聊天工具。你就在我本地开发,开发好了装到这两个框架里都试试,看看是否真的成功运行了这个通讯工具。"
|
||||
- 上游基线:GHB-DEV-20260812-001(光湖桥 v1 独立参考实现,bridge-node.mjs,selftest 五项 PASS)
|
||||
- 状态:**Electron 壳全链路 PASS(含打包 .app);Tauri 壳部分 PASS(接入通、UI 发送被 ACL 拦,未闭合)**
|
||||
|
||||
---
|
||||
|
||||
## 一、任务目标
|
||||
|
||||
把光湖桥从"协议参考实现"变成"人类可用的聊天工具",并分别装进两个桌面框架实测:
|
||||
1. Electron(0.8.0 HoloLake Era 同族路线)
|
||||
2. Tauri(0.4.6 源码线同族路线,冰朔偏好的轻量壳)
|
||||
|
||||
验收标准:两个壳各自能连上会合点、互发消息、收到送达回执,真实运行而非纸面设计。
|
||||
|
||||
## 二、架构决策链(为什么这样做)
|
||||
|
||||
```
|
||||
目标:一套聊天前端,两个壳都能装
|
||||
└─ 决策1:桥运行时统一走 stdio JSON 子进程模式
|
||||
原因:Electron 主进程虽自带 Node,但 Tauri 后端是 Rust 无 Node 运行时;
|
||||
取交集 = 两边都能 spawn 子进程 + 读写 stdio。
|
||||
给 bridge-node.mjs 增加 --stdio 模式(NDJSON 命令进/事件出,日志走 stderr),
|
||||
两壳集成方式完全同构,协议面只有一份。
|
||||
└─ 决策2:聊天前端零构建(纯 HTML/CSS/JS,不用 Vite/Webpack)
|
||||
原因:构建链越短,双壳复用越干净,也符合光湖"可手工审计"原则。
|
||||
└─ 决策3:adapter.js 适配层统一事件面
|
||||
前端只认 window.GHB = { send(to,text), on(event,cb) };
|
||||
Electron 走 preload contextBridge(ghbElectron),
|
||||
Tauri 走 withGlobalTauri 的 __TAURI__.event/core,
|
||||
裸浏览器降级为 mock 提示。壳的差异被隔离在 adapter 一层。
|
||||
└─ 决策4:开发与构建全部落本地盘 /tmp,成品归档 JZAO
|
||||
原因:既有教训——ExFAT(JZAO)上构建会因 AppleDouble 崩签名;
|
||||
且沙箱对工作区外 shell 写入有限制。
|
||||
└─ 决策5:无人值守自检钩子
|
||||
GHB_AUTOSEND="对端|文本|延迟秒"(走 UI 发送路径,气泡真实渲染)
|
||||
+ GHB_SHOT=路径(延迟截屏取证),让"是否真的运行"有图有日志。
|
||||
```
|
||||
|
||||
## 三、实测结果
|
||||
|
||||
### Electron 壳 ✅ PASS
|
||||
- 开发模式双实例(ELECTRON-A ↔ ELECTRON-B):双向消息送达、回执签名验证通过、UI 气泡完整渲染(截图取证 shot-a/shot-b)。
|
||||
- 打包 `.app`(GuanghuBridgeChat.app,手工组装 + ad-hoc 签名)双实例复测:PKG-A ↔ PKG-B 双向送达、验签通过(截图 shot-pkg-a/b)。
|
||||
- 证据:relay 日志四条在线直投;`signature_verified: true`;截屏显示绿连接点、节点号、双向气泡、"✓ 已送达·已验签"。
|
||||
|
||||
### Tauri 壳 ⚠️ 部分 PASS(未闭合)
|
||||
- cargo 编译通过(Tauri v2 + Rust 1.96)。
|
||||
- 双实例接入会合点成功(relay 日志:TAURI-A / TAURI-B 接入)。
|
||||
- **未闭合点**:后端 emit 的事件能到前端,但前端 `invoke('bridge_send')` 没有触发发送——应用命令的 ACL 权限未被 tauri-build 收录进 acl-manifests.json(manifest 只有 core 系列,`allow-bridge-send` 不存在,引用即编译报错)。见未决问题 U1。
|
||||
- 未打包 .app(bundle.active=false,验证未通过前不做)。
|
||||
|
||||
## 四、踩坑因果链(现象 → 原因 → 处置)
|
||||
|
||||
1. **parseArgs 吞开关**:`--stdio` 无值开关被旧配对逻辑吃掉后续 `--id` → 改为逐个扫描,值以 `--` 开头则视为布尔开关。
|
||||
2. **stdio 模式 stdin EOF 即退出**:后台测试时 stdin=/dev/null,节点刚连上就退出,relay 侧表现为"刚接入就离线" → 结论:stdio 子进程要求宿主保持 stdin 管道打开(Electron/Tauri spawn 默认满足);测试用 `(sleep N) | node ...` 保持。
|
||||
3. **connected 事件早于渲染进程就绪**:截屏显示"接入中…红点"但回执事件已到 → 原因:子进程启动快于 webContents 加载,早到事件被丢 → 处置:main 进程加事件缓冲队列,did-finish-load 后补发。
|
||||
4. **Electron 沙箱内 SIGSEGV**:同代码上轮能跑本轮段错误,伴随 `nice(5) failed` → 沙箱策略变化所致 → `--no-sandbox --disable-gpu` 规避。
|
||||
5. **npm 缓存权限**:沙箱禁写 `~/.npm` → `--cache /tmp/npm-cache`。
|
||||
6. **Electron 二进制下载失败**:postinstall 从 GitHub 拉二进制被断 → 换 npmmirror(ELECTRON_MIRROR)+ `ELECTRON_CACHE=/tmp/electron-cache`。
|
||||
7. **electron-builder 打包在沙箱下解包丢二进制**:dist 里 `Contents/MacOS` 为空,rename ENOENT → 放弃 builder,**手工组装 .app**:拷官方 Electron.app → `asar pack --unpack-dir bridge` → 改 Info.plist(CFBundleExecutable/Name/Identifier)→ 改名主二进制 → `codesign --force --deep -s -`。此路线完全可控且可复现。
|
||||
8. **外部 node 读不了 asar 内文件**:打包后 spawn 的系统 node 报 MODULE_NOT_FOUND → asar 透明读取只在 Electron 进程内生效 → bridge 脚本 unpack 到 `app.asar.unpacked/`,main.cjs 加路径探测(打包态优先 unpacked,开发态回退本地目录)。
|
||||
9. **cargo 写 ~/.cargo 被沙箱拦** → `CARGO_HOME=/tmp/cargo-home`。
|
||||
10. **Tauri generate_context 要求 icons/icon.png** → python 纯手写 PNG(光湖青圆形,128px)。
|
||||
11. **Rust E0597**:Exit 事件里 `if let Ok(guard) = state.0.lock()` 的临时 MutexGuard 析构顺序晚于 state 绑定 → 块尾加分号提前落临时对象。
|
||||
12. **zsh 杂项**:`rm -rf x/*.png` 无匹配报错、`echo ====` 被解析、后台进程 nice 警告——全部改用落文件再查看的方式规避。
|
||||
|
||||
## 五、未决问题清单
|
||||
|
||||
- **U1(Tauri ACL,最高优先)**:应用命令 `bridge_send` 的 allow 权限未进 acl-manifests.json。疑点:tauri-build 收集应用命令权限的机制与本工程 [lib] 双 crate 结构(main.rs 调 app_lib::run)的交互;下次优先试 a) 把 run() 逻辑并回 main.rs 单 crate 重建看 manifest 是否收录;b) 查 tauri 官方脚手架的 capabilities 生成差异。
|
||||
- **U2**:Tauri 壳 UI 渲染取证缺(无截屏钩子),可在 lib.rs 加 webview.screenshot 或走系统 screencapture。
|
||||
- **U3**:GHB_AUTOSEND / GHB_SHOT 是开发自检钩子,正式交付前决定保留(运维有用)或摘除。
|
||||
- **U4**:桥协议层未竟项(承 DEV-001):TLS、多会合点、BS-TCS 准入门禁对接、群聊/人格体协作信封。
|
||||
- **U5**:待冰朔裁定——聊天工具源码是否推 REPO-014 走正典登记;真实跨机会合点落哪台节点。
|
||||
- **U6**:本仓库工作区存在 1027 个 0-insertion/0-deletion 的 ExFAT 元数据"假改动"(stat 差异),未处理,不属本次交付范围,仅报告。
|
||||
|
||||
## 六、资产清单与复现
|
||||
|
||||
- 源码归档:`/Volumes/JZAO/HoloLake/development/guanghu-bridge-DEV-20260812-001/`
|
||||
- `bridge-node.mjs`(新增 --stdio 模式与事件缓冲无关,纯运行时)
|
||||
- `chat/`(chat.html/css/js + adapter.js 四件共用前端)
|
||||
- `chat/electron/`(main.cjs + preload.cjs + package.json)
|
||||
- `chat/tauri/`(Cargo.toml + build.rs + tauri.conf.json + src/ + capabilities/)
|
||||
- 构建配方(本地盘):
|
||||
- Electron:`npm i electron --cache /tmp/npm-cache`,`ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/`;打包走手工组装七步(见踩坑 7)。
|
||||
- Tauri:`CARGO_HOME=/tmp/cargo-home cargo build`。
|
||||
- 运行:先起 `node bridge-node.mjs relay --port <P>`,壳通过环境变量 `GHB_NODE_ID` / `GHB_RELAY` 接入。
|
||||
- 实测证据件:截图 shot-a/b(Electron 开发态)、shot-pkg-a/b(.app 打包态)存 `/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/`(shot-a/b)与本次会话日志。
|
||||
|
||||
## 七、状态推进
|
||||
|
||||
- 光湖桥人类产品形态:DESIGN_PROVEN → **ELECTRON_SHELL_PROVEN_LOCAL / TAURI_SHELL_PARTIAL(ACL 未闭合)**
|
||||
- 认知基线 025 的 realtime_transport_state 维持 `REFERENCE_IMPLEMENTATION_PROVEN_LOCAL`,待 Tauri 闭合后可加注双壳验证。
|
||||
Loading…
Reference in a new issue