package lingxian import ( "chatapp3-golang/internal/common" "chatapp3-golang/internal/model" "chatapp3-golang/internal/utils" "context" "net/http" "strings" "time" "gorm.io/gorm" "gorm.io/gorm/clause" ) func (s *Service) defaultRuntimeConfig(sysOrigin string) runtimeConfig { return runtimeConfig{ SysOrigin: normalizeSysOrigin(sysOrigin), Profile: profileProd, GameListURL: defaultIfBlank(s.cfg.Lingxian.GameListURL, defaultListURL), AppKey: strings.TrimSpace(s.cfg.Lingxian.AppKey), } } func (s *Service) activeProfile(ctx context.Context, sysOrigin string) (string, error) { sysOrigin = normalizeSysOrigin(sysOrigin) var row model.LingxianProviderConfig 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.LingxianProviderConfig 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.GameListURL) == "" || strings.TrimSpace(cfg.AppKey) == "" { return runtimeConfig{}, common.NewAppError(http.StatusBadRequest, "lingxian_config_missing", "lingxian config is missing") } return cfg, nil } 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.LingxianProviderConfig _ = 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, GameListURL: defaultIfBlank(runtimeCfg.GameListURL, defaultListURL), AppKey: runtimeCfg.AppKey, TestUID: runtimeCfg.TestUID, TestToken: runtimeCfg.TestToken, TestRoomID: runtimeCfg.TestRoomID, UpdateTime: formatTime(row.UpdateTime), }, nil } func (s *Service) SaveProviderConfig(ctx context.Context, req SaveProviderConfigRequest) (*ProviderConfigItem, error) { sysOrigin := normalizeSysOrigin(req.SysOrigin) profile := normalizeProfile(req.Profile) gameListURL := defaultIfBlank(req.GameListURL, defaultListURL) appKey := strings.TrimSpace(req.AppKey) if gameListURL == "" { return nil, common.NewAppError(http.StatusBadRequest, "game_list_url_required", "gameListUrl is required") } 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.LingxianProviderConfig{ ID: id, SysOrigin: sysOrigin, Profile: profile, GameListURL: gameListURL, AppKey: appKey, TestUID: strings.TrimSpace(req.TestUID), TestToken: strings.TrimSpace(req.TestToken), TestRoomID: strings.TrimSpace(req.TestRoomID), CreateTime: now, UpdateTime: now, } var activeCount int64 if err := s.db.WithContext(ctx). Model(&model.LingxianProviderConfig{}). 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{ "game_list_url", "app_key", "test_uid", "test_token", "test_room_id", "update_time", }), }).Create(&row).Error; err != nil { return nil, err } if row.Active { s.clearJavaGameListCache(ctx) } return s.GetProviderConfig(ctx, sysOrigin, profile) } func (s *Service) ActivateProviderProfile(ctx context.Context, req ActivateProviderProfileRequest) (*ProviderConfigItem, error) { sysOrigin := normalizeSysOrigin(req.SysOrigin) profile := normalizeProfile(req.Profile) var row model.LingxianProviderConfig 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.LingxianProviderConfig{}). Where("sys_origin = ?", sysOrigin). Updates(map[string]any{"active": false, "update_time": now}).Error; err != nil { return err } return tx.Model(&model.LingxianProviderConfig{}). 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() }