diff --git a/internal/router/game_provider_routes.go b/internal/router/game_provider_routes.go index 398ab55..94e5831 100644 --- a/internal/router/game_provider_routes.go +++ b/internal/router/game_provider_routes.go @@ -189,6 +189,10 @@ func registerGameProviderRoutes(engine *gin.Engine, javaClient authGateway, regi func gameListAccess(c *gin.Context, visibility *gameprovider.VisibilityPolicy) (common.AuthUser, bool, bool) { user := mustAuthUser(c) + // iOS 审核和上架场景需要隐藏游戏入口;这里放在统一列表门禁最前面,避免继续请求 Java 区域/等级接口或 provider SQL。 + if isIOSGameListClient(c) { + return user, false, true + } if gameprovider.IsEmptyGameListUser(user.UserID) { return user, false, true } @@ -206,6 +210,10 @@ func gameListAccess(c *gin.Context, visibility *gameprovider.VisibilityPolicy) ( return user, result.Allow, true } +func isIOSGameListClient(c *gin.Context) bool { + return strings.EqualFold(strings.TrimSpace(c.GetHeader("Req-Client")), "ios") +} + func resolveGameProvider(c *gin.Context, registry *gameprovider.Registry) (gameprovider.Provider, bool) { provider, err := registry.Resolve(c.Param("provider")) if err != nil { diff --git a/internal/router/game_provider_routes_test.go b/internal/router/game_provider_routes_test.go index c206864..f4dd305 100644 --- a/internal/router/game_provider_routes_test.go +++ b/internal/router/game_provider_routes_test.go @@ -228,6 +228,108 @@ func TestGameProviderRoutesReturnEmptyWhenVisibilityPolicyDenies(t *testing.T) { } } +func TestGameProviderRoutesReturnEmptyRoomListForIOSClient(t *testing.T) { + gin.SetMode(gin.TestMode) + provider := &routeStubProvider{} + engine := gin.New() + registerGameProviderRoutes( + engine, + routeStubAuthGateway{}, + gameprovider.NewRegistry(provider), + nil, + ) + + req := httptest.NewRequest(http.MethodGet, "/app/game/room/list?roomId=1", nil) + req.Header.Set("Authorization", "Bearer token") + req.Header.Set("Req-Client", "ios") + rec := httptest.NewRecorder() + engine.ServeHTTP(rec, req) + + if rec.Code != http.StatusOK { + t.Fatalf("status = %d, want %d: %s", rec.Code, http.StatusOK, rec.Body.String()) + } + var payload struct { + Body struct { + Items []publicRoomGameItem `json:"items"` + } `json:"body"` + } + if err := json.Unmarshal(rec.Body.Bytes(), &payload); err != nil { + t.Fatalf("response json error = %v: %s", err, rec.Body.String()) + } + if len(payload.Body.Items) != 0 { + t.Fatalf("items = %d, want 0", len(payload.Body.Items)) + } + if provider.listRoomCalls != 0 { + t.Fatalf("provider list calls = %d, want 0", provider.listRoomCalls) + } +} + +func TestGameProviderRoutesReturnEmptyShortcutForIOSClient(t *testing.T) { + gin.SetMode(gin.TestMode) + provider := &routeStubProvider{} + engine := gin.New() + registerGameProviderRoutes( + engine, + routeStubAuthGateway{}, + gameprovider.NewRegistry(provider), + nil, + ) + + req := httptest.NewRequest(http.MethodGet, "/app/game/room/shortcut?roomId=1", nil) + req.Header.Set("Authorization", "Bearer token") + req.Header.Set("Req-Client", " iOS ") + rec := httptest.NewRecorder() + engine.ServeHTTP(rec, req) + + if rec.Code != http.StatusOK { + t.Fatalf("status = %d, want %d: %s", rec.Code, http.StatusOK, rec.Body.String()) + } + var payload struct { + Body []publicRoomGameItem `json:"body"` + } + if err := json.Unmarshal(rec.Body.Bytes(), &payload); err != nil { + t.Fatalf("response json error = %v: %s", err, rec.Body.String()) + } + if len(payload.Body) != 0 { + t.Fatalf("items = %d, want 0", len(payload.Body)) + } + if provider.shortcutCalls != 0 { + t.Fatalf("provider shortcut calls = %d, want 0", provider.shortcutCalls) + } +} + +func TestGameProviderRoutesReturnEmptyProvidersForIOSClient(t *testing.T) { + gin.SetMode(gin.TestMode) + engine := gin.New() + registerGameProviderRoutes( + engine, + routeStubAuthGateway{}, + gameprovider.NewRegistry(&routeStubProvider{}), + nil, + ) + + req := httptest.NewRequest(http.MethodGet, "/app/game/providers", nil) + req.Header.Set("Authorization", "Bearer token") + req.Header.Set("Req-Client", "IOS") + rec := httptest.NewRecorder() + engine.ServeHTTP(rec, req) + + if rec.Code != http.StatusOK { + t.Fatalf("status = %d, want %d: %s", rec.Code, http.StatusOK, rec.Body.String()) + } + var payload struct { + Body struct { + Items []gameprovider.ProviderSummary `json:"items"` + } `json:"body"` + } + if err := json.Unmarshal(rec.Body.Bytes(), &payload); err != nil { + t.Fatalf("response json error = %v: %s", err, rec.Body.String()) + } + if len(payload.Body.Items) != 0 { + t.Fatalf("providers = %d, want 0", len(payload.Body.Items)) + } +} + func TestGameProviderRoutesReturnProvidersWhenVisibilityPolicyAllows(t *testing.T) { gin.SetMode(gin.TestMode) engine := gin.New() @@ -347,6 +449,7 @@ func (s routeStubIPCountryResolver) CountryCode(context.Context, string) (string type routeStubProvider struct { listRoomCalls int + shortcutCalls int } func (p *routeStubProvider) Key() string { return "TEST" } @@ -358,6 +461,7 @@ func (p *routeStubProvider) SupportsLaunch(context.Context, gameprovider.AuthUse } func (p *routeStubProvider) ListShortcutGames(context.Context, gameprovider.AuthUser, string) ([]gameprovider.RoomGameListItem, error) { + p.shortcutCalls++ return []gameprovider.RoomGameListItem{{ID: 1, GameID: "test_1", Provider: "TEST", ProviderGameID: "1", Name: "Test Game"}}, nil }