import { gatewayProfileCapabilities, type GatewayProfileCapabilities } from '@sammo-ts/common'; import type { GatewayOrchestratorHandle } from '../orchestrator/gatewayOrchestrator.js'; import type { GatewayProfileRecord, GatewayProfileRepository, GatewayProfileStatus, } from '../orchestrator/profileRepository.js'; import { orderGatewayProfiles, resolveGatewayProfileKoreanName } from '../profileOrder.js'; export type LobbyMapSnapshot = { updatedAt: string | null; summary?: string | null; }; export type LobbyGeneralStatus = { exists: boolean; cityId: number | null; cityName: string | null; updatedAt: string | null; }; export type LobbyProfileStatus = { profileName: string; profile: string; instanceKey: string; currentScenario: string | null; /** @deprecated Rollback-compatible mirror of currentScenario. */ scenario: string; status: GatewayProfileStatus; lifecycle: GatewayProfileCapabilities & { dataInitialized: boolean; }; apiPort: number; runtime: { apiRunning: boolean; daemonRunning: boolean; auctionRunning: boolean; battleSimRunning: boolean; tournamentRunning: boolean; }; korName: string; color: string; }; export interface GatewayProfileStatusService { listLobbyProfiles(input: { userId?: string } | undefined): Promise; } // 로비에서 사용할 프로필 상태를 메모리에서 반환하는 구현체. export class InMemoryProfileStatusService implements GatewayProfileStatusService { private profiles: LobbyProfileStatus[]; constructor(initial: LobbyProfileStatus[] = []) { this.profiles = [...initial]; } async listLobbyProfiles(): Promise { return orderGatewayProfiles(this.profiles); } setProfiles(profiles: LobbyProfileStatus[]): void { this.profiles = [...profiles]; } } // 프로필 저장소/오케스트레이터를 이용해 로비 상태를 구성하는 기본 구현체. export class RepositoryProfileStatusService implements GatewayProfileStatusService { constructor( private readonly profiles: GatewayProfileRepository, private readonly orchestrator: GatewayOrchestratorHandle ) {} async listLobbyProfiles(): Promise { const rows = orderGatewayProfiles(await this.profiles.listProfiles()); const runtimeStates = await this.orchestrator.listRuntimeStates(rows.map((profile) => profile.profileName)); const runtimeMap = new Map(runtimeStates.map((state) => [state.profileName, state])); return rows.map((row) => this.mapProfile(row, runtimeMap)); } private mapProfile( row: GatewayProfileRecord, runtimeMap: Map< string, { apiRunning: boolean; daemonRunning: boolean; auctionRunning: boolean; battleSimRunning: boolean; tournamentRunning: boolean; } > ): LobbyProfileStatus { const meta = row.meta; return { profileName: row.profileName, profile: row.profile, instanceKey: row.instanceKey, currentScenario: row.currentScenario, scenario: row.scenario, status: row.status, lifecycle: { ...gatewayProfileCapabilities(row.status), dataInitialized: row.currentScenario !== null, }, apiPort: row.apiPort, runtime: runtimeMap.get(row.profileName) ?? { apiRunning: false, daemonRunning: false, auctionRunning: false, battleSimRunning: false, tournamentRunning: false, }, korName: resolveGatewayProfileKoreanName(row.profile, meta.korName), color: (meta.color as string | undefined) ?? '#ffffff', }; } }