desktop.platform-recovery
desktop.platform-recovery 负责在 Electron 主进程中,将账户提供方的私有 PlatformSession 生命周期同步到桌面平台侧,同时确保凭据不会转发给 renderer。
Purpose and Scope
本页覆盖 installPlatformSessionPublisher 的实现语义:账户依赖注入、账户状态流订阅、平台会话读取、同步发布、异常处理以及销毁时的清理行为。当前可用的源材料只包含该函数的带行号摘录,未提供其实际仓库相对路径、调用方、Context/PlatformSession 的完整定义或配置文件,因此无法可靠补充具体 IPC channel 名称、注册位置、会话字段、持久化方式或测试保证;这些实现细节在现有源材料中未找到。
该页面不扩展到 renderer 通信协议、账户提供方内部实现或 Electron 启动编排。若需要这些内容,应分别查阅对应的账户模块、IPC 模块和桌面启动模块。
Overview
该模块的核心职责可以概括为:在 deepseekAccount 依赖可用时建立一个与账户生命周期绑定的异步订阅;每当 account.watch() 产生状态更新,模块就读取当前 PlatformSession,并通过传入的同步 publish 回调将结果发送给桌面平台侧。发布回调的注释明确说明它是私有 IPC 传递机制,并且不会把凭据转发给 renderer。
实现同时处理三类边界:
- 账户依赖出现:通过
ctx.inject(['deepseekAccount'], ...)获取账户上下文。 - 账户状态变化:通过
account.watch(lifetime.signal)异步迭代状态更新;状态值本身被命名为_state,说明本函数只把更新作为重新读取会话的触发器。 - 订阅结束或销毁:通过
AbortController中止订阅,并以publish(null)清除桌面平台侧的会话状态。
Architecture
在现有源码摘录能够确认的范围内,关系如下:
Context持有并注入deepseekAccount依赖。installPlatformSessionPublisher为注入到的账户上下文注册 effect。- effect 创建
AbortController,并启动异步更新任务。 deepseekAccount.watch()提供可中止的异步状态流。deepseekAccount.getPlatformSession()返回当前平台会话。publish接收PlatformSession或null,承担同步的私有 IPC 投递。logger('desktop-platform').warn(...)记录非销毁状态下的订阅失败。
由于没有可用的仓库文件 URL,本文不生成带有猜测路径或主机名的源码链接。
Implementation Walkthrough
依赖注入与 effect 生命周期
函数接收两个参数:ctx: Context 和 publish: (session: PlatformSession | null) => void,返回 void。它并不立即读取账户,也不在函数体中创建全局订阅,而是调用 ctx.inject(['deepseekAccount'], ...),等待名为 deepseekAccount 的依赖进入上下文。
依赖回调获得 accountCtx.deepseekAccount 后,调用 accountCtx.effect(...) 注册生命周期 effect。这个结构使订阅的创建和销毁归属于账户上下文,而不是由调用方手动管理单独的订阅句柄。
AbortController 作为订阅边界
每次 effect 执行都会创建新的 AbortController,并把 lifetime.signal 传给 account.watch()。这意味着 watch 流的取消信号与本次 effect 生命周期一一对应;它不是共享的全局取消器。
更新任务在 effect 内以异步立即执行函数启动。该任务保存为 updates,其 Promise 会在清理阶段等待,从而避免清理逻辑在后台更新任务尚未结束时提前返回。
状态流驱动的会话读取
for await (const _state of account.watch(lifetime.signal)) 将账户状态流作为触发器。循环体并不使用 _state 的内容,而是在每次更新时调用 account.getPlatformSession() 获取当前会话。这种顺序具有明确含义:发布的是读取时的当前平台会话,而不是假定状态事件本身包含完整凭据。
读取完成后再次检查 lifetime.signal.aborted,只有在订阅仍然有效时才调用 publish(session)。源码中的注释特别指出,销毁操作可能发生在异步凭据读取期间,因此第一次循环条件检查不足以防止竞态;读取完成后的第二次检查用于避免把已过期的会话发布出去。
失败处理与最终清理
更新任务包裹在 try/catch/finally 中:
- 如果异常发生时 signal 已中止,错误不会记录。这把正常销毁与异常订阅失败区分开来。
- 如果异常发生时 signal 尚未中止,则通过
accountCtx.logger('desktop-platform').warn('Account session subscription failed')记录警告。源码没有在此处重新抛出异常,也没有重试逻辑。 finally在 signal 未中止时调用publish(null)。因此,非预期的 watch 终止或非销毁异常会清空已发布会话,避免桌面平台继续保留过期凭据。
需要注意,finally 中的 signal 判断使正常清理路径不依赖异步任务的最终清理动作:正常销毁时,清理函数会直接发布 null;随后异步任务结束时不会重复执行同一清理发布。
Effect 清理顺序
effect 返回一个异步清理函数,顺序固定为:
- 调用
lifetime.abort(),通知账户 watch 流停止。 - 立即调用
publish(null),先清理桌面平台侧会话。 await updates,等待后台更新任务完成。
先 abort 再清除会话,可以阻止后续流更新;先发布 null 再等待任务完成,则不会把桌面会话清理延迟到异步流完全结束之后。读取会话的竞态由更新任务中的第二次 aborted 检查兜底。
Core Flow
一次有效更新的实际流程是:账户上下文注入完成后创建 effect;effect 建立取消边界并启动 watch;watch 产生更新;模块读取平台会话;若尚未取消则同步发布会话。订阅异常会记录警告并清空会话,effect 销毁则中止流、立即清空会话并等待后台任务收尾。
Data and Security Behavior
源码明确区分了两种发布值:
PlatformSession:从account.getPlatformSession()读取并发送给publish。null:用于订阅结束、异常终止或 effect 销毁时清除已发布状态。
publish 的类型是同步函数,因此本模块不等待 IPC 投递结果,也没有源码证据表明它会重试、排队或持久化。函数注释明确声明该私有投递不会把凭据转发给 renderer;但当前摘录没有展示 IPC 实现,因而无法进一步说明它使用的 channel、序列化方式或访问控制。
安全上的关键点是生命周期清理和竞态检查:销毁后不发布读取到的会话,异常结束时不保留旧会话,并且正常销毁不会依赖 watch 流自行及时结束。
Usage Examples
现有源材料只提供函数实现本身,没有调用方、测试或配置示例。因此,不能在不编造代码的情况下提供独立的“基础用法”或“高级用法”代码块。可确认的调用契约仅为:调用方提供一个 Context 和一个接受 PlatformSession | null 的同步发布函数,然后由该函数管理账户订阅生命周期。
Configuration Options
该函数实现中没有读取配置键、环境变量或默认配置。配置行为:未在现有源材料中发现。
API Reference
installPlatformSessionPublisher(ctx: Context, publish: (session: PlatformSession | null) => void): void
安装账户平台会话发布器。
参数:
ctx(Context):拥有账户依赖注入和 effect 生命周期的宿主上下文。publish((session: PlatformSession | null) => void):同步的私有 IPC 投递函数。接收当前PlatformSession,或在会话失效、订阅结束和清理时接收null。
返回值:
void。函数通过ctx.inject和accountCtx.effect注册生命周期行为,而不是返回订阅句柄。
异常与失败:
account.watch()或后续异步会话读取抛出的异常会被捕获。- 在未中止的情况下,异常会记录
desktop-platformlogger 的警告,并通过publish(null)清理会话。 - 源码没有显示异常重新抛出、自动重试或错误回调。
Failure Modes, Concurrency, and Operational Notes
订阅失败
订阅失败不会向上层重新抛出;模块记录固定警告文本并清空会话。运维侧如果需要诊断失败原因,当前实现不会把原始异常对象传给 logger,因此仅凭该日志无法获得异常堆栈;这属于现有实现的可观测性限制。
销毁期间的读取竞态
清理可能发生在 getPlatformSession() 等待期间。实现通过读取前后的两次取消检查处理该窗口:循环开始时阻止已取消的迭代,读取完成后再次阻止过期会话发布。清理函数还会等待 updates,保证 effect 的异步销毁不会留下未等待的任务。
重复清理
正常清理中,清理函数发布 null 并中止 signal;随后 finally 检查到已中止,不再发布第二次 null。异常结束则由 finally 执行清理。由此可见,代码有意避免将正常销毁和后台任务收尾重复计为两次清理事件。
重试与背压
当前实现没有重试、延迟、并发限制或显式背压策略。watch 的异步迭代决定更新节奏;每个更新会顺序等待 getPlatformSession(),随后同步调用 publish。关于 watch 是否合并更新、是否缓存状态或如何处理快速连续事件,现有摘录没有实现证据。
Extension Points
可扩展边界由两个依赖定义:账户对象需要提供 watch(signal) 和 getPlatformSession(),宿主需要提供符合签名的同步 publish。如果修改这些接口,必须保留以下不变量:
- 取消后不得发布会话。
- effect 清理必须清空已发布会话。
- 非取消异常必须可观察,并且必须清空会话。
- 清理必须等待已启动的异步更新任务结束。
当前源材料没有展示接口声明、依赖注册实现或替代 publisher,因此更具体的扩展方式无法确认。
Tests
现有源材料中没有测试文件或测试调用示例。未能从提供的摘录确认以下行为是否有自动化覆盖:初始账户状态、多个连续更新、watch 抛错、getPlatformSession 抛错、读取期间销毁、重复销毁以及 publisher 抛错。
Source Limitations
本页严格依据用户提供的 36 行实现摘录编写。由于运行上下文未提供该摘录对应的仓库相对路径和 File Reference Base URL,本文没有生成可能错误的源码链接;由于没有读取到更多仓库文件,也没有推断未展示的调用关系、类型字段、IPC channel、配置、测试或持久化行为。