feat: implement lobby functionality with user and server information retrieval

This commit is contained in:
2026-01-03 13:35:16 +00:00
parent 1988e180c5
commit 67d995c65f
14 changed files with 328 additions and 17 deletions
@@ -12,6 +12,14 @@ export const createInMemoryUserRepository = (
const usersByEmail = new Map<string, UserRecord>();
return {
async findById(id: string): Promise<UserRecord | null> {
for (const user of usersByName.values()) {
if (user.id === id) {
return user;
}
}
return null;
},
async findByUsername(username: string): Promise<UserRecord | null> {
return usersByName.get(username) ?? null;
},
@@ -56,6 +56,14 @@ export const createPostgresUserRepository = (
hasher: PasswordHasher = createSimplePasswordHasher()
): UserRepository => {
return {
async findById(id: string): Promise<UserRecord | null> {
const row = await prisma.appUser.findUnique({
where: {
id,
},
});
return row ? mapUser(row) : null;
},
async findByUsername(username: string): Promise<UserRecord | null> {
const row = await prisma.appUser.findUnique({
where: {
@@ -51,6 +51,7 @@ export interface CreateUserInput {
}
export interface UserRepository {
findById(id: string): Promise<UserRecord | null>;
findByUsername(username: string): Promise<UserRecord | null>;
findByOauthId(type: 'KAKAO', oauthId: string): Promise<UserRecord | null>;
findByEmail(email: string): Promise<UserRecord | null>;
+4
View File
@@ -6,6 +6,7 @@ import type { OAuthSessionStore } from './auth/oauthSessionStore.js';
import type { GatewayProfileRepository } from './orchestrator/profileRepository.js';
import type { GatewayOrchestratorHandle } from './orchestrator/gatewayOrchestrator.js';
import type { GatewayProfileStatusService } from './lobby/profileStatusService.js';
import type { PrismaClient } from '@prisma/client';
export interface GatewayApiContext {
users: UserRepository;
@@ -21,6 +22,7 @@ export interface GatewayApiContext {
profileStatus: GatewayProfileStatusService;
adminToken?: string;
requestHeaders: Record<string, string | string[] | undefined>;
prisma: PrismaClient;
}
export const createGatewayApiContext = (options: {
@@ -37,6 +39,7 @@ export const createGatewayApiContext = (options: {
profileStatus: GatewayProfileStatusService;
adminToken?: string;
requestHeaders?: Record<string, string | string[] | undefined>;
prisma: PrismaClient;
}): GatewayApiContext => ({
users: options.users,
sessions: options.sessions,
@@ -51,4 +54,5 @@ export const createGatewayApiContext = (options: {
profileStatus: options.profileStatus,
adminToken: options.adminToken,
requestHeaders: options.requestHeaders ?? {},
prisma: options.prisma,
});
@@ -22,12 +22,13 @@ export type LobbyProfileStatus = {
profile: string;
scenario: string;
status: GatewayProfileStatus;
apiPort: number;
runtime: {
apiRunning: boolean;
daemonRunning: boolean;
};
map: LobbyMapSnapshot;
myGeneral: LobbyGeneralStatus;
korName: string;
color: string;
};
export interface GatewayProfileStatusService {
@@ -73,25 +74,19 @@ export class RepositoryProfileStatusService implements GatewayProfileStatusServi
row: GatewayProfileRecord,
runtimeMap: Map<string, { apiRunning: boolean; daemonRunning: boolean }>
): LobbyProfileStatus {
const meta = row.meta as Record<string, any>;
return {
profileName: row.profileName,
profile: row.profile,
scenario: row.scenario,
status: row.status,
apiPort: row.apiPort,
runtime: runtimeMap.get(row.profileName) ?? {
apiRunning: false,
daemonRunning: false,
},
map: {
updatedAt: null,
summary: null,
},
myGeneral: {
exists: false,
cityId: null,
cityName: null,
updatedAt: null,
},
korName: (meta.korName as string) ?? row.profile,
color: (meta.color as string) ?? '#ffffff',
};
}
}
+14
View File
@@ -28,7 +28,21 @@ export const appRouter = router({
now: new Date().toISOString(),
})),
}),
me: procedure.query(async ({ ctx }) => {
const sessionToken = ctx.requestHeaders['x-session-token'] as string | undefined;
if (!sessionToken) return null;
const session = await ctx.sessions.getSession(sessionToken);
if (!session) return null;
const user = await ctx.users.findById(session.userId);
return user ? toPublicUser(user) : null;
}),
lobby: router({
notice: procedure.query(async ({ ctx }) => {
const setting = await ctx.prisma.systemSetting.findUnique({
where: { id: 1 },
});
return setting?.notice ?? '';
}),
profiles: procedure
.input(
z.object({
+1
View File
@@ -82,6 +82,7 @@ export const createGatewayApiServer = async () => {
profileStatus,
adminToken: config.adminToken,
requestHeaders: req.headers,
prisma: postgres.prisma as PrismaClient,
}),
},
});