Initial LisgloSIPS V2 implementation
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
# Recording Transfer and Playback Runbook
|
||||
|
||||
> 任务:S24 - 录音搬运与播放
|
||||
> 完成时间:2026-06-21 20:20 +08:00
|
||||
|
||||
## 1. 目标
|
||||
|
||||
S24 完成录音闭环的最小能力:
|
||||
|
||||
- Server B 通过 Tailscale 私网从 Server A 拉取 `.ready` 录音文件。
|
||||
- 拉取后校验文件大小和 SHA-256。
|
||||
- 本地 `.part-*` 临时文件校验成功后原子改名。
|
||||
- 校验和数据库标记成功后才允许删除 Server A 源 `.ready` 文件。
|
||||
- API 提供受 RBAC 保护的播放入口,通过 Nginx `X-Accel-Redirect` 进入内部 `/_recordings/` location,支持 Range。
|
||||
|
||||
## 2. 代码产物
|
||||
|
||||
| 文件 | 说明 |
|
||||
| --- | --- |
|
||||
| `apps/worker-recording/src/transfer.ts` | 录音扫描、SSH 拉取、大小校验、SHA-256、原子落盘、源文件安全删除、`recordings` 入库 |
|
||||
| `apps/worker-recording/src/main.ts` | Recording Worker 主循环 |
|
||||
| `apps/worker-recording/src/transfer.spec.ts` | 搬运、哈希、删除保护和路径安全测试 |
|
||||
| `apps/api/src/modules/recordings/*` | `GET /api/v2/recordings/:id/play` 播放入口 |
|
||||
| `apps/api/src/modules/recordings/recordings.service.spec.ts` | Nginx 内部路径和路径穿越防护测试 |
|
||||
| `infra/server-a/s19/scripts/lisglosips-recording-finalize` | A 端 finalizer 仓库副本,ready 目录改为 `0770`,便于专用拉取用户校验后删除源文件 |
|
||||
|
||||
## 3. Worker 环境变量
|
||||
|
||||
```text
|
||||
DATABASE_URL
|
||||
RECORDING_REMOTE_HOST=lisglosips-a
|
||||
RECORDING_SSH_CONFIG=/etc/lisglosips/recording/ssh_config
|
||||
RECORDING_REMOTE_READY_DIR=/dev/shm/voip_rec/ready
|
||||
RECORDING_LOCAL_ROOT=/data/recordings
|
||||
RECORDING_SCAN_INTERVAL_MS=10000
|
||||
RECORDING_MAX_FILES_PER_SCAN=50
|
||||
RECORDING_DELETE_SOURCE_AFTER_COPY=true
|
||||
```
|
||||
|
||||
本地开发可使用 `.codex-private/ssh/config`;生产或 B 端 systemd 应使用 `/etc/lisglosips/recording/` 下的受控 key 和 known_hosts。
|
||||
|
||||
## 4. 服务器变更
|
||||
|
||||
### Server B
|
||||
|
||||
- 新增 `/etc/lisglosips/recording/a_pull_ed25519`,权限 `0640 root:lisglosips`。
|
||||
- 新增 `/etc/lisglosips/recording/known_hosts`。
|
||||
- 录音持久化目录仍为 `/data/recordings`,由 `lisglo-recorder:lisglosips` 管理。
|
||||
- 备份目录:`/var/backups/lisglosips-s24/20260621T121100Z`。
|
||||
|
||||
### Server A
|
||||
|
||||
- 新增专用用户 `lisglo-rec-pull`,加入 `rtpengine` 组。
|
||||
- 安装 B 端录音拉取公钥到 `/var/lib/lisglo-rec-pull/.ssh/authorized_keys`。
|
||||
- 将 `/dev/shm/voip_rec/ready` 调整为 `0770 rtpengine:rtpengine`。
|
||||
- 更新 `/usr/local/sbin/lisglosips-recording-finalize`,让 ready 根目录和 ready 子目录保持 `0770`。
|
||||
- 备份目录:`/var/backups/lisglosips-s24/20260621T121130Z`。
|
||||
|
||||
未调整 SSH 管理端口,未禁止 SSH key 登录,未重启 OpenSIPS、RTPEngine、Nginx 或 API。
|
||||
|
||||
## 5. 播放路径
|
||||
|
||||
API:
|
||||
|
||||
```text
|
||||
GET /api/v2/recordings/:id/play
|
||||
Permission: recordings.play
|
||||
```
|
||||
|
||||
API 只查询状态为 `READY` 的录音,返回:
|
||||
|
||||
```text
|
||||
X-Accel-Redirect: /_recordings/<storage-key>
|
||||
Content-Type: audio/wav 或 audio/mpeg
|
||||
Cache-Control: private, no-store
|
||||
```
|
||||
|
||||
Nginx 已在 S05 配置:
|
||||
|
||||
```text
|
||||
location /_recordings/ {
|
||||
internal;
|
||||
alias /data/recordings/;
|
||||
add_header Accept-Ranges bytes always;
|
||||
}
|
||||
```
|
||||
|
||||
外部直接访问 `/_recordings/...` 返回 `404`,只能经 API 鉴权后内部转发。
|
||||
|
||||
## 6. 验证结果
|
||||
|
||||
本地:
|
||||
|
||||
- `corepack pnpm@10.33.0 exec vitest run apps/worker-recording/src/transfer.spec.ts apps/api/src/modules/recordings/recordings.service.spec.ts` 通过,5 条测试。
|
||||
- `corepack pnpm@10.33.0 --filter @lisglosips/worker-recording build` 通过。
|
||||
- `corepack pnpm@10.33.0 typecheck` 通过。
|
||||
- `corepack pnpm@10.33.0 lint` 通过。
|
||||
- `corepack pnpm@10.33.0 build` 通过。
|
||||
|
||||
服务器冒烟:
|
||||
|
||||
- A 生成测试文件 `/dev/shm/voip_rec/incoming/s24-smoke/s24-smoke.wav`。
|
||||
- A finalizer 生成 `/dev/shm/voip_rec/ready/s24-smoke/s24-smoke.wav.ready`。
|
||||
- B 使用 `lisglo-recorder` 和专用 SSH key 从 A 私网拉取。
|
||||
- B 落盘 `/data/recordings/s24-smoke/s24-smoke.wav`,大小 `31`,属主 `lisglo-recorder:lisglosips`。
|
||||
- A/B SHA-256 一致:`c72dd3909a317ad55817435b7ed5a0db6947455ffc66e09a2dde787fe4a8c348`。
|
||||
- 校验成功后 A 源 `.ready` 文件已删除。
|
||||
- 外部直接访问 `https://127.0.0.1/_recordings/s24-smoke/s24-smoke.wav` 返回 `404`,内部录音 location 未暴露。
|
||||
|
||||
## 7. 当前限制
|
||||
|
||||
B 当前 `/opt/lisglosips/current` 仍是 S05 placeholder release,未切换到完整 monorepo API/Worker release。因此 S24 本次完成代码、构建、服务器私网拉取链路和 Nginx 内部播放保护验证;正式 `lisglosips@recording-worker.service` 随完整应用 release 发布时启用。
|
||||
|
||||
## 8. 回滚
|
||||
|
||||
Server A:
|
||||
|
||||
```bash
|
||||
sudo cp -a /var/backups/lisglosips-s24/20260621T121130Z/lisglosips-recording-finalize /usr/local/sbin/lisglosips-recording-finalize
|
||||
sudo chmod 0755 /usr/local/sbin/lisglosips-recording-finalize
|
||||
sudo userdel -r lisglo-rec-pull
|
||||
sudo chmod 0750 /dev/shm/voip_rec/ready
|
||||
```
|
||||
|
||||
Server B:
|
||||
|
||||
```bash
|
||||
sudo rm -rf /etc/lisglosips/recording
|
||||
sudo rm -rf /data/recordings/s24-smoke
|
||||
```
|
||||
|
||||
代码回滚:
|
||||
|
||||
- 恢复 `apps/worker-recording/src/main.ts` 到骨架版本。
|
||||
- 删除或恢复 `apps/worker-recording/src/transfer.ts`、`transfer.spec.ts`。
|
||||
- 删除 `apps/api/src/modules/recordings/` 并从 `AppModule` 移除 `RecordingsModule`。
|
||||
- 恢复 `apps/worker-recording/package.json`、`tsconfig.json`、`pnpm-lock.yaml`。
|
||||
- 重新执行 `corepack pnpm@10.33.0 build`。
|
||||
Reference in New Issue
Block a user