package config import ( "net/http" "strings" "time" "hyapp/pkg/configx" "hyapp/pkg/logx" "hyapp/pkg/tencentim" ) // Config 描述 notice-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 是 notice-service 自己的投递位点和死信状态库。 MySQLDSN string `yaml:"mysql_dsn"` // WalletDatabase 是 wallet_outbox 所在库名;notice 只把它当 append-only 事实源读取。 WalletDatabase string `yaml:"wallet_database"` // RoomDatabase 是 room_outbox 所在库名;notice 只读取需要私有通知的房间事实。 RoomDatabase string `yaml:"room_database"` // TencentIM 是私有 IM 投递通道配置;本地默认关闭,避免误发真实消息。 TencentIM TencentIMConfig `yaml:"tencent_im"` // WalletNoticeWorker 消费 wallet_outbox 中的 WalletBalanceChanged 事件。 WalletNoticeWorker WalletNoticeWorkerConfig `yaml:"wallet_notice_worker"` // RoomNoticeWorker 消费 room_outbox 中需要给单个用户发送的房间通知。 RoomNoticeWorker WalletNoticeWorkerConfig `yaml:"room_notice_worker"` MySQLAutoMigrate bool `yaml:"mysql_auto_migrate"` Log logx.Config `yaml:"log"` } // TencentIMConfig 描述服务端调用腾讯云 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"` RequestTimeout time.Duration `yaml:"request_timeout"` } // RESTConfig converts YAML config into shared Tencent IM REST 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, HTTPClient: &http.Client{Timeout: timeout}, } } // WalletNoticeWorkerConfig 控制钱包私有通知投递 worker。 type WalletNoticeWorkerConfig struct { Enabled bool `yaml:"enabled"` PollInterval time.Duration `yaml:"poll_interval"` BatchSize int `yaml:"batch_size"` LockTTL time.Duration `yaml:"lock_ttl"` PublishTimeout time.Duration `yaml:"publish_timeout"` MaxRetryCount int `yaml:"max_retry_count"` InitialBackoff time.Duration `yaml:"initial_backoff"` MaxBackoff time.Duration `yaml:"max_backoff"` } // Default 返回本地开发默认配置。 func Default() Config { return Config{ ServiceName: "notice-service", NodeID: "notice-local", Environment: "local", GRPCAddr: ":13009", HealthHTTPAddr: ":13109", MySQLDSN: "hyapp:hyapp@tcp(127.0.0.1:23306)/hyapp_notice?parseTime=true&charset=utf8mb4&loc=UTC", WalletDatabase: "hyapp_wallet", RoomDatabase: "hyapp_room", MySQLAutoMigrate: false, TencentIM: TencentIMConfig{ Enabled: false, AdminIdentifier: "administrator", AdminUserSigTTL: 24 * time.Hour, Endpoint: tencentim.DefaultEndpoint, RequestTimeout: 5 * time.Second, }, WalletNoticeWorker: WalletNoticeWorkerConfig{ Enabled: false, PollInterval: time.Second, BatchSize: 100, LockTTL: 30 * time.Second, PublishTimeout: 3 * time.Second, MaxRetryCount: 10, InitialBackoff: 5 * time.Second, MaxBackoff: 5 * time.Minute, }, RoomNoticeWorker: WalletNoticeWorkerConfig{ Enabled: false, PollInterval: time.Second, BatchSize: 100, LockTTL: 30 * time.Second, PublishTimeout: 3 * time.Second, MaxRetryCount: 10, InitialBackoff: 5 * time.Second, MaxBackoff: 5 * time.Minute, }, Log: logx.Config{ Level: "info", Format: "json", MaxPayloadBytes: 2048, }, } } // Load 从独立 config.yaml 读取 notice-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 } cfg.ServiceName = strings.TrimSpace(cfg.ServiceName) if cfg.ServiceName == "" { cfg.ServiceName = "notice-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.GRPCAddr = strings.TrimSpace(cfg.GRPCAddr) if cfg.GRPCAddr == "" { cfg.GRPCAddr = ":13009" } cfg.HealthHTTPAddr = strings.TrimSpace(cfg.HealthHTTPAddr) if cfg.HealthHTTPAddr == "" { cfg.HealthHTTPAddr = ":13109" } cfg.WalletDatabase = strings.TrimSpace(cfg.WalletDatabase) if cfg.WalletDatabase == "" { cfg.WalletDatabase = "hyapp_wallet" } cfg.RoomDatabase = strings.TrimSpace(cfg.RoomDatabase) if cfg.RoomDatabase == "" { cfg.RoomDatabase = "hyapp_room" } cfg.WalletNoticeWorker = normalizeWalletNoticeWorker(cfg.WalletNoticeWorker) cfg.RoomNoticeWorker = normalizeWalletNoticeWorker(cfg.RoomNoticeWorker) if strings.TrimSpace(cfg.TencentIM.AdminIdentifier) == "" { cfg.TencentIM.AdminIdentifier = "administrator" } if cfg.TencentIM.AdminUserSigTTL <= 0 { cfg.TencentIM.AdminUserSigTTL = 24 * time.Hour } if strings.TrimSpace(cfg.TencentIM.Endpoint) == "" { cfg.TencentIM.Endpoint = tencentim.DefaultEndpoint } if cfg.TencentIM.RequestTimeout <= 0 { cfg.TencentIM.RequestTimeout = 5 * time.Second } return cfg, nil } func normalizeWalletNoticeWorker(cfg WalletNoticeWorkerConfig) WalletNoticeWorkerConfig { def := Default().WalletNoticeWorker if cfg.PollInterval <= 0 { cfg.PollInterval = def.PollInterval } if cfg.BatchSize <= 0 { cfg.BatchSize = def.BatchSize } if cfg.LockTTL <= 0 { cfg.LockTTL = def.LockTTL } if cfg.PublishTimeout <= 0 { cfg.PublishTimeout = def.PublishTimeout } if cfg.MaxRetryCount <= 0 { cfg.MaxRetryCount = def.MaxRetryCount } if cfg.InitialBackoff <= 0 { cfg.InitialBackoff = def.InitialBackoff } if cfg.MaxBackoff <= 0 { cfg.MaxBackoff = def.MaxBackoff } return cfg }