万字解析 OpenClaw 源码架构-网关实现层面

3 阅读18分钟

服务器实现

项目结构

服务器实现主要集中在 gateway 子系统与 CLI 生命周期管理模块中,并辅以配置加载、健康检查与部署文档支持。下图给出与服务器实现直接相关的模块关系概览:

graph TB
subgraph "网关服务器"
HTTP["HTTP 服务器<br/>server-http.ts"]
WS["WebSocket 服务器<br/>ws-connection.ts"]
LISTEN["端口监听与冲突处理<br/>http-listen.ts"]
SERVER["服务器入口导出<br/>server.ts"]
end
subgraph "CLI 生命周期"
RUNLOOP["运行循环与信号处理<br/>run-loop.ts"]
RESTART["重启调度与冷却<br/>infra/restart.ts"]
end
subgraph "配置与环境"
CFGIO["配置读取与校验<br/>config/io.ts"]
ENVSUB["环境变量替换<br/>config/env-substitution.ts"]
ENVPRES["写回保留环境变量引用<br/>config/env-preserve.ts"]
end
subgraph "健康与监控"
HEALTH["健康快照与心跳<br/>commands/health.ts"]
end
subgraph "部署与安全"
DOCSFLY["Fly.io 部署文档<br/>docs/install/fly.md"]
SECDOC["安全配置与审计<br/>docs/zh-CN/gateway/security/index.md"]
end
HTTP --> WS
HTTP --> LISTEN
SERVER --> HTTP
SERVER --> WS
RUNLOOP --> RESTART
RUNLOOP --> SERVER
CFGIO --> HTTP
ENVSUB --> CFGIO
ENVPRES --> CFGIO
HEALTH --> HTTP
DOCSFLY --> RUNLOOP
SECDOC --> HTTP

核心组件

  • HTTP 服务器与路由分发:负责健康探针、钩子接口、工具调用、OpenAI/OpenResponses 适配、Canvas/A2UI、插件路由、Control UI 等多阶段处理链。
  • WebSocket 服务器:统一接入握手、鉴权、速率限制、事件广播、客户端生命周期管理与断开清理。
  • 端口监听与冲突处理:在端口被占用时进行有限重试与静默关闭,避免“TIME_WAIT”残留导致的启动失败。
  • CLI 生命周期与重启:通过信号处理实现优雅停机与内部重启(SIGUSR1),并提供外部守护进程重启能力。
  • 配置加载与环境变量:支持 .env 加载、环境变量替换、缺失键告警、写回时保留环境变量引用。
  • 健康检查与监控:提供健康快照、心跳统计、会话汇总与探针超时保护。
  • 部署与安全:Fly.io 部署模板与参数、反向代理与可信代理配置、Tailscale Serve 身份头、TLS 指纹固定等。

架构总览

下图展示 HTTP 与 WebSocket 的集成架构:HTTP 服务器在“upgrade”事件到来前拦截所有非升级请求,完成鉴权与路由分发;WebSocket 服务器在升级成功后接管连接生命周期。

graph TB
CLIENT["客户端"]
HTTP["HTTP 服务器<br/>server-http.ts"]
WS["WebSocket 服务器<br/>ws-connection.ts"]
AUTH["鉴权与速率限制<br/>server-http.ts"]
PLUGINS["插件路由与 Canvas/A2UI<br/>server-http.ts"]
HANDLER["消息处理器<br/>ws-connection.ts"]
CLIENT --> HTTP
HTTP --> AUTH
HTTP --> PLUGINS
HTTP -. "upgrade" .-> WS
WS --> HANDLER

详细组件分析

HTTP 服务器与路由分发

  • 探针路由:/health(/z) 与 /ready(/z) 返回 live/ready 状态,支持细粒度可见性控制。
  • 钩子接口:基于基础路径与授权令牌,支持 wake 与 agent 分发,映射与校验严格。
  • 工具调用与第三方适配:OpenAI Chat Completions、OpenResponses、Slack、Canvas/A2UI 等。
  • 插件路由:在 Control UI 之前注册的插件端点优先,避免与内置路由冲突。
  • 安全头与速率限制:统一设置安全响应头,针对鉴权失败与钩子认证失败实施限流。
  • Canvas/A2UI:Canvas 请求鉴权与路径规范化,A2UI 请求直通处理。
flowchart TD
Start(["进入 handleRequest"]) --> Upgrade{"是否 WebSocket 升级?"}
Upgrade --> |是| Skip["交由 ws 处理"]
Upgrade --> |否| LoadCfg["加载配置与可信代理"]
LoadCfg --> Normalize["规范化 Canvas 路径"]
Normalize --> Stages["构建请求处理阶段列表"]
Stages --> Run["顺序执行各阶段"]
Run --> Done(["结束"])

WebSocket 服务器与连接管理

  • 握手挑战:发送 connect.challenge,限定握手超时,协议版本协商与错误处理。
  • 鉴权与速率限制:支持通用与浏览器来源的双速率限制器。
  • 客户端生命周期:记录连接元信息、最后帧元数据、断开原因与清理(Presence、Node 注销等)。
  • 广播与事件:支持带状态版本号的事件广播,维护 Presence 版本与健康版本。
sequenceDiagram
participant C as "客户端"
participant S as "HTTP 服务器"
participant W as "WebSocket 服务器"
participant H as "消息处理器"
C->>S : "HTTP 升级请求"
S->>W : "触发 upgrade 事件"
W->>C : "发送 connect.challenge"
C-->>W : "返回握手参数"
W->>H : "attachGatewayWsMessageHandler"
H-->>C : "连接就绪/事件推送"
C-->>H : "业务帧"
H-->>C : "响应/事件"
C-->>W : "断开"
W-->>S : "清理与日志"

端口监听与冲突处理

  • 重试策略:在端口被占用且未达最大重试次数时,先静默关闭服务器再等待固定间隔后重试。
  • 错误分类:区分“地址已在使用”与其它错误,前者抛出网关锁错误,后者包装为网关锁错误抛出。
flowchart TD
A["尝试 listen(port, host)"] --> B{"错误码为 EADDRINUSE?"}
B --> |是| C{"尝试次数 < 最大重试?"}
C --> |是| D["静默关闭服务器并等待"]
D --> A
C --> |否| E["抛出网关锁错误(已占用)"]
B --> |否| F["抛出网关锁错误(其他错误)"]

生命周期管理、优雅停机与重启

  • 信号处理:接收 SIGTERM/SIGINT 执行优雅停机;SIGUSR1 触发内部重启(无需外部监督者)。
  • 重启调度:支持延迟重启、冷却期合并、原因与审计信息记录;若已有未消费重启信号则合并。
  • 运行循环:持续启动服务器,等待重启解析器触发新一轮迭代;最终释放锁并清理信号。
sequenceDiagram
participant P as "进程"
participant RL as "运行循环"
participant SR as "重启调度"
participant SV as "服务器"
P->>RL : "启动"
RL->>SV : "start()"
P->>P : "监听 SIGTERM/SIGINT/SIGUSR1"
alt "SIGUSR1"
P->>SR : "scheduleGatewaySigusr1Restart(...)"
SR-->>P : "标记重启/合并"
P->>RL : "resolve() 触发重启"
else "SIGTERM/SIGINT"
P->>RL : "请求停止"
end
RL->>SV : "停止/清理"
RL->>SV : "重新 start()"

配置加载与环境变量

  • 配置读取:支持 .env 加载、include 合并、环境变量替换、缺失键告警、重复目录检测。
  • 环境变量替换:字符串内 ${VAR} 替换,支持转义与缺失键抛错。
  • 写回保留引用:在写回配置时,若新值与当前环境变量展开一致,则恢复原 ${VAR} 引用,避免硬编码破坏。
flowchart TD
R["读取配置文件"] --> ENV["加载 .env 与 Shell 环境回退"]
ENV --> SUB["环境变量替换 ${VAR}"]
SUB --> RES["解析与校验"]
RES --> PRES["写回时保留 ${VAR} 引用"]

监控、健康检查与故障恢复

  • 健康快照:聚合代理心跳、会话摘要、默认代理与心跳周期,支持深度探测与超时保护。
  • 故障恢复:WebSocket 握手超时、Canvas/A2UI 认证失败、钩子认证失败均具备限流与错误响应;HTTP 探针在内部异常时返回 503。
  • 测试辅助:提供 HTTP 测试夹具与 CDP 测试工具,便于模拟与验证。
flowchart TD
HStart["健康快照入口"] --> Agents["遍历代理与心跳"]
Agents --> Sessions["构建会话摘要"]
Sessions --> Probe["可选深度探测(超时保护)"]
Probe --> HOut["返回健康摘要"]

安全与 TLS 配置

  • 反向代理与可信代理:通过 gateway.trustedProxies 正确识别客户端真实 IP。
  • TLS 指纹固定:客户端侧支持指纹校验与 TOFU(首次信任)策略,防止中间人攻击。
  • Tailscale Serve 身份头:在允许情况下接受 Serve 注入的身份头,需谨慎配置避免代理转发伪造头。
graph TB
subgraph "客户端"
IOS["iOS 客户端<br/>GatewayTLSPinning.swift"]
AND["Android 客户端<br/>GatewayTls.kt"]
end
subgraph "服务端"
SEC["安全配置与审计<br/>security/index.md"]
end
IOS --> SEC
AND --> SEC

高可用与负载均衡部署

  • Fly.io 部署:提供 processes、http_service、min_machines_running、auto_start_machines 等关键参数,结合持久卷与内存配置保障稳定性。
  • 私有部署:通过移除 http_service 或使用私有模板,隐藏公网 IP,结合 WireGuard、SSH 或本地代理访问。
  • 健康检查端口:internal_port 必须与 --port 或 OPENCLAW_GATEWAY_PORT 一致,确保平台健康探针可达。

依赖关系分析

  • 低耦合:HTTP 与 WebSocket 通过“upgrade”事件解耦,各自职责清晰。
  • 配置驱动:路由与鉴权策略由配置决定,便于在不同环境间切换。
  • 信号驱动:重启与停机通过 Node.js 信号与自定义调度器协同,避免外部监督者依赖。
graph LR
CFG["配置(io.ts)"] --> HTTP["HTTP(server-http.ts)"]
CFG --> WS["WS(ws-connection.ts)"]
HTTP --> WS
RUN["运行循环(run-loop.ts)"] --> HTTP
RUN --> WS
RESTART["重启调度(infra/restart.ts)"] --> RUN

性能考量

  • 握手超时与速率限制:合理设置握手超时与鉴权限流,避免慢连接与暴力破解影响吞吐。
  • 插件与第三方适配:在 HTTP 路由中按需启用,减少不必要的中间件开销。
  • Canvas/A2UI:鉴权前置,避免无效请求进入后续处理链。
  • 重启冷却:合并多次重启请求,降低频繁重启对资源与稳定性的影响。
  • 部署内存:Fly.io 示例建议 2GB 内存起步,结合 NODE_OPTIONS 调整堆大小。

会话管理机制

会话管理机制

会话管理相关代码主要分布在以下模块:

  • 会话数据模型与合并策略:src/config/sessions/types.ts
  • 会话存储与维护:src/config/sessions/store.ts、store-cache.ts、disk-budget.ts
  • 会话写锁与并发控制:src/agents/session-write-lock.ts
  • 路由与会话键绑定:src/discord/monitor/route-resolution.ts、src/infra/outbound/bound-delivery-router.ts、src/infra/outbound/outbound-session.ts
  • 网关协议与会话 API 校验:src/gateway/protocol/index.ts、src/gateway/session-utils.types.ts
  • 事件订阅与广播:src/gateway/server-node-subscriptions.ts
  • 配置参考与策略:docs/gateway/configuration-reference.md
  • ACP 会话配置与运行时选项:src/acp/control-plane/manager.core.ts、src/auto-reply/reply/commands-acp/runtime-options.ts、src/agents/pi-extensions/session-manager-runtime-registry.ts
  • 测试用例与行为验证:多处测试文件
graph TB
subgraph "会话存储层"
Types["types.ts<br/>会话数据模型/合并策略"]
Store["store.ts<br/>加载/保存/维护"]
Cache["store-cache.ts<br/>缓存(TTL)"]
Budget["disk-budget.ts<br/>磁盘预算清理"]
end
subgraph "并发与锁"
Lock["session-write-lock.ts<br/>写锁/队列/看门狗"]
end
subgraph "路由与键"
RouteRes["route-resolution.ts<br/>路由解析/会话键绑定"]
BoundRouter["bound-delivery-router.ts<br/>绑定路由器"]
OutboundSess["outbound-session.ts<br/>出站会话路由"]
end
subgraph "网关与协议"
Proto["protocol/index.ts<br/>会话API校验"]
GwTypes["session-utils.types.ts<br/>网关会话类型"]
end
subgraph "事件与广播"
Subs["server-node-subscriptions.ts<br/>订阅/广播"]
end
Types --> Store
Store --> Cache
Store --> Budget
Store --> Lock
RouteRes --> BoundRouter
BoundRouter --> OutboundSess
Proto --> GwTypes
Store --> Subs

核心组件

  • 会话数据模型与合并策略:定义 SessionEntry 字段集、运行时模型字段规范化、合并策略(保留活动时间戳 vs 触摸活动)、默认重置触发词与空闲时长等。
  • 会话存储与维护:提供加载/保存/更新会话、维护(修剪过期、封顶条目、文件轮转)、磁盘预算清理、序列化缓存与对象缓存、Windows 原子写入与重试。
  • 并发控制:基于文件锁的写入队列,支持超时、过期清理、可重入锁、看门狗释放长时间占用锁。
  • 路由与会话键:根据通道/聊天类型/账号/线程构建或绑定会话键,支持直接会话覆盖持久化路由。
  • 网关协议与 API:AJV 校验器生成各会话操作参数的校验函数,统一错误格式化。
  • 事件订阅与广播:按会话键/节点集合进行事件分发,支持全量广播与连接节点广播。
  • 配置与权限:会话级发送策略、重置策略、磁盘预算阈值、线程绑定默认开关等。

架构总览

会话管理采用“模型-存储-并发-路由-协议-广播”的分层设计。模型层负责数据结构与合并;存储层负责持久化与维护;并发层通过写锁与队列保证一致性;路由层负责会话键生成与绑定;协议层提供 API 校验;广播层负责事件分发。

sequenceDiagram
participant Client as "客户端"
participant Proto as "协议校验(index.ts)"
participant Store as "会话存储(store.ts)"
participant Lock as "写锁(session-write-lock.ts)"
participant Cache as "缓存(store-cache.ts)"
participant Disk as "磁盘"
Client->>Proto : "调用会话API(如 sessions.patch)"
Proto-->>Client : "参数校验通过/失败"
Client->>Store : "updateSessionStore/updateSessionStoreEntry"
Store->>Lock : "acquireSessionWriteLock()"
Lock-->>Store : "获得写锁"
Store->>Store : "loadSessionStore()/mergeSessionEntry()"
Store->>Cache : "writeSessionStoreCache()"
Store->>Disk : "writeTextAtomic()"
Store-->>Lock : "release()"
Lock-->>Store : "释放完成"
Store-->>Client : "返回结果"

详细组件分析

会话数据模型与合并策略

  • 数据模型:包含会话标识、更新时间、路由上下文、运行时选项、令牌用量、ACP 元信息等字段。
  • 合并策略:
    • 默认策略:使用最大 updatedAt,确保活动时间不回退。
    • 保留活动策略:当存在既有条目时,保留其 updatedAt,避免因外部更新导致活动时间被刷新。
  • 运行时模型字段规范化:自动去除空字符串并统一大小写,防止脏数据进入存储。
  • 键生成:若未提供 sessionId,使用随机 UUID 生成。
classDiagram
class SessionEntry {
+string sessionId
+number updatedAt
+string? model
+string? modelProvider
+DeliveryContext? deliveryContext
+string? lastChannel
+string? lastTo
+string? lastAccountId
+number? lastThreadId
+SessionOrigin? origin
+SessionAcpMeta? acp
+...其他运行时/统计字段
}
class MergeStrategy {
+mergeSessionEntry(existing, patch)
+mergeSessionEntryPreserveActivity(existing, patch)
}
SessionEntry <.. MergeStrategy : "使用"

会话存储与维护

  • 加载流程:优先从缓存读取,否则从磁盘读取并应用迁移;Windows 下对空文件进行短暂重试;支持跳过缓存。
  • 保存流程:先进行维护(修剪、封顶、轮转、磁盘预算),再原子写入;写入前后更新缓存。
  • 维护策略:
    • 修剪过期:按 pruneAfterMs 删除旧条目。
    • 封顶条目:按 maxEntries 控制 sessions.json 条目数量。
    • 文件轮转:超过 rotateBytes 自动轮转。
    • 磁盘预算:按 maxDiskBytes/highWaterBytes 清理最旧会话与归档文件。
  • 缓存:对象缓存与序列化缓存双层缓存,带 TTL 与 mtime/size 校验。
flowchart TD
Start(["开始"]) --> Load["加载会话存储"]
Load --> CacheHit{"缓存命中且有效?"}
CacheHit --> |是| ReturnCache["返回缓存"]
CacheHit --> |否| ReadDisk["读取磁盘(JSON)"]
ReadDisk --> ApplyMigrations["应用迁移"]
ApplyMigrations --> Maintain["维护: 修剪/封顶/轮转/磁盘预算"]
Maintain --> AtomicWrite["原子写入磁盘(JSON)"]
AtomicWrite --> UpdateCache["更新缓存"]
UpdateCache --> End(["结束"])
ReturnCache --> End

并发控制与写锁

  • 写锁队列:每个 sessions.json 文件维护一个队列,串行化写操作,支持超时与过期清理。
  • 可重入:同进程内允许重入计数,减少不必要的锁竞争。
  • 看门狗:检测超时持有锁并自动释放,防止死锁。
  • Windows 原子写入:多次重试与回退策略,确保并发安全。
sequenceDiagram
participant Q as "队列"
participant L as "写锁"
Q->>Q : "入队任务"
Q->>L : "acquireSessionWriteLock()"
L-->>Q : "获得锁/超时"
Q->>Q : "执行任务(fn)"
Q-->>L : "release()"
L-->>Q : "释放完成"

路由与会话键生成

  • 会话键绑定:根据通道、聊天类型、账号、线程等生成或绑定会话键,支持路由覆盖(如 webchat 覆盖持久化路由)。
  • 出站会话路由:在无显式目标时推导基础会话键与 from/to,区分 direct/channel/group。
  • 绑定路由器:根据会话当前激活绑定选择目标,支持单绑/回退/歧义处理。
flowchart TD
A["输入: channel/target/thread"] --> B["推导peer/kind"]
B --> C["构建基础会话键(baseSessionKey)"]
C --> D{"是否显式提供路由?"}
D --> |是| E["使用显式路由(覆盖持久化)"]
D --> |否| F["使用持久化/默认路由"]
E --> G["输出: sessionKey/from/to/chatType"]
F --> G

事件订阅与广播

  • 订阅管理:按节点 ID 维护会话订阅集合,支持取消全部订阅。
  • 广播接口:按会话键广播、向所有订阅节点广播、向所有连接节点广播。
  • Payload 序列化:统一 JSON 序列化后发送。
sequenceDiagram
participant S as "订阅管理(server-node-subscriptions.ts)"
participant N as "节点(NodeSendEventFn)"
S->>S : "subscribe/unsubscribe"
S->>N : "sendToSession(event, payload)"
S->>N : "sendToAllSubscribed(event, payload)"
S->>N : "sendToAllConnected(event, payload)"

配置管理与权限控制

  • 发送策略:按通道/聊天类型/键前缀匹配,支持拒绝优先。
  • 重置策略:支持按每日/atHour 或空闲 idleMinutes 重置,二者取先到期者。
  • 磁盘预算:maxDiskBytes/highWaterBytes 控制清理策略,warn/enforce 模式。
  • ACP 运行时选项:通过 set_config_option 设置 runtimeMode、模型、工作目录、权限配置等,支持能力检查与键白名单。
flowchart TD
CFG["配置(session.config)"] --> Policy["发送策略(sendPolicy)"]
CFG --> Reset["重置策略(reset/resetByType)"]
CFG --> Maint["维护(maintenance)<br/>prune/maxEntries/rotate"]
CFG --> Budget["磁盘预算(maxDisk/highWater)"]
CFG --> ACP["ACP选项(set_config_option)"]

API 规范(会话 CRUD 与维护)

  • 列表/预览/解析:AJV 校验 sessions.list/preview/resolve 参数。
  • 更新/重置/删除/压缩/用量:AJV 校验 sessions.patch/reset/delete/compact/usage 参数。
  • 返回类型:统一 SessionsPatchResult,包含最终 SessionEntry 与解析后的模型信息。
classDiagram
class SessionsAPI {
+validateSessionsListParams()
+validateSessionsPreviewParams()
+validateSessionsResolveParams()
+validateSessionsPatchParams()
+validateSessionsResetParams()
+validateSessionsDeleteParams()
+validateSessionsCompactParams()
+validateSessionsUsageParams()
}
class SessionsPatchResult {
+entry : SessionEntry
+resolved? : {modelProvider?, model?}
}
SessionsAPI --> SessionsPatchResult : "返回"

会话状态同步与事件广播

  • 状态同步:内存管理器按阈值批量处理会话增量,触发同步。
  • 事件广播:通过节点订阅系统向订阅者推送事件,支持按会话键过滤。

会话压缩、清理策略与内存管理

  • 压缩:通过 sessions.compact 触发,结合磁盘预算清理策略。
  • 清理:按时间(pruneAfterMs)、数量(maxEntries)、大小(rotateBytes)与磁盘预算(maxDiskBytes/highWaterBytes)清理。
  • 内存管理:会话增量阈值触发同步,避免频繁落盘。

依赖关系分析

  • 存储层依赖:types.ts 提供模型与合并;store-cache.ts 提供缓存;disk-budget.ts 提供清理;session-write-lock.ts 提供并发。
  • 路由层依赖:route-resolution.ts/outbound-session.ts/bound-delivery-router.ts 协作生成/绑定会话键。
  • 协议层依赖:index.ts 生成各会话 API 的 AJV 校验器,session-utils.types.ts 定义返回类型。
  • 广播层依赖:server-node-subscriptions.ts 依赖节点发送接口。
graph LR
Types["types.ts"] --> Store["store.ts"]
Cache["store-cache.ts"] --> Store
Budget["disk-budget.ts"] --> Store
Lock["session-write-lock.ts"] --> Store
RouteRes["route-resolution.ts"] --> Bound["bound-delivery-router.ts"]
Outbound["outbound-session.ts"] --> Bound
Proto["protocol/index.ts"] --> GwTypes["session-utils.types.ts"]
Store --> Subs["server-node-subscriptions.ts"]

性能考量

  • 缓存策略:启用 TTL 的对象与序列化缓存,减少磁盘 IO;缓存失效基于 mtime/size 比较。
  • 写入优化:原子写入与 Windows 重试,降低写冲突;写锁队列串行化写操作。
  • 清理策略:按时间/数量/大小/磁盘预算分层清理,避免 sessions.json 过大。
  • 广播优化:按会话键精确投递,避免全量广播带来的网络压力。

监控与诊断

监控与诊断

围绕监控与诊断的关键目录与文件如下:

  • 文档层:提供 CLI 健康检查、网关健康检查、OAuth 认证监控等使用说明
  • 日志与诊断:集中于诊断子系统,提供心跳、会话状态、消息处理、队列与工具环路检测等事件记录
  • 状态构建:为通道与账户状态汇总提供统一的数据结构与辅助函数
  • 定时任务与告警:CLI 编辑定时任务、服务端定时器与作业调度、失败告警发送
  • 可视化与统计:前端仪表板对用量、错误高峰、峰值进行可视化呈现与聚合
graph TB
subgraph "文档与CLI"
D1["docs/cli/health.md"]
D2["docs/gateway/health.md"]
D3["docs/automation/auth-monitoring.md"]
end
subgraph "日志与诊断"
L1["src/logging/diagnostic.ts"]
S1["src/plugin-sdk/status-helpers.ts"]
end
subgraph "定时任务与告警"
C1["src/cli/cron-cli/register.cron-edit.ts"]
C2["src/cron/service/timer.ts"]
C3["src/cron/service/jobs.ts"]
G1["src/gateway/server-cron.ts"]
end
subgraph "可视化与统计"
U1["ui/src/ui/views/usage-render-overview.ts"]
U2["ui/src/ui/views/usage-render-details.ts"]
SA["src/shared/usage-aggregates.ts"]
UC["ui/src/ui/views/cron.ts"]
end
D1 --> L1
D2 --> L1
D3 --> C1
L1 --> U1
L1 --> U2
S1 --> L1
C1 --> C2
C2 --> C3
G1 --> C2
U1 --> SA
U2 --> SA
UC --> C1

核心组件

  • 健康检查与状态快照
    • CLI 健康命令与网关健康快照,支持 JSON 输出与深度探测
    • 通道健康判断与探针描述(超时、状态码、错误)
  • 诊断日志与心跳
    • Webhook 收发计数与错误统计、消息入队/处理、会话状态变更与卡顿检测
    • 诊断心跳周期性输出活动指标并触发清理与告警
  • 状态汇总与问题收集
    • 默认通道运行态、基础与探针通道状态摘要、账户运行态与计算态快照
    • 从最后错误提取通道问题列表
  • 定时任务与失败告警
    • CLI 编辑定时任务参数(含失败告警 after/cooldown/mode/channel/to/accountId)
    • 服务端定时器在连续失败后发送告警或系统事件
    • 作业调度记录计划计算错误并自动禁用高错误作业
  • 用量与可视化
    • 按日/按模型/按提供商/按工具/按代理/按通道聚合用量与成本
    • 错误高峰(日/小时)与洞察卡片渲染
  • OAuth 认证监控
    • CLI 模型状态检查与退出码约定,自动化脚本与 systemd 定时器

架构总览

下图展示监控与诊断在系统中的交互路径:CLI 健康查询、网关健康快照、诊断日志与心跳、状态汇总、定时任务与告警、用量聚合与可视化。

graph TB
CLI["CLI 健康命令<br/>openclaw health"] --> GW["网关健康快照"]
GW --> SNAP["健康快照<br/>通道/账户/探针"]
SNAP --> DIAG["诊断日志与心跳<br/>webhook/消息/会话/队列"]
DIAG --> HEART["诊断心跳<br/>周期性输出指标"]
DIAG --> STATUS["状态汇总<br/>通道/账户/运行态"]
STATUS --> ALERT["失败告警<br/>定时任务/系统事件"]
DIAG --> USAGE["用量与可视化<br/>日/模型/提供商/工具/代理/通道"]
ALERT --> TIMER["定时器<br/>连续失败告警"]
TIMER --> JOBS["作业调度<br/>计划错误与自动禁用"]
USAGE --> UI["前端仪表板"]

组件详解

健康检查与状态监控

  • CLI 健康命令
    • 支持 JSON 输出与详细模式,打印每账号探针时延
  • 网关健康快照
    • 包含凭证/认证年龄、通道探针摘要、会话存储摘要、探针耗时;可指定超时
  • 通道健康判定
    • 配置为真且探针存在则视为健康;探针缺失视为“已配置但未知”
    • 超时或状态缺失时以超时描述;否则输出错误原因与状态码
  • 状态汇总构建
    • 默认通道运行态、基础与探针通道状态摘要、账户运行态与计算态快照
    • 从最后错误提取通道问题列表
flowchart TD
Start(["开始"]) --> Probe["执行通道探针"]
Probe --> Healthy{"探针成功且配置为真?"}
Healthy --> |是| Ok["标记健康"]
Healthy --> |否| Timeout{"是否超时/状态缺失?"}
Timeout --> |是| TimeoutMsg["记录超时描述"]
Timeout --> |否| StatusErr["记录错误原因与状态码"]
Ok --> Snapshot["生成健康快照"]
TimeoutMsg --> Snapshot
StatusErr --> Snapshot
Snapshot --> End(["结束"])

诊断日志与心跳

  • 关键事件
    • Webhook 接收/处理/错误计数与最近时间
    • 消息入队/处理(完成/跳过/错误)、时延与原因
    • 会话状态变更(idle 时减少队列深度)、卡顿检测
    • 队列通道入队/出队、等待时长
    • 工具环路检测(警告/严重级别、阻断动作)
  • 心跳机制
    • 周期性清理过期会话状态、统计活跃/等待/排队总数
    • 当无活动或长时间无活动时停止输出
    • 对处理中且超过阈值的会话发出卡顿告警
sequenceDiagram
participant Sys as "系统"
participant Log as "诊断日志"
participant HB as "诊断心跳"
participant Ev as "诊断事件"
Sys->>Log : "记录 webhook/received"
Log->>Ev : "emit webhook.received"
Sys->>Log : "记录 webhook/processed"
Log->>Ev : "emit webhook.processed"
Sys->>Log : "记录 message/processed(error)"
Log->>Ev : "emit message.processed"
Sys->>Log : "记录 session/state"
Log->>Ev : "emit session.state"
HB->>HB : "周期性扫描会话状态"
HB->>Log : "logSessionStuck(超阈值)"
Log->>Ev : "emit session.stuck"

定时任务与失败告警

  • CLI 编辑定时任务
    • 支持设置失败告警 after、cooldown、mode、channel、to、accountId
    • 参数校验:after 必须为正整数;cooldown 必须为合法持续时间;mode 仅允许 announce/webhook
  • 服务端定时器
    • 连续失败达到阈值后发送告警(announce 或 webhook),或入队系统事件
    • 失败告警发送失败时记录警告
  • 作业调度
    • 计划计算错误累计到阈值后自动禁用作业,并通过系统事件通知用户
sequenceDiagram
participant User as "用户/CLI"
participant Cron as "定时任务服务"
participant Timer as "定时器"
participant Jobs as "作业调度"
participant Alert as "告警通道"
User->>Cron : "编辑任务(含失败告警参数)"
Cron-->>User : "更新成功"
Timer->>Jobs : "触发失败告警"
Timer->>Alert : "发送失败告警(announce/webhook)"
Alert-->>Timer : "投递结果"
Timer->>Jobs : "必要时请求心跳"
Jobs->>Jobs : "记录计划错误并可能自动禁用"

OAuth 认证监控

  • CLI 检查
    • openclaw models status --check 提供标准化退出码:0 正常;1 缺失/过期;2 即将过期(24 小时内)
  • 自动化脚本
    • systemd 用户定时器与脚本(auth-monitor.sh、claude-auth-status.sh 等)
    • 优先使用 CLI 作为事实来源,回退到文件读取

用量统计与可视化

  • 聚合维度
    • 按日、按模型、按提供商、按工具、按代理、按通道聚合用量与成本
    • 计算平均 tokens/消息、平均 cost/消息、缓存命中率、错误率、吞吐量、平均时长
  • 可视化组件
    • 日度用量柱状图(总量/按类型)、成本/令牌构成条形图
    • 洞察卡片:Top 模型/提供商/工具/代理/通道、峰值错误日/小时
    • 会话列表排序与筛选、复制会话名、最近查看会话标签页
  • 数据范围与过滤
    • 支持日期范围选择、小时选择、会话筛选;按所选天数重新计算会话值
flowchart TD
Load["加载用量数据"] --> Aggregate["按日/模型/提供商/工具/代理/通道聚合"]
Aggregate --> Metrics["计算指标<br/>平均tokens/消息、平均cost/消息、缓存命中率、错误率、吞吐量、平均时长"]
Metrics --> Render["渲染图表与洞察卡片"]
Load --> Filter["按日期/小时/会话筛选"]
Filter --> Recalc["重新计算选区内的会话值"]
Recalc --> Render

依赖关系分析

  • 诊断日志模块依赖配置加载与子系统日志器,向外发出诊断事件
  • 状态汇总模块提供统一的通道与账户状态摘要构建函数
  • 定时任务编辑 CLI 与服务端定时器/作业调度协同,形成“配置-执行-告警-自愈”的闭环
  • 前端用量视图依赖共享聚合工具与后端用量数据
graph LR
CFG["配置加载"] --> DIAG["诊断日志"]
SUB["子系统日志器"] --> DIAG
DIAG --> EVT["诊断事件"]
SH["状态汇总辅助"] --> DIAG
CLI["定时任务编辑CLI"] --> SVC["定时器服务"]
SVC --> JOBS["作业调度"]
JOBS --> ALERT["失败告警"]
DIAG --> UI["用量可视化"]
AGG["用量聚合工具"] --> UI

性能考量

  • 诊断心跳间隔与卡顿阈值
    • 心跳周期固定,卡顿阈值可由配置决定并在合理区间内裁剪
    • 无活动时停止输出,避免无效日志
  • 会话状态管理
    • 周期性修剪过期状态,降低内存占用
    • 处理中会话超过阈值即告警,便于快速定位瓶颈
  • 用量聚合
    • 按日/多维聚合,支持分段计算与范围过滤,避免全量重算
  • 告警节流
    • 失败告警 cooldown 控制最小告警间隔,避免风暴

配置管理

配置管理

配置管理相关代码集中在 src/config 目录,围绕“解析—合并—校验—应用默认—写入—备份—热重载”的闭环展开;网关侧通过独立模块实现配置变更检测与热重载执行。

graph TB
subgraph "配置加载与解析"
A["io.ts<br/>读取/解析/包含/环境变量替换/校验/默认值"]
B["includes.ts<br/>$include 指令与安全读取"]
C["env-substitution.ts<br/>${VAR} 环境变量替换"]
end
subgraph "模型与验证"
D["schema.ts<br/>动态 Schema 生成/提示/查找"]
E["validation.ts<br/>Zod 校验/插件/通道/遗留迁移检查"]
F["defaults.ts<br/>默认值与规范化"]
end
subgraph "安全与持久化"
G["redact-snapshot.ts<br/>敏感信息脱敏/还原"]
H["backup-rotation.ts<br/>备份轮转/权限加固/清理"]
end
subgraph "运行时与热重载"
I["config-reload.ts<br/>变更检测/计划/重启或热重载"]
end
A --> B
A --> C
A --> E
A --> F
D --> E
G --> A
H --> A
I --> A

核心组件

  • 配置 IO 与生命周期:负责从磁盘读取、解析 JSON5、处理 $include、应用环境变量替换、执行校验与默认值注入、最终输出规范化配置,并支持写入与审计。
  • 动态 Schema 与 UI 提示:根据插件与通道扩展生成最终 Schema,并提供 UI 帮助与敏感标记,用于脱敏与提示。
  • 验证与兼容:使用 Zod 进行强类型校验,结合插件清单、通道列表、遗留配置迁移检查,确保配置有效且可运行。
  • 默认值与规范化:对会话、消息、代理并发、模型、日志等进行默认值填充与规范化,保证最小可用配置集。
  • 安全与脱敏:在读取/写入路径上对敏感字段进行脱敏与还原,避免凭据泄露。
  • 备份与版本:写入前进行备份轮转与权限加固,记录写入审计日志,便于回滚与追踪。
  • 热重载:监听配置文件变化,计算变更路径,按策略选择重启或热重载,保证运行时一致性。

架构总览

下图展示从磁盘到运行时配置的完整流程,包括热重载与安全控制。

sequenceDiagram
participant FS as "文件系统"
participant IO as "配置IO(io.ts)"
participant INC as "$include(includes.ts)"
participant ENV as "${VAR}(env-substitution.ts)"
participant VAL as "校验(validation.ts)"
participant DEF as "默认值(defaults.ts)"
participant SNAP as "快照/审计"
participant GW as "网关重载(config-reload.ts)"
FS-->>IO : 读取 openclaw.json(.bak)
IO->>INC : 解析 $include 并合并
IO->>ENV : 应用环境变量替换
IO->>VAL : 执行 Zod 校验与插件/通道检查
VAL-->>IO : 校验结果(issues/warnings)
IO->>DEF : 注入默认值与规范化
IO->>SNAP : 写入前备份轮转/权限加固/审计
IO-->>GW : 提供最新配置快照
GW->>GW : 计算变更路径/构建重载计划
alt 热重载模式
GW-->>IO : 触发热重载回调
else 需要重启
GW-->>IO : 触发重启
end

详细组件分析

组件一:配置加载与写入(含包含、环境变量、校验、默认值)

  • 文件包含与安全读取:支持 $include 字符串或数组,递归深度限制与环检测,路径必须位于配置根目录内,使用边界文件打开限制硬链接与大小,防止越权与滥用。
  • 环境变量替换:仅匹配大写/下划线命名规则,支持转义 $$${VAR} 输出原样,缺失时可回调收集警告而非直接抛错,便于非关键功能降级。
  • 校验与默认值:先执行遗留问题检查与 Zod 校验,再注入模型/代理/会话/日志等默认值,最后进行路径与执行安全配置规范化。
  • 写入与审计:写入前进行备份轮转与权限加固,记录写入审计日志,包含变更计数、网关模式前后对比、可疑行为标记等,便于回溯。
flowchart TD
S["开始"] --> R["读取原始 JSON5"]
R --> I["$include 解析与合并"]
I --> E["环境变量替换(可收集警告)"]
E --> V["Zod 校验/插件/通道/遗留检查"]
V --> |通过| D["注入默认值与规范化"]
V --> |失败| ERR["输出错误与详情"]
D --> W["写入前备份轮转/权限加固/审计"]
W --> OK["完成"]
ERR --> END["结束"]
OK --> END

组件二:动态 Schema 与 UI 提示

  • Schema 生成:以基础 Schema 为根,按插件与通道扩展,合并 UI 提示与敏感标记,支持按需缓存与版本标注,便于前端表单渲染与用户引导。
  • 路径查询:支持标准化路径解析、通配符匹配、层级子节点枚举,返回类型、必填、子项等元信息,辅助 UI 与 CLI 自动补全与帮助。
classDiagram
class SchemaBuilder {
+buildConfigSchema(plugins, channels) ConfigSchemaResponse
+lookupConfigSchema(resp, path) LookupResult
}
class PluginUiMetadata {
+id
+name
+description
+configUiHints
+configSchema
}
class ChannelUiMetadata {
+id
+label
+description
+configSchema
+configUiHints
}
SchemaBuilder --> PluginUiMetadata : "应用插件Schema/提示"
SchemaBuilder --> ChannelUiMetadata : "应用通道Schema/提示"

组件三:配置验证与兼容

  • 强类型校验:基于 Zod 对原始配置进行校验,收集路径与允许值提示,输出人类可读的错误与警告。
  • 插件与通道:扫描插件清单与通道注册表,校验未知通道/插件 ID,校验心跳目标合法性,插件配置按其 Schema 校验。
  • 遗留迁移:发现遗留配置问题后给出修复建议,必要时提示升级版本或调整策略。
flowchart TD
RAW["原始配置"] --> L["遗留问题检查"]
L --> |有| FIX["输出修复建议"]
L --> |无| Z["Zod 校验"]
Z --> |失败| ISS["收集 issues/warnings"]
Z --> |通过| PLUG["插件/通道校验"]
PLUG --> OK["通过"]

组件四:默认值与规范化

  • 默认值覆盖:对会话主键、消息 ACK 范围、代理并发、模型成本/上下文窗口/最大输出、日志敏感度、上下文修剪与心跳策略等进行默认值注入。
  • 规范化:对 Talk 配置、模型别名、路径与执行安全配置进行统一化处理,减少运行时歧义。
flowchart TD
CFG["配置对象"] --> M["模型默认值"]
CFG --> A["代理默认值"]
CFG --> S["会话默认值"]
CFG --> L["日志默认值"]
CFG --> CP["上下文修剪/心跳默认值"]
M --> N["规范化(Talk/路径/安全)"]
A --> N
S --> N
L --> N
CP --> N
N --> OUT["最终配置"]

组件五:安全与敏感信息保护

  • 脱敏策略:基于 UI 提示与敏感路径规则,对字符串与对象进行脱敏;支持 SecretRef 结构化脱敏;同时对原始 JSON5 文本进行敏感值替换。
  • 还原机制:在写入前对带哨兵值的输入进行还原,确保凭据不被破坏;若无法还原则发出警告并拒绝处理无效输入。
  • 审计与日志:记录写入事件、变更数量、网关模式变化、可疑行为等,便于合规与排障。
sequenceDiagram
participant UI as "前端/CLI"
participant SNAP as "redact-snapshot.ts"
UI->>SNAP : 输入配置(可能包含哨兵值)
SNAP->>SNAP : 脱敏(对象/原始文本)
SNAP-->>UI : 返回脱敏后的快照
UI->>SNAP : 写入请求(含哨兵值)
SNAP->>SNAP : 还原敏感值(按路径映射)
SNAP-->>UI : 返回还原后的配置

组件六:备份、版本与回滚

  • 备份轮转:写入前将现有 .bak 移动为 .bak.1,依序向更高编号移动,删除最高编号,形成固定数量的轮转备份。
  • 权限加固:对所有 .bak 文件设置仅属主可读写权限,降低凭据泄露风险。
  • 清理孤儿:移除不在轮转范围内的 .bak.* 文件,避免空间浪费与混淆。
  • 审计日志:记录写入结果、变更计数、网关模式变化、可疑行为等,便于回滚与溯源。
flowchart TD
W["写入开始"] --> ROT["轮转备份(逐级右移)"]
ROT --> COPY["复制当前配置为 .bak"]
COPY --> CHMOD["加固 .bak 权限"]
CHMOD --> CLEAN["清理孤儿 .bak.*"]
CLEAN --> LOG["写入审计日志"]
LOG --> DONE["完成"]

组件七:热重载与回滚策略

  • 变更检测:比较前后配置的差异路径,支持对象与数组结构化比较,避免无关变动触发。
  • 重载策略:依据配置项决定是否需要重启网关;支持 off/restart/hybrid/hot 四种模式,hybrid 为默认;热模式下若需重启则忽略热重载并记录告警。
  • 重启队列:避免并发重启,失败时保留队列并在后续变更中重试。
  • 监听与防抖:使用 chokidar 监听文件增删改,awaitWriteFinish 与轮询参数提升稳定性,错误时优雅关闭监听器。
sequenceDiagram
participant FS as "文件系统"
participant CR as "config-reload.ts"
participant PLAN as "重载计划"
FS-->>CR : 文件事件(add/change/unlink)
CR->>CR : 防抖/去重
CR->>CR : 读取快照/校验/计算变更路径
CR->>PLAN : 构建重载计划
alt 需要重启
CR-->>CR : 入队重启(onRestart)
else 热重载
CR-->>CR : 触发热重载(onHotReload)
end

依赖分析

  • 模块耦合
    • io.ts 依赖 includes.ts、env-substitution.ts、validation.ts、defaults.ts、backup-rotation.ts、redact-snapshot.ts,是配置生命周期的核心枢纽。
    • schema.ts 依赖 zod-schema 与 hints,为 UI 与 CLI 提供 Schema 与提示。
    • config-reload.ts 依赖 io.ts 的快照能力与变更路径计算,驱动运行时更新。
  • 外部依赖
    • JSON5 解析、chokidar 文件监控、NodeFS、边界文件读取工具等。
  • 循环依赖
    • 当前设计通过导出接口与分层职责避免循环依赖;如需扩展插件/通道 Schema,应保持 schema.ts 与 validation.ts 的纯函数式交互。
graph LR
IO["io.ts"] --> INC["includes.ts"]
IO --> ENV["env-substitution.ts"]
IO --> VAL["validation.ts"]
IO --> DEF["defaults.ts"]
IO --> BR["backup-rotation.ts"]
IO --> RS["redact-snapshot.ts"]
SC["schema.ts"] --> VAL
CR["config-reload.ts"] --> IO

性能考虑

  • 合并与遍历
    • $include 合并采用深合并策略,数组拼接、对象递归合并,注意避免过深嵌套与超大文件导致内存压力。
    • 环检测与深度限制(默认 10 层)防止恶意配置造成栈溢出。
  • 环境变量替换
    • 仅在字符串中扫描占位符,避免对大对象重复遍历;缺失变量可回调收集警告,减少阻塞。
  • 校验与默认值
    • Zod 校验与默认值注入按需执行,避免重复计算;Schema 缓存与键排序减少重复构建开销。
  • 热重载
    • 防抖与 pending 标记避免频繁触发;awaitWriteFinish 参数提升写入完成稳定性,减少误判。
  • 备份与审计
    • 轮转与权限加固为异步操作,失败时采用 best-effort,不影响主流程;审计日志追加写入,注意磁盘空间与权限。

认证与授权

认证与授权

OpenClaw 将认证与授权能力分布在多个层次:

  • 共享层:设备认证数据结构与工具函数(角色、作用域规范化)
  • 基础设施层:设备配对状态、令牌生成与校验、作用域扩展与允许判定
  • 网关层:WebSocket 连接认证、HTTP 授权辅助、速率限制、启动时认证策略
  • 浏览器与 HTTP 层:浏览器端 HTTP 授权(Bearer/Basic)
  • 安全与审计:恒时比较、Windows ACL 检测、日志文件权限审计
  • 文档与配置参考:网关配置、信任代理模式、安全模型说明
graph TB
subgraph "共享层"
DA["设备认证类型<br/>src/shared/device-auth.ts"]
end
subgraph "基础设施层"
DP["设备配对与令牌<br/>src/infra/device-pairing.ts"]
end
subgraph "网关层"
SH["认证共享与测试夹具<br/>src/gateway/server.auth.shared.ts"]
SUITE["认证行为测试套件<br/>src/gateway/server.auth.control-ui.suite.ts"]
WS["WS 连接认证入口<br/>src/gateway/server.ws.auth.ts"]
DEVICES["设备 RPC 方法<br/>src/gateway/server-methods/devices.ts"]
SCHEMA["设备事件协议模式<br/>src/gateway/protocol/schema/devices.ts"]
RL["认证速率限制<br/>src/gateway/auth-rate-limit.ts"]
end
subgraph "浏览器/HTTP"
BA["浏览器 HTTP 授权<br/>src/browser/http-auth.ts"]
end
subgraph "安全与审计"
SE["恒时比较<br/>src/security/secret-equal.ts"]
WA["Windows ACL 解析与总结<br/>src/security/windows-acl.ts"]
AUD["日志与配置审计<br/>src/security/audit-extra.async.ts"]
end
subgraph "文档与配置"
CFG["网关配置参考<br/>docs/gateway/configuration-reference.md"]
SECDOC["安全模型与信任边界<br/>docs/gateway/security/index.md"]
TPA["信任代理认证<br/>docs/gateway/trusted-proxy-auth.md"]
SECMD["整体安全声明<br/>SECURITY.md"]
end
DA --> DP
DP --> WS
DP --> DEVICES
SH --> SUITE
SH --> WS
RL --> WS
BA --> WS
SE --> BA
WA --> AUD
AUD --> CFG
SECDOC --> CFG
TPA --> CFG
SECMD --> CFG

核心组件

  • 设备认证数据结构与工具
    • 角色与作用域规范化、去重排序
    • 设备认证存储结构(版本、设备 ID、令牌集合)
  • 设备配对与令牌管理
    • 待批准/已批准设备状态、令牌生成与校验
    • 作用域扩展与“含意”推导(如 admin 含义 read/write/pairing/approvals)
    • 令牌轮换、吊销、使用时间记录
  • 网关认证与速率限制
    • WebSocket 连接认证入口、速率限制(按作用域与客户端 IP)
    • HTTP 授权辅助(Bearer/Basic),恒时比较
  • 安全与审计
    • 恒时比较防止时序攻击
    • Windows ACL 解析与总结,日志文件可读性审计
    • 配置快照读取与安全检查

架构总览

下图展示从客户端发起连接到网关完成认证的关键交互路径,以及设备令牌校验与速率限制的作用点。

sequenceDiagram
participant Client as "客户端"
participant WS as "WebSocket 连接<br/>server.ws.auth.ts"
participant Pair as "设备配对与令牌<br/>infra/device-pairing.ts"
participant RL as "速率限制<br/>auth-rate-limit.ts"
participant Sec as "安全工具<br/>secret-equal.ts"
Client->>WS : "connect 请求含 token 或 device"
WS->>RL : "检查共享密钥/设备令牌速率限制"
alt 使用设备令牌
WS->>Pair : "verifyDeviceToken(deviceId, token, role, scopes)"
Pair->>Sec : "恒时比较可选"
Sec-->>Pair : "比较结果"
Pair-->>WS : "{ok : true/false}"
else 使用共享密钥
WS->>Sec : "safeEqualSecret(provided, expected)"
Sec-->>WS : "比较结果"
end
WS-->>Client : "认证结果成功/失败"

详细组件分析

设备认证与配对(Device Authentication & Pairing)

  • 数据结构
    • 设备认证条目包含令牌、角色、作用域与更新时间
    • 存储结构包含版本、设备 ID 与令牌映射
  • 角色与作用域
    • 角色与作用域均进行修剪与去空白处理
    • 作用域集合去重并排序,保证一致性
  • 作用域含义与继承
    • 内置作用域含义映射:例如 admin 含义 read/write/pairing/approvals;write 含义 read
    • 推理函数对请求与允许作用域进行扩展,再做允许判定
  • 令牌生命周期
    • 生成新令牌、轮换、吊销、使用时间记录
    • 校验时检查设备是否已配对、角色是否存在、令牌未被吊销、令牌匹配、作用域允许
  • 控制界面与配对流程
    • 设备配对请求事件与解析事件的协议模式
    • 设备 RPC 方法支持列出、批准、撤销等操作
    • 测试套件验证配对与速率限制行为
classDiagram
class DeviceAuthEntry {
+string token
+string role
+string[] scopes
+number updatedAtMs
}
class DeviceAuthStore {
+number version
+string deviceId
+Record~string, DeviceAuthEntry~ tokens
}
class PairedDevice {
+string deviceId
+string publicKey
+string[] roles
+string[] scopes
+Record~string, DeviceAuthToken~ tokens
}
class DeviceAuthToken {
+string token
+string role
+string[] scopes
+number createdAtMs
+number rotatedAtMs
+number revokedAtMs
+number lastUsedAtMs
}
DeviceAuthStore --> DeviceAuthEntry : "持有"
PairedDevice --> DeviceAuthToken : "持有"

认证流程与速率限制

  • 速率限制
    • 支持按作用域(共享密钥、设备令牌、钩子)与客户端 IP 维度计数
    • 默认滑动窗口与锁定时长可配置,回环地址默认豁免
    • 提供检查、记录失败、重置与清理接口
  • 连接认证
    • 在 WebSocket 连接阶段先检查速率限制,再执行具体认证(设备令牌或共享密钥)
    • 设备令牌认证包含来源标记(显式设备令牌 vs 其他来源),用于错误原因细化
  • 启动时认证策略
    • 支持 token、trusted-proxy、none 等模式
    • 在受信代理模式下,控制界面可无需设备身份直接连接
    • 不在受信代理模式下生成新令牌
flowchart TD
Start(["收到连接请求"]) --> CheckRL["检查速率限制按作用域/IP"]
CheckRL --> Allowed{"允许继续?"}
Allowed --> |否| Reject["返回速率限制错误"]
Allowed --> |是| ChooseAuth{"选择认证方式"}
ChooseAuth --> |设备令牌| VerifyDT["校验设备令牌与作用域"]
ChooseAuth --> |共享密钥| VerifySK["恒时比较共享密钥"]
VerifyDT --> DTOK{"通过?"}
VerifySK --> SKOK{"通过?"}
DTOK --> |是| OK["认证成功"]
DTOK --> |否| Fail["认证失败"]
SKOK --> |是| OK
SKOK --> |否| Fail

HTTP 授权与浏览器端校验

  • 浏览器端 HTTP 授权
    • 支持 Bearer 与 Basic 认证头解析
    • 使用恒时比较避免时序攻击
  • HTTP 授权辅助
    • 网关侧对 Bearer Token 的转发与失败响应处理
  • 输入标准化与掩码
    • 秘密输入标准化(去除换行、Latin-1 过滤、空白修剪)
    • API Key 掩码显示策略
sequenceDiagram
participant Browser as "浏览器/客户端"
participant GW as "网关 HTTP 层"
participant Sec as "恒时比较"
Browser->>GW : "带 Authorization 头的请求"
GW->>GW : "解析 Bearer/Basic"
GW->>Sec : "safeEqualSecret(provided, expected)"
Sec-->>GW : "比较结果"
GW-->>Browser : "授权通过/失败"

OAuth 与外部提供者集成

  • OAuth 与令牌型凭据
    • 列表命令中统计 OAuth 与 token 类型凭据
    • 使用认证健康摘要聚合各提供者的认证状态
  • 提供者凭据解析
    • 识别 OAuth-like 凭据(oauth/token),结合配置与存储进行解析
  • 实践要点
    • 将敏感凭据置于安全存储或环境变量中,避免明文写入配置
    • 对外提供者凭据进行最小权限授权与定期轮换

安全策略、加密与审计

  • 加密与恒时比较
    • 使用 SHA-256 哈希与恒时比较函数,降低时序攻击风险
  • Windows ACL 审计
    • 解析 icacs 输出,识别可信主体与不可信主体,汇总可读/可写权限
  • 日志与配置审计
    • 检测日志文件是否对其他用户可读,提供修复建议
    • 读取配置快照以进行安全审计
flowchart TD
A["读取日志文件路径"] --> B["解析路径权限"]
B --> C{"是否对世界/组可读?"}
C --> |是| D["记录告警并提供修复建议"]
C --> |否| E["通过"]

多租户与信任边界

  • 信任模型
    • 单网关实例内,认证为受信操作员,非对抗多租户边界
    • 会话标识符为路由选择器,非授权令牌
  • 建议
    • 若需对抗性用户隔离,应使用独立网关/主机/OS 用户
    • 共享代理场景下,建议分离业务与个人身份,避免混合运行时

依赖关系分析

  • 组件耦合
    • 设备认证与配对紧密耦合,前者提供数据结构,后者提供状态机与校验逻辑
    • 网关认证入口依赖速率限制与安全工具,形成“先限流、后校验”的控制流
    • 浏览器端 HTTP 授权依赖恒时比较,确保跨层一致的安全策略
  • 外部依赖与集成点
    • 受信代理模式通过反向代理注入用户身份头,网关据此放行
    • OAuth/令牌型凭据通过提供者存储与配置解析统一管理
graph LR
DA["设备认证<br/>shared/device-auth.ts"] --> DP["设备配对<br/>infra/device-pairing.ts"]
DP --> WS["WS 认证<br/>gateway/server.ws.auth.ts"]
RL["速率限制<br/>gateway/auth-rate-limit.ts"] --> WS
SE["恒时比较<br/>security/secret-equal.ts"] --> BA["HTTP 授权<br/>browser/http-auth.ts"]
SE --> WS
CFG["配置参考<br/>docs/gateway/configuration-reference.md"] --> WS
TPA["信任代理<br/>docs/gateway/trusted-proxy-auth.md"] --> WS

性能考量

  • 速率限制
    • 使用纯内存 Map,周期性清理避免无界增长
    • 回环地址豁免减少本地调试影响
  • 认证路径
    • 恒时比较避免分支导致的时序泄漏
    • 作用域扩展采用队列传播,复杂度与作用域数量线性相关
  • 日志与审计
    • 文件权限检测与配置快照读取为异步 I/O,注意批量扫描规模

网关控制平面

网关控制平面

网关控制平面由“服务端(Node)”和“客户端(多平台)”两部分组成:

  • 服务端:基于 ws 的 WebSocket 服务器,负责握手、鉴权、配对、广播事件、处理请求与响应。
  • 客户端:Node 客户端与 iOS/macOS 客户端,分别通过 ws/wss 连接网关,发送 connect 请求、接收事件、执行方法调用。
graph TB
subgraph "客户端"
NCLI["Node 客户端<br/>src/gateway/client.ts"]
IOS["iOS/macOS 客户端<br/>apps/shared/OpenClawKit/GatewayChannel.swift"]
end
subgraph "网关服务端"
WS["WS 握手与消息处理<br/>src/gateway/server/ws-connection/message-handler.ts"]
AUTH["鉴权上下文<br/>src/gateway/server/ws-connection/auth-context.ts"]
HEALTH["健康快照与版本<br/>src/gateway/server/health-state.ts"]
METHODS["方法分发与限流<br/>src/gateway/server-methods.ts"]
end
NCLI --> WS
IOS --> WS
WS --> AUTH
WS --> HEALTH
WS --> METHODS

核心组件

  • WebSocket 帧与协议模型
    • 服务端与客户端均使用统一的帧类型:req/res/event,以及通用的错误形状与连接参数校验。
  • 握手与鉴权
    • 首包必须是 connect 请求;服务端进行协议版本协商、角色与作用域解析、浏览器来源校验、设备身份验证与配对决策。
  • 会话与配对
    • 设备配对支持静默本地配对、升级场景(角色/作用域/元数据)与审批流程;支持受信代理身份透传。
  • 事件与状态
    • 服务端维护系统存在性快照与健康快照,周期性广播 tick、shutdown、presence、health 等事件。
  • 方法调用与广播
    • 支持控制面写入限流、节点侧能力扩展;方法分发器根据方法名路由至核心处理器或插件处理器。
  • 生命周期与健康检查
    • CLI 提供守护进程式启动/停止/重启,并带超时重试与端口监听健康检查。

架构总览

下图展示从客户端发起连接到服务端完成握手、鉴权、配对与状态同步的关键步骤,以及后续的事件与请求处理路径。

sequenceDiagram
participant C as "客户端<br/>Node/iOS/macOS"
participant S as "网关服务端"
participant AC as "鉴权上下文"
participant PH as "健康快照"
participant HM as "方法分发"
C->>S : "connect(req)"
S->>AC : "解析共享/设备令牌与来源"
AC-->>S : "鉴权结果"
S->>S : "设备身份签名验证/配对决策"
S-->>C : "hello-ok(res)<br/>携带策略与可选设备令牌"
S->>PH : "构建快照/刷新健康"
S-->>C : "connect.challenge(event)"
S-->>C : "tick(event) 循环"
C->>S : "req(method, params)"
S->>HM : "路由到处理器"
HM-->>S : "处理结果"
S-->>C : "res(ok/payload 或 error)"

详细组件分析

WebSocket 协议与帧模型

  • 帧类型
    • req:请求帧,包含 id/method/params。
    • res:响应帧,包含 id/ok/payload 或 error。
    • event:事件帧,包含 event/payload/seq。
  • 模型与校验
    • 使用 AJV Schema 对请求/响应/事件进行运行时校验,错误信息可格式化输出。
  • 客户端与服务端一致性
    • Node 客户端与 Swift 客户端均实现相同的帧编解码与握手流程,确保跨平台兼容。

握手与鉴权流程

  • 协议版本协商
    • 客户端声明 min/maxProtocol,服务端要求与当前协议版本兼容,否则拒绝。
  • 角色与作用域
    • 服务端解析角色,作用域默认为空集合;若无设备身份且未使用共享凭据,会清理作用域以避免越权。
  • 浏览器来源校验
    • 控制 UI 与 WebChat 在特定条件下强制 Origin/Host 校验,支持 Host 头回退的安全开关。
  • 设备身份与签名
    • 服务端验证设备公钥、签名时间戳、随机数 nonce 与签名版本(v2/v3),不匹配则拒绝。
  • 配对与升级
    • 未配对设备需发起配对请求;角色/作用域/元数据升级需审批;本地直连可静默批准。
  • 受信代理
    • 允许受信代理透传身份,operator 场景可跳过设备身份。
flowchart TD
Start(["开始握手"]) --> Parse["解析 connect 参数"]
Parse --> Ver["协议版本检查"]
Ver --> Role["角色解析与作用域初始化"]
Role --> Origin["浏览器来源校验"]
Origin --> Dev["设备身份与签名验证"]
Dev --> Pair{"是否已配对?"}
Pair --> |否| ReqPair["发起配对请求"]
ReqPair --> Approve{"是否静默批准/已批准?"}
Approve --> |否| Reject["拒绝并关闭"]
Approve --> |是| Token["生成/下发设备令牌"]
Pair --> |是| Upgrade{"角色/作用域/元数据升级?"}
Upgrade --> |是| ReqPair
Upgrade --> |否| Token
Token --> Hello["返回 hello-ok 并建立会话"]

会话管理与配对机制

  • 设备令牌
    • 成功鉴权后,服务端为设备签发短期令牌,客户端可缓存用于后续连接。
  • 静默本地配对
    • 本地直连(loopback/tailscale 同机)且无浏览器来源或为控制 UI/WebChat 时,允许静默批准。
  • 升级与审计
    • 角色/作用域/元数据升级均记录审计日志,必要时触发配对审批。
  • 节点侧配对
    • 节点连接时更新节点元数据、记录最近连接时间、探测远端二进制可用性等。

状态同步与事件处理

  • 快照与版本
    • 服务端聚合系统存在性、健康状态、配置路径、会话默认键等,形成快照;版本号用于增量通知。
  • 事件类型
    • 包括 connect.challenge、tick、shutdown、presence、health、heartbeat、cron、node/device pair、voicewake、exec.approval、update.available 等。
  • 客户端事件处理
    • 客户端维护 lastSeq、lastTick,检测丢序与心跳超时,触发重连与告警。
sequenceDiagram
participant S as "服务端"
participant P as "健康模块"
participant C as "客户端"
S->>P : "刷新健康快照"
P-->>S : "健康摘要"
S-->>C : "tick(event)"
S-->>C : "presence/health/event..."
C->>C : "校验 seq/tick 超时"
C->>S : "keepalive/ping必要时"

方法调用与广播

  • 方法白名单与动态扩展
    • 基础方法集与通道插件扩展的方法共同构成可用方法列表。
  • 写入限流
    • 控制面写操作按客户端标识进行速率限制,超限返回可重试错误。
  • 请求处理
    • 核心处理器或插件处理器根据方法名执行,返回 res 帧。

启动流程与生命周期

  • 守护进程式生命周期
    • CLI 提供 start/stop/restart,支持健康检查与重启等待窗口。
  • 端口健康检查
    • 重启后轮询端口监听状态,结合进程运行态判断健康状况。

配置管理与安全策略

  • 认证模式
    • 支持 token/password/trusted-proxy;推荐使用 token;可设置受信代理头透传身份。
  • 远程访问与 TLS
    • wss 推荐用于远程;支持 TLS 指纹固定;私有网络明文 ws 默认仅限 loopback,可通过环境变量放宽。
  • 远程模式凭证
    • 远端主机上的凭据与工作区文件存储于该主机;OAuth 凭据需在网关主机创建。

依赖关系分析

graph LR
A["message-handler.ts"] --> B["auth-context.ts"]
A --> C["health-state.ts"]
A --> D["server-methods.ts"]
E["client.ts"] --> F["protocol/index.ts"]
G["GatewayChannel.swift"] --> F
G --> H["GatewayModels.swift"]

性能考量

  • 心跳与保活
    • 服务端向客户端推送 tick;客户端维护 lastTick,超过阈值触发重连;同时定期 ping 保持 NAT/代理存活。
  • 负载与缓冲
    • 最大帧大小与缓冲字节上限在策略中定义,避免内存压力。
  • 速率限制
    • 控制面写入限流与鉴权速率限制,防止滥用与暴力破解。
  • 广播优化
    • 广播事件支持“慢订阅丢弃”策略,降低高负载下的拥塞风险。

WebSocket 协议实现

WebSocket 协议实现

围绕 WebSocket 协议的关键目录与文件:

  • 协议规范与模式:docs/gateway/protocol.md、src/gateway/protocol/schema/*.ts
  • 客户端实现:src/gateway/client.ts
  • 服务端握手与消息处理:src/gateway/server/ws-connection/message-handler.ts
  • 帧与校验:src/gateway/protocol/index.ts、src/gateway/protocol/schema/frames.ts
  • 服务器常量:src/gateway/server-constants.ts
  • 测试用例与示例:src/gateway/server.auth.default-token.suite.ts、apps/macos/Tests/OpenClawIPCTests/GatewayWebSocketTestSupport.swift、src/gateway/client.watchdog.test.ts
graph TB
subgraph "协议规范"
A["docs/gateway/protocol.md"]
B["src/gateway/protocol/schema/protocol-schemas.ts"]
C["src/gateway/protocol/schema/frames.ts"]
D["src/gateway/protocol/schema/devices.ts"]
end
subgraph "客户端"
E["src/gateway/client.ts"]
end
subgraph "服务端"
F["src/gateway/server/ws-connection/message-handler.ts"]
G["src/gateway/server-constants.ts"]
end
A --> B
B --> C
B --> D
C --> E
C --> F
E --> F
G --> F

核心组件

  • 协议版本与帧模型
    • 版本号:PROTOCOL_VERSION = 3(协议版本在模式中集中定义)
    • 帧类型:请求(req)、响应(res)、事件(event),统一通过网关帧联合类型进行强类型约束
  • 客户端 GatewayClient
    • 负责握手挑战、设备签名、连接参数构造、请求/响应处理、事件分发、心跳监控与指数退避重连
  • 服务端握手处理器
    • 验证首帧为 connect 请求、协议版本协商、角色与作用域解析、浏览器来源检查、设备身份验证与配对策略、鉴权决策与配对升级审计
  • 序列化与校验
    • 使用 TypeBox 定义模式,AJV 编译为运行时校验器,确保消息结构与字段约束一致

架构总览

下图展示从客户端到服务端的完整握手与消息流转路径,包括版本协商、鉴权、配对与心跳监控。

sequenceDiagram
participant C as "客户端"
participant S as "服务端"
participant V as "校验器(AJV)"
participant A as "鉴权/配对策略"
C->>S : "WebSocket 握手"
S-->>C : "connect.challenge(nonce, ts)"
C->>C : "构造 ConnectParams(含 minProtocol/maxProtocol, role, scopes, device, auth)"
C->>S : "req connect(params)"
S->>V : "validateRequestFrame + validateConnectParams"
V-->>S : "校验结果"
S->>A : "解析角色/作用域, 检查来源, 设备签名与配对策略"
A-->>S : "鉴权结果/配对决策"
S-->>C : "res { type : 'hello-ok', protocol, policy{tickIntervalMs}, auth? }"
S-->>C : "event tick(ts)"
C->>C : "启动心跳监视器(lastTick)"
C->>S : "req 方法调用"
S-->>C : "res 或 event"
C->>C : "收到 event tick 更新 lastTick"

详细组件分析

协议版本管理与协商

  • 版本常量:PROTOCOL_VERSION = 3,集中于协议模式定义文件
  • 协商规则:客户端发送 minProtocol/maxProtocol,服务端要求 maxProtocol ≥ 当前版本且 minProtocol ≤ 当前版本,否则拒绝握手并返回协议不匹配错误
  • 兼容性:旧客户端可使用较低版本范围,但需满足服务端当前版本边界
flowchart TD
Start(["开始握手"]) --> ReadParams["读取 ConnectParams.minProtocol / maxProtocol"]
ReadParams --> CheckRange{"maxProtocol ≥ 当前版本<br/>且 minProtocol ≤ 当前版本?"}
CheckRange --> |是| Accept["接受连接"]
CheckRange --> |否| Reject["拒绝: 协议不匹配"]
Accept --> End(["完成"])
Reject --> End

帧格式与序列化

  • 帧类型
    • 请求帧:{ type:"req", id, method, params? }
    • 响应帧:{ type:"res", id, ok, payload?, error? }
    • 事件帧:{ type:"event", event, payload?, seq?, stateVersion? }
  • 强类型模型:通过 TypeBox 定义 Schema,并由 AJV 编译为运行时校验器,统一导出用于客户端与服务端
  • 错误形状:{ code, message, details?, retryable?, retryAfterMs? }
classDiagram
class RequestFrame {
+string type
+string id
+string method
+any params
}
class ResponseFrame {
+string type
+string id
+boolean ok
+any payload
+ErrorShape error
}
class EventFrame {
+string type
+string event
+any payload
+number seq
+StateVersion stateVersion
}
class ErrorShape {
+string code
+string message
+any details
+boolean retryable
+number retryAfterMs
}
RequestFrame --> ErrorShape : "可能携带"
ResponseFrame --> ErrorShape : "可能携带"

连接认证与设备配对

  • 握手挑战:服务端先下发 connect.challenge,包含 nonce 与时间戳
  • 客户端签名:客户端基于服务端 nonce 构造签名负载,发送至服务端
  • 设备身份:所有连接必须携带 device 字段(包含 id/publicKey/signature/signedAt/nonce),服务端校验指纹、时间戳、nonce 与签名版本
  • 角色与作用域:connect.params.role 与 scopes 在握手阶段声明,服务端默认空数组即无权限
  • 来源检查:浏览器场景下进行 Origin 校验,支持 Host 头回退的安全开关
  • 鉴权策略:支持共享令牌/密码与设备令牌两种方式;设备令牌颁发后可持久化以供后续连接复用
flowchart TD
A["接收 connect.challenge"] --> B["生成 device 签名(含 nonce)"]
B --> C["发送 connect 请求(含 role/scopes/device/auth)"]
C --> D{"校验设备签名/指纹/nonce/时间戳"}
D --> |通过| E["解析角色/作用域, 来源检查"]
E --> F{"鉴权通过?"}
F --> |是| G["颁发 hello-ok(含 policy, 可选 auth.deviceToken)"]
F --> |否| H["返回 INVALID_REQUEST 并关闭"]

心跳检测与保活

  • 服务端策略:hello-ok 中包含 policy.tickIntervalMs,客户端据此启动心跳监视器
  • 客户端行为:收到 event tick 后更新 lastTick;若超过 2× tickIntervalMs 未收到心跳,主动关闭连接(代码 4000)
  • 服务器常量:心跳间隔默认 30 秒,握手超时默认 10 秒,最大载荷与缓冲限制在服务器侧统一配置
sequenceDiagram
participant C as "客户端"
participant S as "服务端"
C->>S : "connect 成功, 收到 hello-ok(policy.tickIntervalMs)"
loop 每隔 tickIntervalMs
S-->>C : "event tick(ts)"
C->>C : "lastTick = now()"
end
alt 超过 2×tickIntervalMs 未收到 tick
C->>C : "关闭(4000 : tick timeout)"
end

断开与重连策略

  • 关闭原因:服务端/客户端根据策略设置关闭原因与代码
  • 客户端重连:发生异常或非正常关闭时,按指数退避(上限 30 秒)重连;清理心跳定时器,刷新待处理请求
  • 设备令牌失效:当因设备令牌不匹配导致关闭时,清理本地缓存并提示重新配对
flowchart TD
Start(["连接断开"]) --> CheckCode{"是否 policy-violation 或设备令牌不匹配?"}
CheckCode --> |是| Cleanup["清理设备令牌/配对缓存"]
CheckCode --> |否| Skip["保持现状"]
Cleanup --> Backoff["指数退避(<=30s)"]
Skip --> Backoff
Backoff --> Reconnect["重新连接"]
Reconnect --> End(["完成"])

消息处理流程(客户端)

  • 解析消息:区分事件帧与响应帧,事件帧触发回调,响应帧根据 id 匹配并 resolve/reject
  • 请求发送:构造 req 帧并通过 validateRequestFrame 校验后发送
  • 顺序与间隙:记录事件序号 seq,检测期望与实际之间的间隙并上报
flowchart TD
In(["收到消息(JSON)"]) --> Parse["JSON.parse"]
Parse --> IsEvent{"是否事件帧?"}
IsEvent --> |是| OnEvent["onEvent(evt)"]
IsEvent --> |否| IsResp{"是否响应帧?"}
IsResp --> |是| Match["按 id 匹配 Pending"]
Match --> Ok{"ok ?"}
Ok --> |是| Resolve["resolve(payload)"]
Ok --> |否| Reject["reject(error)"]
IsResp --> |否| Ignore["忽略/记录日志"]

协议规范与示例

  • 文档规范:协议文档定义了握手、帧格式、角色与作用域、能力声明、版本管理与认证等要点
  • 示例数据:文档提供了 connect.challenge、connect 请求与 hello-ok 的示例 JSON,便于客户端实现对照

错误码与诊断

  • 错误码集合:INVALID_REQUEST、NOT_PAIRED、NOT_LINKED、AGENT_TIMEOUT、UNAVAILABLE 等
  • 错误形状:包含 code、message、details、retryable、retryAfterMs 等字段
  • 设备认证迁移诊断:文档列举了常见迁移失败的错误详情与原因,帮助旧客户端平滑过渡

依赖关系分析

  • 客户端依赖
    • 协议模式与校验器:src/gateway/protocol/index.ts 导出各 Schema 的 AJV 校验函数
    • 服务器常量:客户端使用 policy.tickIntervalMs 初始化心跳监视
  • 服务端依赖
    • 协议模式与校验器:用于校验首帧与 connect 参数
    • 设备配对与鉴权模块:解析鉴权状态与决策
    • 健康与快照:构建 hello-ok 中的 snapshot 与 server 信息
graph LR
P["protocol/index.ts(AJV校验)"] --> CL["client.ts"]
P --> SV["server/ws-connection/message-handler.ts"]
SC["server-constants.ts"] --> CL
SC --> SV
DEV["protocol/schema/devices.ts"] --> SV

性能考量

  • 最大载荷与缓冲:服务器与客户端均设置 25MB 最大载荷,避免高分辨率画面/屏幕快照被断开
  • 心跳间隔:默认 30 秒,可根据网络环境调整;客户端最小监视间隔可配置
  • 事件去重:服务器侧存在去重 TTL 与上限,减少重复事件影响
  • 日志与健康:健康快照与版本号增量有助于快速定位状态问题