Files
LanMountainDesktop/.trae/specs/plonds-client-service/spec.md
2026-06-02 10:09:06 +08:00

6.1 KiB
Raw Blame History

PLONDS Client Service 独立化设计

日期2026-06-01 状态:设计中

1. 目标

PLONDS 在应用内必须作为独立服务存在,负责分发发现、下载、校验和本地包准备。它不是现有 Update 模块的 provider也不应把 S3/GitHub/source 选择逻辑混入 LanMountainDesktop/Services/Update/

最终边界:

  • PLONDS 服务:寻找最新版本、选择下载源、下载 manifest 和包、校验文件、准备本地 staging。
  • 安装程序/安装网关:只消费 PLONDS 已准备好的本地安装输入,执行增量安装或完整安装。
  • UI只展示 PLONDS 服务和安装程序返回的状态;完整包也失败后才处理错误。

2. 当前耦合点

当前需要拆离的耦合点:

  • LanMountainDesktop/Services/Settings/SettingsDomainServices.cs
    • 直接持有 PlondsStaticUpdateServicePlondsReleaseUpdateService
    • CheckForUpdatesCoreAsync 中把 PLONDS 和 GitHub Update fallback 逻辑混在一起
  • LanMountainDesktop/Services/Update/UpdateInstallGateway.cs
    • 直接判断 UpdatePayloadKind.DeltaPlonds
    • 直接实例化 PlondsUpdateApplier
  • LanMountainDesktop/Services/Update/Plonds*.cs
    • PLONDS apply/parser/payload resolver 仍位于 Update 命名空间

3. Source 发现规则

PLONDS 客户端内置两个初始地址:

  1. S3 上的 PLONDS manifest 地址
  2. GitHub Release 上的 PLONDS manifest 地址

两个地址读取的是同一种 JSON 文件,当前文件名为 PLONDS.json。客户端每次检查增量更新时,会并行或顺序请求所有已知 source 的 PLONDS.json

3.1 Source 扩展

PLONDS.json 可以声明额外 source。客户端读取到额外 source 后,应把它们加入下一轮寻找列表。

建议 manifest 扩展字段:

{
  "sources": [
    {
      "id": "rainyun-s3",
      "kind": "s3",
      "manifestUrl": "https://example.com/plonds/1.2.3/PLONDS.json",
      "priority": 100
    },
    {
      "id": "github",
      "kind": "github",
      "manifestUrl": "https://github.com/owner/repo/releases/download/v1.2.3/PLONDS.json",
      "priority": 50
    }
  ]
}

规则:

  • sources 为空或缺失时,只使用内置 S3 + GitHub。
  • 新 source 不覆盖内置 source除非 id 相同。
  • source 列表需要去重,按 idmanifestUrl 双重去重。
  • source 持久化到 PLONDS 自己的配置/缓存,不写入 Update 设置。

4. 版本选择规则

如果多个 source 返回的版本不一致,客户端选择 currentVersion 最高的 manifest。

规则:

  • 版本解析使用 Version 语义,忽略前导 v
  • 版本相同时,优先选择下载可用性更高的 source。
  • 如果最高版本 manifest 下载包失败,可以尝试同版本的其他 source。
  • 不因为低版本 source 成功而降级,除非用户显式允许。

5. 下载与回退规则

PLONDS 服务优先走增量包:

  1. 下载所选 manifest。
  2. 下载 changed.zip
  3. 校验 changed.zip 与 manifest 中的 hash/checksum。
  4. 解压或准备增量 staging。
  5. 交给安装程序执行增量安装。

如果增量流程失败PLONDS 服务自动改用完整包:

  1. 下载 Files.zip
  2. 校验 Files.zip
  3. 解压或准备完整包 staging。
  4. 交给安装程序执行完整包安装。

如果完整包也失败PLONDS 服务返回失败结果,由 UI 展示错误和重试入口。

6. 发布产物布局

Publisher 上传到 S3 的版本目录:

<prefix>/<version>/PLONDS.json
<prefix>/<version>/changed.zip
<prefix>/<version>/<version>-changed/**
<prefix>/<version>/Files.zip
<prefix>/<version>/<version>-Files/**

说明:

  • Files.zip 是上传到 S3 时的完整包标准名。
  • <version>-Files/ 是 S3 上解压后的完整包目录。
  • <prefix>/PLONDS.json 是 S3 的固定 latest manifest 地址,和 GitHub Release latest manifest 一起作为客户端内置初始 source。
  • GitHub Release 仍可保留平台原始文件名,例如 files-windows-x64.zip
  • PLONDS.json 的 downloads 字段同时包含 GitHub 与 S3 的增量包、完整包位置。
  • Publisher 必须先完成版本目录内的 changed.zipFiles.zip、解压目录和版本 PLONDS.json 上传,再更新 <prefix>/PLONDS.json latest 指针。
  • Publisher 的 S3 目录上传必须支持重跑续传;同 key 且大小一致的对象可以跳过,避免失败后从头上传完整包目录。
  • Publisher 上传大对象时应使用 S3 multipart upload以避免 changed.zip / Files.zip 在低吞吐链路上被单次 PUT 长时间阻塞。

7. 建议代码结构

LanMountainDesktop/Services/Plonds/
  IPlondsService.cs
  PlondsService.cs
  Sources/
    IPlondsSource.cs
    PlondsHttpManifestSource.cs
    PlondsSourceRegistry.cs
  Download/
    PlondsDownloader.cs
    PlondsDownloadPlanner.cs
  Verification/
    PlondsVerifier.cs
  Staging/
    PlondsPackageStore.cs
    PlondsPreparedPackage.cs
  Models/
    PlondsClientManifest.cs
    PlondsSourceDescriptor.cs
    PlondsCheckResult.cs

后续如果要移植,优先把这棵目录或等价项目抽成独立库。

8. 与安装程序的交接契约

PLONDS 服务输出本地 prepared package

public sealed record PlondsPreparedPackage(
    Version Version,
    PlondsPackageMode Mode,
    string ManifestPath,
    string? ChangedZipPath,
    string? ChangedDirectory,
    string? FilesZipPath,
    string? FilesDirectory);

安装程序只接受这个结果,不参与 source 发现、下载和校验。

9. 实施顺序

  1. Publisher 补齐完整包 S3 上传与 manifest downloads 字段。
  2. 新增 Services/Plonds/ 客户端服务骨架和模型。
  3. PlondsStaticUpdateService / PlondsReleaseUpdateService 合并迁移到独立 PLONDS source 体系。
  4. LanMountainDesktop/Services/Update/Plonds*.cs 迁出 Update 命名空间。
  5. UpdateSettingsService 改为调用 IPlondsService,不再直接组合 S3/GitHub PLONDS fallback。
  6. 安装入口只接收 PlondsPreparedPackage
  7. 添加单元测试覆盖 source 扩展、最高版本选择、增量失败转完整包、完整包失败交 UI。