feat: publish dbussmsforward refactor

This commit is contained in:
2026-05-08 23:54:03 +08:00
commit 9f1ee9ffe6
77 changed files with 15585 additions and 0 deletions
+371
View File
@@ -0,0 +1,371 @@
# 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 或无需 runtimeself-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 部署入口可以现在直接完成。