2026-07-16 14:33:43 +08:00
|
|
|
|
# 协议合约(Catalog / 软件包 / 许可证 / 事件 / CLI)
|
|
|
|
|
|
|
|
|
|
|
|
> 本项目没有自建在线 API;盒子只消费静态签名文件。本文定义所有跨边界数据结构和交互合约的目标形状。
|
|
|
|
|
|
> 实现前可细化,但不要在代码里另起一套不兼容结构。字段变化必须同步更新本文、[04-architecture.md](04-architecture.md) 和 `schemas/` 下的 JSON Schema。
|
|
|
|
|
|
|
|
|
|
|
|
## 通用约定
|
|
|
|
|
|
|
|
|
|
|
|
- 传输:HTTPS;所有 JSON 使用 UTF-8。
|
|
|
|
|
|
- 时间格式:ISO 8601(UTC)。
|
|
|
|
|
|
- 签名:Ed25519;客户端只内置公钥;示例中的 `"signature": "..."` 均为占位符。
|
|
|
|
|
|
- 版本号:语义化版本(SemVer)。
|
|
|
|
|
|
- 软件 ID:`^[a-z0-9-]+$`,永久稳定,发布后不得更改。
|
|
|
|
|
|
|
|
|
|
|
|
## 1. Catalog 清单(远端 → 盒子)
|
|
|
|
|
|
|
|
|
|
|
|
现代版与 Win7 版使用不同 channel 文件:`manifest-modern.json` / `manifest-win7.json`。更新器必须校验 channel,禁止 Win7 版下载现代版包。
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"schema_version": 1,
|
|
|
|
|
|
"channel": "modern",
|
|
|
|
|
|
"generated_at": "2026-07-16T00:00:00Z",
|
|
|
|
|
|
"min_box_version": "1.0.0",
|
|
|
|
|
|
"apps": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "json-parser",
|
|
|
|
|
|
"name": "JSON解析工具",
|
|
|
|
|
|
"description": "示例简介",
|
|
|
|
|
|
"version": "1.2.0",
|
|
|
|
|
|
"channel": "stable",
|
|
|
|
|
|
"status": "active",
|
2026-07-16 16:52:46 +08:00
|
|
|
|
"category": "开发工具",
|
2026-07-16 14:33:43 +08:00
|
|
|
|
"tags": ["工具", "JSON"],
|
2026-07-16 16:52:46 +08:00
|
|
|
|
"icon": "sha256:0000000000000000000000000000000000000000000000000000000000000000",
|
2026-07-16 14:33:43 +08:00
|
|
|
|
"homepage": "https://example.com",
|
|
|
|
|
|
"tutorial": "https://example.com/tutorial",
|
|
|
|
|
|
"min_os": "windows-7-sp1",
|
|
|
|
|
|
"architectures": ["386", "amd64"],
|
|
|
|
|
|
"entry_exe": "JsonParser.exe",
|
|
|
|
|
|
"requires_admin": false,
|
|
|
|
|
|
"packages": {
|
|
|
|
|
|
"amd64": {
|
|
|
|
|
|
"url": "https://download.example.com/json-parser-1.2.0-amd64.zip",
|
|
|
|
|
|
"size": 12345678,
|
|
|
|
|
|
"sha256": "...",
|
|
|
|
|
|
"signature": "..."
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
"signature": "..."
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
行为要求:
|
|
|
|
|
|
|
2026-07-16 16:52:46 +08:00
|
|
|
|
- 网络成功:按“HTTPS 获取 → 验签 → Schema/字段/目标 channel 校验 → 替换缓存”处理;任一步失败都**拒绝**新内容,继续用最后一次验证且客户端可消费的缓存。
|
2026-07-16 14:33:43 +08:00
|
|
|
|
- 网络失败:用缓存;清单过期给提示,但保留已安装软件的启动能力。
|
|
|
|
|
|
- 下架:显式 `status: deprecated | hidden`,不用名称前缀。
|
2026-07-16 16:52:46 +08:00
|
|
|
|
- 分类:`category` 是单一稳定分类,`tags` 是搜索/多标签展示数据;两者都不得为空。
|
|
|
|
|
|
- 过滤:先校验 manifest `channel`,再按 `min_os`、`architectures` 和 `packages` 过滤;不兼容软件可见说明但不可下载。
|
|
|
|
|
|
- 状态:`active` 可安装;`deprecated` 可见但不可新装/更新;`hidden` 不进入目录结果,但本地已安装记录仍由本地状态模块保留。
|
|
|
|
|
|
- URL:Catalog、package、homepage、tutorial 只接受无用户信息、无 fragment 的绝对 HTTPS URL。
|
|
|
|
|
|
- 架构:MVP Schema 接受 `386` / `amd64`;一个 app 的 `architectures` 必须与 `packages` 键一一对应。当前两个客户端发布目标仍是 amd64。
|
|
|
|
|
|
- 系统版本:`min_os` v1 只允许 `windows-7-sp1`、`windows-10`、`windows-11`;更高系统可消费更低最低版本的软件。
|
|
|
|
|
|
- Schema:客户端协议文件为 `schemas/manifest.schema.json`;标准包元数据为 `schemas/app.schema.json`。运行时还会执行 JSON Schema 难以表达的重复 ID、架构映射和 channel 目标一致性检查。
|
2026-07-16 14:33:43 +08:00
|
|
|
|
|
2026-07-16 16:52:46 +08:00
|
|
|
|
### 1.1 Catalog 签名域
|
2026-07-16 16:13:18 +08:00
|
|
|
|
|
2026-07-16 16:52:46 +08:00
|
|
|
|
客户端采用以下签名域,供发布器实现对齐:
|
2026-07-16 16:13:18 +08:00
|
|
|
|
|
|
|
|
|
|
1. 输入必须是单个 UTF-8 JSON object;重复字段、尾随 JSON、浮点/指数数字直接拒绝。
|
|
|
|
|
|
2. 读取顶层 `signature`(标准 Base64 编码的 64 字节 Ed25519 签名),然后从对象中移除该字段。
|
|
|
|
|
|
3. 对剩余值递归规范化:对象键按 Unicode 字符串升序排列;数组保持原顺序;字符串按 JSON 转义;数字仅允许 JSON 整数并保持其合法十进制写法;不保留无意义空白。
|
|
|
|
|
|
4. Ed25519 直接签名/验证上述规范 JSON 字节。
|
|
|
|
|
|
|
2026-07-16 16:52:46 +08:00
|
|
|
|
T-201 已把该签名域接入正式客户端加载链路并用客户端测试向量覆盖。`softbox-catalog` 发布端仍必须补跨实现向量测试;密钥 ID/轮换字段尚未定稿,在单公钥协议升级前不得另造签名域。
|
2026-07-16 16:13:18 +08:00
|
|
|
|
|
2026-07-16 17:22:37 +08:00
|
|
|
|
### 1.2 图标内容引用与本地缓存
|
|
|
|
|
|
|
|
|
|
|
|
Catalog `icon` v1 是 `sha256:<64 hex>` 内容引用,不是可直接请求的 URL。最终分发字段仍由发布端定稿;客户端通过注入的 IconFetcher 把引用解析为图标字节,不得在 UI 中拼接或猜测 URL。
|
|
|
|
|
|
|
|
|
|
|
|
客户端缓存合约:
|
|
|
|
|
|
|
|
|
|
|
|
1. 请求键为 `(icon digest, DPI)`;DPI 接受 48~768 的整数值。
|
|
|
|
|
|
2. 加载顺序为内存 → 磁盘 → 注入 Fetcher;磁盘文件名为 `<digest>-<dpi>.icon`。
|
|
|
|
|
|
3. 远端和磁盘字节都必须复核 SHA-256,并通过图片解码、2 MiB 默认字节上限与 2048×2048 默认尺寸上限。
|
|
|
|
|
|
4. 只有验证成功的远端字节可用同目录临时文件原子写入磁盘;损坏的普通缓存文件删除后可重新获取,symlink/非普通文件按不安全布局拒绝。
|
|
|
|
|
|
5. 新进程断网时可读取再次验证成功的磁盘缓存;缓存损坏且远端不可用时返回 `no valid icon available`,UI 使用稳定占位图。
|
|
|
|
|
|
6. 后台完成 `IconCache.Load` 与 `DecodeIcon` 后调用 Gio `ApplyIcon`;Layout 只复用内存 `paint.ImageOp`。
|
|
|
|
|
|
|
2026-07-16 14:33:43 +08:00
|
|
|
|
## 2. 标准软件包协议 v1(ZIP)
|
|
|
|
|
|
|
|
|
|
|
|
```text
|
|
|
|
|
|
json-parser_1.4.2_windows_amd64.zip
|
|
|
|
|
|
├─ app.json # 身份、版本、入口、兼容性
|
|
|
|
|
|
├─ files.json # 解压后文件清单(v1.1 强制,v1 推荐)
|
|
|
|
|
|
└─ payload/ # 实际安装到 current/ 的程序文件
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2.1 app.json
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"schema_version": 1,
|
|
|
|
|
|
"id": "json-parser",
|
|
|
|
|
|
"name": "JSON解析工具",
|
|
|
|
|
|
"vendor": "MyCompany",
|
|
|
|
|
|
"version": "1.4.2",
|
|
|
|
|
|
"channel": "stable",
|
|
|
|
|
|
"min_os": "windows-7-sp1",
|
|
|
|
|
|
"architecture": "amd64",
|
|
|
|
|
|
"entrypoint": "JsonParser.exe",
|
|
|
|
|
|
"working_directory": ".",
|
|
|
|
|
|
"product_id": "product-json-parser",
|
|
|
|
|
|
"supports_trial": true,
|
|
|
|
|
|
"requires_admin": false,
|
|
|
|
|
|
"data_policy": "local-app-data",
|
|
|
|
|
|
"update_policy": "managed-by-softbox"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
校验规则:`entrypoint`/`working_directory` 必须是 payload 内安全相对路径;`id`、`version`、`channel`、`architecture` 必须与 Catalog 记录一致;`schema_version` 高于盒子支持范围时拒绝安装并提示升级盒子(盒子始终支持当前与前一个 Schema)。
|
|
|
|
|
|
|
|
|
|
|
|
### 2.2 files.json
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"schema_version": 1,
|
|
|
|
|
|
"files": [
|
|
|
|
|
|
{ "path": "JsonParser.exe", "size": 3456789, "sha256": "..." }
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
完整 ZIP 的 SHA-256 由签名 Catalog 保存(不写入包内部);files.json 用于解压后复核关键文件与修复功能。
|
|
|
|
|
|
|
|
|
|
|
|
### 2.3 安全限制(必须拒绝)
|
|
|
|
|
|
|
|
|
|
|
|
绝对路径;`../` 穿越;符号链接/重解析点逃出 staging;写入其他软件或盒子目录;覆盖 `data/` 与 `licenses/`;包内自动执行脚本(install.bat/PowerShell 钩子);未验证 SHA-256/签名的包被执行;解压文件数、总体积或压缩比无上限;entrypoint 指向 payload 之外。
|
|
|
|
|
|
|
2026-07-16 16:22:45 +08:00
|
|
|
|
T-102 Phase 1 原型进一步固定:
|
|
|
|
|
|
|
|
|
|
|
|
- ZIP 名称只接受 UTF-8 `/` 分隔的规范相对路径;拒绝反斜杠、盘符、冒号/NTFS ADS、NUL、`.`/`..` 和大小写折叠后的重复输出路径。
|
|
|
|
|
|
- 顶层只允许必需的 `app.json`、可选 `files.json` 与 `payload/`;只把 `payload/` 内容写入全新的 staging。
|
|
|
|
|
|
- 拒绝符号链接、设备/管道等特殊文件和加密条目。
|
|
|
|
|
|
- 原型默认上限:10,000 个条目、总展开 4 GiB、单条及总体压缩比 200:1。T-302 按真实包体分布复核后再冻结。
|
|
|
|
|
|
- entrypoint 使用 payload 内相对路径表示,不得自带 `payload/` 前缀,且必须精确对应 ZIP 中的普通文件。
|
|
|
|
|
|
|
2026-07-16 14:33:43 +08:00
|
|
|
|
### 2.4 安装记录 installed-app.json(本地)
|
|
|
|
|
|
|
|
|
|
|
|
记录实际安装的软件 ID、版本、架构、channel 和文件清单;与 `current/`、`staging/`、`backup/` 同级存放于 `apps/<id>/`。
|
|
|
|
|
|
|
2026-07-16 17:00:06 +08:00
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"schema_version": 1,
|
|
|
|
|
|
"id": "json-parser",
|
|
|
|
|
|
"version": "1.4.2",
|
|
|
|
|
|
"architecture": "amd64",
|
|
|
|
|
|
"channel": "stable",
|
|
|
|
|
|
"files": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"path": "JsonParser.exe",
|
|
|
|
|
|
"size": 3456789,
|
|
|
|
|
|
"sha256": "0000000000000000000000000000000000000000000000000000000000000000"
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
规则:
|
|
|
|
|
|
|
|
|
|
|
|
- Schema 位于 `schemas/installed-app.schema.json`;未知字段、非法 SemVer、ID/目录不匹配、非 `386|amd64` 架构、非 stable channel、安全相对路径以外的文件名、重复路径和非法 SHA-256 均拒绝。
|
|
|
|
|
|
- `files` 必须是数组;v1 可以为空,完整文件清单由 T-302 安装整合时从已验证包写入。
|
|
|
|
|
|
- 写入使用 app 目录内临时文件 + `installed-app.json.backup` 原子替换;主文件缺失时可读取中断遗留 backup,但所有读取都重新严格校验。
|
|
|
|
|
|
- SemVer 比较遵循 2.0.0:major/minor/patch 与 prerelease 参与 precedence,build metadata 不影响更新判断。
|
|
|
|
|
|
|
|
|
|
|
|
### 2.4.1 本地可见状态推导
|
|
|
|
|
|
|
|
|
|
|
|
状态事实由后台/存储层预先收集,UI Layout 不扫描磁盘。单一可见状态按以下优先级推导:
|
|
|
|
|
|
|
|
|
|
|
|
1. 存在 `install-transaction.json` 或其 backup → `rollback_pending`。
|
|
|
|
|
|
2. 存在活跃任务状态 → `queued|downloading|verifying|extracting|installing|failed`。
|
|
|
|
|
|
3. 已检测到进程运行 → `running`。
|
|
|
|
|
|
4. Catalog 判定不可兼容 → `incompatible`。
|
|
|
|
|
|
5. 无 installed-app.json → `not_installed`。
|
|
|
|
|
|
6. 本地 SemVer 低于 Catalog → `update_available`;否则 → `installed`。Catalog 中已隐藏/下架且无可比较版本时,保留 `installed`。
|
|
|
|
|
|
|
2026-07-16 16:32:58 +08:00
|
|
|
|
### 2.5 安装切换事务(Phase 1 原型)
|
|
|
|
|
|
|
|
|
|
|
|
`apps/<id>/install-transaction.json` 用于断电恢复:
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"schema_version": 1,
|
|
|
|
|
|
"phase": "staging_activated",
|
|
|
|
|
|
"had_current": true
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
phase 只允许:`prepared`、`current_backed_up`、`staging_activated`、`rollback_required`、`committed`。日志使用临时文件 + 同目录 backup 原子替换;恢复时同时检查日志与 current/staging/backup 实际状态。未完成健康检查的 current 不视为可信:有旧版时恢复 backup,首次安装则撤销 current。
|
|
|
|
|
|
|
2026-07-16 19:49:06 +08:00
|
|
|
|
### 2.6 下载任务元数据 download-task.json(本地)
|
|
|
|
|
|
|
|
|
|
|
|
每个任务以稳定 `request_id` 为主键,元数据位于 `downloads/tasks/<request_id>.json`,字节文件位于 `downloads/files/<request_id>.part|.download`。本地路径只由客户端从 request_id 派生,不接受 URL 或 Content-Disposition 提供的文件名。
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"schema_version": 1,
|
|
|
|
|
|
"request_id": "download-json-parser-001",
|
|
|
|
|
|
"app_id": "json-parser",
|
|
|
|
|
|
"url": "https://download.example.com/json-parser.zip",
|
|
|
|
|
|
"status": "paused",
|
|
|
|
|
|
"attempt": 2,
|
|
|
|
|
|
"done": 1048576,
|
|
|
|
|
|
"total_known": true,
|
|
|
|
|
|
"total": 12345678,
|
|
|
|
|
|
"validator": {
|
|
|
|
|
|
"etag": "\"release-1.4.2\""
|
|
|
|
|
|
},
|
|
|
|
|
|
"error_code": "",
|
|
|
|
|
|
"created_at": "2026-07-16T00:00:00Z"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
规则:
|
|
|
|
|
|
|
|
|
|
|
|
- Schema 为 `schemas/download-task.schema.json`;内部状态只允许 queued/downloading/paused/failed/completed。paused 对 UI 映射为 queued + DownloadPaused 事件,不增加第 13 个 AppStatus。
|
|
|
|
|
|
- 默认最多 2 个 downloading;同一 request_id 幂等,身份/URL/size 不同则冲突;同一 app 同时只允许一个非 completed 任务。
|
|
|
|
|
|
- 暂停保留 `.part` 和元数据;失败 retry 保留 `.part`;取消固定删除该 request_id 精确派生的 part/final/metadata,不使用递归删除。取消已线性化后,body close/sync 等非致命错误只记录日志,不能把取消反转成 failed 或跳过清理。
|
|
|
|
|
|
- 续传只在存在 strong ETag 或合法 Last-Modified 时发送 Range + If-Range;无可靠 validator 时从 0 重下。请求固定 `Accept-Encoding: identity`,所有 redirect 重新校验 HTTPS。
|
|
|
|
|
|
- `206` 必须严格匹配 Content-Range 起点、长度、total 与期望 size;已有 part 但服务端返回 `200` 时截断并创建新 attempt,不能 old+new 拼接。
|
|
|
|
|
|
- known total 使用已验签 Catalog package.size 作为精确传输长度;unknown total 使用显式 `total_known: false` 并受 4 GiB 默认硬上限保护。
|
|
|
|
|
|
- known total 的 `.part` 已达到精确 total 时,同进程 resume/retry 与重启恢复都直接 sync、核对身份并 finalize,不得再请求 `Range: bytes=<total>-`。
|
|
|
|
|
|
- 完成顺序为 part sync/close → 核对实际写入文件身份 → rename `.download` → metadata completed → DownloadCompleted。rename 前后必须仍是同一普通文件;恢复时以普通文件实际长度对账,不信任 metadata.done。
|
|
|
|
|
|
- 事件投递是 best-effort,失败不得反向把已完成/已取消的持久任务改成失败。队列必须把投递错误交给 `OnObserverError` 记录;application/UI 在启动或事件通道重连后必须用 `Queue.Tasks()` 对账持久状态,不能只依赖某一次终态事件。
|
|
|
|
|
|
- `.download` 仍是**不可信隔离字节**。T-302 必须重新从已验签 Catalog 取得 app/version/arch/size/SHA-256/signature 并验证,通过后才可读取 app.json 或解压。
|
|
|
|
|
|
|
2026-07-16 14:33:43 +08:00
|
|
|
|
## 3. 许可证(服务端签发 → 本地离线验证)
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"schema_version": 1,
|
|
|
|
|
|
"license_id": "lic-...",
|
|
|
|
|
|
"machine_hash": "...",
|
|
|
|
|
|
"products": ["product-json-parser"],
|
|
|
|
|
|
"issued_at": "2026-07-16T00:00:00Z",
|
|
|
|
|
|
"perpetual": true,
|
|
|
|
|
|
"update_policy": "updates-until-2027-12-31",
|
|
|
|
|
|
"rebind_policy": "self-service-1-per-90d",
|
|
|
|
|
|
"signature": "..."
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- machine_hash 由平台层多个稳定硬件标识清洗生成;许可证中**不保存**原始序列号和 MAC。
|
|
|
|
|
|
- 客户端用内置 Ed25519 公钥离线验签;许可证保存于 `licenses/`,与程序文件、用户配置分离;更新不得覆盖。
|
|
|
|
|
|
- 撤销名单同样签名并缓存,网络失败保留宽限期。
|
|
|
|
|
|
- 盒子负责导入/展示/管理;**子软件必须用 sdk 的 licensing 逻辑独立再验证**(签名 + machine_hash + product_id),决定正式版/试用版/授权错误。
|
|
|
|
|
|
|
|
|
|
|
|
## 4. application 事件合约(core → UI)
|
|
|
|
|
|
|
|
|
|
|
|
后台任务不直接修改 Gio 控件,只发布事件;UI 按 `request_id` + `app_id` 更新 ViewModel 并 `Invalidate`。
|
|
|
|
|
|
|
|
|
|
|
|
| 事件 | 触发时机 | 负载 | 结果 |
|
|
|
|
|
|
| --- | --- | --- | --- |
|
|
|
|
|
|
| CatalogRefreshed | 清单验签并缓存成功 | catalog 摘要、generated_at | 列表刷新 |
|
|
|
|
|
|
| CatalogRejected | 清单验签失败 | 原因码 | 提示 + 继续用缓存 |
|
2026-07-16 19:49:06 +08:00
|
|
|
|
| DownloadStarted | 一个下载 attempt 开始/因安全重下而重置 | request_id, app_id, attempt, done, total_known, total | 状态 → downloading |
|
|
|
|
|
|
| DownloadProgress | 当前 attempt 进度更新 | request_id, app_id, attempt, done, total_known, total, speed | 进度条刷新;done 在同 attempt 内单调 |
|
|
|
|
|
|
| DownloadPaused | 用户暂停且旧 worker 已完全退出 | request_id, app_id, attempt, done | 状态 → queued(暂停态) |
|
|
|
|
|
|
| DownloadCompleted | 字节完整落盘,尚未通过 SHA/签名 | request_id, app_id, attempt, done, path | 状态 → verifying;T-302 接管信任校验 |
|
|
|
|
|
|
| DownloadFailed | 传输/Range/存储失败 | request_id, app_id, attempt, done, error_code | 状态 → failed + 可重试 |
|
|
|
|
|
|
| DownloadCanceled | 取消清理完成且旧 attempt 不再发事件 | request_id, app_id, attempt | 从任务视图移除并回到本地基础状态 |
|
2026-07-16 14:33:43 +08:00
|
|
|
|
| InstallCompleted | 原子切换成功 + 健康检查通过 | app_id, version | 状态 → installed |
|
|
|
|
|
|
| InstallRolledBack | 切换失败恢复 backup | app_id, error_code | 状态 → rollback 完成提示 |
|
|
|
|
|
|
| AppStarted / AppExited | 进程启动/退出检测 | app_id, pid | 状态 → running / installed |
|
|
|
|
|
|
| LicenseChanged | 许可证导入/撤销 | products | 授权视图刷新 |
|
|
|
|
|
|
|
|
|
|
|
|
错误码为稳定英文枚举(如 `hash_mismatch`, `zip_path_escape`, `disk_full`, `app_running`, `signature_invalid`),UI 负责本地化文案。
|
|
|
|
|
|
|
|
|
|
|
|
## 5. CLI 参数合约
|
|
|
|
|
|
|
|
|
|
|
|
### 5.1 SoftBox.exe
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
SoftBox.exe # 正常启动
|
|
|
|
|
|
SoftBox.exe --open-app <id> # 打开并定位到指定软件
|
|
|
|
|
|
SoftBox.exe --update-app <id> # 触发指定软件更新流程
|
|
|
|
|
|
SoftBox.exe --repair-app <id> # 按 files.json 修复安装(V1.1)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
子软件的「检查更新」按钮调用以上参数,不自建下载器;盒子未运行时子软件可启动它。
|
|
|
|
|
|
|
|
|
|
|
|
### 5.2 SoftBoxUpdater.exe(盒子自更新助手)
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
SoftBoxUpdater.exe --pid <主程序PID> --staging <暂存目录> --target <目标目录>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
等待主进程退出 → 备份旧版 → 切换新版 → 启动新版 SoftBox → 失败时恢复备份。退出码:0 成功;非 0 失败并写日志。
|
|
|
|
|
|
|
|
|
|
|
|
### 5.3 子软件推荐参数(v1 推荐,非强制)
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
<App>.exe --softbox-info # 输出软件 ID、版本、架构、协议版本 JSON,退出码 0
|
|
|
|
|
|
<App>.exe --softbox-health # 基本环境自检,成功退出码 0
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
产品自定义参数不得占用 `--softbox-` 前缀。
|
|
|
|
|
|
|
|
|
|
|
|
## 6. 进程退出协议(更新前)
|
|
|
|
|
|
|
|
|
|
|
|
v1:进程快照判断运行 → 提示用户保存关闭 → 等待正常退出 → 超时取消更新,**不默认强杀**。
|
|
|
|
|
|
V1.1:命名管道 `\\.\pipe\softbox.<app-id>`,盒子发送 `{"command": "prepare_update", "request_id": "..."}`,子软件保存数据回复 `ready` 后自行退出。
|
|
|
|
|
|
|
|
|
|
|
|
## 待实现时确认
|
|
|
|
|
|
|
2026-07-16 16:52:46 +08:00
|
|
|
|
- 清单密钥 ID/轮换字段定稿后同步 `schemas/`。
|
2026-07-16 14:33:43 +08:00
|
|
|
|
- 错误码完整枚举表。
|
2026-07-16 17:22:37 +08:00
|
|
|
|
- 图标资源从内容哈希到下载位置/分辨率变体的发布端映射格式。
|
2026-07-16 14:33:43 +08:00
|
|
|
|
- 撤销名单的结构与宽限期时长。
|
|
|
|
|
|
- machine_hash 的标识来源清单与加权算法(平台层内部文档)。
|