496 lines
19 KiB
Go
496 lines
19 KiB
Go
package grpc
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"time"
|
|
|
|
gamev1 "hyapp.local/api/proto/game/v1"
|
|
"hyapp/pkg/appcode"
|
|
"hyapp/pkg/xerr"
|
|
gamedomain "hyapp/services/game-service/internal/domain/game"
|
|
gameservice "hyapp/services/game-service/internal/service/game"
|
|
)
|
|
|
|
// Server 把 game-service 用例层适配为 gRPC 契约。
|
|
type Server struct {
|
|
gamev1.UnimplementedGameAppServiceServer
|
|
gamev1.UnimplementedGameCallbackServiceServer
|
|
gamev1.UnimplementedGameAdminServiceServer
|
|
gamev1.UnimplementedGameCronServiceServer
|
|
|
|
svc *gameservice.Service
|
|
}
|
|
|
|
func NewServer(svc *gameservice.Service) *Server {
|
|
return &Server{svc: svc}
|
|
}
|
|
|
|
func (s *Server) ListGames(ctx context.Context, req *gamev1.ListGamesRequest) (*gamev1.ListGamesResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
items, serverTimeMS, err := s.svc.ListGames(ctx, gameservice.ListGamesQuery{
|
|
AppCode: req.GetMeta().GetAppCode(),
|
|
UserID: req.GetUserId(),
|
|
Scene: req.GetScene(),
|
|
RoomID: req.GetRoomId(),
|
|
RegionID: req.GetRegionId(),
|
|
Language: req.GetLanguage(),
|
|
ClientPlatform: req.GetClientPlatform(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
resp := &gamev1.ListGamesResponse{ServerTimeMs: serverTimeMS, Games: make([]*gamev1.AppGame, 0, len(items))}
|
|
for _, item := range items {
|
|
resp.Games = append(resp.Games, appGameToProto(item))
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (s *Server) ListRecentGames(ctx context.Context, req *gamev1.ListRecentGamesRequest) (*gamev1.ListGamesResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
items, serverTimeMS, err := s.svc.ListRecentGames(ctx, gameservice.ListRecentGamesQuery{
|
|
AppCode: req.GetMeta().GetAppCode(),
|
|
UserID: req.GetUserId(),
|
|
Scene: req.GetScene(),
|
|
RoomID: req.GetRoomId(),
|
|
RegionID: req.GetRegionId(),
|
|
Language: req.GetLanguage(),
|
|
ClientPlatform: req.GetClientPlatform(),
|
|
PageSize: req.GetPageSize(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
resp := &gamev1.ListGamesResponse{ServerTimeMs: serverTimeMS, Games: make([]*gamev1.AppGame, 0, len(items))}
|
|
for _, item := range items {
|
|
resp.Games = append(resp.Games, appGameToProto(item))
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (s *Server) GetBridgeScript(ctx context.Context, req *gamev1.GetBridgeScriptRequest) (*gamev1.GetBridgeScriptResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
result, err := s.svc.GetBridgeScript(ctx, req.GetMeta().GetAppCode())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &gamev1.GetBridgeScriptResponse{
|
|
Config: &gamev1.GameBridgeScriptConfig{
|
|
BridgeScriptUrl: result.URL,
|
|
BridgeScriptVersion: result.Version,
|
|
BridgeScriptSha256: result.SHA256,
|
|
},
|
|
ServerTimeMs: result.ServerTimeMS,
|
|
}, nil
|
|
}
|
|
|
|
func (s *Server) LaunchGame(ctx context.Context, req *gamev1.LaunchGameRequest) (*gamev1.LaunchGameResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
result, err := s.svc.LaunchGame(ctx, gameservice.LaunchCommand{
|
|
AppCode: req.GetMeta().GetAppCode(),
|
|
RequestID: req.GetMeta().GetRequestId(),
|
|
UserID: req.GetUserId(),
|
|
DisplayUserID: req.GetDisplayUserId(),
|
|
GameID: req.GetGameId(),
|
|
Scene: req.GetScene(),
|
|
RoomID: req.GetRoomId(),
|
|
AccessToken: req.GetAccessToken(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &gamev1.LaunchGameResponse{
|
|
SessionId: result.SessionID,
|
|
LaunchUrl: result.LaunchURL,
|
|
ExpiresAtMs: result.ExpiresAtMS,
|
|
Orientation: result.Orientation,
|
|
SafeHeight: result.SafeHeight,
|
|
ServerTimeMs: result.ServerTimeMS,
|
|
}, nil
|
|
}
|
|
|
|
func (s *Server) HandleCallback(ctx context.Context, req *gamev1.CallbackRequest) (*gamev1.CallbackResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
raw, contentType, err := s.svc.HandleCallback(ctx, req)
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &gamev1.CallbackResponse{RawBody: raw, ContentType: contentType}, nil
|
|
}
|
|
|
|
// ProcessLevelEventOutboxBatch 只由 cron-service 调用,批量接管并投递游戏消耗等级事件。
|
|
func (s *Server) ProcessLevelEventOutboxBatch(ctx context.Context, req *gamev1.CronBatchRequest) (*gamev1.CronBatchResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
claimed, processed, success, failure, hasMore, err := s.svc.ProcessLevelEventOutboxBatch(ctx, req.GetRunId(), req.GetWorkerId(), int(req.GetBatchSize()), durationFromMillis(req.GetLockTtlMs()))
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &gamev1.CronBatchResponse{
|
|
ClaimedCount: claimed,
|
|
ProcessedCount: processed,
|
|
SuccessCount: success,
|
|
FailureCount: failure,
|
|
HasMore: hasMore,
|
|
}, nil
|
|
}
|
|
|
|
func (s *Server) ListPlatforms(ctx context.Context, req *gamev1.ListPlatformsRequest) (*gamev1.ListPlatformsResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
items, err := s.svcRepository().ListPlatforms(ctx, req.GetMeta().GetAppCode(), req.GetStatus())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
resp := &gamev1.ListPlatformsResponse{ServerTimeMs: time.Now().UnixMilli(), Platforms: make([]*gamev1.GamePlatform, 0, len(items))}
|
|
for _, item := range items {
|
|
resp.Platforms = append(resp.Platforms, platformToProto(item))
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (s *Server) UpsertPlatform(ctx context.Context, req *gamev1.UpsertPlatformRequest) (*gamev1.PlatformResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
platform := platformFromProto(req.GetPlatform())
|
|
platform.AppCode = req.GetMeta().GetAppCode()
|
|
normalized, err := normalizePlatform(platform)
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
saved, err := s.svcRepository().UpsertPlatform(ctx, normalized)
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &gamev1.PlatformResponse{Platform: platformToProto(saved), ServerTimeMs: time.Now().UnixMilli()}, nil
|
|
}
|
|
|
|
func (s *Server) ListCatalog(ctx context.Context, req *gamev1.ListCatalogRequest) (*gamev1.ListCatalogResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
items, next, err := s.svcRepository().ListCatalog(ctx, gameservice.ListCatalogQuery{
|
|
AppCode: req.GetMeta().GetAppCode(),
|
|
PlatformCode: req.GetPlatformCode(),
|
|
Status: req.GetStatus(),
|
|
PageSize: req.GetPageSize(),
|
|
Cursor: req.GetCursor(),
|
|
})
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
resp := &gamev1.ListCatalogResponse{NextCursor: next, ServerTimeMs: time.Now().UnixMilli(), Games: make([]*gamev1.GameCatalogItem, 0, len(items))}
|
|
for _, item := range items {
|
|
resp.Games = append(resp.Games, catalogToProto(item))
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
func (s *Server) UpsertCatalog(ctx context.Context, req *gamev1.UpsertCatalogRequest) (*gamev1.CatalogResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
item := catalogFromProto(req.GetGame())
|
|
item.AppCode = req.GetMeta().GetAppCode()
|
|
normalized, err := normalizeCatalog(item)
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
saved, err := s.svcRepository().UpsertCatalog(ctx, normalized)
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &gamev1.CatalogResponse{Game: catalogToProto(saved), ServerTimeMs: time.Now().UnixMilli()}, nil
|
|
}
|
|
|
|
func (s *Server) SetGameStatus(ctx context.Context, req *gamev1.SetGameStatusRequest) (*gamev1.CatalogResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
status := normalizeStatus(req.GetStatus())
|
|
if status == "" {
|
|
return nil, xerr.ToGRPCError(xerr.New(xerr.InvalidArgument, "status is invalid"))
|
|
}
|
|
item, err := s.svcRepository().SetGameStatus(ctx, req.GetMeta().GetAppCode(), req.GetGameId(), status, time.Now().UnixMilli())
|
|
if err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &gamev1.CatalogResponse{Game: catalogToProto(item), ServerTimeMs: time.Now().UnixMilli()}, nil
|
|
}
|
|
|
|
func (s *Server) DeleteCatalog(ctx context.Context, req *gamev1.DeleteCatalogRequest) (*gamev1.DeleteCatalogResponse, error) {
|
|
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
|
|
if err := s.svcRepository().DeleteCatalog(ctx, req.GetMeta().GetAppCode(), req.GetGameId()); err != nil {
|
|
return nil, xerr.ToGRPCError(err)
|
|
}
|
|
return &gamev1.DeleteCatalogResponse{ServerTimeMs: time.Now().UnixMilli()}, nil
|
|
}
|
|
|
|
func (s *Server) svcRepository() gameservice.Repository {
|
|
if s == nil || s.svc == nil || s.svc.Repository() == nil {
|
|
return unavailableRepository{}
|
|
}
|
|
return s.svc.Repository()
|
|
}
|
|
|
|
type unavailableRepository struct{}
|
|
|
|
func (unavailableRepository) Ping(context.Context) error {
|
|
return xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) ListGames(context.Context, gameservice.ListGamesQuery) ([]gamedomain.AppGame, error) {
|
|
return nil, xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) ListRecentGames(context.Context, gameservice.ListRecentGamesQuery) ([]gamedomain.AppGame, error) {
|
|
return nil, xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) GetLaunchableGame(context.Context, string, string) (gamedomain.LaunchableGame, error) {
|
|
return gamedomain.LaunchableGame{}, xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) GetPlatform(context.Context, string, string) (gamedomain.Platform, error) {
|
|
return gamedomain.Platform{}, xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) CreateLaunchSession(context.Context, gamedomain.LaunchSession) error {
|
|
return xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) GetLaunchSessionByToken(context.Context, string, string) (gamedomain.LaunchSession, error) {
|
|
return gamedomain.LaunchSession{}, xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) InsertCallbackLog(context.Context, gamedomain.CallbackLog) error {
|
|
return xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) CreateGameOrder(context.Context, gamedomain.GameOrder) (gamedomain.GameOrder, bool, error) {
|
|
return gamedomain.GameOrder{}, false, xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) MarkOrderSucceeded(context.Context, string, string, string, int64, int64) error {
|
|
return xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) MarkOrderFailed(context.Context, string, string, string, string, string, int64) error {
|
|
return xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) CreateRepairOrder(context.Context, gamedomain.RepairOrder) (gamedomain.RepairOrder, bool, error) {
|
|
return gamedomain.RepairOrder{}, false, xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) ClaimPendingLevelEvents(context.Context, string, int64, time.Duration, int) ([]gamedomain.LevelEventOutbox, error) {
|
|
return nil, xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) MarkLevelEventDelivered(context.Context, string, int64) error {
|
|
return xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) MarkLevelEventFailed(context.Context, string, string, int64, int64) error {
|
|
return xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) ListPlatforms(context.Context, string, string) ([]gamedomain.Platform, error) {
|
|
return nil, xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) UpsertPlatform(context.Context, gamedomain.Platform) (gamedomain.Platform, error) {
|
|
return gamedomain.Platform{}, xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) ListCatalog(context.Context, gameservice.ListCatalogQuery) ([]gamedomain.CatalogItem, string, error) {
|
|
return nil, "", xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) UpsertCatalog(context.Context, gamedomain.CatalogItem) (gamedomain.CatalogItem, error) {
|
|
return gamedomain.CatalogItem{}, xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) SetGameStatus(context.Context, string, string, string, int64) (gamedomain.CatalogItem, error) {
|
|
return gamedomain.CatalogItem{}, xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
func (unavailableRepository) DeleteCatalog(context.Context, string, string) error {
|
|
return xerr.New(xerr.Unavailable, "game repository is not configured")
|
|
}
|
|
|
|
func appGameToProto(item gamedomain.AppGame) *gamev1.AppGame {
|
|
return &gamev1.AppGame{
|
|
GameId: item.GameID,
|
|
PlatformCode: item.PlatformCode,
|
|
NameKey: item.NameKey,
|
|
Name: item.Name,
|
|
IconUrl: item.IconURL,
|
|
CoverUrl: item.CoverURL,
|
|
Category: item.Category,
|
|
LaunchMode: item.LaunchMode,
|
|
Orientation: item.Orientation,
|
|
SafeHeight: item.SafeHeight,
|
|
MinCoin: item.MinCoin,
|
|
Enabled: item.Enabled,
|
|
Maintenance: item.Maintenance,
|
|
SortOrder: item.SortOrder,
|
|
}
|
|
}
|
|
|
|
func platformToProto(item gamedomain.Platform) *gamev1.GamePlatform {
|
|
return &gamev1.GamePlatform{
|
|
AppCode: item.AppCode,
|
|
PlatformCode: item.PlatformCode,
|
|
PlatformName: item.PlatformName,
|
|
Status: item.Status,
|
|
ApiBaseUrl: item.APIBaseURL,
|
|
SortOrder: item.SortOrder,
|
|
CreatedAtMs: item.CreatedAtMS,
|
|
UpdatedAtMs: item.UpdatedAtMS,
|
|
AdapterType: item.AdapterType,
|
|
// admin 后台要把当前厂商 key 提供给运营/对接人员核对;更新接口仍以空值表示保留旧密钥。
|
|
CallbackSecret: item.CallbackSecretCiphertext,
|
|
CallbackSecretSet: item.CallbackSecretConfigured,
|
|
CallbackIpWhitelist: item.CallbackIPWhitelist,
|
|
AdapterConfigJson: item.AdapterConfigJSON,
|
|
}
|
|
}
|
|
|
|
func platformFromProto(item *gamev1.GamePlatform) gamedomain.Platform {
|
|
if item == nil {
|
|
return gamedomain.Platform{}
|
|
}
|
|
return gamedomain.Platform{
|
|
AppCode: item.GetAppCode(),
|
|
PlatformCode: item.GetPlatformCode(),
|
|
PlatformName: item.GetPlatformName(),
|
|
Status: item.GetStatus(),
|
|
APIBaseURL: item.GetApiBaseUrl(),
|
|
AdapterType: item.GetAdapterType(),
|
|
// 更新接口只有在 callback_secret 非空时才会覆盖旧密钥,空值表示保留原密钥。
|
|
CallbackSecretCiphertext: item.GetCallbackSecret(),
|
|
CallbackSecretConfigured: item.GetCallbackSecretSet(),
|
|
CallbackIPWhitelist: item.GetCallbackIpWhitelist(),
|
|
AdapterConfigJSON: item.GetAdapterConfigJson(),
|
|
SortOrder: item.GetSortOrder(),
|
|
}
|
|
}
|
|
|
|
func catalogToProto(item gamedomain.CatalogItem) *gamev1.GameCatalogItem {
|
|
return &gamev1.GameCatalogItem{
|
|
AppCode: item.AppCode,
|
|
GameId: item.GameID,
|
|
PlatformCode: item.PlatformCode,
|
|
ProviderGameId: item.ProviderGameID,
|
|
GameName: item.GameName,
|
|
Category: item.Category,
|
|
IconUrl: item.IconURL,
|
|
CoverUrl: item.CoverURL,
|
|
LaunchMode: item.LaunchMode,
|
|
Orientation: item.Orientation,
|
|
SafeHeight: item.SafeHeight,
|
|
MinCoin: item.MinCoin,
|
|
Status: item.Status,
|
|
SortOrder: item.SortOrder,
|
|
Tags: item.Tags,
|
|
CreatedAtMs: item.CreatedAtMS,
|
|
UpdatedAtMs: item.UpdatedAtMS,
|
|
}
|
|
}
|
|
|
|
func catalogFromProto(item *gamev1.GameCatalogItem) gamedomain.CatalogItem {
|
|
if item == nil {
|
|
return gamedomain.CatalogItem{}
|
|
}
|
|
return gamedomain.CatalogItem{
|
|
AppCode: item.GetAppCode(),
|
|
GameID: item.GetGameId(),
|
|
PlatformCode: item.GetPlatformCode(),
|
|
ProviderGameID: item.GetProviderGameId(),
|
|
GameName: item.GetGameName(),
|
|
Category: item.GetCategory(),
|
|
IconURL: item.GetIconUrl(),
|
|
CoverURL: item.GetCoverUrl(),
|
|
LaunchMode: item.GetLaunchMode(),
|
|
Orientation: item.GetOrientation(),
|
|
SafeHeight: item.GetSafeHeight(),
|
|
MinCoin: item.GetMinCoin(),
|
|
Status: item.GetStatus(),
|
|
SortOrder: item.GetSortOrder(),
|
|
Tags: item.GetTags(),
|
|
}
|
|
}
|
|
|
|
func normalizePlatform(item gamedomain.Platform) (gamedomain.Platform, error) {
|
|
// gRPC 边界只做通用字段清洗,厂商 JSON 的具体语义留给 adapter 解析。
|
|
item.PlatformCode = strings.TrimSpace(item.PlatformCode)
|
|
item.PlatformName = strings.TrimSpace(item.PlatformName)
|
|
item.Status = normalizeStatus(item.Status)
|
|
item.APIBaseURL = strings.TrimSpace(item.APIBaseURL)
|
|
item.AdapterType = normalizeAdapterType(item.AdapterType)
|
|
item.CallbackSecretCiphertext = strings.TrimSpace(item.CallbackSecretCiphertext)
|
|
item.CallbackIPWhitelist = compactStrings(item.CallbackIPWhitelist)
|
|
item.AdapterConfigJSON = strings.TrimSpace(item.AdapterConfigJSON)
|
|
if item.AdapterConfigJSON == "" {
|
|
item.AdapterConfigJSON = "{}"
|
|
}
|
|
if item.PlatformCode == "" || item.PlatformName == "" || item.Status == "" {
|
|
return gamedomain.Platform{}, xerr.New(xerr.InvalidArgument, "platform is incomplete")
|
|
}
|
|
if item.AdapterType == "" {
|
|
return gamedomain.Platform{}, xerr.New(xerr.InvalidArgument, "platform adapter_type is invalid")
|
|
}
|
|
return item, nil
|
|
}
|
|
|
|
func normalizeCatalog(item gamedomain.CatalogItem) (gamedomain.CatalogItem, error) {
|
|
item.GameID = strings.TrimSpace(item.GameID)
|
|
item.PlatformCode = strings.TrimSpace(item.PlatformCode)
|
|
item.ProviderGameID = strings.TrimSpace(item.ProviderGameID)
|
|
item.GameName = strings.TrimSpace(item.GameName)
|
|
item.Status = normalizeStatus(item.Status)
|
|
if item.LaunchMode == "" {
|
|
item.LaunchMode = gamedomain.LaunchModeFullScreen
|
|
}
|
|
if item.Orientation == "" {
|
|
item.Orientation = "portrait"
|
|
}
|
|
if item.SafeHeight < 0 {
|
|
item.SafeHeight = 0
|
|
}
|
|
if item.GameID == "" || item.PlatformCode == "" || item.ProviderGameID == "" || item.GameName == "" || item.Status == "" {
|
|
return gamedomain.CatalogItem{}, xerr.New(xerr.InvalidArgument, "game is incomplete")
|
|
}
|
|
return item, nil
|
|
}
|
|
|
|
func normalizeStatus(status string) string {
|
|
switch strings.ToLower(strings.TrimSpace(status)) {
|
|
case gamedomain.StatusActive:
|
|
return gamedomain.StatusActive
|
|
case gamedomain.StatusMaintenance:
|
|
return gamedomain.StatusMaintenance
|
|
case gamedomain.StatusDisabled:
|
|
return gamedomain.StatusDisabled
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func normalizeAdapterType(adapterType string) string {
|
|
// 允许的 adapter 必须在这里登记,后台传错值时直接拒绝,避免落库后回调走错协议。
|
|
switch strings.ToLower(strings.TrimSpace(adapterType)) {
|
|
case gamedomain.AdapterYomiV4:
|
|
return gamedomain.AdapterYomiV4
|
|
case gamedomain.AdapterLeaderCCV1:
|
|
return gamedomain.AdapterLeaderCCV1
|
|
case gamedomain.AdapterZeeOneV1:
|
|
return gamedomain.AdapterZeeOneV1
|
|
case gamedomain.AdapterBaishunV1:
|
|
return gamedomain.AdapterBaishunV1
|
|
case gamedomain.AdapterVivaGamesV1:
|
|
return gamedomain.AdapterVivaGamesV1
|
|
case gamedomain.AdapterReyouV1:
|
|
return gamedomain.AdapterReyouV1
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func compactStrings(values []string) []string {
|
|
out := make([]string, 0, len(values))
|
|
seen := make(map[string]struct{}, len(values))
|
|
for _, value := range values {
|
|
value = strings.TrimSpace(value)
|
|
if value == "" {
|
|
continue
|
|
}
|
|
if _, ok := seen[value]; ok {
|
|
continue
|
|
}
|
|
seen[value] = struct{}{}
|
|
out = append(out, value)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func durationFromMillis(value int64) time.Duration {
|
|
if value <= 0 {
|
|
return 0
|
|
}
|
|
return time.Duration(value) * time.Millisecond
|
|
}
|