视频保存
This commit is contained in:
@@ -2,11 +2,11 @@ package controller
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/echochat/backend/app/meeting/model"
|
||||
"github.com/echochat/backend/app/meeting/service"
|
||||
"github.com/echochat/backend/config"
|
||||
"github.com/echochat/backend/pkg/logs"
|
||||
"github.com/echochat/backend/pkg/utils"
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -21,11 +21,17 @@ import (
|
||||
// - GET /rooms/:code/recordings 列出录制(host 或参与者)
|
||||
type MeetingRecordingController struct {
|
||||
recordingSvc *service.MeetingRecordingService
|
||||
cfg *config.MeetingConfig
|
||||
}
|
||||
|
||||
// NewMeetingRecordingController Wire Provider
|
||||
func NewMeetingRecordingController(svc *service.MeetingRecordingService) *MeetingRecordingController {
|
||||
return &MeetingRecordingController{recordingSvc: svc}
|
||||
//
|
||||
// cfg 提供 InternalWebhookSecret,用于校验 media-server 失败回调 X-Internal-Secret header
|
||||
func NewMeetingRecordingController(
|
||||
svc *service.MeetingRecordingService,
|
||||
cfg *config.MeetingConfig,
|
||||
) *MeetingRecordingController {
|
||||
return &MeetingRecordingController{recordingSvc: svc, cfg: cfg}
|
||||
}
|
||||
|
||||
// handleErr 将录制相关领域错误映射成 HTTP 状态码
|
||||
@@ -161,9 +167,11 @@ type mediaServerFailurePayload struct {
|
||||
// - 始终返回 200(webhook 语义:吞错避免 media-server 端反复重试)
|
||||
func (ctl *MeetingRecordingController) MediaServerFailureWebhook(c *gin.Context) {
|
||||
funcName := "controller.meeting_recording_controller.MediaServerFailureWebhook"
|
||||
secret := os.Getenv("INTERNAL_WEBHOOK_SECRET")
|
||||
// 优先 config.meeting.internal_webhook_secret(yaml/viper)。
|
||||
// 环境变量覆盖走 ECHOCHAT_MEETING_INTERNAL_WEBHOOK_SECRET(LoadConfig 已启用 viper.AutomaticEnv)。
|
||||
secret := ctl.cfg.InternalWebhookSecret
|
||||
if secret == "" {
|
||||
logs.Warn(c.Request.Context(), funcName, "INTERNAL_WEBHOOK_SECRET 未配置,拒绝 webhook 请求")
|
||||
logs.Warn(c.Request.Context(), funcName, "meeting.internal_webhook_secret 未配置,拒绝 webhook 请求")
|
||||
utils.ResponseForbidden(c, "internal webhook not configured")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -185,6 +185,12 @@ func provideLLMSourceConfig(cfg *config.Config) *config.LLMSourceConfig {
|
||||
return &cfg.LLMSource
|
||||
}
|
||||
|
||||
// provideMeetingConfig 从全局 Config 中提取 MeetingConfig
|
||||
// Phase B:会议模块需要 InternalWebhookSecret 用于校验 media-server 失败回调
|
||||
func provideMeetingConfig(cfg *config.Config) *config.MeetingConfig {
|
||||
return &cfg.Meeting
|
||||
}
|
||||
|
||||
// InfraSet 基础设施层 Provider Set
|
||||
var InfraSet = wire.NewSet(
|
||||
provideDBConfig,
|
||||
@@ -193,6 +199,7 @@ var InfraSet = wire.NewSet(
|
||||
provideMinioConfig,
|
||||
provideServerConfig,
|
||||
provideLLMSourceConfig,
|
||||
provideMeetingConfig,
|
||||
db.NewPostgres,
|
||||
db.NewRedis,
|
||||
db.NewLLMSourceDB,
|
||||
|
||||
@@ -119,7 +119,8 @@ func InitializeApp(cfg *config.Config) (*App, error) {
|
||||
meetingManageService := service2.NewMeetingManageService(meetingManageDAO, meetingRecordingService)
|
||||
meetingManageController := controller2.NewMeetingManageController(meetingManageService)
|
||||
meetingController := controller7.NewMeetingController(meetingService)
|
||||
meetingRecordingController := controller7.NewMeetingRecordingController(meetingRecordingService)
|
||||
meetingConfig := provideMeetingConfig(cfg)
|
||||
meetingRecordingController := controller7.NewMeetingRecordingController(meetingRecordingService, meetingConfig)
|
||||
meetingWSHandler := controller7.NewMeetingWSHandler(meetingSignalService, hub)
|
||||
meetingCleanupTask := task2.NewMeetingCleanupTask(meetingLifecycleService, meetingRoomDAO, meetingChatDAO)
|
||||
llmSourceConfig := provideLLMSourceConfig(cfg)
|
||||
|
||||
@@ -86,7 +86,8 @@ llm_source:
|
||||
meeting:
|
||||
host_grace_seconds: 120 # 主持人掉线宽限期(秒),期间保留 host 身份
|
||||
empty_room_ttl_seconds: 300 # 空房自动销毁 TTL(秒),期间有人加入可复活
|
||||
cleanup_interval_seconds: 30 # 兜底扫描周期(秒),定时任务检查过期 grace/empty_ttl key
|
||||
cleanup_interval_seconds: 60 # 兜底扫描周期(秒),定时任务检查过期 grace/empty_ttl key
|
||||
stale_room_hours: 4 # 活跃超过此小时且无活跃成员视为 stale,强制结束
|
||||
# webhook 共享密钥:必须与 go-service 端 INTERNAL_WEBHOOK_SECRET 一致,否则 go-service 直接 403
|
||||
INTERNAL_WEBHOOK_SECRET: internal-webhook-12xqs
|
||||
# media-server 失败回调共享密钥:必须与 media-server 端 INTERNAL_WEBHOOK_SECRET 环境变量一致
|
||||
# 留空时 /internal/meeting/recordings/failure 全部 403(默认安全)
|
||||
internal_webhook_secret: internal-webhook-12xqs
|
||||
@@ -79,3 +79,6 @@ meeting:
|
||||
empty_room_ttl_seconds: 300
|
||||
cleanup_interval_seconds: 30
|
||||
stale_room_hours: 4
|
||||
# media-server 失败回调共享密钥:必须与 docker-compose 中 media-server 服务的 INTERNAL_WEBHOOK_SECRET 一致
|
||||
# 生产部署请通过环境变量 ECHOCHAT_MEETING_INTERNAL_WEBHOOK_SECRET 覆盖(viper.AutomaticEnv 已开启)
|
||||
internal_webhook_secret: internal-webhook-12xqs
|
||||
|
||||
@@ -76,6 +76,9 @@ type MeetingConfig struct {
|
||||
HostGraceSeconds int `mapstructure:"host_grace_seconds"` // host 掉线宽限期秒数,默认 120
|
||||
EmptyRoomTTLSeconds int `mapstructure:"empty_room_ttl_seconds"` // 空房自动销毁 TTL 秒数,默认 300
|
||||
CleanupIntervalSeconds int `mapstructure:"cleanup_interval_seconds"` // 兜底扫描周期秒数,默认 30
|
||||
// Phase B:media-server 失败回调 webhook 共享密钥,必须与 media-server 端 INTERNAL_WEBHOOK_SECRET 一致
|
||||
// 留空时 /internal/meeting/recordings/failure 全部直接 403(默认安全)
|
||||
InternalWebhookSecret string `mapstructure:"internal_webhook_secret"`
|
||||
StaleRoomHours int `mapstructure:"stale_room_hours"` // 活跃超过此小时且无成员视为 stale,默认 4
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user