Skip to content

feat(swift): 远程运行时 listen: 与 dial:,一致性的 Swift 列(#387) - #496

Merged
eric8810 merged 8 commits into
mainfrom
feat/swift-remote
Oct 20, 2026
Merged

eric8810 merged 8 commits into
mainfrom
feat/swift-remote

Conversation

@eric8810

Copy link
Copy Markdown
Contributor

#387(Swift S2)的第二部分,接 #495:Swift 运行时的远程连接 listen: 与 dial:,以及一致性的 Swift 列。设计:Swift SDK §6.1、S14、§17.3 #12;拨出规则按 远程运行时:拨出与动态接入 §六。基于 #495 的分支,#495 合入后改到 main。

监听:listen:ws://… / listen:wss://…

  • Remote/Listen.swift:Network.framework 的 NWListener(TCP,或 TLS 1.2+),绑定后在 stderr 写 rutis: listening on <实际地址>。
  • 升级请求与 WebSocket 帧由 SDK 自己处理(Remote/WebSocket.swift,同 Go 的 listen.go):实测 Network.framework 的 NWProtocolWebSocket 拒绝时一律回 400、也看不到路径,而 rutis 的拨号方按状态码分类(401 / 403 重试,400 停止),所以不用它的 WebSocket 层。
  • 拒绝:路径不对 404;没有 Bearer 401;令牌不对(常量时间比较)403;没有提供 rutis.3 400,正文是 rutis-bridge 同样的话(this endpoint speaks rutis.3, the dialer offered rutis.99: upgrade this endpoint (the Swift package Rutis of github.com/arcships/rutis) / …: upgrade the dialer)。
  • 非回环地址必须 wss://;wss:// 要 RUTIS_CERT / RUTIS_KEY(PEM;私钥 EC P-256/384/521 或 RSA,PKCS#8 / SEC1 / PKCS#1,只在进程内,不进钥匙串)。
  • 帧:未掩码 1002、二进制 1003、超过 16 MiB 1009、非 UTF-8 1007;心跳(RUTIS_HEARTBEAT,默认 10 s / 30 s);一次一个控制方,新连接让旧连接以 4002 关闭、旧租约结束后才问候新的。

拨出:dial:ws://… / dial:wss://…

  • Remote/Dial.swift:URLSessionWebSocketTask(设计 §17.3 feat(core): 设计卸载截止时间及超时后的任务与资源语义 #12),升级被拒的状态码取自任务的 response;RUTIS_TOKEN 作 Bearer(读后从环境删除),RUTIS_CA 在系统根之外加信任。
  • 分类与 Go 相同:401 / 403、证书不受信、接入点以 4003 拒绝 id、对端问候成别的 endpoint → auth-rejected,每 30 s 再试;400 / 404 / 405 / 426、子协议不符、问候不兼容、旧宿主被拒 → rutis: refused: incompatible (…); stopping,状态 1;其余(含 4002 被接管)→ 退避 0.5 s 翻倍到 30 s、±20 %,会话满 60 s 重置;RUTIS_RETRY 供测试缩短。
  • 每次断开先卸载全部行;SIGTERM / Ctrl-C 卸载全部行、关闭连接、以 0 退出,不再拨。
  • 启动即拒绝:非回环的 ws://、不合法的 --id、不是 ws/wss 的地址(状态 1)。

serve

--id / --peer 进入 endpoint 握手(协议 3,声明 runtime),网络通道必须给 --id。

测试(本机 macOS 26.6 / Swift 6.3.2)

测试 内容 结果
session_matrix swift_listening_on_a_websocket(新) 运行时契约全套经 Swift 的监听 过;Swift 四列 3 次全过
dial_conformance swift::*(新列,8 项) 用 id 接入、错令牌重试、id 被拒重试、不兼容停止、非法 id、退避与重连、同 id 接管、SIGTERM 8 过,连跑 5 次全过
swift_remote.rs(新,6 项) 拒绝的状态码与协议拒绝原文;启动即拒绝的地址;坏帧的关闭码;接管 4002 与心跳丢弃 1001;listen:wss 用 rcgen 证书被 rutis 以 CA 信任连上;dial:wss 不信任的证书为 auth-rejected、RUTIS_CA 信任后通过 TLS 6 过
rutis-host --test swift(加 2 项) 远程 Swift 监听、peer 行连上,行 <运行时名>:<插件>;Swift 拨入宿主的接入点成为实例,断开实例关闭 4 过
手测 openssl 生成的 RSA PKCS#8 证书 listen:wss 过

CI

runtimes-swift 加 dial_conformance swift:: 与 swift_remote;docs/ci 矩阵加 Swift 行(会话契约四列、拨出契约)。

文档

Swift 指南加“在另一台机器上运行”(中英);nodes(中英)说明 Go / Swift 二进制都接受 dial: / listen:。

- 监听(Remote/Listen.swift):Network.framework 的 NWListener(ws / wss),升级与帧由 SDK 自己处理(Remote/WebSocket.swift),每种拒绝有自己的状态码(404 / 401 / 403 / 400,协议拒绝说明升级哪一端);非回环必须 wss(RUTIS_CERT / RUTIS_KEY,EC 或 RSA,PKCS#8 / SEC1 / PKCS#1);令牌常量时间比较;心跳;一次一个控制方,新连接接管(4002)
- 拨出(Remote/Dial.swift):URLSessionWebSocketTask;RUTIS_TOKEN 作 Bearer,RUTIS_CA 加信任;按状态码 / 关闭码分类重试或停止,退避与 RUTIS_RETRY;每次断开卸载全部行;SIGTERM / Ctrl-C 卸载后以 0 退出;状态行与其他运行时一字不差
- serve:--id / --peer 进入 endpoint 握手;拨出前拒绝非回环 ws:// 与不合法 id
- 测试:session_matrix 的 Swift 监听列、dial_conformance 的 Swift 列(8 项)、swift_remote.rs(拒绝状态、帧、心跳、接管、两端 TLS)、rutis-host 的远程 Swift(监听与拨入实例)
- 文档:Swift 指南的远程一节、nodes、ci 矩阵
@eric8810 eric8810 added this to the 0.14 milestone Oct 19, 2026
@eric8810
eric8810 changed the base branch from feat/swift-host to main October 19, 2026 10:19
)

- rutis-host dev(Go、Swift):每次构建先打印 `<名字>: building`,成功后 `<名字>: built in 12.3s`;第一次构建(依赖、SDK 的宏)可能要几分钟,等的人看得到进展
- e2e dev_loop:Swift 场景在任何计时步骤前预热构建(swift build --product demo,build_guard 内,报告 first build took Ns);dev 的第一次构建、之后的重建与失败的构建各按 build_guard 等待,其余步骤仍是 30 秒的 hang guard
- e2e Host 加 wait_for_within
被取消的监听器在自己的 Task 里调用 events-log:调用先发出、随即因 Task 已取消而发 cancel,宿主是否在 cancel 到达前记下 b:cancelled 取决于时序。夹具改为在非结构化 Task 里记日志(保留调用链、不带取消),同 Go 夹具的 context.WithoutCancel。指南写明取消后仍要调用时这样做。
@eric8810 eric8810 modified the milestones: 0.14, 0.15 Oct 20, 2026
@eric8810
eric8810 merged commit 4e23339 into main Oct 20, 2026
101 of 105 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant