接入小游
This commit is contained in:
parent
0bb719d1b8
commit
b2362eefe8
@ -28,6 +28,7 @@ const (
|
|||||||
adapterZeeOneV1 = "zeeone_v1"
|
adapterZeeOneV1 = "zeeone_v1"
|
||||||
adapterVivaGamesV1 = "vivagames_v1"
|
adapterVivaGamesV1 = "vivagames_v1"
|
||||||
adapterReyouV1 = "reyou_v1"
|
adapterReyouV1 = "reyou_v1"
|
||||||
|
adapterYomiV4 = "yomi_v4"
|
||||||
defaultGameStatus = "disabled"
|
defaultGameStatus = "disabled"
|
||||||
defaultGameCategory = "casino"
|
defaultGameCategory = "casino"
|
||||||
defaultLaunchMode = "full_screen"
|
defaultLaunchMode = "full_screen"
|
||||||
@ -137,6 +138,8 @@ func fetchProviderGameSyncPlan(ctx context.Context, platform *gamev1.GamePlatfor
|
|||||||
return fetchVivaGamesGameSyncPlan(platform, req)
|
return fetchVivaGamesGameSyncPlan(platform, req)
|
||||||
case adapterReyouV1:
|
case adapterReyouV1:
|
||||||
return fetchReyouGameSyncPlan(platform, req)
|
return fetchReyouGameSyncPlan(platform, req)
|
||||||
|
case adapterYomiV4:
|
||||||
|
return fetchYomiGameSyncPlan(platform, req)
|
||||||
default:
|
default:
|
||||||
// 不在配置文件写死游戏:每家厂商新增“列表 API”时只加一个 adapter fetcher,后台入口保持不变。
|
// 不在配置文件写死游戏:每家厂商新增“列表 API”时只加一个 adapter fetcher,后台入口保持不变。
|
||||||
return providerGameSyncPlan{}, fmt.Errorf("当前适配器暂未接入厂商游戏列表 API: %s", platform.GetAdapterType())
|
return providerGameSyncPlan{}, fmt.Errorf("当前适配器暂未接入厂商游戏列表 API: %s", platform.GetAdapterType())
|
||||||
@ -199,6 +202,14 @@ type reyouSyncConfig struct {
|
|||||||
GameCovers map[string]string `json:"game_covers"`
|
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) {
|
func fetchZeeOneGameSyncPlan(platform *gamev1.GamePlatform, req syncGamesRequest) (providerGameSyncPlan, error) {
|
||||||
config, err := decodeZeeOneSyncConfig(platform.GetAdapterConfigJson())
|
config, err := decodeZeeOneSyncConfig(platform.GetAdapterConfigJson())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -355,6 +366,21 @@ func fetchReyouGameSyncPlan(platform *gamev1.GamePlatform, req syncGamesRequest)
|
|||||||
}, nil
|
}, 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) {
|
func decodeReyouSyncConfig(raw string) (reyouSyncConfig, error) {
|
||||||
if strings.TrimSpace(raw) == "" {
|
if strings.TrimSpace(raw) == "" {
|
||||||
return reyouSyncConfig{}, nil
|
return reyouSyncConfig{}, nil
|
||||||
@ -366,6 +392,17 @@ func decodeReyouSyncConfig(raw string) (reyouSyncConfig, error) {
|
|||||||
return config, nil
|
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) {
|
func reyouCatalogItems(platformCode string, config reyouSyncConfig, req syncGamesRequest) ([]catalogRequest, map[string]string) {
|
||||||
keys := make([]string, 0, len(config.GameURLs))
|
keys := make([]string, 0, len(config.GameURLs))
|
||||||
for providerGameID, launchURL := range config.GameURLs {
|
for providerGameID, launchURL := range config.GameURLs {
|
||||||
@ -401,6 +438,59 @@ func reyouCatalogItems(platformCode string, config reyouSyncConfig, req syncGame
|
|||||||
return items, gameURLs
|
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 {
|
func titleGameName(value string) string {
|
||||||
tokens := splitGameNameTokens(value)
|
tokens := splitGameNameTokens(value)
|
||||||
if len(tokens) == 0 {
|
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) {
|
func TestSelectProviderGamesKeepsOnlySelectedIDs(t *testing.T) {
|
||||||
games := []catalogRequest{
|
games := []catalogRequest{
|
||||||
{ProviderGameID: "1001", GameName: "one"},
|
{ProviderGameID: "1001", GameName: "one"},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user