package baishun import ( "chatapp3-golang/internal/model" "chatapp3-golang/internal/utils" "context" "net/http" "strings" "time" "gorm.io/gorm" "gorm.io/gorm/clause" ) type baishunRuntimeConfig struct { SysOrigin string Profile string PlatformBaseURL string AppID int64 AppName string AppChannel string AppKey string GSP int LaunchCodeTTLSeconds int SSTokenTTLSeconds int } func (c baishunRuntimeConfig) appChannel() string { return defaultIfBlank(strings.TrimSpace(c.AppChannel), "skychat") } func (c baishunRuntimeConfig) gsp() int { if c.GSP > 0 { return c.GSP } return 101 } func (c baishunRuntimeConfig) launchCodeTTLSeconds() int { if c.LaunchCodeTTLSeconds > 0 { return c.LaunchCodeTTLSeconds } return 300 } func (c baishunRuntimeConfig) ssTokenTTLSeconds() int { if c.SSTokenTTLSeconds > 0 { return c.SSTokenTTLSeconds } return 86400 } func (s *BaishunService) defaultRuntimeConfig(sysOrigin string) baishunRuntimeConfig { return baishunRuntimeConfig{ SysOrigin: normalizeAdminSysOrigin(sysOrigin), Profile: baishunProfileProd, PlatformBaseURL: strings.TrimSpace(s.cfg.Baishun.PlatformBaseURL), AppID: s.cfg.Baishun.AppID, AppName: strings.TrimSpace(s.cfg.Baishun.AppName), AppChannel: strings.TrimSpace(s.cfg.Baishun.AppChannel), AppKey: strings.TrimSpace(s.cfg.Baishun.AppKey), GSP: s.cfg.Baishun.GSP, LaunchCodeTTLSeconds: s.cfg.Baishun.LaunchCodeTTLSeconds, SSTokenTTLSeconds: s.cfg.Baishun.SSTokenTTLSeconds, } } func applyProviderRow(base baishunRuntimeConfig, row model.BaishunProviderConfig) baishunRuntimeConfig { base.SysOrigin = normalizeAdminSysOrigin(defaultIfBlank(row.SysOrigin, base.SysOrigin)) base.Profile = normalizeBaishunProfile(defaultIfBlank(row.Profile, base.Profile)) if strings.TrimSpace(row.PlatformBaseURL) != "" { base.PlatformBaseURL = strings.TrimSpace(row.PlatformBaseURL) } if row.AppID > 0 { base.AppID = row.AppID } if strings.TrimSpace(row.AppName) != "" { base.AppName = strings.TrimSpace(row.AppName) } if strings.TrimSpace(row.AppChannel) != "" { base.AppChannel = strings.TrimSpace(row.AppChannel) } if strings.TrimSpace(row.AppKey) != "" { base.AppKey = strings.TrimSpace(row.AppKey) } if row.GSP > 0 { base.GSP = row.GSP } if row.LaunchCodeTTLSeconds > 0 { base.LaunchCodeTTLSeconds = row.LaunchCodeTTLSeconds } if row.SSTokenTTLSeconds > 0 { base.SSTokenTTLSeconds = row.SSTokenTTLSeconds } return base } func (s *BaishunService) resolveRuntimeConfig(ctx context.Context, sysOrigin string) (baishunRuntimeConfig, error) { sysOrigin = normalizeAdminSysOrigin(sysOrigin) profile, err := s.activeProfile(ctx, sysOrigin) if err != nil { return baishunRuntimeConfig{}, err } return s.resolveRuntimeConfigForProfile(ctx, sysOrigin, profile) } func (s *BaishunService) resolveRuntimeConfigForProfile(ctx context.Context, sysOrigin string, profile string) (baishunRuntimeConfig, error) { sysOrigin = normalizeAdminSysOrigin(sysOrigin) profile, err := validateBaishunProfile(profile) if err != nil { return baishunRuntimeConfig{}, err } base := s.defaultRuntimeConfig(sysOrigin) base.Profile = profile var row model.BaishunProviderConfig err = s.repo.DB.WithContext(ctx). Where("sys_origin = ? AND profile = ?", sysOrigin, profile). Limit(1). First(&row).Error if err == nil { return applyProviderRow(base, row), nil } if err == gorm.ErrRecordNotFound { return base, nil } return baishunRuntimeConfig{}, err } func (s *BaishunService) resolveRuntimeConfigByApp(ctx context.Context, appID int64, appChannel string) (baishunRuntimeConfig, error) { base := s.defaultRuntimeConfig("LIKEI") appChannel = strings.TrimSpace(appChannel) queries := make([]func(*gorm.DB) *gorm.DB, 0, 3) if appID > 0 && appChannel != "" { queries = append(queries, func(db *gorm.DB) *gorm.DB { return db.Where("app_id = ? AND app_channel = ?", appID, appChannel) }) } if appID > 0 { queries = append(queries, func(db *gorm.DB) *gorm.DB { return db.Where("app_id = ?", appID) }) } if appChannel != "" { queries = append(queries, func(db *gorm.DB) *gorm.DB { return db.Where("app_channel = ?", appChannel) }) } for _, build := range queries { var row model.BaishunProviderConfig err := build(s.repo.DB.WithContext(ctx)). Order("active DESC"). Order("update_time DESC"). Limit(1). First(&row).Error if err == nil { return applyProviderRow(s.defaultRuntimeConfig(row.SysOrigin), row), nil } if err != gorm.ErrRecordNotFound { return baishunRuntimeConfig{}, err } } return base, nil } func (s *BaishunService) GetProviderConfig(ctx context.Context, sysOrigin string, profile string) (*BaishunProviderConfigItem, error) { sysOrigin = normalizeAdminSysOrigin(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.BaishunProviderConfig _ = s.repo.DB.WithContext(ctx). Where("sys_origin = ? AND profile = ?", sysOrigin, profile). Limit(1). First(&row).Error return &BaishunProviderConfigItem{ ID: row.ID, SysOrigin: runtimeCfg.SysOrigin, Profile: runtimeCfg.Profile, ActiveProfile: activeProfile, Active: runtimeCfg.Profile == activeProfile, PlatformBaseURL: runtimeCfg.PlatformBaseURL, AppID: runtimeCfg.AppID, AppName: runtimeCfg.AppName, AppChannel: runtimeCfg.appChannel(), AppKey: runtimeCfg.AppKey, GSP: runtimeCfg.gsp(), LaunchCodeTTLSeconds: runtimeCfg.launchCodeTTLSeconds(), SSTokenTTLSeconds: runtimeCfg.ssTokenTTLSeconds(), UpdateTime: formatAdminTime(row.UpdateTime), }, nil } func (s *BaishunService) SaveProviderConfig(ctx context.Context, req SaveBaishunProviderConfigRequest) (*BaishunProviderConfigItem, error) { sysOrigin := normalizeAdminSysOrigin(req.SysOrigin) profile, err := validateBaishunProfile(req.Profile) if err != nil { return nil, err } platformBaseURL := strings.TrimSpace(req.PlatformBaseURL) appChannel := strings.TrimSpace(req.AppChannel) appKey := strings.TrimSpace(req.AppKey) switch { case platformBaseURL == "": return nil, NewAppError(http.StatusBadRequest, "platform_base_url_required", "platformBaseUrl is required") case req.AppID <= 0: return nil, NewAppError(http.StatusBadRequest, "app_id_required", "appId is required") case appChannel == "": return nil, NewAppError(http.StatusBadRequest, "app_channel_required", "appChannel is required") case appKey == "": return nil, NewAppError(http.StatusBadRequest, "app_key_required", "appKey is required") } id, err := utils.NextID() if err != nil { return nil, err } now := time.Now() row := model.BaishunProviderConfig{ ID: id, SysOrigin: sysOrigin, Profile: profile, PlatformBaseURL: platformBaseURL, AppID: req.AppID, AppName: strings.TrimSpace(req.AppName), AppChannel: appChannel, AppKey: appKey, GSP: req.GSP, LaunchCodeTTLSeconds: req.LaunchCodeTTLSeconds, SSTokenTTLSeconds: req.SSTokenTTLSeconds, CreateTime: now, UpdateTime: now, } if row.GSP <= 0 { row.GSP = 101 } if row.LaunchCodeTTLSeconds <= 0 { row.LaunchCodeTTLSeconds = 300 } if row.SSTokenTTLSeconds <= 0 { row.SSTokenTTLSeconds = 86400 } var activeCount int64 if err := s.repo.DB.WithContext(ctx). Model(&model.BaishunProviderConfig{}). Where("sys_origin = ? AND active = ?", sysOrigin, true). Count(&activeCount).Error; err != nil { return nil, err } row.Active = activeCount == 0 if err := s.repo.DB.WithContext(ctx).Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "sys_origin"}, {Name: "profile"}}, DoUpdates: clause.AssignmentColumns([]string{ "platform_base_url", "app_id", "app_name", "app_channel", "app_key", "gsp", "launch_code_ttl_seconds", "ss_token_ttl_seconds", "update_time", }), }).Create(&row).Error; err != nil { return nil, err } if row.Active { s.clearJavaGameListCache(ctx) } return s.GetProviderConfig(ctx, sysOrigin, profile) } func (s *BaishunService) ActivateProviderProfile(ctx context.Context, req ActivateBaishunProviderProfileRequest) (*BaishunProviderConfigItem, error) { sysOrigin := normalizeAdminSysOrigin(req.SysOrigin) profile, err := validateBaishunProfile(req.Profile) if err != nil { return nil, err } var row model.BaishunProviderConfig if err := s.repo.DB.WithContext(ctx). Where("sys_origin = ? AND profile = ?", sysOrigin, profile). Limit(1). First(&row).Error; err != nil { if err == gorm.ErrRecordNotFound { return nil, NewAppError(http.StatusBadRequest, "profile_config_missing", "profile config is missing") } return nil, err } now := time.Now() if err := s.repo.DB.WithContext(ctx).Transaction(func(tx *gorm.DB) error { if err := tx.Model(&model.BaishunProviderConfig{}). Where("sys_origin = ?", sysOrigin). Updates(map[string]any{ "active": false, "update_time": now, }).Error; err != nil { return err } return tx.Model(&model.BaishunProviderConfig{}). 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) }