495 lines
16 KiB
Markdown
495 lines
16 KiB
Markdown
|
|
# Neta Windows 托盘模式设计
|
|||
|
|
|
|||
|
|
> 日期:2026-04-25
|
|||
|
|
> 状态:待实施
|
|||
|
|
> 修订:v2 — 按架构复核收紧运行时边界、控制接口与实施顺序
|
|||
|
|
|
|||
|
|
## 目标
|
|||
|
|
|
|||
|
|
在现有 Windows 离线安装链路基础上,为 Neta 增加首版托盘模式。
|
|||
|
|
首版要求保留当前安装器总体体验,但新增完整的 Windows 托盘入口,使用户可以通过托盘完成打开系统、启停服务、打开目录和退出程序。
|
|||
|
|
|
|||
|
|
本期目标不是重做桌面端架构,而是在不改动数据库安全方案的前提下,补齐 Windows 本地使用体验中最明显的缺口。
|
|||
|
|
|
|||
|
|
## 当前项目现实
|
|||
|
|
|
|||
|
|
当前 Neta 的 Windows 运行链路已经具备以下真实状态:
|
|||
|
|
|
|||
|
|
- `backend.exe` 是现有唯一运行入口,启动入口为 `packages/backend/bootstrap.js`
|
|||
|
|
- 启动前已会读取外部 `config.yaml` 并注入运行配置
|
|||
|
|
- `backend.exe` 已负责真实端口选择、`data.dir` 路径收口、日志目录、运行锁和自动打开浏览器
|
|||
|
|
- Inno Setup 当前默认安装、快捷方式、首次启动和卸载都直接围绕 `backend.exe`
|
|||
|
|
- 仓库当前没有现成的桌面端托盘基础设施,也没有 `.NET` / Rust / Go 托盘项目
|
|||
|
|
|
|||
|
|
因此,这次托盘设计必须是对现有单进程 Windows 架构的增量改造,而不是重画一套新的桌面运行时。
|
|||
|
|
|
|||
|
|
## 已确认约束
|
|||
|
|
|
|||
|
|
- 保持当前启动方式总体体验不变,只是额外增加托盘图标和托盘菜单
|
|||
|
|
- 首版托盘菜单必须包含:
|
|||
|
|
- 打开系统
|
|||
|
|
- 重启服务
|
|||
|
|
- 停止服务
|
|||
|
|
- 打开日志目录
|
|||
|
|
- 打开配置目录
|
|||
|
|
- 退出程序
|
|||
|
|
- 安装器允许新增独立 `tray.exe`
|
|||
|
|
- 桌面快捷方式和开机自启都统一启动 `tray.exe`
|
|||
|
|
- `tray.exe` 负责拉起和监控 `backend.exe`
|
|||
|
|
- 数据库安全相关问题本期不改,继续沿用当前 `config.yaml` 方案
|
|||
|
|
- 不引入 Windows Service
|
|||
|
|
- 不实现“关闭浏览器窗口后最小化到托盘”
|
|||
|
|
- 不实现自动更新、首次启动配置向导
|
|||
|
|
- 不调整 `config.yaml` 的当前存放位置
|
|||
|
|
|
|||
|
|
## 1. 方案对比
|
|||
|
|
|
|||
|
|
### 方案 A:独立 `tray.exe` + 现有 `backend.exe`(推荐)
|
|||
|
|
|
|||
|
|
- `backend.exe` 继续承载 Midway.js 后端与前端静态资源
|
|||
|
|
- 新增一个轻量原生 Windows 托盘程序 `tray.exe`
|
|||
|
|
- `tray.exe` 负责托盘图标、菜单、开机自启、单实例、启动/停止/重启 `backend.exe`
|
|||
|
|
- 安装器入口、桌面快捷方式、开始菜单和开机自启统一指向 `tray.exe`
|
|||
|
|
|
|||
|
|
优点:
|
|||
|
|
- Windows 职责边界清晰,托盘控制和 Web 服务解耦
|
|||
|
|
- 便于处理托盘生命周期、单实例和目录打开等原生能力
|
|||
|
|
- 后续若继续扩展状态提示、升级控制器、最小化托盘等能力,演进路径更自然
|
|||
|
|
|
|||
|
|
代价:
|
|||
|
|
- 安装产物从一个主 exe 变成两个 exe
|
|||
|
|
- 打包链路需要增加一个托盘程序构建步骤
|
|||
|
|
- 打包环境要新增桌面端工具链依赖
|
|||
|
|
|
|||
|
|
### 方案 B:把托盘能力并入 `backend.exe`
|
|||
|
|
|
|||
|
|
- 继续只保留 `backend.exe`
|
|||
|
|
- 同一个进程同时承担后端服务与托盘功能
|
|||
|
|
|
|||
|
|
优点:
|
|||
|
|
- 产物更少
|
|||
|
|
- 打包表面上更简单
|
|||
|
|
|
|||
|
|
代价:
|
|||
|
|
- Node/pkg 进程承载 Windows 原生托盘能力更复杂
|
|||
|
|
- 进程窗口形态、生命周期和服务控制容易互相耦合
|
|||
|
|
- 后续加菜单状态和异常恢复时复杂度明显更高
|
|||
|
|
|
|||
|
|
### 方案 C:`tray.exe` 仅做启动器,核心控制仍回到 `backend.exe`
|
|||
|
|
|
|||
|
|
优点:
|
|||
|
|
- 比单进程更容易落地
|
|||
|
|
|
|||
|
|
代价:
|
|||
|
|
- 职责边界仍不干净
|
|||
|
|
- 后续扩菜单、状态同步和异常恢复时容易重新耦合
|
|||
|
|
|
|||
|
|
### 结论
|
|||
|
|
|
|||
|
|
采用方案 A:新增独立 `tray.exe` 作为 Windows 壳层,`backend.exe` 保持当前服务职责。
|
|||
|
|
|
|||
|
|
## 2. 总体架构
|
|||
|
|
|
|||
|
|
安装产物分成两层:
|
|||
|
|
|
|||
|
|
- `backend.exe`:现有 pkg 产物,继续负责 Midway.js 服务、静态前端、配置加载、数据目录解析、真实端口选择、单实例、优雅退出
|
|||
|
|
- `tray.exe`:新增 Windows 托盘控制器,负责本地托盘交互、菜单操作和后端进程编排
|
|||
|
|
|
|||
|
|
启动路径改为:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
桌面快捷方式 / 开机自启 / 开始菜单
|
|||
|
|
-> tray.exe
|
|||
|
|
-> 检查 backend.exe 是否已运行
|
|||
|
|
-> 未运行则拉起 backend.exe
|
|||
|
|
-> 已运行则仅挂托盘
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
核心原则:
|
|||
|
|
|
|||
|
|
- `backend.exe` 是唯一运行时真源
|
|||
|
|
- Web 服务职责、真实端口、路径、锁、ready 状态全部保留在 `backend.exe`
|
|||
|
|
- `tray.exe` 不是第二个运行时中心,只是本地壳层和控制面消费者
|
|||
|
|
- 两者之间只通过最小化的本机控制协议通信,不共享业务逻辑
|
|||
|
|
|
|||
|
|
## 3. 托盘菜单定义
|
|||
|
|
|
|||
|
|
首版托盘菜单固定包含以下项目:
|
|||
|
|
|
|||
|
|
1. 打开系统
|
|||
|
|
- 打开当前本地前端首页
|
|||
|
|
- URL 必须来自 `backend.exe` 状态接口返回值,不由 `tray.exe` 自行猜测
|
|||
|
|
|
|||
|
|
2. 重启服务
|
|||
|
|
- 由 `tray.exe` 先请求 `backend.exe` 优雅停止
|
|||
|
|
- 停止完成后,再由 `tray.exe` 重新拉起 `backend.exe`
|
|||
|
|
- “重启”是托盘侧的编排动作,不是后端自重启接口
|
|||
|
|
|
|||
|
|
3. 停止服务
|
|||
|
|
- 由 `tray.exe` 调用本机 stop 控制接口
|
|||
|
|
- 等待后端退出,并将托盘状态更新为“服务未运行”
|
|||
|
|
|
|||
|
|
4. 打开日志目录
|
|||
|
|
- 打开 `{dataDir}/logs`
|
|||
|
|
|
|||
|
|
5. 打开配置目录
|
|||
|
|
- 打开安装目录中 `config.yaml` 所在目录
|
|||
|
|
|
|||
|
|
6. 退出程序
|
|||
|
|
- 默认同时退出托盘和后端服务
|
|||
|
|
- 顺序为:先请求后端优雅退出,再退出 `tray.exe`
|
|||
|
|
- 如后端超时未退出,可执行兜底强制结束
|
|||
|
|
|
|||
|
|
## 4. 本机控制协议
|
|||
|
|
|
|||
|
|
`tray.exe` 不承载业务逻辑,只作为本机控制层。
|
|||
|
|
`backend.exe` 在现有 Web 服务之外,新增一个仅本机可用的最小控制入口供托盘调用。
|
|||
|
|
|
|||
|
|
### 4.1 通信方式
|
|||
|
|
|
|||
|
|
首版采用 loopback HTTP:
|
|||
|
|
|
|||
|
|
- 仅监听 `127.0.0.1`
|
|||
|
|
- 不对外网暴露
|
|||
|
|
- 使用本地 secret 进行鉴权,避免同机其他进程随意控制
|
|||
|
|
|
|||
|
|
### 4.2 首次发现机制
|
|||
|
|
|
|||
|
|
为了解决动态端口和托盘首次附着问题,`backend.exe` 启动后必须在 `{dataDir}/runtime-info.json` 写入本机运行时引导信息。
|
|||
|
|
|
|||
|
|
该文件至少包含:
|
|||
|
|
|
|||
|
|
- `pid`
|
|||
|
|
- `ready`
|
|||
|
|
- `startedAt`
|
|||
|
|
- `port`
|
|||
|
|
- `url`
|
|||
|
|
- `controlBaseUrl`
|
|||
|
|
- `controlSecret`
|
|||
|
|
- `dataDir`
|
|||
|
|
- `logDir`
|
|||
|
|
- `configDir`
|
|||
|
|
|
|||
|
|
用途:
|
|||
|
|
|
|||
|
|
- `tray.exe` 首次启动时,先通过安装目录下的 `config.yaml` 定位 `data.dir`
|
|||
|
|
- 再从 `{dataDir}/runtime-info.json` 读取当前 `backend.exe` 的真实控制地址和本机 secret
|
|||
|
|
- 从而避免硬编码 8003,也避免在“backend 已经在运行”时无法获知 secret
|
|||
|
|
|
|||
|
|
`runtime-info.json` 是本地桌面版运行时的引导文件,不是对外 API,也不是新的业务配置入口。
|
|||
|
|
|
|||
|
|
### 4.3 最小控制面
|
|||
|
|
|
|||
|
|
首版只提供两个接口:
|
|||
|
|
|
|||
|
|
- `GET /base/runtime/status`
|
|||
|
|
- `POST /base/runtime/stop`
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- 路由层级必须遵循当前 `modules/base/controller/app/*.ts` 的现有挂载风格
|
|||
|
|
- 这里的 `/base/runtime/*` 是基于当前 `app/comm` 控制器实际访问模式确定的逻辑落点
|
|||
|
|
|
|||
|
|
明确不提供:
|
|||
|
|
|
|||
|
|
- `POST /base/runtime/restart`
|
|||
|
|
- `POST /base/runtime/open`
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
|
|||
|
|
- `restart` 应由 `tray.exe` 负责 stop + spawn 编排,不应由 `backend.exe` 自己承担自重启职责
|
|||
|
|
- `open` 不需要独立控制接口,`tray.exe` 从状态接口取得真实 URL 后自行打开浏览器即可
|
|||
|
|
|
|||
|
|
### 4.4 状态接口返回内容
|
|||
|
|
|
|||
|
|
状态接口至少返回:
|
|||
|
|
|
|||
|
|
- 当前运行状态
|
|||
|
|
- ready 状态
|
|||
|
|
- 实际监听端口
|
|||
|
|
- 首页 URL
|
|||
|
|
- 数据目录路径
|
|||
|
|
- 日志目录路径
|
|||
|
|
- 配置目录路径
|
|||
|
|
- 后端 PID
|
|||
|
|
|
|||
|
|
这样 `tray.exe` 可以始终依赖真实运行状态驱动菜单,而不是自行拼接路径或端口。
|
|||
|
|
|
|||
|
|
### 4.5 启动握手
|
|||
|
|
|
|||
|
|
`tray.exe` 启动后执行:
|
|||
|
|
|
|||
|
|
1. 读取安装目录下的 `config.yaml`,得到 `data.dir`
|
|||
|
|
2. 读取 `{dataDir}/runtime-info.json`
|
|||
|
|
3. 若引导文件存在,则先根据其中的 `pid` 与 `controlBaseUrl` 尝试附着已有 `backend.exe`
|
|||
|
|
4. 若状态接口返回 ready,则仅挂载托盘
|
|||
|
|
5. 若引导文件缺失、陈旧或接口不可达,则由 `tray.exe` 拉起新的 `backend.exe`
|
|||
|
|
6. 新进程启动后,先轮询 `runtime-info.json`,再轮询 `status` 接口直到 ready
|
|||
|
|
7. ready 后刷新菜单状态
|
|||
|
|
|
|||
|
|
运行时存活性判断优先级保持为:
|
|||
|
|
|
|||
|
|
1. `status` 接口
|
|||
|
|
2. `backend.exe` 进程是否仍存活
|
|||
|
|
3. `neta.lock` 仅作诊断辅助
|
|||
|
|
|
|||
|
|
### 4.6 鉴权
|
|||
|
|
|
|||
|
|
首版控制接口必须具备本机鉴权机制:
|
|||
|
|
|
|||
|
|
- `backend.exe` 每次启动都生成新的 `controlSecret`
|
|||
|
|
- `controlSecret` 仅写入 `{dataDir}/runtime-info.json`,供本机 `tray.exe` 复用
|
|||
|
|
- `tray.exe` 后续请求必须携带该 secret
|
|||
|
|
- 正常退出时必须清理 `runtime-info.json`
|
|||
|
|
|
|||
|
|
这样既保留了“每次启动轮换 secret”的边界,也解决了托盘在附着已运行 backend 时的发现问题。
|
|||
|
|
## 5. 运行时行为与边界条件
|
|||
|
|
|
|||
|
|
### 5.1 单实例
|
|||
|
|
|
|||
|
|
- `backend.exe` 继续保留现有单实例锁与运行检测逻辑
|
|||
|
|
- `tray.exe` 也需要独立单实例保护,避免出现多个托盘图标
|
|||
|
|
- 如果重复启动 `tray.exe`,不创建第二个实例,而是唤起已有实例并执行“打开系统”
|
|||
|
|
|
|||
|
|
### 5.2 状态判断优先级
|
|||
|
|
|
|||
|
|
`tray.exe` 判断 `backend.exe` 状态时,优先级固定为:
|
|||
|
|
|
|||
|
|
1. 先探测本机 `status` 接口
|
|||
|
|
2. 接口不可达时,再检查 `backend.exe` 进程是否存在
|
|||
|
|
3. `neta.lock` 仅作为诊断辅助,不作为一等控制协议
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
|
|||
|
|
- 当前真实端口由 `backend.exe` 决定
|
|||
|
|
- `backend.exe` 已有自己的锁和退出清理机制
|
|||
|
|
- 直接依赖锁文件容易与真实 ready 状态漂移
|
|||
|
|
|
|||
|
|
### 5.3 端口处理
|
|||
|
|
|
|||
|
|
- `backend.exe` 继续沿用现有可用端口探测逻辑,不强制固定 8003
|
|||
|
|
- `tray.exe` 不自行猜测端口
|
|||
|
|
- “打开系统”始终使用状态接口返回的真实 URL
|
|||
|
|
|
|||
|
|
### 5.4 启动失败
|
|||
|
|
|
|||
|
|
- `tray.exe` 拉起后端后,在限定时间内轮询状态接口
|
|||
|
|
- 若超时仍未 ready,托盘图标进入“异常”状态
|
|||
|
|
- 菜单保留“打开日志目录”和“重试启动”的恢复路径
|
|||
|
|
- 首版不增加复杂配置向导,只提示“服务启动失败,请查看日志”
|
|||
|
|
|
|||
|
|
### 5.5 后端异常退出
|
|||
|
|
|
|||
|
|
- `tray.exe` 持续感知 `backend.exe` 状态
|
|||
|
|
- 若后端异常崩溃,托盘菜单切换为“服务未运行”
|
|||
|
|
- 用户可以直接从托盘执行重启服务
|
|||
|
|
|
|||
|
|
### 5.6 优雅退出
|
|||
|
|
|
|||
|
|
退出顺序固定为:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
tray.exe 发起 stop 请求
|
|||
|
|
-> backend.exe 执行优雅收尾
|
|||
|
|
-> 超时则由 tray.exe 兜底结束
|
|||
|
|
-> tray.exe 自身退出
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
同一顺序也用于安装器卸载阶段。
|
|||
|
|
|
|||
|
|
### 5.7 手动运行 backend.exe
|
|||
|
|
|
|||
|
|
如果用户绕过标准入口,直接双击 `backend.exe`:
|
|||
|
|
|
|||
|
|
- 服务仍可启动
|
|||
|
|
- 但不保证拥有完整托盘体验
|
|||
|
|
- 标准使用入口仍是 `tray.exe`
|
|||
|
|
|
|||
|
|
## 6. 技术选型
|
|||
|
|
|
|||
|
|
建议新增一个独立包:`packages/windows-tray/`。
|
|||
|
|
|
|||
|
|
### 6.1 推荐实现
|
|||
|
|
|
|||
|
|
使用 `.NET 8` 实现原生 Windows 托盘程序,并发布为自包含单文件 `tray.exe`。
|
|||
|
|
|
|||
|
|
推荐原因:
|
|||
|
|
|
|||
|
|
- 做系统托盘、单实例、打开目录、进程管理这些 Windows 原生动作更稳妥
|
|||
|
|
- 与 Node/pkg 运行时彻底解耦
|
|||
|
|
- 可以直接产出适合 Inno Setup 分发的单文件 exe
|
|||
|
|
- 不要求最终用户额外安装 .NET Runtime
|
|||
|
|
|
|||
|
|
### 6.2 当前仓库前提
|
|||
|
|
|
|||
|
|
当前 Neta 仓库中没有现成的 `.NET` 托盘工程,因此这不是接入现有桌面端项目,而是新增一条桌面端工具链。
|
|||
|
|
|
|||
|
|
这意味着打包环境必须新增前置条件:
|
|||
|
|
|
|||
|
|
- 打包机安装 `.NET 8 SDK`
|
|||
|
|
- 安装器构建脚本支持 `dotnet publish`
|
|||
|
|
- Windows 打包说明同步补充 `.NET 8 SDK` 依赖
|
|||
|
|
|
|||
|
|
### 6.3 为什么不放进现有前后端栈里做
|
|||
|
|
|
|||
|
|
- 前端 Vue 不是桌面托盘技术栈
|
|||
|
|
- 后端 Node/pkg 进程更适合承担服务,不适合顺带承载稳定的 Windows 壳层能力
|
|||
|
|
- 用独立托盘程序更符合当前项目边界:业务继续在后端,UI 继续在浏览器,Windows 壳层作为单独辅助包存在
|
|||
|
|
|
|||
|
|
## 7. 仓库改动清单
|
|||
|
|
|
|||
|
|
### 7.1 新增后端控制层
|
|||
|
|
|
|||
|
|
建议新增:
|
|||
|
|
|
|||
|
|
- `packages/backend/src/modules/base/controller/app/runtime.ts`
|
|||
|
|
- `packages/backend/src/modules/base/service/runtime.ts`
|
|||
|
|
- `packages/backend/src/comm/runtime-secret.ts`
|
|||
|
|
- `packages/backend/src/comm/runtime-state.ts`
|
|||
|
|
- `packages/backend/src/comm/runtime-info.ts`
|
|||
|
|
- `packages/backend/src/comm/graceful-shutdown.ts`
|
|||
|
|
|
|||
|
|
建议修改:
|
|||
|
|
|
|||
|
|
- `packages/backend/bootstrap.js`
|
|||
|
|
- 新增最小 CLI 参数支持,例如:
|
|||
|
|
- `--tray-secret`
|
|||
|
|
- `--no-browser`
|
|||
|
|
- `packages/backend/src/configuration.ts`
|
|||
|
|
- 注册统一 shutdown coordinator
|
|||
|
|
- 暴露真实端口、目录和运行状态
|
|||
|
|
- 维护并清理 `{dataDir}/runtime-info.json`
|
|||
|
|
|
|||
|
|
### 7.2 新增托盘包
|
|||
|
|
|
|||
|
|
建议新增:
|
|||
|
|
|
|||
|
|
- `packages/windows-tray/Neta.Tray.csproj`
|
|||
|
|
- `packages/windows-tray/Program.cs`
|
|||
|
|
- `packages/windows-tray/TrayApplicationContext.cs`
|
|||
|
|
- `packages/windows-tray/BackendProcessManager.cs`
|
|||
|
|
- `packages/windows-tray/RuntimeInfoStore.cs`
|
|||
|
|
- `packages/windows-tray/StatusClient.cs`
|
|||
|
|
- `packages/windows-tray/SingleInstance.cs`
|
|||
|
|
- `packages/windows-tray/Assets/neta.ico`
|
|||
|
|
|
|||
|
|
职责包括:
|
|||
|
|
|
|||
|
|
- 托盘图标与菜单
|
|||
|
|
- 单实例
|
|||
|
|
- 读取 `config.yaml` 与 `runtime-info.json`
|
|||
|
|
- 启动 `backend.exe`
|
|||
|
|
- 请求停止 `backend.exe`
|
|||
|
|
- 编排重启 `backend.exe`
|
|||
|
|
- 打开浏览器
|
|||
|
|
- 打开日志目录
|
|||
|
|
- 打开配置目录
|
|||
|
|
- 按“status > process > lock”顺序判断状态
|
|||
|
|
- 支持安装器卸载阶段的无界面 `--shutdown` 模式
|
|||
|
|
|
|||
|
|
### 7.3 修改打包和安装器链路
|
|||
|
|
|
|||
|
|
建议修改:
|
|||
|
|
|
|||
|
|
- `packages/backend/scripts/build-windows-installer.js`
|
|||
|
|
- 先生成 `backend.exe`
|
|||
|
|
- 再执行 `dotnet publish` 生成 `tray.exe`
|
|||
|
|
- 最后一起交给 Inno Setup 打包
|
|||
|
|
- `packages/backend/installer/setup.iss`
|
|||
|
|
- 安装 `backend.exe` 与 `tray.exe`
|
|||
|
|
- 桌面快捷方式改为指向 `tray.exe`
|
|||
|
|
- 开机自启注册表改为指向 `tray.exe`
|
|||
|
|
- 卸载时优先调用 `tray.exe --shutdown`
|
|||
|
|
- 若优雅停机失败,再兜底 `taskkill`
|
|||
|
|
|
|||
|
|
## 8. 实施顺序
|
|||
|
|
|
|||
|
|
这次改造必须严格分阶段推进,不能并行混改:
|
|||
|
|
|
|||
|
|
1. 先在 `backend.exe` 中补齐最小本机控制面
|
|||
|
|
2. 再实现 `tray.exe` 并接入状态轮询、启停编排与单实例
|
|||
|
|
3. 最后修改安装器、快捷方式、开机自启和卸载流程
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
|
|||
|
|
- `tray.exe` 必须依赖 `backend.exe` 的真实状态面才能稳定工作
|
|||
|
|
- 当前安装器和卸载逻辑是围绕 `backend.exe` 写死的
|
|||
|
|
- 若未先立住控制面,托盘实现会被迫用端口猜测、进程猜测和锁文件硬拼状态
|
|||
|
|
|
|||
|
|
## 9. 安装器行为
|
|||
|
|
|
|||
|
|
### 9.1 安装后入口
|
|||
|
|
|
|||
|
|
安装完成后:
|
|||
|
|
|
|||
|
|
- 桌面快捷方式指向 `tray.exe`
|
|||
|
|
- 开始菜单入口指向 `tray.exe`
|
|||
|
|
- 若勾选开机自启,注册表项写入 `tray.exe`
|
|||
|
|
|
|||
|
|
### 9.2 卸载顺序
|
|||
|
|
|
|||
|
|
卸载时执行:
|
|||
|
|
|
|||
|
|
1. 调用 `tray.exe --shutdown`,由托盘侧先请求 `backend.exe` 优雅退出
|
|||
|
|
2. 等待短超时,让 `tray.exe` 自身退出
|
|||
|
|
3. 若仍有残留进程,再兜底强制结束 `tray.exe` / `backend.exe`
|
|||
|
|
4. 删除程序目录
|
|||
|
|
5. 根据现有安装器策略决定是否保留数据目录
|
|||
|
|
|
|||
|
|
### 9.3 重装
|
|||
|
|
|
|||
|
|
- 重装继续保留当前“程序目录覆盖、数据目录尽量不动”的原则
|
|||
|
|
- `tray.exe` 只是新增程序层产物,不改变现有数据目录策略
|
|||
|
|
|
|||
|
|
## 10. 验证策略
|
|||
|
|
|
|||
|
|
### 10.1 自动验证
|
|||
|
|
|
|||
|
|
后端测试:
|
|||
|
|
|
|||
|
|
- 本机状态接口返回真实端口和目录
|
|||
|
|
- 本机 secret 校验有效
|
|||
|
|
- stop 行为符合预期
|
|||
|
|
- 优雅退出逻辑符合预期
|
|||
|
|
|
|||
|
|
打包脚本 smoke:
|
|||
|
|
|
|||
|
|
- 能生成 `packages/backend/build/pkg-output/backend.exe`
|
|||
|
|
- 能生成托盘发布产物 `tray.exe`
|
|||
|
|
- Inno Setup 能将两者一并打包进安装器
|
|||
|
|
|
|||
|
|
### 10.2 Windows 手工验收
|
|||
|
|
|
|||
|
|
必须验证:
|
|||
|
|
|
|||
|
|
- 安装后系统托盘出现图标
|
|||
|
|
- “打开系统”能打开正确 URL
|
|||
|
|
- “停止服务 / 重启服务”状态切换正确
|
|||
|
|
- “打开日志目录 / 打开配置目录”路径正确
|
|||
|
|
- “退出程序”能同时退出托盘与后端
|
|||
|
|
- 卸载后程序目录清理正常
|
|||
|
|
- 重装后数据目录不会被误删
|
|||
|
|
|
|||
|
|
## 11. 本期明确不做
|
|||
|
|
|
|||
|
|
本期范围明确排除以下内容:
|
|||
|
|
|
|||
|
|
- 数据库安全改造
|
|||
|
|
- 首次启动配置向导
|
|||
|
|
- 自动更新机制
|
|||
|
|
- 浏览器关闭后最小化到托盘
|
|||
|
|
- 将 `backend.exe` 改造成 Windows Service
|
|||
|
|
- 调整 `config.yaml` 到 ProgramData 或其他新位置
|
|||
|
|
|
|||
|
|
## 12. 结论
|
|||
|
|
|
|||
|
|
本期采用“独立 `tray.exe` + 现有 `backend.exe`”的双进程方案。
|
|||
|
|
|
|||
|
|
其中:
|
|||
|
|
|
|||
|
|
- `backend.exe` 是唯一运行时真源
|
|||
|
|
- `tray.exe` 是 Windows 本地托盘控制层,也是安装器标准入口
|
|||
|
|
- 两者通过仅本机可用、带 secret 鉴权的最小控制接口通信
|
|||
|
|
- `tray.exe` 只消费状态并编排 stop + spawn,不承担后端自重启职责
|
|||
|
|
|
|||
|
|
这样可以在不重做现有安装器和服务架构的前提下,为 Windows 用户补齐托盘入口、服务启停、目录打开和整体退出能力,并为后续继续扩展桌面体验保留清晰边界。
|