package hotgame import ( "context" "net/http" "strings" "time" "chatapp3-golang/internal/common" "chatapp3-golang/internal/model" "chatapp3-golang/internal/utils" "gorm.io/gorm" "gorm.io/gorm/clause" ) func (s *Service) defaultRuntimeConfig(sysOrigin string) runtimeConfig { return runtimeConfig{ SysOrigin: normalizeSysOrigin(sysOrigin), Profile: profileProd, AppKey: strings.TrimSpace(s.cfg.Hotgame.AppKey), CallbackBaseURL: strings.TrimSpace(s.cfg.Hotgame.CallbackBaseURL), } } func (s *Service) activeProfile(ctx context.Context, sysOrigin string) (string, error) { sysOrigin = normalizeSysOrigin(sysOrigin) var row model.HotgameProviderConfig err := s.db.WithContext(ctx). Where("sys_origin = ? AND active = ?", sysOrigin, true). Order("update_time DESC"). Limit(1). First(&row).Error if err == nil { return normalizeProfile(row.Profile), nil } if err == gorm.ErrRecordNotFound { return profileProd, nil } return "", err } func (s *Service) requestProfile(ctx context.Context, sysOrigin, profile string) (string, error) { if strings.TrimSpace(profile) != "" { return normalizeProfile(profile), nil } return s.activeProfile(ctx, sysOrigin) } func (s *Service) resolveRuntimeConfigForProfile(ctx context.Context, sysOrigin, profile string) (runtimeConfig, error) { sysOrigin = normalizeSysOrigin(sysOrigin) profile = normalizeProfile(profile) base := s.defaultRuntimeConfig(sysOrigin) base.Profile = profile var row model.HotgameProviderConfig err := s.db.WithContext(ctx). Where("sys_origin = ? AND profile = ?", sysOrigin, profile). Limit(1). First(&row).Error if err == nil { return configToRuntime(base, row), nil } if err == gorm.ErrRecordNotFound { return base, nil } return runtimeConfig{}, err } func (s *Service) requireRuntimeConfigForProfile(ctx context.Context, sysOrigin, profile string) (runtimeConfig, error) { cfg, err := s.resolveRuntimeConfigForProfile(ctx, sysOrigin, profile) if err != nil { return runtimeConfig{}, err } if strings.TrimSpace(cfg.AppKey) == "" { return runtimeConfig{}, common.NewAppError(http.StatusBadRequest, "hotgame_config_missing", "hotgame appKey is required") } return cfg, nil } // GetProviderConfig 读取某个系统、某个环境的热游配置,并附带当前启用环境。 func (s *Service) GetProviderConfig(ctx context.Context, sysOrigin, profile string) (*ProviderConfigItem, error) { sysOrigin = normalizeSysOrigin(sysOrigin) activeProfile, err := s.activeProfile(ctx, sysOrigin) if err != nil { return nil, err } profile, err = s.requestProfile(ctx, sysOrigin, profile) if err != nil { return nil, err } runtimeCfg, err := s.resolveRuntimeConfigForProfile(ctx, sysOrigin, profile) if err != nil { return nil, err } var row model.HotgameProviderConfig _ = s.db.WithContext(ctx). Where("sys_origin = ? AND profile = ?", sysOrigin, profile). Limit(1). First(&row).Error return &ProviderConfigItem{ ID: row.ID, SysOrigin: runtimeCfg.SysOrigin, Profile: runtimeCfg.Profile, ActiveProfile: activeProfile, Active: runtimeCfg.Profile == activeProfile, AppKey: runtimeCfg.AppKey, CallbackBaseURL: runtimeCfg.CallbackBaseURL, TestUID: runtimeCfg.TestUID, TestToken: runtimeCfg.TestToken, UpdateTime: formatTime(row.UpdateTime), }, nil } // SaveProviderConfig 保存热游配置;首个配置自动设为当前启用环境。 func (s *Service) SaveProviderConfig(ctx context.Context, req SaveProviderConfigRequest) (*ProviderConfigItem, error) { sysOrigin := normalizeSysOrigin(req.SysOrigin) profile := normalizeProfile(req.Profile) appKey := strings.TrimSpace(req.AppKey) if appKey == "" { return nil, common.NewAppError(http.StatusBadRequest, "app_key_required", "appKey is required") } id, err := utils.NextID() if err != nil { return nil, err } now := time.Now() row := model.HotgameProviderConfig{ ID: id, SysOrigin: sysOrigin, Profile: profile, AppKey: appKey, CallbackBaseURL: strings.TrimSpace(req.CallbackBaseURL), TestUID: strings.TrimSpace(req.TestUID), TestToken: strings.TrimSpace(req.TestToken), CreateTime: now, UpdateTime: now, } var activeCount int64 if err := s.db.WithContext(ctx). Model(&model.HotgameProviderConfig{}). Where("sys_origin = ? AND active = ?", sysOrigin, true). Count(&activeCount).Error; err != nil { return nil, err } row.Active = activeCount == 0 if err := s.db.WithContext(ctx).Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "sys_origin"}, {Name: "profile"}}, DoUpdates: clause.AssignmentColumns([]string{ "app_key", "callback_base_url", "test_uid", "test_token", "update_time", }), }).Create(&row).Error; err != nil { return nil, err } if row.Active { s.clearJavaGameListCache(ctx) } return s.GetProviderConfig(ctx, sysOrigin, profile) } // ActivateProviderProfile 切换 app 侧读取的热游环境,并清理 Java 老游戏列表缓存。 func (s *Service) ActivateProviderProfile(ctx context.Context, req ActivateProviderProfileRequest) (*ProviderConfigItem, error) { sysOrigin := normalizeSysOrigin(req.SysOrigin) profile := normalizeProfile(req.Profile) var row model.HotgameProviderConfig if err := s.db.WithContext(ctx). Where("sys_origin = ? AND profile = ?", sysOrigin, profile). Limit(1). First(&row).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, common.NewAppError(http.StatusBadRequest, "profile_config_missing", "profile config is missing") } return nil, err } now := time.Now() if err := s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error { if err := tx.Model(&model.HotgameProviderConfig{}). Where("sys_origin = ?", sysOrigin). Updates(map[string]any{"active": false, "update_time": now}).Error; err != nil { return err } return tx.Model(&model.HotgameProviderConfig{}). Where("sys_origin = ? AND profile = ?", sysOrigin, profile). Updates(map[string]any{"active": true, "update_time": now}).Error }); err != nil { return nil, err } s.clearJavaGameListCache(ctx) return s.GetProviderConfig(ctx, sysOrigin, profile) } func (s *Service) clearJavaGameListCache(ctx context.Context) { if s.cache == nil { return } _ = s.cache.Del(ctx, "GAME_LIST").Err() }