package config import ( "fmt" "strings" "time" "hyapp/pkg/configx" "hyapp/pkg/tencentrtc" ) // Config 描述 gateway-service 启动所需的最小配置。 type Config struct { HTTPAddr string `yaml:"http_addr"` JWTSecret string `yaml:"jwt_secret"` RoomServiceAddr string `yaml:"room_service_addr"` UserServiceAddr string `yaml:"user_service_addr"` AuthRateLimit AuthRateLimitConfig `yaml:"auth_rate_limit"` TencentIM TencentIMConfig `yaml:"tencent_im"` TencentRTC TencentRTCConfig `yaml:"tencent_rtc"` } // AuthRateLimitConfig 控制 gateway public auth 入口的 Redis 频控。 type AuthRateLimitConfig struct { // Enabled 为 false 时关闭 gateway auth 入口频控。 Enabled bool `yaml:"enabled"` // RedisAddr 是 public auth 频控 Redis 地址。 RedisAddr string `yaml:"redis_addr"` // RedisPassword 是 Redis 鉴权密码,本地默认留空。 RedisPassword string `yaml:"redis_password"` // RedisDB 是 Redis logical DB。 RedisDB int `yaml:"redis_db"` // KeyPrefix 是频控 key 前缀,用于区分环境和服务。 KeyPrefix string `yaml:"key_prefix"` // WindowSec 是固定窗口秒数。 WindowSec int64 `yaml:"window_sec"` // IPLimit 限制同一入口 IP 对所有 public auth API 的请求数。 IPLimit int `yaml:"ip_limit"` // DeviceIDLimit 限制同一 device_id 对登录、注册和 refresh 的请求数。 DeviceIDLimit int `yaml:"device_id_limit"` // ProviderIPLimit 限制同一 IP 对同一三方 provider 的注册/登录请求数。 ProviderIPLimit int `yaml:"provider_ip_limit"` // DisplayUserIDIPLimit 限制同一 IP 对同一 display_user_id 的密码尝试。 DisplayUserIDIPLimit int `yaml:"display_user_id_ip_limit"` // DisplayUserIDLimit 限制同一 display_user_id 被跨 IP 喷射尝试。 DisplayUserIDLimit int `yaml:"display_user_id_limit"` // SessionIDIPLimit 限制同一 IP 对同一 session_id 的 logout 请求数。 SessionIDIPLimit int `yaml:"session_id_ip_limit"` } // TencentIMConfig 描述 gateway 给客户端签发腾讯云 IM UserSig 的配置。 type TencentIMConfig struct { // SDKAppID 是腾讯云 IM 控制台分配的应用 ID。 SDKAppID int64 `yaml:"sdk_app_id"` // SecretKey 只允许出现在服务端配置中,不能下发给客户端。 SecretKey string `yaml:"secret_key"` // UserSigTTL 是客户端 IM 登录票据有效期。 UserSigTTL time.Duration `yaml:"user_sig_ttl"` // CallbackURL 是在腾讯云 IM 控制台配置的服务端回调地址。 CallbackURL string `yaml:"callback_url"` // CallbackAuthToken 是腾讯云 IM 回调鉴权 token,只用于校验回调来源。 CallbackAuthToken string `yaml:"callback_auth_token"` } // TencentRTCConfig 描述 gateway 给客户端签发腾讯 RTC 进房 UserSig 的配置。 type TencentRTCConfig struct { // Enabled 控制 RTC token endpoint 是否可以对外签发,配置缺失时必须 fail-closed。 Enabled bool `yaml:"enabled"` // SDKAppID 是腾讯 RTC 控制台分配的应用 ID。 SDKAppID int64 `yaml:"sdk_app_id"` // SecretKey 只允许出现在服务端配置中,不能下发给客户端。 SecretKey string `yaml:"secret_key"` // UserSigTTL 是客户端 RTC 进房票据有效期。 UserSigTTL time.Duration `yaml:"user_sig_ttl"` // RoomIDType 首版固定 string,确保客户端只使用 TRTC strRoomId。 RoomIDType string `yaml:"room_id_type"` // AppScene 首版固定 voice_chat_room,所有端必须一致。 AppScene string `yaml:"app_scene"` } // Default 返回本地开发默认配置。 func Default() Config { return Config{ HTTPAddr: ":13000", JWTSecret: "gateway-dev-secret", RoomServiceAddr: "127.0.0.1:13001", UserServiceAddr: "127.0.0.1:13005", AuthRateLimit: AuthRateLimitConfig{ Enabled: true, RedisAddr: "127.0.0.1:13379", KeyPrefix: "gateway:auth:rate:", WindowSec: 60, IPLimit: 120, DeviceIDLimit: 30, ProviderIPLimit: 20, DisplayUserIDIPLimit: 10, DisplayUserIDLimit: 50, SessionIDIPLimit: 30, }, TencentIM: TencentIMConfig{ UserSigTTL: 24 * time.Hour, }, TencentRTC: TencentRTCConfig{ UserSigTTL: 2 * time.Hour, RoomIDType: "string", AppScene: "voice_chat_room", }, } } // Load 从独立 config.yaml 读取 gateway-service 配置。 func Load(path string) (Config, error) { cfg := Default() if path == "" { if err := cfg.Normalize(); err != nil { return Config{}, err } return cfg, nil } if err := configx.LoadYAML(path, &cfg); err != nil { return Config{}, err } if err := cfg.Normalize(); err != nil { return Config{}, err } return cfg, nil } // Normalize fills policy defaults and rejects unsupported RTC room/app modes at startup. func (cfg *Config) Normalize() error { cfg.TencentRTC.RoomIDType = strings.TrimSpace(cfg.TencentRTC.RoomIDType) if cfg.TencentRTC.RoomIDType == "" { cfg.TencentRTC.RoomIDType = tencentrtc.RoomIDTypeString } if cfg.TencentRTC.RoomIDType != tencentrtc.RoomIDTypeString { // Numeric TRTC roomId would fork users into a different room than internal string room_id. return fmt.Errorf("tencent_rtc.room_id_type must be %q", tencentrtc.RoomIDTypeString) } cfg.TencentRTC.AppScene = strings.TrimSpace(cfg.TencentRTC.AppScene) if cfg.TencentRTC.AppScene == "" { cfg.TencentRTC.AppScene = tencentrtc.AppSceneVoiceChatRoom } if cfg.TencentRTC.AppScene != tencentrtc.AppSceneVoiceChatRoom { // v1 has no gateway policy surface for multiple RTC scenes, so reject drift early. return fmt.Errorf("tencent_rtc.app_scene must be %q", tencentrtc.AppSceneVoiceChatRoom) } return nil }