接入小游
This commit is contained in:
parent
0bb719d1b8
commit
b2362eefe8
@ -28,6 +28,7 @@ const (
|
||||
adapterZeeOneV1 = "zeeone_v1"
|
||||
adapterVivaGamesV1 = "vivagames_v1"
|
||||
adapterReyouV1 = "reyou_v1"
|
||||
adapterYomiV4 = "yomi_v4"
|
||||
defaultGameStatus = "disabled"
|
||||
defaultGameCategory = "casino"
|
||||
defaultLaunchMode = "full_screen"
|
||||
@ -137,6 +138,8 @@ func fetchProviderGameSyncPlan(ctx context.Context, platform *gamev1.GamePlatfor
|
||||
return fetchVivaGamesGameSyncPlan(platform, req)
|
||||
case adapterReyouV1:
|
||||
return fetchReyouGameSyncPlan(platform, req)
|
||||
case adapterYomiV4:
|
||||
return fetchYomiGameSyncPlan(platform, req)
|
||||
default:
|
||||
// 不在配置文件写死游戏:每家厂商新增“列表 API”时只加一个 adapter fetcher,后台入口保持不变。
|
||||
return providerGameSyncPlan{}, fmt.Errorf("当前适配器暂未接入厂商游戏列表 API: %s", platform.GetAdapterType())
|
||||
@ -199,6 +202,14 @@ type reyouSyncConfig struct {
|
||||
GameCovers map[string]string `json:"game_covers"`
|
||||
}
|
||||
|
||||
type yomiSyncConfig struct {
|
||||
// Yomi V4 文档只提供启动鉴权地址,没有游戏列表 API;后台通过 game_names 维护截图里的 gameUid 清单。
|
||||
GameNames map[string]string `json:"game_names"`
|
||||
GameURLs map[string]string `json:"game_urls"`
|
||||
GameIcons map[string]string `json:"game_icons"`
|
||||
GameCovers map[string]string `json:"game_covers"`
|
||||
}
|
||||
|
||||
func fetchZeeOneGameSyncPlan(platform *gamev1.GamePlatform, req syncGamesRequest) (providerGameSyncPlan, error) {
|
||||
config, err := decodeZeeOneSyncConfig(platform.GetAdapterConfigJson())
|
||||
if err != nil {
|
||||
@ -355,6 +366,21 @@ func fetchReyouGameSyncPlan(platform *gamev1.GamePlatform, req syncGamesRequest)
|
||||
}, nil
|
||||
}
|
||||
|
||||
func fetchYomiGameSyncPlan(platform *gamev1.GamePlatform, req syncGamesRequest) (providerGameSyncPlan, error) {
|
||||
config, err := decodeYomiSyncConfig(platform.GetAdapterConfigJson())
|
||||
if err != nil {
|
||||
return providerGameSyncPlan{}, err
|
||||
}
|
||||
games, gameURLs := yomiCatalogItems(platform.GetPlatformCode(), config, req)
|
||||
if len(games) == 0 {
|
||||
return providerGameSyncPlan{}, fmt.Errorf("小游游戏列表为空:请在 adapterConfigJson.game_names 配置游戏 ID 到名称的映射")
|
||||
}
|
||||
return providerGameSyncPlan{
|
||||
Games: games,
|
||||
GameURLs: gameURLs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func decodeReyouSyncConfig(raw string) (reyouSyncConfig, error) {
|
||||
if strings.TrimSpace(raw) == "" {
|
||||
return reyouSyncConfig{}, nil
|
||||
@ -366,6 +392,17 @@ func decodeReyouSyncConfig(raw string) (reyouSyncConfig, error) {
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func decodeYomiSyncConfig(raw string) (yomiSyncConfig, error) {
|
||||
if strings.TrimSpace(raw) == "" {
|
||||
return yomiSyncConfig{}, nil
|
||||
}
|
||||
var config yomiSyncConfig
|
||||
if err := json.Unmarshal([]byte(raw), &config); err != nil {
|
||||
return yomiSyncConfig{}, fmt.Errorf("小游适配器配置 JSON 不合法")
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func reyouCatalogItems(platformCode string, config reyouSyncConfig, req syncGamesRequest) ([]catalogRequest, map[string]string) {
|
||||
keys := make([]string, 0, len(config.GameURLs))
|
||||
for providerGameID, launchURL := range config.GameURLs {
|
||||
@ -401,6 +438,59 @@ func reyouCatalogItems(platformCode string, config reyouSyncConfig, req syncGame
|
||||
return items, gameURLs
|
||||
}
|
||||
|
||||
func yomiCatalogItems(platformCode string, config yomiSyncConfig, req syncGamesRequest) ([]catalogRequest, map[string]string) {
|
||||
keys := make([]string, 0, len(config.GameNames)+len(config.GameURLs))
|
||||
seen := make(map[string]struct{}, len(config.GameNames)+len(config.GameURLs))
|
||||
// 小游没有列表 API,game_names 是本地候选游戏的事实来源;game_urls 只用于后台预览,不参与启动拼参。
|
||||
for providerGameID := range config.GameNames {
|
||||
key := strings.TrimSpace(providerGameID)
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
seen[key] = struct{}{}
|
||||
keys = append(keys, key)
|
||||
}
|
||||
for providerGameID, launchURL := range config.GameURLs {
|
||||
key := strings.TrimSpace(providerGameID)
|
||||
if key == "" || strings.TrimSpace(launchURL) == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[key]; ok {
|
||||
continue
|
||||
}
|
||||
seen[key] = struct{}{}
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
items := make([]catalogRequest, 0, len(keys))
|
||||
gameURLs := make(map[string]string, len(keys))
|
||||
for index, providerGameID := range keys {
|
||||
launchURL := strings.TrimSpace(config.GameURLs[providerGameID])
|
||||
if launchURL != "" {
|
||||
gameURLs[providerGameID] = launchURL
|
||||
}
|
||||
name := firstNonEmpty(config.GameNames[providerGameID], zeeoneGameNameFromURL(launchURL), providerGameID)
|
||||
iconURL := strings.TrimSpace(config.GameIcons[providerGameID])
|
||||
coverURL := firstNonEmpty(config.GameCovers[providerGameID], iconURL)
|
||||
items = append(items, catalogRequest{
|
||||
GameID: stableGameID(platformCode, providerGameID),
|
||||
PlatformCode: strings.TrimSpace(platformCode),
|
||||
ProviderGameID: providerGameID,
|
||||
GameName: name,
|
||||
Category: defaulted(req.Category, defaultGameCategory),
|
||||
IconURL: iconURL,
|
||||
CoverURL: coverURL,
|
||||
LaunchMode: defaulted(req.LaunchMode, defaultLaunchMode),
|
||||
Orientation: defaultOrientation,
|
||||
MinCoin: req.MinCoin,
|
||||
Status: defaulted(req.Status, defaultGameStatus),
|
||||
SortOrder: int32((index + 1) * 10),
|
||||
Tags: compactTags(append([]string{strings.TrimSpace(platformCode), adapterYomiV4}, req.Tags...)),
|
||||
})
|
||||
}
|
||||
return items, gameURLs
|
||||
}
|
||||
|
||||
func titleGameName(value string) string {
|
||||
tokens := splitGameNameTokens(value)
|
||||
if len(tokens) == 0 {
|
||||
|
||||
@ -167,6 +167,42 @@ func TestFetchReyouGameSyncPlanReadsConfiguredGameURLs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchYomiGameSyncPlanReadsConfiguredGameNames(t *testing.T) {
|
||||
plan, err := fetchProviderGameSyncPlan(t.Context(), &gamev1.GamePlatform{
|
||||
PlatformCode: "yomi",
|
||||
AdapterType: adapterYomiV4,
|
||||
AdapterConfigJson: `{
|
||||
"game_names": {
|
||||
"481": "MahjongWays",
|
||||
"480": "ChickenPlinko"
|
||||
},
|
||||
"game_urls": {
|
||||
"481": "https://api-testv2.yomigame.games/gate/gateway/auth"
|
||||
}
|
||||
}`,
|
||||
}, syncGamesRequest{Status: "active"})
|
||||
if err != nil {
|
||||
t.Fatalf("fetchProviderGameSyncPlan failed: %v", err)
|
||||
}
|
||||
if len(plan.Games) != 2 {
|
||||
t.Fatalf("games len = %d, want 2", len(plan.Games))
|
||||
}
|
||||
first := plan.Games[0]
|
||||
if first.GameID != "yomi_480" || first.ProviderGameID != "480" || first.GameName != "ChickenPlinko" {
|
||||
t.Fatalf("first yomi game mismatch: %+v", first)
|
||||
}
|
||||
second := plan.Games[1]
|
||||
if second.GameID != "yomi_481" || second.ProviderGameID != "481" || second.GameName != "MahjongWays" {
|
||||
t.Fatalf("second yomi game mismatch: %+v", second)
|
||||
}
|
||||
if plan.GameURLs["481"] != "https://api-testv2.yomigame.games/gate/gateway/auth" {
|
||||
t.Fatalf("game url mismatch: %+v", plan.GameURLs)
|
||||
}
|
||||
if first.Status != "active" || first.LaunchMode != "full_screen" || first.Orientation != "portrait" {
|
||||
t.Fatalf("default fields mismatch: %+v", first)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectProviderGamesKeepsOnlySelectedIDs(t *testing.T) {
|
||||
games := []catalogRequest{
|
||||
{ProviderGameID: "1001", GameName: "one"},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user