2026-04-22 20:12:59 +08:00

760 lines
23 KiB
Go

package baishun
import (
"chatapp3-golang/internal/model"
"chatapp3-golang/internal/utils"
"context"
"fmt"
"net/http"
"strconv"
"strings"
"time"
"gorm.io/gorm"
)
const adminTimeLayout = "2006-01-02 15:04:05"
type adminGameRow struct {
ID int64
SysOrigin string
InternalGameID string
Name string
Category string
GameCode string
Cover string
Amounts string
Showcase bool
Sort int64
Height float64
Width float64
FullScreen bool
ClientOrigin string
Regions string
GameModeRaw string
CreateTime time.Time
UpdateTime time.Time
VendorGameID string
LaunchMode string
ExtPackageVersion string
ExtPreviewURL string
PackageURL string
ExtOrientation *int
ExtSafeHeight int
ExtGSP string
CurrencyIcon string
ExtExtraJSON string
CatalogStatus string
CatalogPreviewURL string
CatalogDownloadURL string
CatalogPackage string
CatalogOrientation *int
CatalogSafeHeight int
CatalogGameModeJSON string
}
// PageAdminGames 返回后台百顺游戏管理分页数据。
func (s *BaishunService) PageAdminGames(
ctx context.Context,
sysOrigin string,
keyword string,
showcase *bool,
cursor int,
limit int,
) (*AdminBaishunGamePageResponse, error) {
sysOrigin = normalizeAdminSysOrigin(sysOrigin)
cursor = normalizePageCursor(cursor)
limit = normalizePageLimit(limit)
countQuery := s.buildAdminGameQuery(ctx, sysOrigin, keyword, showcase)
var total int64
if err := countQuery.Count(&total).Error; err != nil {
return nil, err
}
var rows []adminGameRow
listQuery := s.buildAdminGameQuery(ctx, sysOrigin, keyword, showcase)
if err := listQuery.
Select(`
cfg.id AS id,
cfg.sys_origin AS sys_origin,
cfg.game_id AS internal_game_id,
cfg.name AS name,
cfg.category AS category,
cfg.game_code AS game_code,
cfg.cover AS cover,
cfg.amounts AS amounts,
cfg.is_showcase AS showcase,
cfg.sort AS sort,
cfg.height AS height,
cfg.width AS width,
cfg.full_screen AS full_screen,
cfg.client_origin AS client_origin,
cfg.regions AS regions,
cfg.game_mode AS game_mode_raw,
cfg.create_time AS create_time,
cfg.update_time AS update_time,
ext.vendor_game_id AS vendor_game_id,
ext.launch_mode AS launch_mode,
ext.package_version AS ext_package_version,
ext.preview_url AS ext_preview_url,
ext.package_url AS package_url,
ext.orientation AS ext_orientation,
ext.safe_height AS ext_safe_height,
ext.gsp AS ext_gsp,
ext.currency_icon AS currency_icon,
ext.extra_json AS ext_extra_json,
cat.status AS catalog_status,
cat.preview_url AS catalog_preview_url,
cat.download_url AS catalog_download_url,
cat.package_version AS catalog_package,
cat.orientation AS catalog_orientation,
cat.safe_height AS catalog_safe_height,
cat.game_mode_json AS catalog_game_mode_json
`).
Order("cfg.is_showcase DESC").
Order("cfg.sort DESC").
Order("cfg.update_time DESC").
Limit(limit).
Offset((cursor - 1) * limit).
Scan(&rows).Error; err != nil {
return nil, err
}
items := make([]AdminBaishunGameItem, 0, len(rows))
for _, row := range rows {
items = append(items, row.toAdminItem())
}
return &AdminBaishunGamePageResponse{
Cursor: cursor,
Limit: limit,
Records: items,
Total: total,
}, nil
}
// SaveAdminGame 保存后台百顺游戏配置。
func (s *BaishunService) SaveAdminGame(ctx context.Context, req SaveAdminBaishunGameRequest) (*AdminBaishunGameItem, error) {
sysOrigin := normalizeAdminSysOrigin(req.SysOrigin)
runtimeCfg, err := s.resolveRuntimeConfig(ctx, sysOrigin)
if err != nil {
return nil, err
}
catalog, err := s.findCatalogForAdmin(ctx, sysOrigin, req.VendorGameID, req.GameID)
if err != nil {
return nil, err
}
if req.VendorGameID <= 0 {
req.VendorGameID = catalog.VendorGameID
}
if req.VendorGameID <= 0 {
return nil, NewAppError(http.StatusBadRequest, "vendor_game_id_required", "vendorGameId is required")
}
gameID := strings.TrimSpace(req.GameID)
if gameID == "" {
gameID = defaultIfBlank(catalog.InternalGameID, fmt.Sprintf("bs_%d", req.VendorGameID))
}
if gameID == "" {
return nil, NewAppError(http.StatusBadRequest, "game_id_required", "gameId is required")
}
name := defaultIfBlank(strings.TrimSpace(req.Name), defaultIfBlank(catalog.Name, gameID))
if name == "" {
return nil, NewAppError(http.StatusBadRequest, "name_required", "name is required")
}
category := defaultIfBlank(strings.TrimSpace(req.Category), "OTHER")
cover := defaultIfBlank(strings.TrimSpace(req.Cover), defaultIfBlank(catalog.Cover, catalog.PreviewURL))
clientOrigin := defaultIfBlank(strings.TrimSpace(req.ClientOrigin), "COMMON")
gameCode := defaultIfBlank(strings.TrimSpace(req.GameCode), strconv.Itoa(req.VendorGameID))
launchMode := defaultIfBlank(strings.TrimSpace(req.LaunchMode), baishunLaunchModeRemote)
packageVersion := defaultIfBlank(strings.TrimSpace(req.PackageVersion), catalog.PackageVersion)
previewURL := defaultIfBlank(strings.TrimSpace(req.PreviewURL), catalog.PreviewURL)
packageURL := defaultIfBlank(strings.TrimSpace(req.PackageURL), catalog.DownloadURL)
gsp := defaultIfBlank(strings.TrimSpace(req.GSP), defaultAdminGSP(catalog.GSP, runtimeCfg.gsp()))
safeHeight := req.SafeHeight
if safeHeight <= 0 {
safeHeight = catalog.SafeHeight
}
orientation := req.Orientation
if orientation == nil && catalog.Orientation != nil {
value := *catalog.Orientation
orientation = &value
}
gameMode := baishunFixedGameMode
tx := s.repo.DB.WithContext(ctx).Begin()
if tx.Error != nil {
return nil, tx.Error
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
panic(r)
}
}()
cfg, err := s.findAdminConfigForSave(tx, sysOrigin, req.ID, gameID, req.VendorGameID)
if err != nil {
tx.Rollback()
return nil, err
}
showcase := resolveAdminShowcase(req.Showcase, cfg.Showcase, cfg.ID == 0)
cfgValues := map[string]any{
"sys_origin": sysOrigin,
"game_origin": baishunVendorType,
"game_id": gameID,
"name": name,
"category": category,
"game_code": gameCode,
"cover": cover,
"amounts": strings.TrimSpace(req.Amounts),
"is_showcase": showcase,
"sort": req.Sort,
"height": req.Height,
"width": req.Width,
"full_screen": req.FullScreen,
"client_origin": clientOrigin,
"regions": strings.TrimSpace(req.Regions),
"game_mode": formatAdminGameModeRaw(gameMode),
}
if cfg.ID == 0 {
nextID, idErr := utils.NextID()
if idErr != nil {
tx.Rollback()
return nil, idErr
}
cfg = model.SysGameListConfig{
ID: nextID,
SysOrigin: sysOrigin,
GameOrigin: baishunVendorType,
GameID: gameID,
Name: name,
Category: category,
GameCode: gameCode,
Cover: cover,
Amounts: strings.TrimSpace(req.Amounts),
Showcase: showcase,
Sort: req.Sort,
Height: req.Height,
Width: req.Width,
FullScreen: req.FullScreen,
ClientOrigin: clientOrigin,
Regions: strings.TrimSpace(req.Regions),
GameMode: formatAdminGameModeRaw(gameMode),
}
if err := tx.Create(&cfg).Error; err != nil {
tx.Rollback()
return nil, err
}
} else {
if err := tx.Model(&model.SysGameListConfig{}).
Where("id = ?", cfg.ID).
Updates(cfgValues).Error; err != nil {
tx.Rollback()
return nil, err
}
}
var ext model.SysGameListVendorExt
err = tx.Where("game_list_config_id = ? AND vendor_type = ?", cfg.ID, baishunVendorType).First(&ext).Error
if err != nil && err != gorm.ErrRecordNotFound {
tx.Rollback()
return nil, err
}
now := time.Now()
extraJSON := updateExtExtraJSONWithGameType(ext.ExtraJSON, req.LaunchParams, baishunVendorType, ext.ID != 0)
if ext.ID == 0 {
nextID, idErr := utils.NextID()
if idErr != nil {
tx.Rollback()
return nil, idErr
}
ext = model.SysGameListVendorExt{
ID: nextID,
GameListConfigID: cfg.ID,
SysOrigin: sysOrigin,
VendorType: baishunVendorType,
VendorGameID: strconv.Itoa(req.VendorGameID),
LaunchMode: launchMode,
PackageVersion: packageVersion,
PackageURL: packageURL,
PreviewURL: previewURL,
Orientation: orientation,
SafeHeight: safeHeight,
GSP: gsp,
CurrencyIcon: strings.TrimSpace(req.CurrencyIcon),
ExtraJSON: extraJSON,
Enabled: true,
CreateTime: now,
UpdateTime: now,
}
if err := tx.Create(&ext).Error; err != nil {
tx.Rollback()
return nil, err
}
} else {
if err := tx.Model(&model.SysGameListVendorExt{}).
Where("id = ?", ext.ID).
Updates(map[string]any{
"sys_origin": sysOrigin,
"vendor_game_id": strconv.Itoa(req.VendorGameID),
"launch_mode": launchMode,
"package_version": packageVersion,
"package_url": packageURL,
"preview_url": previewURL,
"orientation": orientation,
"safe_height": safeHeight,
"gsp": gsp,
"currency_icon": strings.TrimSpace(req.CurrencyIcon),
"extra_json": extraJSON,
"enabled": true,
"bridge_schema_version": defaultIfBlank(ext.BridgeSchemaVersion, "1.0"),
"update_time": now,
}).Error; err != nil {
tx.Rollback()
return nil, err
}
}
if err := tx.Commit().Error; err != nil {
return nil, err
}
return s.getAdminGame(ctx, sysOrigin, cfg.ID)
}
// DeleteAdminGame 删除后台百顺游戏配置,不影响目录表。
func (s *BaishunService) DeleteAdminGame(ctx context.Context, sysOrigin string, id int64) error {
if id <= 0 {
return NewAppError(http.StatusBadRequest, "id_required", "id is required")
}
sysOrigin = normalizeAdminSysOrigin(sysOrigin)
tx := s.repo.DB.WithContext(ctx).Begin()
if tx.Error != nil {
return tx.Error
}
if err := tx.Where("game_list_config_id = ? AND vendor_type = ?", id, baishunVendorType).
Delete(&model.SysGameListVendorExt{}).Error; err != nil {
tx.Rollback()
return err
}
if err := tx.Where("id = ? AND sys_origin = ? AND game_origin = ?", id, sysOrigin, baishunVendorType).
Delete(&model.SysGameListConfig{}).Error; err != nil {
tx.Rollback()
return err
}
return tx.Commit().Error
}
// ImportCatalogGames 把本地目录中尚未进入后台列表的百顺游戏补齐成可配置记录。
func (s *BaishunService) ImportCatalogGames(ctx context.Context, sysOrigin string, vendorGameIDs []int) (*ImportCatalogResponse, error) {
tx := s.repo.DB.WithContext(ctx).Begin()
if tx.Error != nil {
return nil, tx.Error
}
resp, err := s.importCatalogGamesTx(tx, normalizeAdminSysOrigin(sysOrigin), buildVendorGameIDFilter(vendorGameIDs))
if err != nil {
tx.Rollback()
return nil, err
}
if err := tx.Commit().Error; err != nil {
return nil, err
}
return resp, nil
}
// SyncAdminGames 先同步百顺平台目录,再把缺失配置导入后台列表。
func (s *BaishunService) SyncAdminGames(ctx context.Context, req SyncCatalogRequest) (*SyncAdminCatalogResponse, error) {
syncResp, err := s.SyncCatalog(ctx, req)
if err != nil {
return nil, err
}
importResp, err := s.ImportCatalogGames(ctx, req.SysOrigin, req.VendorGameIDs)
if err != nil {
return nil, err
}
return &SyncAdminCatalogResponse{
Inserted: syncResp.Inserted,
Updated: syncResp.Updated,
Skipped: syncResp.Skipped,
Existing: importResp.Existing,
Imported: importResp.Imported,
}, nil
}
func (s *BaishunService) buildAdminGameQuery(ctx context.Context, sysOrigin, keyword string, showcase *bool) *gorm.DB {
query := s.repo.DB.WithContext(ctx).
Table("sys_game_list_config AS cfg").
Joins("LEFT JOIN sys_game_list_vendor_ext ext ON ext.game_list_config_id = cfg.id AND ext.vendor_type = ?", baishunVendorType).
Joins(`
LEFT JOIN baishun_game_catalog cat
ON cat.sys_origin = cfg.sys_origin
AND (
CAST(cat.vendor_game_id AS CHAR) = ext.vendor_game_id
OR cat.internal_game_id = cfg.game_id
)
`).
Where("cfg.sys_origin = ? AND cfg.game_origin = ?", sysOrigin, baishunVendorType)
if showcase != nil {
query = query.Where("cfg.is_showcase = ?", *showcase)
}
keyword = strings.TrimSpace(keyword)
if keyword != "" {
like := "%" + keyword + "%"
query = query.Where(`
cfg.name LIKE ?
OR cfg.game_id LIKE ?
OR cfg.game_code LIKE ?
OR ext.vendor_game_id LIKE ?
`, like, like, like, like)
}
return query
}
func (s *BaishunService) getAdminGame(ctx context.Context, sysOrigin string, id int64) (*AdminBaishunGameItem, error) {
var rows []adminGameRow
err := s.buildAdminGameQuery(ctx, sysOrigin, "", nil).
Where("cfg.id = ?", id).
Select(`
cfg.id AS id,
cfg.sys_origin AS sys_origin,
cfg.game_id AS internal_game_id,
cfg.name AS name,
cfg.category AS category,
cfg.game_code AS game_code,
cfg.cover AS cover,
cfg.amounts AS amounts,
cfg.is_showcase AS showcase,
cfg.sort AS sort,
cfg.height AS height,
cfg.width AS width,
cfg.full_screen AS full_screen,
cfg.client_origin AS client_origin,
cfg.regions AS regions,
cfg.game_mode AS game_mode_raw,
cfg.create_time AS create_time,
cfg.update_time AS update_time,
ext.vendor_game_id AS vendor_game_id,
ext.launch_mode AS launch_mode,
ext.package_version AS ext_package_version,
ext.preview_url AS ext_preview_url,
ext.package_url AS package_url,
ext.orientation AS ext_orientation,
ext.safe_height AS ext_safe_height,
ext.gsp AS ext_gsp,
ext.currency_icon AS currency_icon,
ext.extra_json AS ext_extra_json,
cat.status AS catalog_status,
cat.preview_url AS catalog_preview_url,
cat.download_url AS catalog_download_url,
cat.package_version AS catalog_package,
cat.orientation AS catalog_orientation,
cat.safe_height AS catalog_safe_height,
cat.game_mode_json AS catalog_game_mode_json
`).
Limit(1).
Scan(&rows).Error
if err != nil {
return nil, err
}
if len(rows) == 1 {
item := rows[0].toAdminItem()
return &item, nil
}
return nil, NewAppError(http.StatusNotFound, "game_not_found", "admin baishun game not found")
}
func (s *BaishunService) findCatalogForAdmin(ctx context.Context, sysOrigin string, vendorGameID int, gameID string) (model.BaishunGameCatalog, error) {
query := s.repo.DB.WithContext(ctx).Where("sys_origin = ?", sysOrigin)
switch {
case vendorGameID > 0:
query = query.Where("vendor_game_id = ?", vendorGameID)
case strings.TrimSpace(gameID) != "":
query = query.Where("internal_game_id = ?", strings.TrimSpace(gameID))
default:
return model.BaishunGameCatalog{}, nil
}
var catalog model.BaishunGameCatalog
if err := query.First(&catalog).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return model.BaishunGameCatalog{}, nil
}
return model.BaishunGameCatalog{}, err
}
return catalog, nil
}
func (s *BaishunService) findAdminConfigForSave(tx *gorm.DB, sysOrigin string, id int64, gameID string, vendorGameID int) (model.SysGameListConfig, error) {
var cfg model.SysGameListConfig
if id > 0 {
err := tx.Where("id = ? AND sys_origin = ? AND game_origin = ?", id, sysOrigin, baishunVendorType).First(&cfg).Error
if err == gorm.ErrRecordNotFound {
return model.SysGameListConfig{}, NewAppError(http.StatusNotFound, "game_not_found", "admin baishun game not found")
}
return cfg, err
}
if vendorGameID > 0 {
var ext model.SysGameListVendorExt
err := tx.Where("sys_origin = ? AND vendor_type = ? AND vendor_game_id = ?", sysOrigin, baishunVendorType, strconv.Itoa(vendorGameID)).First(&ext).Error
if err != nil && err != gorm.ErrRecordNotFound {
return model.SysGameListConfig{}, err
}
if ext.GameListConfigID > 0 {
err = tx.Where("id = ? AND sys_origin = ? AND game_origin = ?", ext.GameListConfigID, sysOrigin, baishunVendorType).First(&cfg).Error
if err == nil {
return cfg, nil
}
if err != gorm.ErrRecordNotFound {
return model.SysGameListConfig{}, err
}
}
}
if strings.TrimSpace(gameID) == "" {
return model.SysGameListConfig{}, nil
}
err := tx.Where("sys_origin = ? AND game_origin = ? AND game_id = ?", sysOrigin, baishunVendorType, strings.TrimSpace(gameID)).First(&cfg).Error
if err == gorm.ErrRecordNotFound {
return model.SysGameListConfig{}, nil
}
return cfg, err
}
func (s *BaishunService) importCatalogGamesTx(tx *gorm.DB, sysOrigin string, filter map[int]struct{}) (*ImportCatalogResponse, error) {
ctx := tx.Statement.Context
if ctx == nil {
ctx = context.Background()
}
runtimeCfg, err := s.resolveRuntimeConfig(ctx, sysOrigin)
if err != nil {
return nil, err
}
query := tx.Where("sys_origin = ? AND status = ?", sysOrigin, baishunCatalogEnabled)
if len(filter) > 0 {
ids := make([]int, 0, len(filter))
for id := range filter {
ids = append(ids, id)
}
query = query.Where("vendor_game_id IN ?", ids)
}
var catalogs []model.BaishunGameCatalog
if err := query.Order("vendor_game_id ASC").Find(&catalogs).Error; err != nil {
return nil, err
}
resp := &ImportCatalogResponse{}
for _, catalog := range catalogs {
vendorGameID := strconv.Itoa(catalog.VendorGameID)
now := time.Now()
var ext model.SysGameListVendorExt
err := tx.Where("sys_origin = ? AND vendor_type = ? AND vendor_game_id = ?", sysOrigin, baishunVendorType, vendorGameID).First(&ext).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
if err == nil && ext.GameListConfigID > 0 {
resp.Existing++
continue
}
var cfg model.SysGameListConfig
err = tx.Where("sys_origin = ? AND game_origin = ? AND game_id = ?", sysOrigin, baishunVendorType, catalog.InternalGameID).First(&cfg).Error
if err != nil && err != gorm.ErrRecordNotFound {
return nil, err
}
if err == gorm.ErrRecordNotFound {
nextID, idErr := utils.NextID()
if idErr != nil {
return nil, idErr
}
cfg = model.SysGameListConfig{
ID: nextID,
SysOrigin: sysOrigin,
GameOrigin: baishunVendorType,
GameID: defaultIfBlank(catalog.InternalGameID, fmt.Sprintf("bs_%d", catalog.VendorGameID)),
Name: catalog.Name,
Category: "OTHER",
GameCode: vendorGameID,
Cover: defaultIfBlank(catalog.Cover, catalog.PreviewURL),
Showcase: true,
Sort: int64(catalog.VendorGameID),
FullScreen: true,
ClientOrigin: "COMMON",
GameMode: formatAdminGameModeRaw(baishunFixedGameMode),
}
if err := tx.Create(&cfg).Error; err != nil {
return nil, err
}
}
nextID, idErr := utils.NextID()
if idErr != nil {
return nil, idErr
}
newExt := model.SysGameListVendorExt{
ID: nextID,
GameListConfigID: cfg.ID,
SysOrigin: sysOrigin,
VendorType: baishunVendorType,
VendorGameID: vendorGameID,
LaunchMode: baishunLaunchModeRemote,
PackageVersion: catalog.PackageVersion,
PackageURL: catalog.DownloadURL,
PreviewURL: catalog.PreviewURL,
Orientation: catalog.Orientation,
SafeHeight: catalog.SafeHeight,
GSP: defaultAdminGSP(catalog.GSP, runtimeCfg.gsp()),
BridgeSchemaVersion: "1.0",
ExtraJSON: updateExtExtraJSONWithGameType("", nil, baishunVendorType, false),
Enabled: true,
CreateTime: now,
UpdateTime: now,
}
if err := tx.Create(&newExt).Error; err != nil {
return nil, err
}
resp.Imported++
}
return resp, nil
}
func (r adminGameRow) toAdminItem() AdminBaishunGameItem {
return AdminBaishunGameItem{
ID: r.ID,
SysOrigin: r.SysOrigin,
GameID: r.InternalGameID,
GameType: gameTypeFromExtraJSON(r.ExtExtraJSON, baishunVendorType),
VendorGameID: parseAdminVendorGameID(r.VendorGameID, r.InternalGameID),
Name: r.Name,
Category: r.Category,
GameCode: r.GameCode,
Cover: r.Cover,
Amounts: r.Amounts,
Showcase: r.Showcase,
Sort: r.Sort,
Height: r.Height,
Width: r.Width,
FullScreen: r.FullScreen,
ClientOrigin: r.ClientOrigin,
Regions: r.Regions,
GameMode: baishunFixedGameMode,
LaunchMode: defaultIfBlank(r.LaunchMode, baishunLaunchModeRemote),
PackageVersion: defaultIfBlank(r.ExtPackageVersion, r.CatalogPackage),
PreviewURL: defaultIfBlank(r.ExtPreviewURL, r.CatalogPreviewURL),
PackageURL: defaultIfBlank(r.PackageURL, r.CatalogDownloadURL),
Orientation: chooseAdminOrientation(r.ExtOrientation, r.CatalogOrientation),
SafeHeight: chooseAdminSafeHeight(r.ExtSafeHeight, r.CatalogSafeHeight),
GSP: r.ExtGSP,
CurrencyIcon: r.CurrencyIcon,
CatalogStatus: r.CatalogStatus,
LaunchParams: launchParamsWithGameType(r.ExtExtraJSON, baishunVendorType),
CreateTime: formatAdminTime(r.CreateTime),
UpdateTime: formatAdminTime(r.UpdateTime),
}
}
func normalizeAdminSysOrigin(sysOrigin string) string {
sysOrigin = strings.ToUpper(strings.TrimSpace(sysOrigin))
if sysOrigin == "" {
return "LIKEI"
}
return sysOrigin
}
func normalizePageCursor(cursor int) int {
if cursor <= 0 {
return 1
}
return cursor
}
func normalizePageLimit(limit int) int {
if limit <= 0 {
return 20
}
if limit > 200 {
return 200
}
return limit
}
func resolveAdminShowcase(showcase *bool, current bool, isCreate bool) bool {
if showcase != nil {
return *showcase
}
if isCreate {
return true
}
return current
}
func defaultAdminGSP(catalogGSP string, fallback int) string {
if strings.TrimSpace(catalogGSP) != "" {
return strings.TrimSpace(catalogGSP)
}
if fallback > 0 {
return strconv.Itoa(fallback)
}
return "101"
}
func formatAdminGameModeRaw(gameMode int) string {
return fmt.Sprintf("[%d]", baishunFixedGameMode)
}
func parseAdminVendorGameID(raw string, gameID string) int {
if parsed, err := strconv.Atoi(strings.TrimSpace(raw)); err == nil {
return parsed
}
if strings.HasPrefix(strings.TrimSpace(gameID), "bs_") {
if parsed, err := strconv.Atoi(strings.TrimPrefix(strings.TrimSpace(gameID), "bs_")); err == nil {
return parsed
}
}
return 0
}
func chooseAdminOrientation(extOrientation, catalogOrientation *int) int {
if extOrientation != nil {
return *extOrientation
}
if catalogOrientation != nil {
return *catalogOrientation
}
return 0
}
func chooseAdminSafeHeight(extSafeHeight, catalogSafeHeight int) int {
if extSafeHeight > 0 {
return extSafeHeight
}
return catalogSafeHeight
}
func formatAdminTime(value time.Time) string {
if value.IsZero() {
return ""
}
return value.Format(adminTimeLayout)
}
func buildVendorGameIDFilter(vendorGameIDs []int) map[int]struct{} {
filter := make(map[int]struct{}, len(vendorGameIDs))
for _, id := range vendorGameIDs {
if id > 0 {
filter[id] = struct{}{}
}
}
return filter
}