跳轉到

Signaling Service 架構圖

文件角色:implementation flow 投影;圖與步驟不得另建產品規則或參數 authority。

Implementation authority 產品 canon/流程 全域索引
signaling-service.md 配對 · 資安規範 流程.md §2

整體架構

%%{init: {"theme":"base","themeVariables":{"fontSize":"14px","primaryTextColor":"#1f2937","lineColor":"#64748b"},"flowchart":{"curve":"basis"}}}%%
flowchart TB
    P1([玩家 1])
    P2([玩家 2])

    subgraph C1[玩家端 scoped mux]
        WSS[依玩家排序的 WSS endpoints]
        GS[GossipSub scope topic]
    end

    subgraph SG1[open-4wd-signaling]
        CF[Cloudflare Worker adapter<br/>SQLite-backed Durable Object]
        Node[Node/ws adapter]
        Core[共用純協定核心]
        TT[POST /turn-token<br/>選配 TURN 短期憑證]
    end

    P1 --> C1
    WSS -->|可選 provider 實作| CF
    WSS -.->|可選 provider 實作| Node
    CF --> Core
    Node --> Core
    GS <-.->|純 P2P fallback| P2
    Core -->|signed signal-v1| P2
    P1 -.->|"proof 驗身"| TT
    P1 -. WebRTC P2P .-> P2

    style SG1 fill:transparent,stroke:#b9c4d2,stroke-dasharray:4 3
    classDef local fill:#e8f3ec,stroke:#3f8f5f,stroke-width:1.4px,color:#173525;
    classDef chain fill:#e7eefb,stroke:#3f6bb0,stroke-width:1.4px,color:#152848;
    class P1,P2 local
    class WSS,GS,CF,Node,Core,TT chain

架構權威見 signaling-service.md §3(協定核心 + 傳輸適配器、伺服器義務、安全規則)。

WebRTC 連線建立流程

sequenceDiagram
    participant P1 as Player 1
    participant SS as Signaling Server
    participant P2 as Player 2

    P1->>SS: GET /ws?room=room:<roomId> + signed register
    P2->>SS: GET /ws?room=room:<roomId> + signed register

    P1->>P1: 建立 RTCPeerConnection
    P1->>P1: createOffer
    P1->>SS: signed signal-v1 {scope,target=P2,message:offer}
    SS->>P2: 驗證後 1:1 轉發 envelope

    P2->>P2: 建立 RTCPeerConnection
    P2->>P2: setRemoteDescription(offer)
    P2->>P2: createAnswer
    P2->>SS: signed signal-v1 {scope,target=P1,message:answer}
    SS->>P1: 驗證後 1:1 轉發 envelope

    par ICE Candidate 交換
        P1->>SS: signed signal-v1 {message:ice-candidate}
        SS->>P2: 轉發
    and
        P2->>SS: signed signal-v1 {message:ice-candidate}
        SS->>P1: 轉發
    end

    Note over P1,P2: WebRTC 連線建立成功
    P1->>P2: DataChannel 直連
    P2->>P1: DataChannel 直連

    P1->>SS: 關閉 scoped signaling session
    P2->>SS: 關閉 scoped signaling session

多 transport(client 端)

GossipSub scope 從 rendezvous 開始即監聽。建房端只維持第一個可註冊 room scope 的 WSS; 加入端依使用者順序嘗試 WSS candidates,只有精確 roster 含非本機 peer 才停止,否則關閉該 session 並續試。冷啟動 WSS roster 不含目標時走 Gossip;入站後沿該 transport sticky,跨 transport 以 signed nonce 去重。配對流程本身只走 GossipSub,見 matchmaking.md

%%{init: {"theme":"base","themeVariables":{"fontSize":"14px","primaryTextColor":"#1f2937","lineColor":"#64748b"},"flowchart":{"curve":"basis"}}}%%
flowchart TD
    Start([需要 scoped signaling]) --> Role{角色}
    Start --> Gossip{libp2p GossipSub 可用?}
    Gossip -->|是| UseGossip[立即開 Gossip scope session]
    Gossip -->|否| NoGossip[無 Gossip session]
    Role -->|建房| HostWss[只維持第一個可註冊 WSS]
    Role -->|加入| JoinWss[依設定順序開 WSS candidate]
    JoinWss --> Roster{roster 有非本機 peer?}
    Roster -->|否| Next[關閉並續試下一個]
    Next --> JoinWss
    Roster -->|是| Found[選定該 WSS]
    HostWss --> Mux[SignalingMux]
    Found --> Mux
    UseGossip --> Mux
    NoGossip --> Mux
    Mux --> Route{最後入站或 WSS roster 有目標?}
    Route -->|是| Sticky[沿已驗路徑]
    Route -->|否且 Gossip 可用| GossipRoute[走 Gossip]
    Route -->|無任何 transport| Offline[網路房間/比賽不可用<br/>本機測試仍可用]

    classDef local fill:#e8f3ec,stroke:#3f8f5f,stroke-width:1.4px,color:#173525;
    classDef consensus fill:#fdf3df,stroke:#c08a2d,stroke-width:1.4px,color:#3d2c0d;
    classDef fail fill:#fae9e7,stroke:#b4544a,stroke-width:1.4px,color:#471d18;
    class HostWss,JoinWss,Found,Mux,Sticky local
    class UseGossip,GossipRoute consensus
    class Offline fail

訊息流

flowchart LR
    P1[P1] -->|"signed register"| Scope["room:<roomId>"]
    P1 -->|"signed signal-v1<br/>target=P2"| Scope
    Scope -->|"驗證後 1:1 轉發"| P2[P2]
    P2 -->|"signed signal-v1<br/>target=P1"| Scope
    Scope -->|"驗證後 1:1 轉發"| P1

    Note["伺服器不保存 SDP/ICE 或遊戲資料<br/>Worker SQLite 僅存短期成員、nonce、限流"]

部署形狀

部署細節與其他平台評估見 signaling-service.md §4部署資訊/open-4wd-signaling.md §5

%%{init: {"theme":"base","themeVariables":{"fontSize":"14px","primaryTextColor":"#1f2937","lineColor":"#64748b"},"flowchart":{"curve":"basis"}}}%%
flowchart LR
    Repo[open-4wd-signaling<br/>公版 reusable repo] --> Fork[營運者 fork]
    Fork --> Dispatch[workflow_dispatch<br/>人工輸入與核准]
    Fork --> NodeConfig[部署者 compose/config]
    Dispatch --> CF[Cloudflare Workers<br/>SQLite-backed Durable Objects]
    NodeConfig --> Node[docker compose<br/>Node adapter]
    NodeConfig --> AIO[all-in-one<br/>Node signaling+coturn]
    Player[玩家設定/session hint/registry] -.->|自行選擇,不內建預設 endpoint| CF
    Player -.->|自行選擇| Node
    Player -.->|自行選擇| AIO

    classDef local fill:#e8f3ec,stroke:#3f8f5f,stroke-width:1.4px,color:#173525;
    classDef chain fill:#e7eefb,stroke:#3f6bb0,stroke-width:1.4px,color:#152848;
    class Repo,Fork,Dispatch,NodeConfig chain
    class CF,Node,AIO,Player local

所有部署皆由各維護者獨立負責;專案不指定營運節點、預設清單或必須持續運作的部署。