372 lines
10 KiB
Markdown
372 lines
10 KiB
Markdown
# DbusSmsForward Debian Web 版实施计划
|
||
|
||
> **For Hermes:** Use subagent-driven-development skill to implement this plan task-by-task.
|
||
|
||
**Goal:** 把当前 Debian 版 DbusSmsForward 改造成“带 Web 管理界面、可直接在 Debian 上运行、默认不要求本地编译”的版本。
|
||
|
||
**Architecture:** 保留现有 Generic Host + Worker 的短信转发核心,补一层 ASP.NET Core Minimal API 与静态 `wwwroot` 页面;运行形态改为 `dotnet DbusSmsForward.dll web` 或发布后的自包含目录直接运行。通过配置文件和环境变量驱动,不再依赖交互式初始化。
|
||
|
||
**Tech Stack:** .NET 8, ASP.NET Core Minimal API, Generic Host, Static Files, JSON config, systemd-friendly hosting.
|
||
|
||
---
|
||
|
||
## 0. 当前仓库真实状态(已核实)
|
||
|
||
**已存在:**
|
||
- `DbusTest/Program.cs`:已经是 Generic Host 风格入口。
|
||
- `DbusTest/appsettingsModel.cs`:已引入 `DbusSmsForwardOptions` / `DaemonConfig` / `AutmanPushConfig`。
|
||
- `DbusTest/Services/SmsForwardWorker.cs`:已有后台转发 worker。
|
||
- `DbusTest/Notifications/*`:已拆分通知发送器。
|
||
- `DbusTest/Helper/ConfigHelper.cs`:已支持 `/etc/dbussmsforward/appsettings.json` 优先加载。
|
||
|
||
**缺失:**
|
||
- `wwwroot/` 不存在。
|
||
- 没有任何 Web API。
|
||
- `DbusSmsForward.csproj` 仍是 `Microsoft.NET.Sdk.Worker`,不是 Web SDK。
|
||
- `Program.cs` 里引用了若干当前仓库中不存在的类型:
|
||
- `SampleConfigFactory`
|
||
- `LegacyConfigurationBridge`
|
||
- `CommandLineConfigurationApplier`
|
||
- `ConfigurationValidator`
|
||
- 本机当前 `dotnet` 命令不存在,无法本地编译验证;因此本阶段要优先完成“代码落地 + 文档化运行路径”。
|
||
|
||
---
|
||
|
||
## 1. 目标运行方式
|
||
|
||
### 目标 A:Debian 上直接运行(不在目标机编译)
|
||
|
||
推荐两种:
|
||
|
||
1. **Framework-dependent**
|
||
- 目标机只安装 .NET 8 runtime / aspnetcore runtime
|
||
- 直接运行:
|
||
- `dotnet DbusSmsForward.dll web --urls http://0.0.0.0:8080`
|
||
|
||
2. **Self-contained 发布包**
|
||
- 预先在别处发布好 Linux x64 / arm64 包
|
||
- 目标机无需装 dotnet
|
||
- 直接运行发布目录中的可执行文件
|
||
|
||
**注意:** 当前用户要求“最好不需要编译,直接运行在 Debian 上”,因此仓库要优先支持 **运行已发布产物**,而不是要求 Debian 机器安装 SDK 编译源码。
|
||
|
||
---
|
||
|
||
## 2. 代码实施任务
|
||
|
||
### Task 1: 切换项目为 Web 宿主
|
||
|
||
**Objective:** 让项目具备 Minimal API + Static Files 能力。
|
||
|
||
**Files:**
|
||
- Modify: `DbusTest/DbusSmsForward.csproj`
|
||
|
||
**Step 1: 修改 SDK**
|
||
|
||
把:
|
||
|
||
```xml
|
||
<Project Sdk="Microsoft.NET.Sdk.Worker">
|
||
```
|
||
|
||
改成:
|
||
|
||
```xml
|
||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||
```
|
||
|
||
**Step 2: 保留现有依赖,继续复制配置文件**
|
||
|
||
保留现有 `PackageReference` 与 `appsettings*.json` 输出策略。
|
||
|
||
**Step 3: 增加 Web 静态资源复制规则(如需要)**
|
||
|
||
确认 `wwwroot/**` 默认由 Web SDK 处理。
|
||
|
||
**Verification:**
|
||
- 代码层面确认 csproj 已切到 Web SDK。
|
||
|
||
---
|
||
|
||
### Task 2: 补齐缺失的配置与兼容辅助类
|
||
|
||
**Objective:** 解决 `Program.cs` 当前引用缺失导致的不可编译问题。
|
||
|
||
**Files:**
|
||
- Create: `DbusTest/Helper/SampleConfigFactory.cs`
|
||
- Create: `DbusTest/Helper/LegacyConfigurationBridge.cs`
|
||
- Create: `DbusTest/Helper/CommandLineConfigurationApplier.cs`
|
||
- Create: `DbusTest/Helper/ConfigurationValidator.cs`
|
||
|
||
**Step 1: `SampleConfigFactory`**
|
||
- 返回一个最小可用的 `DbusSmsForwardOptions` 示例对象。
|
||
- 含 `Daemon/Modem/Forwarding/Notifications/LegacyCompatibility` 基本结构。
|
||
|
||
**Step 2: `LegacyConfigurationBridge`**
|
||
- 从旧格式 `appSettings` 节点读取值,映射到新 `DbusSmsForwardOptions`。
|
||
- 至少映射:
|
||
- `DeviceName`
|
||
- `SmsCodeKey`
|
||
- `ForwardIgnoreStorageType`
|
||
- Email / PushPlus / DingTalk / Bark / WeCom / TG / Shell
|
||
|
||
**Step 3: `CommandLineConfigurationApplier`**
|
||
- 把 `AppCommand.EnabledChannels` 写入 `options.Forwarding.EnabledChannels`
|
||
- 如果旧 flags 指定了渠道,则同步将对应 `options.Notifications.*.Enabled = true`
|
||
|
||
**Step 4: `ConfigurationValidator`**
|
||
- 做最小校验:
|
||
- `Daemon.Mode` 合法值:`forward` / `web` / `both`
|
||
- 若启用 email,必须有 host / sender / receiver
|
||
- 若启用 autmanpush,必须有 ApiUrl
|
||
- 校验失败抛 `InvalidOperationException`
|
||
|
||
**Verification:**
|
||
- `Program.cs` 的缺失引用都能对应到真实文件。
|
||
|
||
---
|
||
|
||
### Task 3: 扩展命令模型支持 web/both 与 HTTP 端口
|
||
|
||
**Objective:** 让启动命令能表达 Web 模式。
|
||
|
||
**Files:**
|
||
- Modify: `DbusTest/Models/AppCommand.cs`
|
||
- Modify: `DbusTest/Services/CommandLineParser.cs`
|
||
|
||
**Step 1: 扩展 `AppCommand` 字段**
|
||
|
||
新增:
|
||
- `bool WebMode`
|
||
- `bool ForwardMode`
|
||
- `string Urls`
|
||
- `int Port`
|
||
- `string ConfigPath`
|
||
|
||
**Step 2: 解析新参数**
|
||
|
||
新增支持:
|
||
- `web`
|
||
- `both`
|
||
- `--urls http://0.0.0.0:8080`
|
||
- `--port 8080`
|
||
- `--config /etc/dbussmsforward/appsettings.json`
|
||
|
||
**Step 3: 默认策略**
|
||
- `run` = 仅 forward
|
||
- `web` = 仅 web
|
||
- `both` = forward + web
|
||
- 当只传 `--urls` / `--port` 时,默认仍按 `web` 理解更合理;若保持兼容性,也可要求显式 `web`。
|
||
|
||
**Verification:**
|
||
- 参数设计能清晰表达三种启动形态。
|
||
|
||
---
|
||
|
||
### Task 4: 建立 Web API 服务层
|
||
|
||
**Objective:** 把 Web 层依赖从 `Program.cs` 抽出来,避免一团乱。
|
||
|
||
**Files:**
|
||
- Create: `DbusTest/Services/SystemStatusService.cs`
|
||
- Create: `DbusTest/Services/SmsWebService.cs`
|
||
- Create: `DbusTest/Web/WebDtos.cs`
|
||
|
||
**Step 1: `SystemStatusService`**
|
||
- 复用 `ModemManagerHelper` 暴露:
|
||
- `GetStatusAsync()`
|
||
- 返回 modem path / qmi path / device / manufacturer / model / revision / operator / signal
|
||
|
||
**Step 2: `SmsWebService`**
|
||
- 封装:
|
||
- `SendAsync(phone, content)`
|
||
- `GetMessagesAsync(limit, phoneFilter, keyword, sort)`
|
||
- `GetSettings()`
|
||
- `SaveSettings()`
|
||
- 若 `ModemManagerHelper` 尚无历史短信读取能力,则先补最小方法;至少支持列表读取。
|
||
|
||
**Step 3: DTO**
|
||
- 请求与响应 DTO:
|
||
- `SendSmsRequest`
|
||
- `SettingsResponse`
|
||
- `SmsMessageItem`
|
||
- `ApiEnvelope<T>`
|
||
|
||
**Verification:**
|
||
- Web API 调用不直接散落访问底层 helper。
|
||
|
||
---
|
||
|
||
### Task 5: 在 `ModemManagerHelper` 中补历史短信列表接口
|
||
|
||
**Objective:** 支持 Web 历史短信页。
|
||
|
||
**Files:**
|
||
- Modify: `DbusTest/ModemManagerHelper.cs`
|
||
- Create: `DbusTest/Web/SmsMessageRecord.cs`(如 DTO 不想放 helper 内)
|
||
|
||
**Step 1: 新增异步方法**
|
||
|
||
建议新增:
|
||
|
||
```csharp
|
||
Task<IReadOnlyList<SmsMessageRecord>> ListMessagesAsync(CancellationToken cancellationToken = default)
|
||
```
|
||
|
||
**Step 2: 实现逻辑**
|
||
- 使用现有 `CreateMessaging(_modemObjectPathNowUse)`
|
||
- 枚举 DBus message path
|
||
- 读取:
|
||
- Number
|
||
- Text
|
||
- Timestamp
|
||
- Storage
|
||
- State
|
||
- 做时间转换与空值兜底
|
||
|
||
**Step 3: 不破坏现有 forward 逻辑**
|
||
- 保持现有短信监听逻辑不变
|
||
- 新增方法只做读取
|
||
|
||
**Verification:**
|
||
- 代码上已经有明确的历史短信读取入口。
|
||
|
||
---
|
||
|
||
### Task 6: 重写 `Program.cs` 为“单进程双模式入口”
|
||
|
||
**Objective:** 同一个程序既能跑后台转发,也能跑 Web。
|
||
|
||
**Files:**
|
||
- Modify: `DbusTest/Program.cs`
|
||
|
||
**Step 1: 统一宿主构建**
|
||
- 注册:
|
||
- `ModemManagerHelper`
|
||
- `NotificationDispatcher`
|
||
- 各通知 sender
|
||
- `SystemStatusService`
|
||
- `SmsWebService`
|
||
- 仅在 forward 模式下注册 `SmsForwardWorker`
|
||
|
||
**Step 2: Web 模式构建**
|
||
- 使用 `WebApplication.CreateBuilder(args)` 或在现有 host 上兼容 Web host
|
||
- 开启:
|
||
- `UseDefaultFiles()`
|
||
- `UseStaticFiles()`
|
||
|
||
**Step 3: Minimal API 路由**
|
||
- `GET /api/system/status`
|
||
- `GET /api/sms/messages`
|
||
- `POST /api/sms/send`
|
||
- `GET /api/settings`
|
||
- `POST /api/settings`
|
||
- `GET /api/health`
|
||
|
||
**Step 4: 启动逻辑**
|
||
- `send`:一次性发短信后退出
|
||
- `run`:只跑后台 worker
|
||
- `web`:只跑 Web
|
||
- `both`:Web + worker 同时运行
|
||
|
||
**Verification:**
|
||
- `Program.cs` 不再只会 `host.RunAsync()` 一条路。
|
||
|
||
---
|
||
|
||
### Task 7: 增加最小可用 Web UI
|
||
|
||
**Objective:** 让 BOSS 在浏览器里直接看效果。
|
||
|
||
**Files:**
|
||
- Create: `DbusTest/wwwroot/index.html`
|
||
- Create: `DbusTest/wwwroot/app.js`
|
||
- Create: `DbusTest/wwwroot/app.css`
|
||
|
||
**Step 1: 页面结构**
|
||
- 菜单:
|
||
- 仪表盘
|
||
- 历史短信
|
||
- 发送短信
|
||
- 系统配置
|
||
|
||
**Step 2: 页面能力**
|
||
- 仪表盘:加载 `/api/system/status`
|
||
- 历史短信:加载 `/api/sms/messages`
|
||
- 发送短信:调用 `/api/sms/send`
|
||
- 配置:读写 `/api/settings`
|
||
|
||
**Step 3: 保持纯静态实现**
|
||
- 原生 HTML/CSS/JS
|
||
- 不引入前端构建工具
|
||
- 保证部署简单
|
||
|
||
**Verification:**
|
||
- 浏览器打开根路径 `/` 能直接进入管理页。
|
||
|
||
---
|
||
|
||
### Task 8: 提供 Debian 直接运行所需文件
|
||
|
||
**Objective:** 让“直接运行在 Debian 上”真正落地。
|
||
|
||
**Files:**
|
||
- Create: `DbusTest/appsettings.example.json`
|
||
- Create: `DbusTest/dbussmsforward.service`
|
||
- Modify: `README.md`
|
||
|
||
**Step 1: 示例配置**
|
||
- 提供新结构 JSON 样例
|
||
- 默认 `Daemon.Mode = "both"`
|
||
- 默认 `urls` 示例写到 README,不强绑进配置
|
||
|
||
**Step 2: systemd unit**
|
||
- 示例:
|
||
- `WorkingDirectory=/opt/dbussmsforward`
|
||
- `ExecStart=/usr/bin/dotnet /opt/dbussmsforward/DbusSmsForward.dll both --urls http://0.0.0.0:8080`
|
||
- `Environment=DBUSSMSFORWARD_CONFIG_PATH=/etc/dbussmsforward/appsettings.json`
|
||
|
||
**Step 3: README 更新重点**
|
||
- 明确区分:
|
||
- 运行源码需要 SDK
|
||
- 运行发布产物只需 runtime 或无需 runtime(self-contained)
|
||
- 给出 Debian 直接运行命令
|
||
- 给出 systemd 安装步骤
|
||
|
||
**Verification:**
|
||
- 文档能支撑“别人拿到发布包就在 Debian 跑起来”。
|
||
|
||
---
|
||
|
||
## 3. 本次实施优先级
|
||
|
||
1. 先修复仓库当前“缺失类导致不可编译”的问题
|
||
2. 再补 Web API 骨架
|
||
3. 再补 `wwwroot` 管理页
|
||
4. 最后补 README / example config / systemd
|
||
|
||
---
|
||
|
||
## 4. 运行验收标准
|
||
|
||
满足以下即视为达到目标:
|
||
|
||
- 可用命令:
|
||
- `dotnet DbusSmsForward.dll run`
|
||
- `dotnet DbusSmsForward.dll web --urls http://0.0.0.0:8080`
|
||
- `dotnet DbusSmsForward.dll both --urls http://0.0.0.0:8080`
|
||
- `dotnet DbusSmsForward.dll send --to 13800138000 --text "测试短信"`
|
||
- 根路径 `/` 可打开 Web UI
|
||
- `/api/health` 返回成功
|
||
- `/api/system/status` 返回 modem 状态
|
||
- `/api/sms/messages` 返回历史短信列表
|
||
- `/api/settings` 可读写配置
|
||
- 提供 Debian 的 systemd unit 示例
|
||
|
||
---
|
||
|
||
## 5. 当前阻塞说明
|
||
|
||
- 本机没有 `dotnet`,所以暂时不能做本地编译/运行验证。
|
||
- 但仓库代码改造、文件补齐、运行文档和 Debian 部署入口可以现在直接完成。
|