Initial commit: ssessesse ki battle

This commit is contained in:
2026-10-13 11:15:26 +09:00
commit 4f24129e29
104 changed files with 10520 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { randomBytes, randomUUID, createHmac } from 'node:crypto';
import { createServer } from 'node:http';
import { Server } from 'socket.io';
import { io as connect, type Socket } from 'socket.io-client';
import { MongoClient } from 'mongodb';
import { createGameSessionStore } from '../src/server/game-session-store.js';
import { createRoomStore } from '../src/server/rooms.js';
import { registerSignaling } from '../src/server/signaling.js';
test('signaling authenticates membership, relays only within room and releases sockets without forfeiting', { skip: !process.env.TEST_MONGODB_URI }, async () => {
const client = await new MongoClient(process.env.TEST_MONGODB_URI!, { serverSelectionTimeoutMS: 5000 }).connect();
const db = client.db(`dragon_ball_test_signal_${randomUUID().replaceAll('-', '')}`);
const http = createServer(), io = new Server(http); const sockets: Socket[] = [];
try {
const sessions = await createGameSessionStore(db), rooms = await createRoomStore(db);
const a = await sessions.create(randomBytes(32).toString('base64url')), b = await sessions.create(randomBytes(32).toString('base64url')), outsider = await sessions.create(randomBytes(32).toString('base64url'));
const room = await rooms.create(a.gameSessionId, randomUUID()); await rooms.join(b.gameSessionId, room.code);
const signaling = registerSignaling(io, sessions, rooms, { turnUrls: ['turn:localhost:3478'], turnSecret: 'test-secret' });
await new Promise<void>(r => http.listen(0, '127.0.0.1', r));
const url = `http://127.0.0.1:${(http.address() as any).port}/signal`;
function socket(auth: typeof a) { const s = connect(url, { transports: ['websocket'], reconnection: false, autoConnect: false, auth: { ...auth, roomId: room.id } }); sockets.push(s); return s; }
const sa = socket(a), sb = socket(b), stranger = socket(outsider);
const ready = (s: Socket) => new Promise<void>((r, reject) => { s.once('connect', () => r()); s.once('connect_error', reject); s.connect(); });
await Promise.all([ready(sa), ready(sb)]); await assert.rejects(ready(stranger));
const received = new Promise<any>(r => sb.once('signal', r));
const packet = { type: 'offer', matchId: room.currentMatchId, epoch: 0, payload: { type: 'offer', sdp: 'test-sdp' } };
assert.equal((await sa.timeout(2000).emitWithAck('signal', packet)).ok, true);
assert.equal((await received).payload.sdp, 'test-sdp');
assert.equal((await sa.timeout(2000).emitWithAck('signal', { ...packet, matchId: randomUUID() })).ok, false);
assert.equal((await sb.timeout(2000).emitWithAck('signal', packet)).ok, false);
const resumed = socket(a); await ready(resumed); await new Promise(r => setTimeout(r, 20));
assert.equal(sa.connected, false); assert.equal(resumed.connected, true);
assert.equal(signaling.namespace.sockets.size, 2);
const resumedMessage = new Promise<any>(r => sb.once('signal', r));
assert.equal((await resumed.timeout(2000).emitWithAck('signal', { ...packet, epoch: 1 })).ok, true);
assert.equal((await resumedMessage).epoch, 1);
const active = await sessions.register(a, { requestId: randomUUID(), matchId: room.currentMatchId, roomId: room.id, mode: 'friend', expectedPreviousSeq: 0 });
resumed.disconnect(); sb.disconnect(); await new Promise(r => setTimeout(r, 20));
assert.equal(signaling.namespace.sockets.size, 0);
assert.equal((await sessions.get(a)).activeMatch?.matchId, active.matchId);
const rtc = await signaling.rtcConfig(a, room.id);
const turn = rtc.iceServers[0]; assert.ok(turn.username);
assert.equal(turn.credential, createHmac('sha1', 'test-secret').update(turn.username!).digest('base64'));
assert.ok(rtc.expiresAt > Date.now());
} finally {
sockets.forEach(s => s.disconnect()); await new Promise<void>(r => io.close(() => r()));
try { await db.dropDatabase(); } finally { await client.close(); }
}
});