6.0 KiB
Gateway 主动出站 demo
本文是 hwlab-gateway 最小主动出站闭环的长期参考。该 demo 只验证 gateway 主动连接 cloud、cloud 下发命令、gateway 执行并回传结果;不得把它当作 M3 DEV-LIVE 虚拟硬件可信闭环,也不得替代 BOX-SIMU / Gateway-SIMU / hwlab-patch-panel 的 M3 验收链路。
边界
hwlab-gateway运行在用户 PC 或本地环境,主动访问hwlab-cloud-api;cloud 不需要也不应入站访问 gateway。- demo 采用普通 HTTP poll/result:gateway 调
POST /v1/gateway/poll拉取命令,执行后调POST /v1/gateway/result回传 JSON-RPC response。 hardware.invoke.shell仍是 cloud-api 对外 RPC 方法;有在线 gateway 时通过主动出站链路派发,没有在线 gateway 时保留not_connected降级返回。- 当前命令执行能力只用于受限 demo;正式真实硬件控制仍应沿用统一 capability、audit、evidence 和后续 WebSocket/设备身份设计。
Cloud API 入口
GET /v1/gateway/sessions:只读查看在线 gateway、队列深度和 last-seen。POST /v1/gateway/poll:gateway 主动注册、心跳并领取下一条待执行 JSON-RPC 请求。POST /v1/gateway/result:gateway 主动回传 JSON-RPC response,cloud-api 用 request id 完成等待中的hardware.invoke.shell。POST /json-rpc或POST /v1/rpc/hardware.invoke.shell:用户、agent 或 smoke 仍只调用 cloud-api,不直连 gateway。
Poll Loop 和长命令并发
Gateway 的 poll loop 不能等待单条 shell 命令结束后才继续 poll。Keil build/download、烧录或 Windows skill 可能运行数分钟;这些长命令必须在 gateway 内作为 in-flight 请求后台执行,poll loop 继续注册心跳并领取短状态读取、日志读取和取消/诊断请求。
判断问题类型时区分两种 timeout:
shellExecuted=true且有operationId:命令已经到达 gateway,本次 shell 超过了命令超时;下一步应读取 job state、日志或产物时间戳,而不是盲目把超时继续调大。shellExecuted=false、dispatchStatus=timed_out且旧链路可能operationId=null:cloud-api 等不到 gateway 领取或回传,通常是 gateway poll loop 被前一个长命令队头阻塞,或 gateway 离线;修复重点是非阻塞 poll 和 in-flight 可观测性,不是只加大 dispatch timeout。
Gateway 必须在 registration payload 和 /v1/gateway/sessions 中暴露 inflightCount、maxInflightRequests 和当前 in-flight 摘要。默认允许少量并发,使一个长 Keil 操作不会阻塞后续只读 job-status、state/log 读取或健康探测;超过并发上限时应返回结构化 gateway_busy,不能让请求静默排队到 cloud dispatch timeout。
Gateway 环境变量
| 变量 | 作用 |
|---|---|
HWLAB_GATEWAY_CLOUD_URL |
cloud-api 或 edge-proxy 地址;本地可用 http://127.0.0.1:6667,DEV 可用 http://74.48.78.17:16667。 |
HWLAB_GATEWAY_ID |
gateway 稳定身份,例如 gtw_windows_1。 |
HWLAB_GATEWAY_SESSION_ID |
gateway session id;不填时默认为 gws_${HWLAB_GATEWAY_ID}。 |
HWLAB_GATEWAY_CMD_EXEC_ENABLED=1 |
允许执行 shell 命令;未设置时 gateway 拒绝 hardware.invoke.shell。 |
HWLAB_GATEWAY_DEMO_OPEN=1 |
demo 明确打开标记;本地 smoke 会设置。 |
HWLAB_GATEWAY_POLL_INTERVAL_MS |
poll 间隔,默认 500ms。 |
HWLAB_GATEWAY_MAX_INFLIGHT |
同一 gateway 同时执行的 cloud 请求数,默认 3;用于避免长 Keil/UV4 命令阻塞短状态查询。 |
HWLAB_GATEWAY_CMD_TIMEOUT_MS |
单条命令超时,默认 120000ms;Workbench 发起 Code Agent 请求时可通过“Gateway 命令超时”控件把本轮 wrapper --timeout-ms 调到 1/2/3/5/10 分钟。 |
HWLAB_GATEWAY_CMD_OUTPUT_LIMIT_BYTES |
stdout/stderr 单路输出上限,默认 65536 bytes。 |
本地或内网存在代理时,必须显式设置:
$env:NO_PROXY="localhost,127.0.0.1,::1"
$env:no_proxy="localhost,127.0.0.1,::1"
本地验证
优先使用一键 smoke,避免手动多终端状态不一致:
npm run gateway:demo:smoke
npm run gateway:demo:edge-smoke
gateway:demo:smoke启动本地hwlab-cloud-api和hwlab-gateway,验证hardware.invoke.shell返回stdout=hwlab-demo。gateway:demo:edge-smoke额外启动本地hwlab-edge-proxy,验证普通 HTTP proxy 能转发/v1/gateway/poll、/v1/gateway/result和/json-rpc。- 两个 smoke 都会设置
NO_PROXY/no_proxy,用于规避本地代理误触发。 - 对 D601 pod 内部
127.0.0.1:6667或 service:6667做 Node 探测时,不要用 Web/undicifetch;6667属于 WHATWG bad port,Node 会直接报bad port。gateway 传输层和 repo-owned 探测脚本应使用http/https原生 request,公网:16667或浏览器入口不受这个限制。
DEV 使用
DEV cloud-api 部署包含 /v1/gateway/* 后,Windows gateway 可用以下方式主动连接:
$env:HWLAB_GATEWAY_CLOUD_URL="http://74.48.78.17:16667"
$env:HWLAB_GATEWAY_ID="gtw_windows_1"
$env:HWLAB_GATEWAY_SESSION_ID="gws_gtw_windows_1"
$env:HWLAB_GATEWAY_CMD_EXEC_ENABLED="1"
$env:HWLAB_GATEWAY_DEMO_OPEN="1"
node .\cmd\hwlab-gateway\main.mjs
验证时从 cloud-api 侧调用 hardware.invoke.shell,不要尝试从 cloud 入站访问 Windows gateway。若 GET /v1/gateway/sessions 能看到对应 gatewaySessionId 且 JSON-RPC 返回 dispatch.shellExecuted=true,说明主动出站 demo 链路成立。
后续替换为 WebSocket
HTTP poll 是最小 demo 形态。后续替换成 WebSocket 时,应保留:
hardware.invoke.shell对外 RPC 方法名;- JSON-RPC request/response envelope;
- gateway 执行器的 stdout/stderr/exitCode/timedOut 返回形态;
- audit/evidence 由 gateway/cloud 硬件通道产生的原则;
- cloud-web、agent 和 CLI 不直连 gateway 的边界。
只替换传输层:/v1/gateway/poll 和 /v1/gateway/result 合并到 gateway 主动建立的 /v1/gateway/ws 长连接。