依 autoflow-agent workspace v2 設計把 PRD / 設計 / 架構 / 交付類 共享文件從個人層 .autoflow/(ignored)搬到 docs/autoflow/(進 git), 讓團隊可共享產品與架構文件,個人層只留 progress / review / testing 等 per-branch 筆記。 - 02-prd/ 21 個檔(PRD、features、market-analysis 等) - 03-design/ 18 個檔(design-spec、wireframes、flows 等) - 04-architecture/ 31 個檔(TDD、design-doc、ADR×14、API 規格等) - 07-delivery/ 3 個檔(project-summary、phase-0.6-handover、stage-deployment-setup) 合計 73 檔。原檔已從 .autoflow/ 移除(migration 工具執行 git mv, 但因 .autoflow/ 在 .gitignore 中、git 將此操作視為新增、無 rename history)。
92 lines
5.5 KiB
Markdown
92 lines
5.5 KiB
Markdown
# ADR-002:沿用 POC 的 Tunnel 協定(WebSocket + yamux)
|
||
|
||
## 狀態
|
||
Accepted — 2026-04-21
|
||
|
||
## 背景 (Context)
|
||
|
||
visionA Cloud 最核心的技術要素是:**瀏覽器透過雲端反向代理,操作使用者本地電腦上的 Kneron 裝置**。
|
||
|
||
這要求在「雲端 Proxy」與「使用者電腦的 local agent」之間建立一條:
|
||
- **由 local agent 主動出站建立**(穿越 NAT / 企業防火牆)
|
||
- **雙向多工**:同時傳遞 HTTP 控制指令、長輪詢 WebSocket、MJPEG 串流、推論結果串流
|
||
- **低延遲**:串流資料需保留 real-time 特性
|
||
- **可重連**:網路短暫斷線後自動恢復
|
||
|
||
POC(edge-ai-platform)已用 **WebSocket + hashicorp/yamux** 實作並驗證可行:
|
||
- 外層 `gorilla/websocket` 負責「由 client 發起、能穿越企業代理」
|
||
- 內層 `yamux` 把單條 WebSocket 升級為多工 stream,每個 HTTP 請求開一條 yamux stream
|
||
- WebSocket binary frame 之上用 `wsconn` adapter 把 WebSocket 包成 `net.Conn`
|
||
|
||
POC 源碼重點:
|
||
- `relay/server.go`:收 `/tunnel/connect`、建立 `yamux.Server(netConn)`、按 token 收在 `map[token]*yamux.Session`
|
||
- `tunnel/client.go`:Dial WebSocket → `yamux.Client()` → 接收 stream → 轉給本機 `127.0.0.1:3721`
|
||
- `pkg/wsconn/wsconn.go`:`websocket.Conn` → `net.Conn` adapter(binary frame)
|
||
|
||
## 決策 (Decision)
|
||
|
||
**雛形沿用 POC 的 tunnel 協定不做重大改變**:
|
||
|
||
- 外層:`github.com/gorilla/websocket`(version ≥ 1.5.3)
|
||
- 多工:`github.com/hashicorp/yamux`(default config)
|
||
- Adapter:把 POC 的 `wsconn` 搬到 `visionA-backend/internal/wsconn`(或 `pkg/wsconn`,視是否對外暴露)
|
||
- 端點:`WS /tunnel/connect?token=xxx`(remote-proxy 側)
|
||
- 訊息語義:沿用 POC 的「yamux stream 裡傳完整 HTTP request/response」
|
||
|
||
**沿用的好處:代碼已在 POC 驗證過能穿越 NAT、能處理 WebSocket upgrade(`proxyWebSocket` 的 Hijack 邏輯)、能處理 MJPEG streaming。**
|
||
|
||
**雛形會升級的部分(與 ADR-003 相關)**:
|
||
- Token 生成機制(SHA256(MAC) → Pairing Token,詳見 ADR-003)
|
||
- `handleTunnel` 加上 token 驗證 hook(雛形驗 env 寫死 token;未來驗 DB)
|
||
- Session 管理抽 interface(雛形 in-memory,未來 Redis,詳見 ADR-001)
|
||
|
||
**未來可能會重新評估的項目(非雛形範疇)**:
|
||
- 若 stream 吞吐或 head-of-line blocking 成瓶頸 → 評估 HTTP/3 (QUIC) 或 gRPC bidi stream
|
||
- 若需要端對端加密(繞過雲端看到明文)→ 在 yamux 之上再包一層 TLS / Noise
|
||
- 若需要跨雲的地理就近路由 → 加入 proxy routing 層,由 local agent 選擇 entrypoint
|
||
|
||
## 考慮過的替代方案
|
||
|
||
| 方案 | 優點 | 缺點 | 排除原因 |
|
||
|------|------|------|---------|
|
||
| **重頭設計 gRPC bidi stream** | 現代 RPC,有 code-gen、型別安全 | 要重新定義所有訊息 schema;POC 已用 HTTP semantics 讓搬遷成本低 | 雛形期不值得,未來可升級 |
|
||
| **HTTP/3 (QUIC) 原生多工** | 未來標準、天生多工、零 HOL blocking | Go 生態的 QUIC 客戶端 / 伺服器還在 beta,反向代理成熟度低 | 還太新 |
|
||
| **單一 WebSocket 無多工(每請求新開 WS)** | 最簡單 | 每請求一次 WS handshake(~50-200ms),串流無法疊加 | 效能差 |
|
||
| **SSH tunnel / WireGuard 等 VPN 方案** | 標準 | 需要使用者端安裝額外軟體、開特定埠、難穿越企業防火牆 | 使用者體驗差 |
|
||
| **純 TCP tunnel over TLS** | 簡單 | 通常被企業防火牆封鎖,WebSocket 因為外觀像 HTTP 能穿透 | 穿透力差 |
|
||
|
||
## 後果 (Consequences)
|
||
|
||
### 正面影響
|
||
|
||
- **零移植成本**:POC relay / tunnel 程式碼可直接搬到 `visionA-backend/internal/relay` 和 `visionA-backend/internal/tunnel`
|
||
- **已驗證 NAT 穿透**:POC 測試過能穿越公司 NAT、家用路由器 NAT
|
||
- **已驗證 WebSocket-in-WebSocket**:瀏覽器 → Proxy → tunnel stream → local agent 的 WebSocket upgrade 流程,POC 的 `proxyWebSocket` 已處理 Hijack 並雙向 pipe,這個最難的部分已經能跑
|
||
- **已驗證 MJPEG streaming**:POC 的 `handleProxy` 用 `http.Flusher` 處理串流回應,visionA 的 camera stream 可直接用
|
||
- **擴展空間大**:yamux 天生多工,一個 tunnel 可以同時跑 10+ 個 HTTP 請求不互相阻塞
|
||
|
||
### 負面影響(接受的取捨)
|
||
|
||
- **訊息格式是 HTTP 明文**:yamux stream 內跑的是 raw HTTP request/response,需靠 TLS(WebSocket 外層)保密;Proxy 節點可以看到明文請求內容
|
||
- **yamux 依賴**:hashicorp/yamux 已久無大版本更新,但 v0.x 穩定
|
||
- **單 WebSocket = 單 tunnel**:一個 local agent 一條 WebSocket;若要跨地理區域 active-active,需應用層路由
|
||
- **HOL blocking 風險低但存在**:yamux 是多工,但底層單一 TCP connection,若網路抖動整條都延遲
|
||
|
||
### 風險
|
||
|
||
- **WebSocket 升級失敗率**:企業防火牆 / 中間人代理可能阻擋 WebSocket upgrade。雛形先不處理 fallback(SSE / long-poll),TODO
|
||
- **單條 WebSocket 頻寬極限**:若使用者端上傳 MJPEG 4K 60fps 會打滿一條 TCP。實測後若有問題再引入「多條 WebSocket + 分流」
|
||
- **yamux 的 keepalive**:POC 用 default config,是否足夠穿越企業 idle timeout?TODO 壓測驗證
|
||
|
||
## 合規性
|
||
|
||
- [x] Architect 確認
|
||
- [x] POC 實測驗證(`edge-ai-platform` 已部署到 EC2 + 本地測試)
|
||
- [ ] 未來壓測:TODO
|
||
|
||
## 相關文件
|
||
- Design Doc §3(資料流)
|
||
- TDD §6(Tunnel 協定)
|
||
- TDD §7(Session 管理)
|
||
- POC 源碼:`edge-ai-platform/server/internal/{relay,tunnel}`、`edge-ai-platform/server/pkg/wsconn`
|