diff --git a/internal/config/config.go b/internal/config/config.go index e36cbb4..479d8ed 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -93,6 +93,8 @@ type WeekStarRocketMQConfig struct { // BaishunConfig 保存百顺模块配置。 type BaishunConfig struct { PlatformBaseURL string + GameListURL string + LuckyGiftURL string AppID int64 AppName string AppChannel string @@ -185,6 +187,8 @@ func Load() Config { }, Baishun: BaishunConfig{ PlatformBaseURL: getEnvAny([]string{"CHATAPP_BAISHUN_PLATFORM_BASE_URL", "BAISHUN_PLATFORM_BASE_URL"}, ""), + GameListURL: getEnvAny([]string{"CHATAPP_BAISHUN_GAME_LIST_URL", "BAISHUN_GAME_LIST_URL"}, ""), + LuckyGiftURL: getEnvAny([]string{"CHATAPP_BAISHUN_LUCKY_GIFT_URL", "BAISHUN_LUCKY_GIFT_URL"}, ""), AppID: getEnvInt64Any([]string{"CHATAPP_BAISHUN_APP_ID", "BAISHUN_APP_ID"}, 0), AppName: getEnvAny([]string{"CHATAPP_BAISHUN_APP_NAME", "BAISHUN_APP_NAME"}, ""), AppChannel: getEnvAny([]string{"CHATAPP_BAISHUN_APP_CHANNEL", "BAISHUN_APP_CHANNEL"}, ""), diff --git a/internal/model/baishun_models.go b/internal/model/baishun_models.go index 51616bb..decb4c7 100644 --- a/internal/model/baishun_models.go +++ b/internal/model/baishun_models.go @@ -60,6 +60,8 @@ type BaishunProviderConfig struct { Profile string `gorm:"column:profile;size:32;default:PROD;uniqueIndex:uk_baishun_provider_sys_origin_profile,priority:2"` // 配置档案:PROD/TEST Active bool `gorm:"column:active;index:idx_baishun_provider_active,priority:2"` // 是否当前启用 PlatformBaseURL string `gorm:"column:platform_base_url;size:1024"` // 百顺平台基础地址 + GameListURL string `gorm:"column:game_list_url;size:1024"` // 百顺游戏列表完整地址 + LuckyGiftURL string `gorm:"column:lucky_gift_url;size:1024"` // 幸运礼物完整地址 AppID int64 `gorm:"column:app_id;index:idx_baishun_provider_app,priority:1"` // 百顺应用 ID AppName string `gorm:"column:app_name;size:128"` // 百顺应用名 AppChannel string `gorm:"column:app_channel;size:64;index:idx_baishun_provider_app,priority:2"` // 百顺渠道 diff --git a/internal/service/baishun/admin_test.go b/internal/service/baishun/admin_test.go index ffc4833..3597281 100644 --- a/internal/service/baishun/admin_test.go +++ b/internal/service/baishun/admin_test.go @@ -2,6 +2,8 @@ package baishun import ( "context" + "net/http" + "net/http/httptest" "testing" "time" @@ -29,6 +31,37 @@ func TestResolveAdminShowcase(t *testing.T) { }) } +func TestFetchPlatformGamesUsesConfiguredGameListURL(t *testing.T) { + service, _ := newTestBaishunService(t) + ctx := context.Background() + + var gotPath string + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + gotPath = r.URL.Path + w.Header().Set("Content-Type", "application/json") + _, _ = w.Write([]byte(`{"code":0,"message":"ok","data":[{"game_id":1021,"name":"LuckyGift","download_url":"https://cdn.example.com/lucky/index.html","preview_url":"https://cdn.example.com/lucky.png","game_version":"1.0.0","game_mode":[1],"game_orientation":1,"safe_height":0,"venue_level":[1]}]}`)) + })) + defer server.Close() + service.httpClient = server.Client() + + games, err := service.fetchPlatformGames(ctx, baishunRuntimeConfig{ + PlatformBaseURL: "https://unused.example.com", + GameListURL: server.URL + "/custom/game-list", + AppID: 1001, + AppChannel: "test", + AppKey: "test-key", + }) + if err != nil { + t.Fatalf("fetchPlatformGames() error = %v", err) + } + if gotPath != "/custom/game-list" { + t.Fatalf("request path = %q, want configured game list path", gotPath) + } + if len(games) != 1 || games[0].GameID != 1021 { + t.Fatalf("games = %+v, want fetched game 1021", games) + } +} + func TestImportAndListRoomGamesUseActiveProfile(t *testing.T) { service, db := newTestBaishunService(t) ctx := context.Background() diff --git a/internal/service/baishun/catalog.go b/internal/service/baishun/catalog.go index e8deb8e..22d46d5 100644 --- a/internal/service/baishun/catalog.go +++ b/internal/service/baishun/catalog.go @@ -106,7 +106,7 @@ func (s *BaishunService) fetchPlatformGames(ctx context.Context, runtimeCfg bais payload["app_name"] = runtimeCfg.AppName } body, _ := json.Marshal(payload) - endpoint := strings.TrimRight(runtimeCfg.PlatformBaseURL, "/") + "/v1/api/gamelist" + endpoint := runtimeCfg.gameListURL() req, err := http.NewRequestWithContext(ctx, http.MethodPost, endpoint, bytes.NewReader(body)) if err != nil { return nil, err diff --git a/internal/service/baishun/provider_config.go b/internal/service/baishun/provider_config.go index c070d01..6e78036 100644 --- a/internal/service/baishun/provider_config.go +++ b/internal/service/baishun/provider_config.go @@ -16,6 +16,8 @@ type baishunRuntimeConfig struct { SysOrigin string Profile string PlatformBaseURL string + GameListURL string + LuckyGiftURL string AppID int64 AppName string AppChannel string @@ -29,6 +31,14 @@ func (c baishunRuntimeConfig) appChannel() string { return defaultIfBlank(strings.TrimSpace(c.AppChannel), "skychat") } +func (c baishunRuntimeConfig) gameListURL() string { + return resolveBaishunGameListURL(c.PlatformBaseURL, c.GameListURL) +} + +func (c baishunRuntimeConfig) luckyGiftURL() string { + return resolveBaishunLuckyGiftURL(c.PlatformBaseURL, c.LuckyGiftURL) +} + func (c baishunRuntimeConfig) gsp() int { if c.GSP > 0 { return c.GSP @@ -51,10 +61,13 @@ func (c baishunRuntimeConfig) ssTokenTTLSeconds() int { } func (s *BaishunService) defaultRuntimeConfig(sysOrigin string) baishunRuntimeConfig { + platformBaseURL := strings.TrimSpace(s.cfg.Baishun.PlatformBaseURL) return baishunRuntimeConfig{ SysOrigin: normalizeAdminSysOrigin(sysOrigin), Profile: baishunProfileProd, - PlatformBaseURL: strings.TrimSpace(s.cfg.Baishun.PlatformBaseURL), + PlatformBaseURL: platformBaseURL, + GameListURL: resolveBaishunGameListURL(platformBaseURL, s.cfg.Baishun.GameListURL), + LuckyGiftURL: resolveBaishunLuckyGiftURL(platformBaseURL, s.cfg.Baishun.LuckyGiftURL), AppID: s.cfg.Baishun.AppID, AppName: strings.TrimSpace(s.cfg.Baishun.AppName), AppChannel: strings.TrimSpace(s.cfg.Baishun.AppChannel), @@ -71,6 +84,16 @@ func applyProviderRow(base baishunRuntimeConfig, row model.BaishunProviderConfig if strings.TrimSpace(row.PlatformBaseURL) != "" { base.PlatformBaseURL = strings.TrimSpace(row.PlatformBaseURL) } + if strings.TrimSpace(row.GameListURL) != "" { + base.GameListURL = strings.TrimSpace(row.GameListURL) + } else { + base.GameListURL = resolveBaishunGameListURL(base.PlatformBaseURL, "") + } + if strings.TrimSpace(row.LuckyGiftURL) != "" { + base.LuckyGiftURL = strings.TrimSpace(row.LuckyGiftURL) + } else { + base.LuckyGiftURL = resolveBaishunLuckyGiftURL(base.PlatformBaseURL, "") + } if row.AppID > 0 { base.AppID = row.AppID } @@ -193,6 +216,8 @@ func (s *BaishunService) GetProviderConfig(ctx context.Context, sysOrigin string ActiveProfile: activeProfile, Active: runtimeCfg.Profile == activeProfile, PlatformBaseURL: runtimeCfg.PlatformBaseURL, + GameListURL: runtimeCfg.gameListURL(), + LuckyGiftURL: runtimeCfg.luckyGiftURL(), AppID: runtimeCfg.AppID, AppName: runtimeCfg.AppName, AppChannel: runtimeCfg.appChannel(), @@ -211,12 +236,22 @@ func (s *BaishunService) SaveProviderConfig(ctx context.Context, req SaveBaishun return nil, err } platformBaseURL := strings.TrimSpace(req.PlatformBaseURL) + gameListURL := strings.TrimSpace(req.GameListURL) + luckyGiftURL := strings.TrimSpace(req.LuckyGiftURL) appChannel := strings.TrimSpace(req.AppChannel) appKey := strings.TrimSpace(req.AppKey) + if gameListURL == "" { + gameListURL = resolveBaishunGameListURL(platformBaseURL, "") + } + if luckyGiftURL == "" { + luckyGiftURL = resolveBaishunLuckyGiftURL(platformBaseURL, "") + } switch { case platformBaseURL == "": return nil, NewAppError(http.StatusBadRequest, "platform_base_url_required", "platformBaseUrl is required") + case luckyGiftURL == "": + return nil, NewAppError(http.StatusBadRequest, "lucky_gift_url_required", "luckyGiftUrl is required") case req.AppID <= 0: return nil, NewAppError(http.StatusBadRequest, "app_id_required", "appId is required") case appChannel == "": @@ -235,6 +270,8 @@ func (s *BaishunService) SaveProviderConfig(ctx context.Context, req SaveBaishun SysOrigin: sysOrigin, Profile: profile, PlatformBaseURL: platformBaseURL, + GameListURL: gameListURL, + LuckyGiftURL: luckyGiftURL, AppID: req.AppID, AppName: strings.TrimSpace(req.AppName), AppChannel: appChannel, @@ -266,7 +303,7 @@ func (s *BaishunService) SaveProviderConfig(ctx context.Context, req SaveBaishun 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", + "platform_base_url", "game_list_url", "lucky_gift_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 { @@ -278,6 +315,30 @@ func (s *BaishunService) SaveProviderConfig(ctx context.Context, req SaveBaishun return s.GetProviderConfig(ctx, sysOrigin, profile) } +func resolveBaishunGameListURL(platformBaseURL string, gameListURL string) string { + gameListURL = strings.TrimSpace(gameListURL) + if gameListURL != "" { + return gameListURL + } + platformBaseURL = strings.TrimRight(strings.TrimSpace(platformBaseURL), "/") + if platformBaseURL == "" { + return "" + } + return platformBaseURL + "/v1/api/gamelist" +} + +func resolveBaishunLuckyGiftURL(platformBaseURL string, luckyGiftURL string) string { + luckyGiftURL = strings.TrimSpace(luckyGiftURL) + if luckyGiftURL != "" { + return luckyGiftURL + } + platformBaseURL = strings.TrimRight(strings.TrimSpace(platformBaseURL), "/") + if platformBaseURL == "" { + return "" + } + return platformBaseURL + "/lucky_gift/start_game" +} + func (s *BaishunService) ActivateProviderProfile(ctx context.Context, req ActivateBaishunProviderProfileRequest) (*BaishunProviderConfigItem, error) { sysOrigin := normalizeAdminSysOrigin(req.SysOrigin) profile, err := validateBaishunProfile(req.Profile) diff --git a/internal/service/baishun/types.go b/internal/service/baishun/types.go index accc633..0d76fe5 100644 --- a/internal/service/baishun/types.go +++ b/internal/service/baishun/types.go @@ -284,6 +284,8 @@ type BaishunProviderConfigItem struct { ActiveProfile string `json:"activeProfile"` Active bool `json:"active"` PlatformBaseURL string `json:"platformBaseUrl"` + GameListURL string `json:"gameListUrl"` + LuckyGiftURL string `json:"luckyGiftUrl"` AppID int64 `json:"appId"` AppName string `json:"appName"` AppChannel string `json:"appChannel"` @@ -299,6 +301,8 @@ type SaveBaishunProviderConfigRequest struct { SysOrigin string `json:"sysOrigin"` Profile string `json:"profile"` PlatformBaseURL string `json:"platformBaseUrl"` + GameListURL string `json:"gameListUrl"` + LuckyGiftURL string `json:"luckyGiftUrl"` AppID int64 `json:"appId"` AppName string `json:"appName"` AppChannel string `json:"appChannel"` diff --git a/internal/service/luckygift/runtime_config.go b/internal/service/luckygift/runtime_config.go index 39717d8..1c9a314 100644 --- a/internal/service/luckygift/runtime_config.go +++ b/internal/service/luckygift/runtime_config.go @@ -82,10 +82,13 @@ func (s *LuckyGiftService) resolveActiveBaishunProfile(ctx context.Context, sysO func defaultLuckyGiftRuntimeAccount(cfg config.Config) luckyGiftRuntimeAccount { account := luckyGiftRuntimeAccount{ - URL: strings.TrimSpace(cfg.Baishun.PlatformBaseURL), + URL: strings.TrimSpace(cfg.Baishun.LuckyGiftURL), AppChannel: strings.TrimSpace(cfg.Baishun.AppChannel), AppKey: strings.TrimSpace(cfg.Baishun.AppKey), } + if account.URL == "" { + account.URL = strings.TrimSpace(cfg.Baishun.PlatformBaseURL) + } if cfg.Baishun.AppID > 0 { account.AppID = strconv.FormatInt(cfg.Baishun.AppID, 10) } @@ -93,7 +96,9 @@ func defaultLuckyGiftRuntimeAccount(cfg config.Config) luckyGiftRuntimeAccount { } func applyLuckyGiftRuntimeAccount(base luckyGiftRuntimeAccount, row model.BaishunProviderConfig) luckyGiftRuntimeAccount { - if strings.TrimSpace(row.PlatformBaseURL) != "" { + if strings.TrimSpace(row.LuckyGiftURL) != "" { + base.URL = strings.TrimSpace(row.LuckyGiftURL) + } else if strings.TrimSpace(row.PlatformBaseURL) != "" { base.URL = strings.TrimSpace(row.PlatformBaseURL) } if row.AppID > 0 { diff --git a/internal/service/luckygift/runtime_config_test.go b/internal/service/luckygift/runtime_config_test.go index 4975f45..49343a2 100644 --- a/internal/service/luckygift/runtime_config_test.go +++ b/internal/service/luckygift/runtime_config_test.go @@ -49,12 +49,13 @@ func TestApplyLuckyGiftRuntimeAccountUsesProviderConfigRow(t *testing.T) { AppKey: "fallback-app-key", }, model.BaishunProviderConfig{ PlatformBaseURL: "https://provider.example.com", + LuckyGiftURL: "https://lucky.example.com/lucky_gift/start_game", AppID: 4581045902, AppChannel: "yumiparty", AppKey: "test-key", }) - if account.URL != "https://provider.example.com" { + if account.URL != "https://lucky.example.com/lucky_gift/start_game" { t.Fatalf("expected row url, got %q", account.URL) } if account.AppID != "4581045902" { @@ -72,13 +73,14 @@ func TestDefaultLuckyGiftRuntimeAccountUsesBaishunConfig(t *testing.T) { account := defaultLuckyGiftRuntimeAccount(config.Config{ Baishun: config.BaishunConfig{ PlatformBaseURL: "https://provider.example.com", + LuckyGiftURL: "https://lucky.example.com/lucky_gift/start_game", AppID: 7485318192, AppChannel: "yumiparty", AppKey: "shared-key", }, }) - if account.URL != "https://provider.example.com" { + if account.URL != "https://lucky.example.com/lucky_gift/start_game" { t.Fatalf("expected baishun platform base url, got %q", account.URL) } if account.AppID != "7485318192" { @@ -120,6 +122,7 @@ func TestResolveProviderConfigUsesActiveBaishunProfile(t *testing.T) { Profile: "PROD", Active: false, PlatformBaseURL: "https://prod.example.com", + LuckyGiftURL: "https://prod-lucky.example.com/lucky_gift/start_game", AppID: 222, AppChannel: "prod", AppKey: "prod-key", @@ -132,6 +135,7 @@ func TestResolveProviderConfigUsesActiveBaishunProfile(t *testing.T) { Profile: "TEST", Active: true, PlatformBaseURL: "https://test.example.com", + LuckyGiftURL: "https://test-lucky.example.com/lucky_gift/start_game", AppID: 333, AppChannel: "test", AppKey: "test-key", @@ -153,7 +157,7 @@ func TestResolveProviderConfigUsesActiveBaishunProfile(t *testing.T) { if err != nil { t.Fatalf("resolve lucky gift endpoint: %v", err) } - if endpoint != "https://test.example.com/lucky_gift/start_game" { + if endpoint != "https://test-lucky.example.com/lucky_gift/start_game" { t.Fatalf("endpoint = %q, want active test endpoint", endpoint) } if resolved.AppID != "333" || resolved.AppChannel != "test" || resolved.AppKey != "test-key" { diff --git a/migrations/007_baishun_provider_config.sql b/migrations/007_baishun_provider_config.sql index e1f7f22..1922968 100644 --- a/migrations/007_baishun_provider_config.sql +++ b/migrations/007_baishun_provider_config.sql @@ -4,6 +4,8 @@ CREATE TABLE IF NOT EXISTS baishun_provider_config ( profile VARCHAR(32) NOT NULL DEFAULT 'PROD', active TINYINT(1) NOT NULL DEFAULT 1, platform_base_url VARCHAR(1024) NOT NULL, + game_list_url VARCHAR(1024) NOT NULL DEFAULT '', + lucky_gift_url VARCHAR(1024) NOT NULL DEFAULT '', app_id BIGINT NOT NULL, app_name VARCHAR(128) DEFAULT NULL, app_channel VARCHAR(64) NOT NULL, diff --git a/migrations/010_baishun_game_list_url.sql b/migrations/010_baishun_game_list_url.sql new file mode 100644 index 0000000..7495a3f --- /dev/null +++ b/migrations/010_baishun_game_list_url.sql @@ -0,0 +1,20 @@ +SET @current_schema := DATABASE(); + +SET @add_provider_game_list_url_sql := IF( + NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = @current_schema + AND table_name = 'baishun_provider_config' + AND column_name = 'game_list_url' + ), + 'ALTER TABLE `baishun_provider_config` ADD COLUMN `game_list_url` varchar(1024) NOT NULL DEFAULT '''' AFTER `platform_base_url`', + 'SELECT 1' +); +PREPARE add_provider_game_list_url_stmt FROM @add_provider_game_list_url_sql; +EXECUTE add_provider_game_list_url_stmt; +DEALLOCATE PREPARE add_provider_game_list_url_stmt; + +UPDATE `baishun_provider_config` +SET `game_list_url` = CONCAT(TRIM(TRAILING '/' FROM `platform_base_url`), '/v1/api/gamelist') +WHERE COALESCE(TRIM(`game_list_url`), '') = '' + AND COALESCE(TRIM(`platform_base_url`), '') <> ''; diff --git a/migrations/011_baishun_lucky_gift_url.sql b/migrations/011_baishun_lucky_gift_url.sql new file mode 100644 index 0000000..f035bd7 --- /dev/null +++ b/migrations/011_baishun_lucky_gift_url.sql @@ -0,0 +1,20 @@ +SET @current_schema := DATABASE(); + +SET @add_provider_lucky_gift_url_sql := IF( + NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = @current_schema + AND table_name = 'baishun_provider_config' + AND column_name = 'lucky_gift_url' + ), + 'ALTER TABLE `baishun_provider_config` ADD COLUMN `lucky_gift_url` varchar(1024) NOT NULL DEFAULT '''' AFTER `game_list_url`', + 'SELECT 1' +); +PREPARE add_provider_lucky_gift_url_stmt FROM @add_provider_lucky_gift_url_sql; +EXECUTE add_provider_lucky_gift_url_stmt; +DEALLOCATE PREPARE add_provider_lucky_gift_url_stmt; + +UPDATE `baishun_provider_config` +SET `lucky_gift_url` = CONCAT(TRIM(TRAILING '/' FROM `platform_base_url`), '/lucky_gift/start_game') +WHERE COALESCE(TRIM(`lucky_gift_url`), '') = '' + AND COALESCE(TRIM(`platform_base_url`), '') <> '';