Skip to content

fix(device-link): 清理离线控制端的陈旧状态 - #3309

Merged
MagicLizi merged 2 commits into
mainfrom
dash/device-link-peer-lifecycle
Aug 25, 2026
Merged

fix(device-link): 清理离线控制端的陈旧状态#3309
MagicLizi merged 2 commits into
mainfrom
dash/device-link-peer-lifecycle

Conversation

@dashhuang

Copy link
Copy Markdown
Member

这次改了什么

摘要

修复 device-link 控制端离线后 Desktop 仍显示“被 iPhone 控制”的生命周期问题。将 relay 的 DEVICE_OFFLINE、presence offline、relay 整体断开和永久 link-close 收敛到统一的 active controller 失活路径,同时保留断线恢复所需的 remembered routing。

变更类型

  • fix 缺陷修复

范围

  • 关联 Issue / 需求:与 PR fix(device-link): soften transient relay heartbeat recovery #3284(transient relay heartbeat recovery)互补
  • 本 PR 包含:
    • DeviceLinkClientDEVICE_OFFLINE 提供 typed peer route lifecycle 事件,覆盖 pending / non-pending 路径并按连接代去重;
    • Desktop 统一清理单 peer 的 active topics、控制横幅、update-relaunch busy、临时 stage/retry;
    • relay 断开时清理全部 active projection,但保留 remembered topics/capabilities、可靠 pending、result outbox 和离线队列;
    • 旧连接迟到的 offline 事件不会清掉新连接的 active controller;
    • 补充多控制端隔离、relay 断开恢复、跨连接代和反向控制保护测试。
  • 明确不包含:服务端改动、wire protocol 新消息、数据库迁移、UI 组件/文案/样式重做、手机端 UI 改动。
  • 用户可见变化:手机真正离线或 relay 断开后,“被 iPhone 控制”会及时消失;手机恢复并重新订阅后才重新显示;其他控制端不受影响。
  • 是否存在 breaking change:无。未改变现有 wire protocol;新增的是客户端内部 typed lifecycle callback。

UI 变化

  • 引用的设计规范:不涉及:未修改 UI 组件、样式或文案,只修正已有 controlled-state 数据源的生命周期。

怎么验证的

自动验证

pnpm --filter @cindy/device-link test -- src/__tests__/client.test.ts
结果:6 个测试文件、221 个测试通过

pnpm exec vitest run apps/desktop/src/main/__tests__/deviceLinkDispatch.test.ts apps/desktop/src/main/device-link/__tests__/dispatchWeakNetwork.test.ts apps/desktop/src/main/device-link/__tests__/dispatchMakerEventBatch.test.ts apps/desktop/src/main/device-link/__tests__/subscriptionsTopicLifecycle.test.ts --reporter=dot
结果:4 个测试文件、157 个测试通过

pnpm --filter @cindy/device-link run --if-present typecheck
结果:通过

pnpm --filter desktop run --if-present typecheck
结果:通过

git diff --check
结果:通过

pnpm test:unit:related 已执行;本次相关的 packages/device-link 和 Desktop device-link 测试通过,但整体门禁仍被既有基线问题阻断:Desktop ghostInstallReceipt.test.ts 有 2 个既有断言失败,Mobile startupSplashOverlay.test.ts 有 1 个既有超时,均不涉及本 PR 文件。

手工验证

不涉及真实手机、relay 或 Desktop DEV 启动;本 PR 使用单元测试覆盖生命周期和多 peer 故障半径。

未执行的验证

未执行真实手机后台休眠、真实 relay 弱网和多台真实控制端 E2E。建议合入后用现有 device-link 日志验证 presence offline、DEVICE_OFFLINE、relay reconnect 与 controlled-state 的时序。

风险

风险分类

  • 协议兼容
  • 跨平台差异
  • SQLite / migration
  • system prompt
  • 权限 / 安全 / 用户数据
  • 存量插件兼容(批准状态 / 指纹 / manifest 校验 / 安装布局 / 包格式)
  • 原生层 / fingerprint / OTA

影响与回滚

  • 影响范围:packages/device-link 客户端路由生命周期通知,以及 Desktop device-link host 的 active controller projection;手机端继续使用共享 client,但没有 Desktop 控制横幅,因此无需新增移动端入口或协议适配。
  • 远程连接与手机版适配:已一并适配。peer 级错误只清对应 peer;relay 级错误清所有 active projection;remembered recovery state 保留。没有新增 IPC channel 或 allowlist 项。
  • 故障半径三问:
    1. 触发层级:单 peer 的 DEVICE_OFFLINE 路由失败,或共享 relay 连接离线;
    2. 动作层级:peer 事件只失活该 peer,relay 事件只清 active projection,不删除恢复记忆;
    3. 多 peer:回归测试覆盖 A/B 共用同一被控端时 A 离线只清 A,以及 relay 断开后 active 清空、remembered routing 保留。
  • 回滚 / 降级方式:回滚提交 790b59ab8;wire protocol 未变化,旧客户端可继续互通。
  • 存量插件影响:无。

提交前检查

  • 已 review 完整 diff
  • 每个 commit 都带 DCO 签名(git commit -s
  • UI 改动已在「UI 变化」注明引用的设计规范章节(不涉及 UI)
  • 未提交凭证、令牌或授权文件
  • 已确认测试结果或说明未执行原因

Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
@dashhuang
dashhuang requested a review from a team as a code owner August 23, 2026 22:11
@greptile-apps

greptile-apps Bot commented Aug 23, 2026

Copy link
Copy Markdown

Greptile Summary

本 PR 统一了控制端离线和 relay 断开时的 active controller 失活流程,同时保留断线恢复所需的 remembered routing。

  • DeviceLinkClient 新增带连接代次的 typed peer route offline 事件,并对同一连接代的重复事件去重
  • Desktop 在单 peer 离线时仅清理对应 active projection,在 relay 断开时清理全部 active projection
  • 永久关闭或撤权继续清除 remembered routing,临时断线则保留恢复状态
  • 新增多控制端隔离、relay 断线恢复及旧连接代事件保护测试

Confidence Score: 5/5

当前没有仍需阻止合并的已确认故障,PR 看起来可以安全合并。

没有阻塞性故障仍然存在。

Important Files Changed

Filename Overview
packages/device-link/src/client.ts 新增带 connection epoch 的 peer route offline 生命周期事件、连接代内去重及恢复时的在线标记。
apps/desktop/src/main/device-link/dispatch.ts 将单控制端、全 relay 和永久关闭场景收敛到统一的 controller 失活状态转换。
apps/desktop/src/main/device-link/index.ts 接入 peer offline 回调,并在 relay 离开 online 状态时清理全部 active controller projection。
packages/device-link/src/tests/client.test.ts 覆盖 pending 与非 pending DEVICE_OFFLINE、事件去重及旧 socket 回调隔离。
apps/desktop/src/main/device-link/tests/dispatchWeakNetwork.test.ts 覆盖多 peer 故障隔离、relay 全量失活和跨连接代离线事件保护。

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Relay 或 peer 状态变化] --> B{故障范围}
  B -->|DEVICE_OFFLINE / presence offline| C[失活单个 controller]
  B -->|Relay 非 online| D[失活全部 active controllers]
  C --> E[清理 active topics、横幅、busy 与临时 stage]
  D --> E
  E --> F[保留 remembered topics、capabilities 与可靠待发送状态]
  F --> G[重连后通过 link-open 与 subscribe 恢复]
  B -->|永久 link-close / 撤权| H[清理 active 与 remembered routing]
Loading

Reviews (2): Last reviewed commit: "test(device-link): cover peer offline is..." | Re-trigger Greptile

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 790b59ab80

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/desktop/src/main/device-link/__tests__/dispatchWeakNetwork.test.ts Outdated
Signed-off-by: Dash <125997726+dashhuang@users.noreply.github.com>
@dashhuang

Copy link
Copy Markdown
Member Author

已按 review 建议补上真实链路回归(commit 986121d):A/B 使用真实 DeviceLinkClient 建链,relay 注入 target→A 的 DEVICE_OFFLINE;B 的在途 subscribe invoke-result 暂存后,在 A 失活期间释放并成功完成,同时断言 B 的 active/remembered 状态保持。新增回归所在的 dispatchWeakNetwork.test.ts 17 个测试全部通过。原 inline thread 因当前 token 不具备 AddPullRequestReviewComment 权限,无法直接回复。

@MagicLizi MagicLizi added the touches:core 改动碰到架构核心路径(review-pr 自动维护,仅展示) label Aug 24, 2026
@MagicLizi
MagicLizi merged commit 388414e into main Aug 25, 2026
19 checks passed
@MagicLizi
MagicLizi deleted the dash/device-link-peer-lifecycle branch August 25, 2026 02:08
@MagicLizi

Copy link
Copy Markdown
Contributor

合了。控制端掉线后陈旧投影不再赖着,对端不用再对着一个已经不在的设备发请求。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

touches:core 改动碰到架构核心路径(review-pr 自动维护,仅展示)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants