package config import ( "net/http" "strings" "time" "hyapp/pkg/configx" "hyapp/pkg/logx" "hyapp/pkg/tencentim" ) // Config 描述 activity-service 启动配置。 type Config struct { ServiceName string `yaml:"service_name"` NodeID string `yaml:"node_id"` Environment string `yaml:"environment"` GRPCAddr string `yaml:"grpc_addr"` // HealthHTTPAddr 是给 CLB/发布脚本探活使用的 HTTP 监听地址,不承载业务流量。 HealthHTTPAddr string `yaml:"health_http_addr"` // MySQLDSN 是活动状态、事件消费幂等和 outbox 的必需存储连接串。 MySQLDSN string `yaml:"mysql_dsn"` // UserServiceAddr 是 fanout worker 读取目标用户游标的内部 gRPC 地址。 UserServiceAddr string `yaml:"user_service_addr"` // WalletServiceAddr 是任务奖励入账依赖;activity 只发命令,不直接写余额。 WalletServiceAddr string `yaml:"wallet_service_addr"` // TencentIM 是 activity-service 发送全局/区域播报群消息的 REST 配置。 TencentIM TencentIMConfig `yaml:"tencent_im"` // Broadcast 控制 IM 播报群 reconciler、outbox worker 和贵重礼物阈值。 Broadcast BroadcastConfig `yaml:"broadcast"` // MySQLAutoMigrate 保留给显式本地迁移;线上 schema 由发布流程或 initdb 管理。 MySQLAutoMigrate bool `yaml:"mysql_auto_migrate"` Consumer ConsumerConfig `yaml:"consumer"` MessageInbox MessageInboxConfig `yaml:"message_inbox"` Log logx.Config `yaml:"log"` } // ConsumerConfig 保存 room outbox 消费底座配置。 type ConsumerConfig struct { RoomOutboxPollIntervalMs int64 `yaml:"room_outbox_poll_interval_ms"` BatchSize int `yaml:"batch_size"` } // MessageInboxConfig 保存 App system/activity inbox 的读取缓存参数;fanout 扫描由 cron-service 调度。 type MessageInboxConfig struct { UnreadCacheTTL string `yaml:"unread_cache_ttl"` } // TencentIMConfig 描述 activity-service 调用腾讯云 IM REST API 的配置。 type TencentIMConfig struct { Enabled bool `yaml:"enabled"` SDKAppID int64 `yaml:"sdk_app_id"` SecretKey string `yaml:"secret_key"` AdminIdentifier string `yaml:"admin_identifier"` AdminUserSigTTL time.Duration `yaml:"admin_user_sig_ttl"` Endpoint string `yaml:"endpoint"` GroupType string `yaml:"group_type"` RequestTimeout time.Duration `yaml:"request_timeout"` } // RESTConfig converts YAML into the shared Tencent IM REST client config. func (c TencentIMConfig) RESTConfig() tencentim.RESTConfig { timeout := c.RequestTimeout if timeout <= 0 { timeout = 5 * time.Second } return tencentim.RESTConfig{ SDKAppID: c.SDKAppID, SecretKey: c.SecretKey, AdminIdentifier: c.AdminIdentifier, AdminUserSigTTL: c.AdminUserSigTTL, Endpoint: c.Endpoint, GroupType: c.GroupType, HTTPClient: &http.Client{Timeout: timeout}, } } // BroadcastConfig stores activity-service broadcast worker policy. type BroadcastConfig struct { Enabled bool `yaml:"enabled"` SuperGiftMinValue int64 `yaml:"super_gift_min_value"` WorkerPollInterval time.Duration `yaml:"worker_poll_interval"` WorkerBatchSize int `yaml:"worker_batch_size"` WorkerLockTTL time.Duration `yaml:"worker_lock_ttl"` WorkerMaxRetry int `yaml:"worker_max_retry"` EnsureGroupsOnStartup bool `yaml:"ensure_groups_on_startup"` } // Default 返回本地默认配置。 func Default() Config { return Config{ ServiceName: "activity-service", NodeID: "activity-local", Environment: "local", GRPCAddr: ":13006", HealthHTTPAddr: ":13106", MySQLDSN: "hyapp:hyapp@tcp(127.0.0.1:23306)/hyapp_activity?parseTime=true&charset=utf8mb4&loc=UTC", UserServiceAddr: "127.0.0.1:13005", WalletServiceAddr: "127.0.0.1:13004", TencentIM: TencentIMConfig{ Enabled: false, AdminIdentifier: "administrator", AdminUserSigTTL: 24 * time.Hour, Endpoint: tencentim.DefaultEndpoint, GroupType: tencentim.DefaultGroupType, RequestTimeout: 5 * time.Second, }, Broadcast: BroadcastConfig{ Enabled: false, SuperGiftMinValue: 100000, WorkerPollInterval: time.Second, WorkerBatchSize: 100, WorkerLockTTL: 30 * time.Second, WorkerMaxRetry: 8, EnsureGroupsOnStartup: true, }, MySQLAutoMigrate: false, Consumer: ConsumerConfig{ RoomOutboxPollIntervalMs: 1000, BatchSize: 100, }, MessageInbox: MessageInboxConfig{ UnreadCacheTTL: "60s", }, Log: logx.Config{ Level: "info", Format: "json", MaxPayloadBytes: 2048, }, } } // Load 从独立 config.yaml 读取 activity-service 配置。 func Load(path string) (Config, error) { cfg := Default() if path == "" { return cfg, nil } if err := configx.LoadYAML(path, &cfg); err != nil { return Config{}, err } if strings.TrimSpace(cfg.UserServiceAddr) == "" { cfg.UserServiceAddr = Default().UserServiceAddr } if strings.TrimSpace(cfg.WalletServiceAddr) == "" { cfg.WalletServiceAddr = Default().WalletServiceAddr } cfg.ServiceName = strings.TrimSpace(cfg.ServiceName) if cfg.ServiceName == "" { cfg.ServiceName = "activity-service" } cfg.NodeID = strings.TrimSpace(cfg.NodeID) if cfg.NodeID == "" { cfg.NodeID = cfg.ServiceName } cfg.Environment = strings.ToLower(strings.TrimSpace(cfg.Environment)) if cfg.Environment == "" { cfg.Environment = "local" } cfg.HealthHTTPAddr = strings.TrimSpace(cfg.HealthHTTPAddr) if cfg.HealthHTTPAddr == "" { cfg.HealthHTTPAddr = ":13106" } cfg.TencentIM.AdminIdentifier = strings.TrimSpace(cfg.TencentIM.AdminIdentifier) if cfg.TencentIM.AdminIdentifier == "" { cfg.TencentIM.AdminIdentifier = "administrator" } cfg.TencentIM.Endpoint = strings.TrimSpace(cfg.TencentIM.Endpoint) if cfg.TencentIM.Endpoint == "" { cfg.TencentIM.Endpoint = tencentim.DefaultEndpoint } cfg.TencentIM.GroupType = strings.TrimSpace(cfg.TencentIM.GroupType) if cfg.TencentIM.GroupType == "" { cfg.TencentIM.GroupType = tencentim.DefaultGroupType } if cfg.TencentIM.AdminUserSigTTL <= 0 { cfg.TencentIM.AdminUserSigTTL = 24 * time.Hour } if cfg.TencentIM.RequestTimeout <= 0 { cfg.TencentIM.RequestTimeout = 5 * time.Second } if cfg.Broadcast.SuperGiftMinValue <= 0 { cfg.Broadcast.SuperGiftMinValue = 100000 } if cfg.Broadcast.WorkerPollInterval <= 0 { cfg.Broadcast.WorkerPollInterval = time.Second } if cfg.Broadcast.WorkerBatchSize <= 0 { cfg.Broadcast.WorkerBatchSize = 100 } if cfg.Broadcast.WorkerLockTTL <= 0 { cfg.Broadcast.WorkerLockTTL = 30 * time.Second } if cfg.Broadcast.WorkerMaxRetry <= 0 { cfg.Broadcast.WorkerMaxRetry = 8 } return cfg, nil }