컴퓨터 방 자동 정리 + 게스트 계정 삭제(로그아웃·하루 미접속) + 테스트 10분→1분
- 방 화면을 벗어나면(홈·규칙) detach: 자리·접속 상태는 유지, 방 접속 수에서 빠짐 - 컴퓨터가 있는 방: 사람이 모두 [방 나가기]하면 바로 닫고, 아무도 안 보면 대기실·끝난 방 1분, 게임 중 30분 뒤 정리 - 게스트 로그아웃 = 계정 삭제(자리·전적·세션·소켓), 사이트를 닫고 24시간 지난 게스트도 1분 주기로 삭제 - users.last_seen_at을 요청·소켓 종료 때 갱신(이전엔 갱신 안 됨), 003 마이그레이션에서 기존 게스트 시계 초기화 - 테스트: 무작위 대국 시드를 playoutSeeds()로 평소 1/10, test:full은 전부. bun test --parallel=4, 테스트 서버 종료 대기 1s→50ms Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,8 @@ export interface GatewayDeps {
|
||||
me(userId: string): PublicUser | null;
|
||||
now?: () => number;
|
||||
log?: (level: 'info' | 'warn' | 'error', msg: string, extra?: Record<string, unknown>) => void;
|
||||
/** A socket closed (the user may have left the site). */
|
||||
onClose?: (userId: string) => void;
|
||||
}
|
||||
|
||||
export const MAX_CONNS_PER_USER = 5;
|
||||
@@ -118,6 +120,7 @@ export class Gateway {
|
||||
if (this.byUser.get(ws.data.userId)?.size === 0) this.byUser.delete(ws.data.userId);
|
||||
const room = ws.data.room ? this.deps.rooms.get(ws.data.room) : undefined;
|
||||
if (room && ws.data.conn) room.disconnect(ws.data.conn);
|
||||
this.deps.onClose?.(ws.data.userId);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -143,6 +146,11 @@ export class Gateway {
|
||||
return;
|
||||
}
|
||||
const room: Room | undefined = ws.data.room ? this.deps.rooms.get(ws.data.room) : undefined;
|
||||
if (m.t === 'detach') {
|
||||
// ws.data.room stays: when this socket closes, the room still learns that the person went offline.
|
||||
if (room && ws.data.conn) room.detach(ws.data.conn);
|
||||
return;
|
||||
}
|
||||
if (!room || room.conns.get(u) !== ws.data.conn) return err('먼저 방에 들어가 주세요.', 'not-in-room');
|
||||
let e: string | null = null;
|
||||
switch (m.t) {
|
||||
@@ -209,6 +217,18 @@ export class Gateway {
|
||||
}
|
||||
}
|
||||
|
||||
isOnline(userId: string): boolean {
|
||||
return (this.byUser.get(userId)?.size ?? 0) > 0;
|
||||
}
|
||||
|
||||
/** The account is gone (guest logged out or expired): close its sockets quietly. */
|
||||
closeUser(userId: string): void {
|
||||
for (const ws of [...(this.byUser.get(userId) ?? [])]) {
|
||||
this.send(ws, { t: 'bye', reason: 'closed' });
|
||||
ws.close(4401, 'logged out');
|
||||
}
|
||||
}
|
||||
|
||||
/** Graceful shutdown: tell everyone to reconnect shortly (docs/03 §10). */
|
||||
shutdown(): void {
|
||||
this.closing = true;
|
||||
|
||||
Reference in New Issue
Block a user