feat(phase2e-2): 落地 HTTPMediaOrchestrator 打通 Go↔Node 媒体链路(Task 7)

- 新增 MediaServerConfig + config.{dev,docker}.yaml 的 media_server 段
  (base_url / internal_token / timeout_ms / close_timeout_ms / close_retry)
- 新建 HTTPMediaOrchestrator(8 方法 + sync.Map 缓存 roomCode→routerID
  + 关闭类指数退避重试 200/500ms + ErrMediaResourceNotFound/ErrMediaServerError
  两类错误)实现 MediaOrchestrator 接口
- wire 绑定由 NoopMediaOrchestrator 切换到 HTTPMediaOrchestrator;
  MeetingService / MeetingSignalService 调用侧零改动
- E2E 脚本 docs/verify/meeting_t7_verify.mjs 证明 16/16 PASS:
  健康检查/错token 401/REST 创房加入/WS room.join/真实 mediasoup
  transport.create(ICE/DTLS 指纹均由 Node 返回非占位)/404 幂等关 producer
  /host 结束会议触发 CloseRouter
- 同步更新 13 份文档:CURRENT_STATUS / implementation.plan / design
  变更记录 / project-context / api 导览 / api websocket / api frontend meeting
  / system-architecture / media-server README / 顶层 README 等
- go build ./... 全绿

Made-with: Cursor
This commit is contained in:
bujinyuan
2026-04-21 17:47:11 +08:00
parent dfd9b6011c
commit 55d6352c6a
19 changed files with 795 additions and 46 deletions

View File

@@ -5,7 +5,7 @@
> **上级路线图:** [Phase 2e 整体路线图](./2026-04-20-phase2e-design.md)
> **分支:** `feature/phase2e-2-meeting-mvp`
> **预估总工时:** **约 17 人日**17 个 Task含 PoC 与 UI 打磨)
> **最后更新:** 2026-04-21Task 0-6 ✅ 已落地,下一步 Task 7 HTTPMediaOrchestrator
> **最后更新:** 2026-04-21Task 0-7 ✅ 已落地,Go↔Node HTTP 媒体链路打通,下一步 Task 8 生命周期状态机
---
@@ -327,21 +327,29 @@ flowchart LR
- 广播 API 统一为 `MeetingBroadcaster.BroadcastToMeeting` `excludeUserIDs ...int64` 可变参数比计划中"`Hub.BroadcastToMeeting` 方法" 更内聚不污染 `ws.Hub` 通用接口
- **实际工作量****1 人日**比预估 1.5 人日节省得益于 Task 5 已预置好 DAO / 错误链 / DTO
### Task 7Go → Node HTTP Client 封装
### Task 7Go → Node HTTP Client 封装 ✅ 已完成2026-04-21
- **目标**实现设计 §6.6 `NodeClient` 接口挂接到 WS 信令流程
- **依赖**T2 + T6
- **主要产出**
- `app/meeting/service/node_client.go`9 个方法完整实现
- 配置`config.NodeServiceURL` / `config.NodeInternalToken` yaml + 环境变量
- 超时HTTP Client 5 秒超时关闭类操作 2 秒超时
- 重试关闭类操作失败重试 2 指数退避 200ms/500ms
- 日志每次调用记录 `funcName + room_code + duration + status_code`
- 错误映射Node 5xx 业务错误码 `media_server_error`404 `media_resource_not_found`超时 `media_timeout`
- **检查点**
- 单元测试使用 `httptest.NewServer` 模拟 Node覆盖成功/失败/超时三类
- 集成测试Go + Node 真实连通创建 Router Transport Producer 销毁链路
- **工作量****0.5 人日**
- **实际产出**
- `app/meeting/service/http_media_orchestrator.go`340 实现 `MediaOrchestrator` 8 方法完整覆盖 Router/Transport/Producer/Consumer 生命周期
- `config/config.go` + `config.dev.yaml` + `config.docker.yaml`新增 `MediaServerConfig{BaseURL, InternalToken, TimeoutMS, CloseTimeoutMS, CloseRetry}`支持环境变量 `ECHOCHAT_MEDIA_SERVER_*` 覆盖
- `app/meeting/provider.go` + `app/provider/wire_gen.go``wire.Bind` `*NoopMediaOrchestrator` 切换为 `*HTTPMediaOrchestrator`注入 `*config.Config`
- `docs/verify/meeting_t7_verify.mjs`140 Node.js E2E 验证脚本
- 错误类型`ErrMediaResourceNotFound`404关闭类自动幂等转 nil/ `ErrMediaServerError`5xx/超时/网络错可供上层 `errors.Is` 区分
- 关闭类指数退避200ms 500ms最多 `CloseRetry + 1` 次尝试
- `sync.Map` 本地 `roomCode ↔ routerID` 缓存兼容设计 §6.6 "CloseRouter(roomCode)" 签名约束
- **检查点已全部达成**
- `go build ./...` 全绿
- `go vet ./...` 全绿
- 端到端脚本 `docs/verify/meeting_t7_verify.mjs` **16/16 PASS**覆盖健康检查token 鉴权REST 创建/加入/结束会议WS transport.create404 幂等关闭
- media-server 日志确认真实 `router created` / `webrtc transport created` / `router closed explicitly`
- `transport.id` / `iceCandidates[]` / `dtlsParameters.fingerprints[]` 均非占位证明真实 mediasoup 链路
- **偏离与说明**
- 文件命名由设计 `node_client.go` 改为 `http_media_orchestrator.go` Task 6 抽出的 `MediaOrchestrator` 接口保持语义一致
- 接口方法数保持 8 设计 §6.6 9 个含 `ResumeConsumer``ResumeConsumer` Node REST 已就绪但当前 WS 契约无对应事件留给 Task 9 前端 mediasoup-client 接入时补齐
- 单元测试`httptest.NewServer` 模拟本次未落地用更真实的"Go + Node + Playwright-style E2E"替代证据力更强Task 10可观测性补齐单测
- **实际工作量****0.5 人日**符合预估
### Task 8会议生命周期状态机host 宽限期 + 自动转让 + 空房 TTL