2026-05-23 12:27:44 +08:00

201 lines
6.7 KiB
Go

package storage
import (
"context"
"database/sql"
"strconv"
"strings"
)
func (r *MySQLRepository) ResolveWalletGame(ctx context.Context, sysOrigin string, eventType string, eventID string) (string, string, string, error) {
if provider, gameID, fallback, ok := directGameMeta(eventType); ok {
gameName, err := r.lookupGameName(ctx, sysOrigin, provider, gameID)
if gameName == "" {
gameName = fallback
}
return provider, gameID, gameName, err
}
if provider, gameID, gameName, ok, err := r.resolveGameOpenByWalletEvent(ctx, sysOrigin, eventType, eventID); ok || err != nil {
return provider, gameID, gameName, err
}
if provider, gameID, gameName, ok, err := r.resolveBaishunByWalletEvent(ctx, sysOrigin, eventID); ok || err != nil {
return provider, gameID, gameName, err
}
provider, gameID, fallback := fallbackGameMeta(eventType)
gameName, err := r.lookupGameName(ctx, sysOrigin, provider, gameID)
if err != nil {
return provider, gameID, fallback, err
}
if gameName == "" {
gameName = fallback
}
return provider, gameID, gameName, nil
}
func (r *MySQLRepository) resolveBaishunByWalletEvent(ctx context.Context, sysOrigin string, eventID string) (string, string, string, bool, error) {
if strings.TrimSpace(eventID) == "" {
return "", "", "", false, nil
}
var vendorID int64
err := r.db.QueryRowContext(ctx, `
SELECT vendor_game_id
FROM baishun_order_idempotency
WHERE sys_origin = ? AND wallet_event_id = ?
LIMIT 1
`, sysOrigin, eventID).Scan(&vendorID)
if err == sql.ErrNoRows {
return "", "", "", false, nil
}
if err != nil {
return "", "", "", false, err
}
gameID := strconv.FormatInt(vendorID, 10)
gameName, err := r.lookupGameName(ctx, sysOrigin, "BAISHUN", gameID)
if gameName == "" {
gameName = gameID
}
return "BAISHUN", gameID, gameName, true, err
}
func (r *MySQLRepository) resolveGameOpenByWalletEvent(ctx context.Context, sysOrigin string, eventType string, eventID string) (string, string, string, bool, error) {
orderID := strings.TrimPrefix(eventID, "GAME_OPEN:")
if orderID == eventID && !strings.HasPrefix(eventType, "GAME_OPEN_") {
return "", "", "", false, nil
}
if orderID != "" && orderID != eventID {
var gameID string
err := r.db.QueryRowContext(ctx, `
SELECT game_id
FROM game_open_callback_log
WHERE sys_origin = ? AND order_id = ?
LIMIT 1
`, sysOrigin, orderID).Scan(&gameID)
if err != nil && err != sql.ErrNoRows {
return "", "", "", false, err
}
if err == nil && strings.TrimSpace(gameID) != "" {
gameName, err := r.lookupGameName(ctx, sysOrigin, "GAME_OPEN", gameID)
if gameName == "" {
gameName = gameID
}
return "GAME_OPEN", gameID, gameName, true, err
}
}
if strings.HasPrefix(eventType, "GAME_OPEN_") {
gameID := strings.TrimPrefix(eventType, "GAME_OPEN_")
gameName, err := r.lookupGameName(ctx, sysOrigin, "GAME_OPEN", gameID)
if gameName == "" {
gameName = gameID
}
return "GAME_OPEN", gameID, gameName, true, err
}
return "", "", "", false, nil
}
func (r *MySQLRepository) lookupGameName(ctx context.Context, sysOrigin string, provider string, gameID string) (string, error) {
cacheKey := strings.Join([]string{sysOrigin, provider, gameID}, "|")
if name, ok := r.gameNameCache.Get(cacheKey); ok {
return name, nil
}
var name string
if provider == "BAISHUN" {
err := r.db.QueryRowContext(ctx, `
SELECT name
FROM baishun_game_catalog
WHERE sys_origin = ? AND profile = 'PROD' AND vendor_game_id = ?
LIMIT 1
`, sysOrigin, gameID).Scan(&name)
if err == nil || err != sql.ErrNoRows {
if err == nil {
r.gameNameCache.Set(cacheKey, name)
}
return name, err
}
}
err := r.db.QueryRowContext(ctx, `
SELECT name
FROM lingxian_game_catalog
WHERE sys_origin = ? AND profile = 'PROD' AND vendor_game_id = ?
LIMIT 1
`, sysOrigin, gameID).Scan(&name)
if err == nil || err != sql.ErrNoRows {
if err == nil {
r.gameNameCache.Set(cacheKey, name)
}
return name, err
}
err = r.db.QueryRowContext(ctx, `
SELECT name
FROM sys_game_list_config
WHERE sys_origin = ? AND game_id = ?
LIMIT 1
`, sysOrigin, gameID).Scan(&name)
if err == sql.ErrNoRows {
r.gameNameCache.Set(cacheKey, "")
return "", nil
}
if err == nil {
r.gameNameCache.Set(cacheKey, name)
}
return name, err
}
func directGameMeta(eventType string) (string, string, string, bool) {
switch {
case strings.HasPrefix(eventType, "BAISHUN_GAME_"),
strings.HasPrefix(eventType, "GAME_OPEN_"),
strings.HasPrefix(eventType, "YOMI_GAME_"),
strings.HasPrefix(eventType, "HKYS_GAME_"),
strings.HasPrefix(eventType, "HOT_GAME_"),
in(eventType, "FRUIT_GAME", "DOUBLE_LAYER_FRUIT", "GAME_FRUIT_BET", "GAME_FRUIT_AWARD",
"LUDO_GAME", "LUDO_VICTORY", "LUDO_REFUND", "GAME_LUDO_REFUND",
"GAME_BARBECUE", "DOUBLE_LAYER_BARBECUE", "GAME_SLOT_MACHINE", "TURNTABLE_GAME",
"GAME_BURST_CRYSTAL", "TEEN_PATTI", "BET_TEEN_PATTI", "LOTTERY_NUMBER_BET", "LOTTERY_REWARD"):
provider, gameID, fallback := fallbackGameMeta(eventType)
return provider, gameID, fallback, true
default:
return "", "", "", false
}
}
func fallbackGameMeta(eventType string) (string, string, string) {
switch {
case strings.HasPrefix(eventType, "BAISHUN_GAME_"):
return "BAISHUN", strings.TrimPrefix(eventType, "BAISHUN_GAME_"), strings.TrimPrefix(eventType, "BAISHUN_GAME_")
case strings.HasPrefix(eventType, "YOMI_GAME_"):
return "YOMI", strings.TrimPrefix(eventType, "YOMI_GAME_"), strings.TrimPrefix(eventType, "YOMI_GAME_")
case strings.HasPrefix(eventType, "HKYS_GAME_"):
return "HKYS", strings.TrimPrefix(eventType, "HKYS_GAME_"), strings.TrimPrefix(eventType, "HKYS_GAME_")
case strings.HasPrefix(eventType, "HOT_GAME_"):
return "HOT", strings.TrimPrefix(eventType, "HOT_GAME_"), strings.TrimPrefix(eventType, "HOT_GAME_")
case in(eventType, "FRUIT_GAME", "DOUBLE_LAYER_FRUIT", "GAME_FRUIT_BET", "GAME_FRUIT_AWARD"):
return "INTERNAL", "FRUIT_GAME", "Fruit Game"
case in(eventType, "LUDO_GAME", "LUDO_VICTORY", "LUDO_REFUND", "GAME_LUDO_REFUND"):
return "INTERNAL", "LUDO_GAME", "Ludo Game"
case in(eventType, "GAME_BARBECUE", "DOUBLE_LAYER_BARBECUE"):
return "INTERNAL", "BARBECUE_GAME", "Barbecue Game"
case eventType == "GAME_SLOT_MACHINE":
return "INTERNAL", "SLOT_MACHINE", "Slot Machine"
case eventType == "TURNTABLE_GAME":
return "INTERNAL", "TURNTABLE_GAME", "Turntable Game"
case eventType == "GAME_BURST_CRYSTAL":
return "INTERNAL", "BURST_CRYSTAL", "Burst Crystal"
case in(eventType, "TEEN_PATTI", "BET_TEEN_PATTI"):
return "INTERNAL", "TEEN_PATTI", "Teen Patti"
case in(eventType, "LOTTERY_NUMBER_BET", "LOTTERY_REWARD"):
return "INTERNAL", "LOTTERY_NUMBER", "Lottery Number"
default:
return "INTERNAL", eventType, eventType
}
}
func in(value string, candidates ...string) bool {
for _, candidate := range candidates {
if value == candidate {
return true
}
}
return false
}