2026-04-24 13:04:06 +08:00

264 lines
9.6 KiB
Go

package baishun
import (
"chatapp3-golang/internal/model"
"context"
"fmt"
"net/http"
"strconv"
"strings"
"gorm.io/gorm"
)
// ListShortcutGames 返回房间里的快捷游戏列表,数量上限为 5 个。
func (s *BaishunService) ListShortcutGames(ctx context.Context, user AuthUser, roomID string) ([]RoomGameListItem, error) {
items, err := s.listRoomGames(ctx, user.SysOrigin, roomID, "")
if err != nil {
return nil, err
}
if len(items) > 5 {
items = items[:5]
}
return items, nil
}
// ListRoomGames 返回房间可启动的完整游戏列表。
func (s *BaishunService) ListRoomGames(ctx context.Context, user AuthUser, roomID string, category string) (*RoomGameListResponse, error) {
items, err := s.listRoomGames(ctx, user.SysOrigin, roomID, category)
if err != nil {
return nil, err
}
return &RoomGameListResponse{Items: items}, nil
}
// GetRoomState 返回房间当前的游戏挂载状态。
func (s *BaishunService) GetRoomState(ctx context.Context, user AuthUser, roomID string) (*BaishunRoomStateResponse, error) {
var state model.BaishunRoomState
if err := s.repo.DB.WithContext(ctx).
Where("sys_origin = ? AND room_id = ?", user.SysOrigin, roomID).
First(&state).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return &BaishunRoomStateResponse{RoomID: roomID, State: baishunRoomStateIdle}, nil
}
return nil, err
}
resp := &BaishunRoomStateResponse{
RoomID: roomID,
State: defaultIfBlank(state.State, baishunRoomStateIdle),
GameSessionID: state.GameSessionID,
CurrentGameID: state.CurrentGameID,
CurrentGameName: state.CurrentGameName,
CurrentGameCover: state.CurrentGameCover,
HostUserID: state.HostUserID,
}
if state.CurrentVendorGameID != nil {
resp.CurrentVendorGameID = *state.CurrentVendorGameID
}
return resp, nil
}
// listRoomGames 联表读取房间可启动游戏,并按展示规则排序。
func (s *BaishunService) listRoomGames(ctx context.Context, sysOrigin, roomID, category string) ([]RoomGameListItem, error) {
sysOrigin = normalizeAdminSysOrigin(sysOrigin)
profile, err := s.activeProfile(ctx, sysOrigin)
if err != nil {
return nil, err
}
var rows []gameListRow
query := s.repo.DB.WithContext(ctx).
Table("sys_game_list_config AS cfg").
Select(`
cfg.id AS config_id,
cfg.sys_origin AS sys_origin,
ext.profile AS profile,
cfg.game_id AS internal_game_id,
cfg.name AS name,
cfg.category AS category,
cfg.cover AS cover,
cfg.sort AS sort,
cfg.full_screen AS full_screen,
cfg.game_mode AS game_mode_raw,
ext.vendor_type AS vendor_type,
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.currency_icon AS currency_icon,
ext.gsp AS ext_gsp,
ext.extra_json AS ext_extra_json,
cat.name AS catalog_name,
cat.cover AS catalog_cover,
cat.preview_url AS catalog_preview_url,
cat.download_url AS catalog_download_url,
cat.package_version AS catalog_package_version,
cat.orientation AS catalog_orientation,
cat.safe_height AS catalog_safe_height,
cat.status AS catalog_status
`).
Joins("JOIN sys_game_list_vendor_ext ext ON ext.game_list_config_id = cfg.id AND ext.enabled = 1 AND ext.profile = ?", profile).
Joins("LEFT JOIN baishun_game_catalog cat ON cat.sys_origin = cfg.sys_origin AND cat.profile = ext.profile AND CAST(cat.vendor_game_id AS CHAR) = ext.vendor_game_id").
Where("cfg.sys_origin = ? AND cfg.is_showcase = 1 AND ext.vendor_type = ?", sysOrigin, baishunVendorType)
if strings.TrimSpace(category) != "" && !strings.EqualFold(strings.TrimSpace(category), "CHAT_ROOM") {
query = query.Where("cfg.category = ?", category)
}
if err := query.Order("cfg.sort DESC").Scan(&rows).Error; err != nil {
return nil, err
}
items := make([]RoomGameListItem, 0, len(rows))
for _, row := range rows {
items = append(items, row.toListItem())
}
return items, nil
}
// findGameRow 按内部游戏 ID 查询游戏聚合信息。
func (s *BaishunService) findGameRow(ctx context.Context, sysOrigin, gameID string) (gameListRow, error) {
sysOrigin = normalizeAdminSysOrigin(sysOrigin)
profile, err := s.activeProfile(ctx, sysOrigin)
if err != nil {
return gameListRow{}, err
}
var row gameListRow
err = s.repo.DB.WithContext(ctx).
Table("sys_game_list_config AS cfg").
Select(`
cfg.id AS config_id,
cfg.sys_origin AS sys_origin,
ext.profile AS profile,
cfg.game_id AS internal_game_id,
cfg.name AS name,
cfg.category AS category,
cfg.cover AS cover,
cfg.sort AS sort,
cfg.full_screen AS full_screen,
cfg.game_mode AS game_mode_raw,
ext.vendor_type AS vendor_type,
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.currency_icon AS currency_icon,
ext.gsp AS ext_gsp,
ext.extra_json AS ext_extra_json,
cat.name AS catalog_name,
cat.cover AS catalog_cover,
cat.preview_url AS catalog_preview_url,
cat.download_url AS catalog_download_url,
cat.package_version AS catalog_package_version,
cat.orientation AS catalog_orientation,
cat.safe_height AS catalog_safe_height,
cat.status AS catalog_status
`).
Joins("JOIN sys_game_list_vendor_ext ext ON ext.game_list_config_id = cfg.id AND ext.enabled = 1 AND ext.profile = ?", profile).
Joins("LEFT JOIN baishun_game_catalog cat ON cat.sys_origin = cfg.sys_origin AND cat.profile = ext.profile AND CAST(cat.vendor_game_id AS CHAR) = ext.vendor_game_id").
Where("cfg.sys_origin = ? AND cfg.game_id = ? AND ext.vendor_type = ?", sysOrigin, gameID, baishunVendorType).
Limit(1).
Scan(&row).Error
if err != nil {
return gameListRow{}, err
}
if strings.TrimSpace(row.InternalGameID) != "" {
return row, nil
}
var catalog model.BaishunGameCatalog
if err := s.repo.DB.WithContext(ctx).
Where("sys_origin = ? AND profile = ? AND internal_game_id = ?", sysOrigin, profile, gameID).
First(&catalog).Error; err == nil {
return gameListRow{
SysOrigin: sysOrigin,
Profile: profile,
InternalGameID: defaultIfBlank(catalog.InternalGameID, fmt.Sprintf("bs_%d", catalog.VendorGameID)),
Name: catalog.Name,
Cover: catalog.Cover,
VendorType: baishunVendorType,
VendorGameID: strconv.Itoa(catalog.VendorGameID),
LaunchMode: baishunLaunchModeRemote,
ExtGSP: catalog.GSP,
CatalogCover: catalog.Cover,
CatalogPreviewURL: catalog.PreviewURL,
CatalogDownloadURL: catalog.DownloadURL,
CatalogPackageVersion: catalog.PackageVersion,
CatalogSafeHeight: catalog.SafeHeight,
CatalogOrientation: catalog.Orientation,
CatalogStatus: catalog.Status,
GameModeRaw: formatAdminGameModeRaw(baishunFixedGameMode),
}, nil
} else if err != gorm.ErrRecordNotFound {
return gameListRow{}, err
}
return gameListRow{}, NewAppError(http.StatusNotFound, "game_not_found", "room game config not found")
}
// findGameRowByConfigID 按系统游戏配置主键查询游戏聚合信息。
func (s *BaishunService) findGameRowByConfigID(ctx context.Context, sysOrigin string, configID int64) (gameListRow, error) {
sysOrigin = normalizeAdminSysOrigin(sysOrigin)
profile, err := s.activeProfile(ctx, sysOrigin)
if err != nil {
return gameListRow{}, err
}
var row gameListRow
err = s.repo.DB.WithContext(ctx).
Table("sys_game_list_config AS cfg").
Select(`
cfg.id AS config_id,
cfg.sys_origin AS sys_origin,
ext.profile AS profile,
cfg.game_id AS internal_game_id,
cfg.name AS name,
cfg.category AS category,
cfg.cover AS cover,
cfg.sort AS sort,
cfg.full_screen AS full_screen,
cfg.game_mode AS game_mode_raw,
ext.vendor_type AS vendor_type,
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.currency_icon AS currency_icon,
ext.gsp AS ext_gsp,
ext.extra_json AS ext_extra_json,
cat.name AS catalog_name,
cat.cover AS catalog_cover,
cat.preview_url AS catalog_preview_url,
cat.download_url AS catalog_download_url,
cat.package_version AS catalog_package_version,
cat.orientation AS catalog_orientation,
cat.safe_height AS catalog_safe_height,
cat.status AS catalog_status
`).
Joins("JOIN sys_game_list_vendor_ext ext ON ext.game_list_config_id = cfg.id AND ext.enabled = 1 AND ext.profile = ?", profile).
Joins("LEFT JOIN baishun_game_catalog cat ON cat.sys_origin = cfg.sys_origin AND cat.profile = ext.profile AND CAST(cat.vendor_game_id AS CHAR) = ext.vendor_game_id").
Where("cfg.sys_origin = ? AND cfg.id = ? AND ext.vendor_type = ?", sysOrigin, configID, baishunVendorType).
Limit(1).
Scan(&row).Error
if err != nil {
return gameListRow{}, err
}
if row.ConfigID > 0 {
return row, nil
}
return gameListRow{}, NewAppError(http.StatusNotFound, "game_not_found", "room game config not found")
}
// resolveGSP 解析行模型中的 GSP 值。
func (s *BaishunService) resolveGSP(row gameListRow, runtimeCfg baishunRuntimeConfig) int {
if parsed, err := strconv.Atoi(strings.TrimSpace(row.ExtGSP)); err == nil && parsed > 0 {
return parsed
}
return runtimeCfg.gsp()
}