118 lines
3.9 KiB
TypeScript
118 lines
3.9 KiB
TypeScript
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<LobbyProfileStatus[]>;
|
|
}
|
|
|
|
// 로비에서 사용할 프로필 상태를 메모리에서 반환하는 구현체.
|
|
export class InMemoryProfileStatusService implements GatewayProfileStatusService {
|
|
private profiles: LobbyProfileStatus[];
|
|
|
|
constructor(initial: LobbyProfileStatus[] = []) {
|
|
this.profiles = [...initial];
|
|
}
|
|
|
|
async listLobbyProfiles(): Promise<LobbyProfileStatus[]> {
|
|
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<LobbyProfileStatus[]> {
|
|
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',
|
|
};
|
|
}
|
|
}
|