├─ loadGatewayTlsRuntime()                 // ⑩ TLS 加载(可选)

├─ createChannelManager()                  // ⑪ 通道管理器(discord/telegram/wecom...)

├─ createGatewayRuntimeState()             // ⑫ 核心:HTTP/WS 服务器创建 ⭐⭐

│     ├─ Canvas Host(画布托管)

│     ├─ 为每个 bindHost 创建 HTTP server

│     │     ├─ Control UI 路由

│     │     ├─ OpenAI Chat Completions 路由

│     │     ├─ Hooks 路由

│     │     ├─ Plugin HTTP 路由

│     │     └─ 认证中间件 + Rate Limiter

│     ├─ new WebSocketServer({ noServer: true })

│     ├─ attachGatewayUpgradeHandler() → HTTP Upgrade → WS

│     └─ startListening() → 绑定端口 ��

L1118-1120

加载gateway的tls。加载 gateway 的 TLS 运行时状态(证书/密钥是否可用等),不在 startup trace 里做耗时统计。

L1121-1123

配置说"启用 TLS",但运行时加载失败(证书文件不存在、权限问题等),直接抛异常。这两个 enabled 不是"互斥",而是配置期望 vs 运行时现实不一致——配置说能开,实际开不了

L1124-1135 你跳过的中间变量

几个重要变量值得注意:

  • startupSidecarsReady:标记所有 sidecar(通道等)是否已就绪,minimalTestGateway 模式下直接跳过
  • startupAccountStartsReady:一个 Promise,用于延迟通道的自动启动,等 sidecar 都好了再放行
  • gatewayInstanceDispatchReady:标记 gateway 实例是否可接收请求(bind 之后才翻 true,关闭时翻 false)
L1137-1151

创建通道管理器,通过获取运行时配置、通道日志、通道运行环境变量等所有相关信息,来建立通道管理器。

L1152

控制通道是否自动启动(比如 --channel-autostart-suppression 标志)。

L1159-1165

创建验证器,验证是否已经准备好,验证项包括:通道管理器(L1156)、gateway启动是否未完成(L1158)、启动未完成的原因(L1159)、获取event loop的健康状态快照(L1160)、如果运行中的环境变量中OPENCLAW_SKIP_CHANNELS/OPENCLAW_SKIP_PROVIDERS为true,则跳过通道检查

L1162-1164

createReadinessChecker 返回一个 getReadiness 函数,检查项包括你说的那些。其中 shouldSkipChannelReadiness 的逻辑是:如果环境变量 OPENCLAW_SKIP_CHANNELS 或 OPENCLAW_SKIP_PROVIDERS 为 truthy,就跳过通道就绪检查。

L1166

这行只是打日志,实际的 HTTP 服务器创建还在后面的 createGatewayRuntimeState 里。你可以理解为"准备创建 HTTP 服务器",真正绑端口、启动 HTTPS/WS 都在 createGatewayRuntimeState 内部完成。

L1167

这不是"获取 gateway 请求上下文",而是声明一个变量,后面才会赋值。它是一个可变引用——每次请求进来时更新当前的 context

L1168-1170

这不是"观察请求的 request 和 response",而是声明了一个延迟绑定的处理器对象.current 字段初始为 undefined,等 watch-node HTTP runtime 创建好后(约 L1308)才会赋值

L1171-1232

创建gateway运行时状态。包括基本信息,以及gateway 钩子的配置、钩子客户端ip的配置、注册插件、注册插件路由、gateway请求上下文、如果不是最小测试那么也注册通道等

L1171-1232:createGatewayRuntimeState 的完整参数分析

参数

你的理解

评价

hooksConfig

gateway 钩子配置

✅ 注意用了 lazy getter:() => runtimeState?.hooksConfig ?? initialHooksConfig,因为 runtimeState 此时还没创建

getHookClientIpConfig

钩子客户端 IP 配置

✅ 同理 lazy

pluginRegistry

注册插件

getPluginRouteRegistry

注册插件路由

getGatewayRequestContext

gateway 请求上下文

✅ lazy getter

pinChannelRegistry: !minimalTestGateway

非最小测试则注册通道

✅ pinChannelRegistry 控制是否把 channel 

L1228-1230:你问的这两行

handleWatchNodeRequest: async (req, res) =>

  (await watchNodeRequestHandler.current?.(req, res)) ?? false,

这是一个延迟绑定的 HTTP 请求代理处理器。运行机制:

  1. 创建时:watchNodeRequestHandler.current 是 undefined
  2. 后面约 L1308:watchNodeRequestHandler.current = watchNodeHttpRuntime.handleRequest; 才绑定真正的处理函数
  3. 运行时:每次有 HTTP 请求进来,如果路由匹配到 watch-node 路径,就转给 watchNodeRequestHandler.current 处理
  4. ?? false:如果处理器不存在或返回 undefined,返回 false(表示"这个请求我没处理")

为什么要用这种间接模式? 因为 createGatewayRuntimeState 创建 HTTP 服务器时需要这个 handler,但真正的 watch-node HTTP runtime 依赖 HTTP 服务器创建后才能初始化——形成了循环依赖。用 .current 对象做中间层打破这个循环。

L1233  resolveWorkerGatewayEndpoint = getWorkerIngressEndpoint; 

// 保存 worker 入口地址,供 worker 环境服务使用

L1234  const restartRecoveryCandidates = new Map(); 

// 热重启时,保存可恢复的会话候选

L1235-1261  createGatewayNodeSessionRuntime({...})

       // 创建「节点会话运行时」

       // 管理连接到 gateway 的节点(手机、IoT 设备等)

       // 返回:nodeRegistry(节点注册表)、nodeSendToSession(向节点发消息)、 nodeSubscribe/unsubscribe(订阅管理)、broadcastVoiceWakeChanged 等

L1255-1295  createWatchNodeHttpRuntime({...})

       // 创建「watch-node HTTP 运行时」

       // 处理节点的 HTTP 连接生命周期:

       //   - onNodeConnected: 节点上线 → 记录到 presence、更新 remoteNodeInfo

       //   - onNodeDisconnected: 节点下线 → 标记 presence、清理订阅、清除 wake 状态

       //   - onError: 打 warn 日志

       // L1296: 关键一行!把真正的 handler 绑定到延迟引用

       watchNodeRequestHandler.current = watchNodeHttpRuntime.handleRequest;

L1300-1323 — 最后的运行时组件
L1297-1305  TerminalSessionManager

       // 创建「终端会话管理器」

       // 管理 PTY 终端会话(如 SSH 到远程机器)

       // detachedSessionTimeoutSeconds 控制断连后终端保留多久(断连超时时间)

L1306  applyGatewayLaneConcurrency(...)

       // 应用 gateway 并发通道(lane)限制配置同时处理的请求数(并发数)

L1308-1317  runtimeState = createGatewayServerLiveState({...})

       // 创建 gateway 的「运行时状态」对象(之前只是声明变量)

       // 包含:hooks 配置、cron 状态(懒加载)、活跃的 gateway 方法列表等 L1318  deps.cron = runtimeState.cronState.cron;

       // 把 cron 实例注入依赖图,其他模块可以通过 deps 访问

L1319 pluginHostServices 目前只有一个 cron getter

L1319-1323  const pluginHostServices = {...} 

// 开始构建「插件宿主服务」对象将 cron 实例注入依赖容器,其他模块可通过 deps.cron 访问

// 插件宿主服务——给插件提供的托管能力容器目前只有 cron,后续可能扩展

整体来看,核心主题是:HTTP 服务器已经创建好了,现在要组装所有运行在它之上的子系统——节点连接、终端会话、插件服务、cron 调度等,最后绑定到一个统一的 runtimeState 对象里。

好了,看得很清楚了。L1300 之后的代码可以分为几个清晰的阶段。我按逻辑块来解析

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐