twinwire 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/LICENSE +21 -0
- package/README.md +128 -2
- package/dist/browser/twinwire.js +2075 -0
- package/dist/browser/twinwire.js.map +7 -0
- package/dist/browser/twinwire.min.js +1 -0
- package/dist/browser/twinwire.mjs +2052 -0
- package/dist/browser/twinwire.mjs.map +7 -0
- package/dist/browser.d.ts +5 -0
- package/dist/browser.js +6 -0
- package/dist/browser.js.map +1 -0
- package/dist/client/client.d.ts +128 -0
- package/dist/client/client.js +470 -0
- package/dist/client/client.js.map +1 -0
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.js +4 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/lobby.d.ts +40 -0
- package/dist/client/lobby.js +122 -0
- package/dist/client/lobby.js.map +1 -0
- package/dist/client/rtc.d.ts +17 -0
- package/dist/client/rtc.js +102 -0
- package/dist/client/rtc.js.map +1 -0
- package/dist/core/budget.d.ts +27 -0
- package/dist/core/budget.js +39 -0
- package/dist/core/budget.js.map +1 -0
- package/dist/core/endpoint.d.ts +144 -0
- package/dist/core/endpoint.js +501 -0
- package/dist/core/endpoint.js.map +1 -0
- package/dist/core/lobby.d.ts +59 -0
- package/dist/core/lobby.js +53 -0
- package/dist/core/lobby.js.map +1 -0
- package/dist/core/protocol.d.ts +52 -0
- package/dist/core/protocol.js +100 -0
- package/dist/core/protocol.js.map +1 -0
- package/dist/core/reliable.d.ts +52 -0
- package/dist/core/reliable.js +116 -0
- package/dist/core/reliable.js.map +1 -0
- package/dist/core/rtc.d.ts +28 -0
- package/dist/core/rtc.js +21 -0
- package/dist/core/rtc.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/netcode/clock.d.ts +15 -0
- package/dist/netcode/clock.js +37 -0
- package/dist/netcode/clock.js.map +1 -0
- package/dist/netcode/codec.d.ts +10 -0
- package/dist/netcode/codec.js +95 -0
- package/dist/netcode/codec.js.map +1 -0
- package/dist/netcode/index.d.ts +9 -0
- package/dist/netcode/index.js +10 -0
- package/dist/netcode/index.js.map +1 -0
- package/dist/netcode/inputs.d.ts +7 -0
- package/dist/netcode/inputs.js +43 -0
- package/dist/netcode/inputs.js.map +1 -0
- package/dist/netcode/interpolation.d.ts +44 -0
- package/dist/netcode/interpolation.js +101 -0
- package/dist/netcode/interpolation.js.map +1 -0
- package/dist/netcode/prediction.d.ts +40 -0
- package/dist/netcode/prediction.js +97 -0
- package/dist/netcode/prediction.js.map +1 -0
- package/dist/netcode/replication.d.ts +36 -0
- package/dist/netcode/replication.js +90 -0
- package/dist/netcode/replication.js.map +1 -0
- package/dist/netcode/snapshots.d.ts +29 -0
- package/dist/netcode/snapshots.js +78 -0
- package/dist/netcode/snapshots.js.map +1 -0
- package/dist/netcode/spatial.d.ts +16 -0
- package/dist/netcode/spatial.js +63 -0
- package/dist/netcode/spatial.js.map +1 -0
- package/dist/netcode/timing.d.ts +37 -0
- package/dist/netcode/timing.js +41 -0
- package/dist/netcode/timing.js.map +1 -0
- package/dist/server/index.d.ts +4 -0
- package/dist/server/index.js +5 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/lobby.d.ts +134 -0
- package/dist/server/lobby.js +462 -0
- package/dist/server/lobby.js.map +1 -0
- package/dist/server/rtc.d.ts +38 -0
- package/dist/server/rtc.js +102 -0
- package/dist/server/rtc.js.map +1 -0
- package/dist/server/server.d.ts +145 -0
- package/dist/server/server.js +457 -0
- package/dist/server/server.js.map +1 -0
- package/dist/server/turn.d.ts +22 -0
- package/dist/server/turn.js +52 -0
- package/dist/server/turn.js.map +1 -0
- package/docs/ADOPTING.md +64 -0
- package/docs/API.md +181 -0
- package/docs/ARCHITECTURE.md +101 -0
- package/docs/OPERATIONS.md +93 -0
- package/docs/RELEASE-CHECKLIST.md +25 -0
- package/package.json +100 -4
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
import { randomInt } from 'node:crypto';
|
|
2
|
+
import { CODE_ALPHABET, LOBBY_KEY, cleanMeta, cleanName, isLobbyMessage, metaMatches, normalizeCode, } from '../core/lobby.js';
|
|
3
|
+
export class Room {
|
|
4
|
+
lobby;
|
|
5
|
+
code;
|
|
6
|
+
mode;
|
|
7
|
+
visibility;
|
|
8
|
+
maxMembers;
|
|
9
|
+
phase = 'lobby';
|
|
10
|
+
meta;
|
|
11
|
+
/** Free for the application (its simulation, world). */
|
|
12
|
+
data = undefined;
|
|
13
|
+
members = new Map();
|
|
14
|
+
host = null;
|
|
15
|
+
countdownEndsAt = null;
|
|
16
|
+
createdAt = Date.now();
|
|
17
|
+
emptySince = null;
|
|
18
|
+
closed = false;
|
|
19
|
+
/** @internal */ countdown;
|
|
20
|
+
constructor(lobby, code, mode, visibility, maxMembers, meta) {
|
|
21
|
+
this.lobby = lobby;
|
|
22
|
+
this.code = code;
|
|
23
|
+
this.mode = mode;
|
|
24
|
+
this.visibility = visibility;
|
|
25
|
+
this.maxMembers = maxMembers;
|
|
26
|
+
this.meta = meta;
|
|
27
|
+
}
|
|
28
|
+
get connectedCount() { let n = 0; for (const m of this.members.values())
|
|
29
|
+
if (m.connected)
|
|
30
|
+
n++; return n; }
|
|
31
|
+
memberAt(seat) { for (const m of this.members.values())
|
|
32
|
+
if (m.seat === seat)
|
|
33
|
+
return m; return undefined; }
|
|
34
|
+
view(viewer) {
|
|
35
|
+
const members = [...this.members.values()].sort((a, b) => a.seat - b.seat).map(m => ({
|
|
36
|
+
seat: m.seat, name: m.name, ready: m.ready, connected: m.connected, host: m === this.host, meta: m.meta,
|
|
37
|
+
}));
|
|
38
|
+
return { code: this.code, mode: this.mode, visibility: this.visibility, phase: this.phase, maxMembers: this.maxMembers,
|
|
39
|
+
meta: this.meta, you: viewer?.seat ?? -1, members, countdownEndsAt: this.countdownEndsAt };
|
|
40
|
+
}
|
|
41
|
+
/** Reliable event to every member (disconnected ones get it on resume). Returns members whose outbox was full. */
|
|
42
|
+
broadcast(data, except) {
|
|
43
|
+
const rejected = [];
|
|
44
|
+
for (const m of this.members.values())
|
|
45
|
+
if (m !== except && !this.send(m, data))
|
|
46
|
+
rejected.push(m);
|
|
47
|
+
return rejected;
|
|
48
|
+
}
|
|
49
|
+
send(member, data) {
|
|
50
|
+
try {
|
|
51
|
+
member.session.sendEvent(data);
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
this.lobby.report(e);
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
setPhase(phase) {
|
|
60
|
+
if (typeof phase !== 'string' || !phase || phase.length > 24)
|
|
61
|
+
throw new RangeError('Invalid phase');
|
|
62
|
+
if (phase === this.phase)
|
|
63
|
+
return;
|
|
64
|
+
this.phase = phase;
|
|
65
|
+
this.lobby.cancelCountdown(this);
|
|
66
|
+
if (phase === 'lobby')
|
|
67
|
+
for (const m of this.members.values())
|
|
68
|
+
m.ready = false;
|
|
69
|
+
this.lobby.changed(this);
|
|
70
|
+
}
|
|
71
|
+
setMeta(patch) { Object.assign(this.meta, patch); this.lobby.changed(this); }
|
|
72
|
+
setVisibility(v) { this.visibility = v; this.lobby.changed(this); }
|
|
73
|
+
/** Start now (skips the ready countdown). */
|
|
74
|
+
start() { this.lobby.startRoom(this); }
|
|
75
|
+
close(reason = 'closed') { this.lobby.closeRoom(this, reason); }
|
|
76
|
+
}
|
|
77
|
+
export class Lobby {
|
|
78
|
+
server;
|
|
79
|
+
rooms = new Map();
|
|
80
|
+
bySession = new Map();
|
|
81
|
+
creations = new Map();
|
|
82
|
+
timer;
|
|
83
|
+
off;
|
|
84
|
+
options;
|
|
85
|
+
/** A room was made by request; `request.init` carries the creator's setup data (validate it). */
|
|
86
|
+
onCreate = () => { };
|
|
87
|
+
onJoin = () => { };
|
|
88
|
+
onLeave = () => { };
|
|
89
|
+
onDisconnect = () => { };
|
|
90
|
+
/** A member's session is back on a new connection: after a drop, or a reloaded page taking it over. */
|
|
91
|
+
onReconnect = () => { };
|
|
92
|
+
onStart = () => { };
|
|
93
|
+
onClose = () => { };
|
|
94
|
+
/** Application events (anything that is not a lobby request). room/member are null outside a room. */
|
|
95
|
+
onEvent = () => { };
|
|
96
|
+
onState = () => { };
|
|
97
|
+
onError = () => { };
|
|
98
|
+
constructor(server, o = {}) {
|
|
99
|
+
this.server = server;
|
|
100
|
+
this.options = {
|
|
101
|
+
maxMembers: o.maxMembers ?? 4, codeLength: o.codeLength ?? 4, emptyCloseMs: o.emptyCloseMs ?? 30_000,
|
|
102
|
+
maxRooms: o.maxRooms ?? 500, maxRoomsPerIpPerHour: o.maxRoomsPerIpPerHour ?? 30,
|
|
103
|
+
joinablePhases: o.joinablePhases ?? ['lobby', 'playing'], quickPlayPhases: o.quickPlayPhases ?? ['lobby'],
|
|
104
|
+
evictDisconnected: o.evictDisconnected ?? true, allowHostKick: o.allowHostKick ?? true,
|
|
105
|
+
ready: o.ready === undefined ? { countdownMs: 3000, minMembers: 1 } : o.ready, canCreate: o.canCreate, canJoin: o.canJoin, clientMetaKeys: o.clientMetaKeys,
|
|
106
|
+
};
|
|
107
|
+
const opt = this.options;
|
|
108
|
+
if (!Number.isInteger(opt.maxMembers) || opt.maxMembers < 1 || opt.maxMembers > 64 ||
|
|
109
|
+
!Number.isInteger(opt.codeLength) || opt.codeLength < 3 || opt.codeLength > 12)
|
|
110
|
+
throw new RangeError('Invalid lobby options');
|
|
111
|
+
this.off = [
|
|
112
|
+
server.on('session', (s, resumed) => this.attach(s, resumed)),
|
|
113
|
+
server.on('disconnect', s => this.disconnected(s)),
|
|
114
|
+
server.on('expire', s => { const m = this.bySession.get(s.id); if (m)
|
|
115
|
+
this.removeMember(m, 'expired'); }),
|
|
116
|
+
];
|
|
117
|
+
for (const s of server.sessions.values())
|
|
118
|
+
if (s.connected)
|
|
119
|
+
this.attach(s, false);
|
|
120
|
+
this.timer = setInterval(() => this.sweep(), 1000);
|
|
121
|
+
this.timer.unref?.();
|
|
122
|
+
}
|
|
123
|
+
/** @internal */ report(e) { try {
|
|
124
|
+
this.onError(e instanceof Error ? e : new Error(String(e)));
|
|
125
|
+
}
|
|
126
|
+
catch { /* ignore */ } }
|
|
127
|
+
memberOf(session) { return this.bySession.get(session.id); }
|
|
128
|
+
roomOf(session) { return this.bySession.get(session.id)?.room; }
|
|
129
|
+
dispose() { clearInterval(this.timer); for (const f of this.off)
|
|
130
|
+
f(); for (const r of [...this.rooms.values()])
|
|
131
|
+
this.closeRoom(r, 'shutdown'); }
|
|
132
|
+
attach(s, resumed) {
|
|
133
|
+
s.onEvent = data => this.event(s, data);
|
|
134
|
+
s.onState = state => { const m = this.bySession.get(s.id); try {
|
|
135
|
+
this.onState(m?.room ?? null, m ?? null, state, s);
|
|
136
|
+
}
|
|
137
|
+
catch (e) {
|
|
138
|
+
this.report(e);
|
|
139
|
+
} };
|
|
140
|
+
// back on a new connection: after a drop, or taking over from a socket the server hasn't seen close yet (a reloaded
|
|
141
|
+
// page resuming its checkpoint). Either way the client is a fresh instance, so the game re-sends what it needs.
|
|
142
|
+
const m = this.bySession.get(s.id);
|
|
143
|
+
if (m && resumed) {
|
|
144
|
+
m.connected = true;
|
|
145
|
+
m.disconnectedAt = 0;
|
|
146
|
+
this.safe(() => this.onReconnect(m.room, m));
|
|
147
|
+
this.changed(m.room);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
disconnected(s) {
|
|
151
|
+
const m = this.bySession.get(s.id);
|
|
152
|
+
if (!m || !m.connected)
|
|
153
|
+
return;
|
|
154
|
+
m.connected = false;
|
|
155
|
+
m.disconnectedAt = Date.now();
|
|
156
|
+
m.ready = false;
|
|
157
|
+
if (m.room.host === m)
|
|
158
|
+
this.pickHost(m.room);
|
|
159
|
+
this.cancelCountdown(m.room);
|
|
160
|
+
this.safe(() => this.onDisconnect(m.room, m));
|
|
161
|
+
this.changed(m.room);
|
|
162
|
+
}
|
|
163
|
+
safe(fn) { try {
|
|
164
|
+
fn();
|
|
165
|
+
}
|
|
166
|
+
catch (e) {
|
|
167
|
+
this.report(e);
|
|
168
|
+
} }
|
|
169
|
+
event(s, data) {
|
|
170
|
+
if (!isLobbyMessage(data)) {
|
|
171
|
+
const m = this.bySession.get(s.id);
|
|
172
|
+
this.safe(() => this.onEvent(m?.room ?? null, m ?? null, data, s));
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const d = data, id = d.id, op = d[LOBBY_KEY];
|
|
176
|
+
const reply = (r) => { if (typeof id === 'number')
|
|
177
|
+
this.send(s, { [LOBBY_KEY]: 'res', id, ...r }); };
|
|
178
|
+
try {
|
|
179
|
+
switch (op) {
|
|
180
|
+
case 'create': return reply(this.create(s, d));
|
|
181
|
+
case 'join': return reply(this.join(s, d));
|
|
182
|
+
case 'quick': return reply(this.quickPlay(s, d));
|
|
183
|
+
case 'leave': {
|
|
184
|
+
const m = this.bySession.get(s.id);
|
|
185
|
+
if (m)
|
|
186
|
+
this.removeMember(m, 'left', false);
|
|
187
|
+
return reply({ ok: true, room: null });
|
|
188
|
+
}
|
|
189
|
+
case 'ready': return reply(this.member(s, m => { this.setReady(m, d.ready === true); }));
|
|
190
|
+
case 'name': return reply(this.member(s, m => { const n = cleanName(d.name); if (n)
|
|
191
|
+
m.name = n; this.changed(m.room); }));
|
|
192
|
+
case 'meta': return reply(this.member(s, m => {
|
|
193
|
+
const meta = this.clientMeta(d.meta);
|
|
194
|
+
if (!meta)
|
|
195
|
+
throw new Error('invalid meta');
|
|
196
|
+
const merged = { ...m.meta, ...meta };
|
|
197
|
+
if (Object.keys(merged).length > 32 || JSON.stringify(merged).length > 4096)
|
|
198
|
+
throw new Error('too much meta');
|
|
199
|
+
m.meta = merged;
|
|
200
|
+
this.changed(m.room);
|
|
201
|
+
}));
|
|
202
|
+
case 'kick': return reply(this.member(s, m => {
|
|
203
|
+
if (!this.options.allowHostKick || m.room.host !== m)
|
|
204
|
+
throw new Error('only the host can do that');
|
|
205
|
+
const target = typeof d.seat === 'number' ? m.room.memberAt(d.seat) : undefined;
|
|
206
|
+
if (!target || target === m)
|
|
207
|
+
throw new Error('no such player');
|
|
208
|
+
this.removeMember(target, 'kicked');
|
|
209
|
+
}));
|
|
210
|
+
default: return reply({ ok: false, error: 'unknown request' });
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
catch (e) {
|
|
214
|
+
reply({ ok: false, error: e instanceof Error ? e.message.slice(0, 120) : 'error' });
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
member(s, fn) {
|
|
218
|
+
const m = this.bySession.get(s.id);
|
|
219
|
+
if (!m)
|
|
220
|
+
return { ok: false, error: 'not in a room' };
|
|
221
|
+
fn(m);
|
|
222
|
+
return { ok: true, room: m.room.view(m) };
|
|
223
|
+
}
|
|
224
|
+
send(s, data) { try {
|
|
225
|
+
s.sendEvent(data);
|
|
226
|
+
}
|
|
227
|
+
catch (e) {
|
|
228
|
+
this.report(e);
|
|
229
|
+
} }
|
|
230
|
+
/** A client's meta, cleaned and limited to the keys clients may set (null: invalid). */
|
|
231
|
+
clientMeta(v) {
|
|
232
|
+
const meta = cleanMeta(v), keys = this.options.clientMetaKeys;
|
|
233
|
+
if (!meta || !keys)
|
|
234
|
+
return meta;
|
|
235
|
+
for (const k of Object.keys(meta))
|
|
236
|
+
if (!keys.includes(k))
|
|
237
|
+
delete meta[k];
|
|
238
|
+
return meta;
|
|
239
|
+
}
|
|
240
|
+
newCode() {
|
|
241
|
+
for (let tries = 0; tries < 1000; tries++) {
|
|
242
|
+
let c = '';
|
|
243
|
+
for (let i = 0; i < this.options.codeLength; i++)
|
|
244
|
+
c += CODE_ALPHABET[randomInt(CODE_ALPHABET.length)];
|
|
245
|
+
if (!this.rooms.has(c))
|
|
246
|
+
return c;
|
|
247
|
+
}
|
|
248
|
+
throw new Error('no free room codes');
|
|
249
|
+
}
|
|
250
|
+
rateOk(ip) {
|
|
251
|
+
const now = Date.now(), list = (this.creations.get(ip) ?? []).filter(t => now - t < 3600_000);
|
|
252
|
+
if (list.length >= this.options.maxRoomsPerIpPerHour) {
|
|
253
|
+
this.creations.set(ip, list);
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
list.push(now);
|
|
257
|
+
this.creations.set(ip, list);
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
/** Create a room on the server's own initiative (no creator). */
|
|
261
|
+
createRoom(o = {}) {
|
|
262
|
+
if (this.rooms.size >= this.options.maxRooms)
|
|
263
|
+
throw new Error('the server is busy: try again soon');
|
|
264
|
+
const max = Math.min(this.options.maxMembers, Number.isInteger(o.maxMembers) && o.maxMembers > 0 ? o.maxMembers : this.options.maxMembers);
|
|
265
|
+
const mode = typeof o.mode === 'string' && /^[\w.-]{1,32}$/.test(o.mode) ? o.mode : 'default';
|
|
266
|
+
const room = new Room(this, this.newCode(), mode, o.visibility === 'public' ? 'public' : 'private', max, o.meta ?? {});
|
|
267
|
+
this.rooms.set(room.code, room);
|
|
268
|
+
room.emptySince = Date.now();
|
|
269
|
+
return room;
|
|
270
|
+
}
|
|
271
|
+
create(s, req) {
|
|
272
|
+
const meta = cleanMeta(req.meta), memberMeta = this.clientMeta(req.memberMeta);
|
|
273
|
+
if (!meta || !memberMeta)
|
|
274
|
+
return { ok: false, error: 'invalid meta' };
|
|
275
|
+
const refused = this.options.canCreate?.(s, req);
|
|
276
|
+
if (refused)
|
|
277
|
+
return { ok: false, error: refused };
|
|
278
|
+
if (!this.rateOk(s.ip))
|
|
279
|
+
return { ok: false, error: 'too many rooms made from here: try again later' };
|
|
280
|
+
const room = this.createRoom({ ...req, meta });
|
|
281
|
+
this.safe(() => this.onCreate(room, s, req));
|
|
282
|
+
if (room.closed)
|
|
283
|
+
return { ok: false, error: 'room closed' };
|
|
284
|
+
return this.seat(room, s, req.name, memberMeta);
|
|
285
|
+
}
|
|
286
|
+
join(s, req) {
|
|
287
|
+
const code = normalizeCode(req.code), room = code ? this.rooms.get(code) : undefined;
|
|
288
|
+
if (!room || room.closed)
|
|
289
|
+
return { ok: false, error: `no room called ${code ?? String(req.code).slice(0, 12).toUpperCase()}` };
|
|
290
|
+
const already = this.bySession.get(s.id);
|
|
291
|
+
if (already?.room === room)
|
|
292
|
+
return { ok: true, room: room.view(already) };
|
|
293
|
+
if (!this.options.joinablePhases.includes(room.phase))
|
|
294
|
+
return { ok: false, error: 'that game has already started' };
|
|
295
|
+
const refused = this.options.canJoin?.(room, s, req);
|
|
296
|
+
if (refused)
|
|
297
|
+
return { ok: false, error: refused };
|
|
298
|
+
const memberMeta = this.clientMeta(req.memberMeta);
|
|
299
|
+
if (!memberMeta)
|
|
300
|
+
return { ok: false, error: 'invalid meta' };
|
|
301
|
+
return this.seat(room, s, req.name, memberMeta);
|
|
302
|
+
}
|
|
303
|
+
quickPlay(s, req) {
|
|
304
|
+
const mode = typeof req.mode === 'string' ? req.mode : 'default', match = cleanMeta(req.match), memberMeta = this.clientMeta(req.memberMeta);
|
|
305
|
+
if (!match || !memberMeta)
|
|
306
|
+
return { ok: false, error: 'invalid meta' };
|
|
307
|
+
const current = this.bySession.get(s.id)?.room;
|
|
308
|
+
let best = null, bestScore = -1;
|
|
309
|
+
for (const r of this.rooms.values()) {
|
|
310
|
+
if (r.closed || r.visibility !== 'public' || r.mode !== mode || !this.options.quickPlayPhases.includes(r.phase) || !metaMatches(r.meta, match))
|
|
311
|
+
continue;
|
|
312
|
+
if (r !== current && !this.hasSeat(r))
|
|
313
|
+
continue;
|
|
314
|
+
if (r !== current && this.options.canJoin?.(r, s, req))
|
|
315
|
+
continue;
|
|
316
|
+
const score = r.connectedCount * 1e6 + (1e6 - Math.min(1e6 - 1, (Date.now() - r.createdAt) / 1000));
|
|
317
|
+
if (r.connectedCount > 0 || r === current)
|
|
318
|
+
if (score > bestScore) {
|
|
319
|
+
best = r;
|
|
320
|
+
bestScore = score;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (best) {
|
|
324
|
+
const m = this.bySession.get(s.id);
|
|
325
|
+
return best === current && m ? { ok: true, room: best.view(m) } : this.seat(best, s, req.name, memberMeta);
|
|
326
|
+
}
|
|
327
|
+
return this.create(s, { ...(req.create ?? {}), meta: { ...(req.create?.meta ?? {}), ...match }, mode, visibility: 'public', name: req.name, memberMeta });
|
|
328
|
+
}
|
|
329
|
+
hasSeat(r) {
|
|
330
|
+
return r.members.size < r.maxMembers || this.options.evictDisconnected && [...r.members.values()].some(m => !m.connected);
|
|
331
|
+
}
|
|
332
|
+
seat(room, s, name, meta) {
|
|
333
|
+
if (room.members.size >= room.maxMembers) {
|
|
334
|
+
const away = [...room.members.values()].filter(m => !m.connected).sort((a, b) => a.disconnectedAt - b.disconnectedAt)[0];
|
|
335
|
+
if (!this.options.evictDisconnected || !away)
|
|
336
|
+
return { ok: false, error: 'that room is full' };
|
|
337
|
+
this.removeMember(away, 'replaced');
|
|
338
|
+
}
|
|
339
|
+
const old = this.bySession.get(s.id);
|
|
340
|
+
if (old)
|
|
341
|
+
this.removeMember(old, 'switched', false);
|
|
342
|
+
const taken = new Set([...room.members.values()].map(m => m.seat));
|
|
343
|
+
let seat = 0;
|
|
344
|
+
while (taken.has(seat))
|
|
345
|
+
seat++;
|
|
346
|
+
const fallback = cleanName(s.hello?.name) || `PLAYER ${seat + 1}`;
|
|
347
|
+
const m = { session: s, room, seat, joinedAt: Date.now(), name: cleanName(name) || fallback, ready: false, connected: s.connected,
|
|
348
|
+
disconnectedAt: 0, meta, data: undefined };
|
|
349
|
+
room.members.set(s.id, m);
|
|
350
|
+
this.bySession.set(s.id, m);
|
|
351
|
+
room.emptySince = null;
|
|
352
|
+
if (!room.host || !room.host.connected)
|
|
353
|
+
this.pickHost(room);
|
|
354
|
+
this.cancelCountdown(room);
|
|
355
|
+
this.safe(() => this.onJoin(room, m));
|
|
356
|
+
this.changed(room, m);
|
|
357
|
+
return { ok: true, room: room.view(m) };
|
|
358
|
+
}
|
|
359
|
+
pickHost(room) {
|
|
360
|
+
const list = [...room.members.values()].sort((a, b) => a.joinedAt - b.joinedAt);
|
|
361
|
+
room.host = list.find(m => m.connected) ?? list[0] ?? null;
|
|
362
|
+
}
|
|
363
|
+
removeMember(m, reason, notify = true) {
|
|
364
|
+
const room = m.room;
|
|
365
|
+
if (room.members.get(m.session.id) !== m)
|
|
366
|
+
return;
|
|
367
|
+
room.members.delete(m.session.id);
|
|
368
|
+
this.bySession.delete(m.session.id);
|
|
369
|
+
if (notify)
|
|
370
|
+
this.send(m.session, { [LOBBY_KEY]: 'left', reason });
|
|
371
|
+
if (room.host === m)
|
|
372
|
+
this.pickHost(room);
|
|
373
|
+
if (!room.members.size)
|
|
374
|
+
room.emptySince = Date.now();
|
|
375
|
+
this.cancelCountdown(room);
|
|
376
|
+
this.safe(() => this.onLeave(room, m, reason));
|
|
377
|
+
if (reason === 'kicked')
|
|
378
|
+
this.server.endSession(m.session, 'kicked');
|
|
379
|
+
this.changed(room);
|
|
380
|
+
}
|
|
381
|
+
setReady(m, ready) {
|
|
382
|
+
if (!this.options.ready)
|
|
383
|
+
throw new Error('this game has no ready-up');
|
|
384
|
+
if (m.room.phase !== 'lobby')
|
|
385
|
+
throw new Error('the game is already running');
|
|
386
|
+
m.ready = ready;
|
|
387
|
+
if (!ready)
|
|
388
|
+
this.cancelCountdown(m.room);
|
|
389
|
+
this.changed(m.room);
|
|
390
|
+
}
|
|
391
|
+
/** @internal Everyone gets the new room view; a ready room starts its countdown. */
|
|
392
|
+
changed(room, skip) {
|
|
393
|
+
if (room.closed)
|
|
394
|
+
return;
|
|
395
|
+
for (const m of room.members.values())
|
|
396
|
+
if (m !== skip)
|
|
397
|
+
this.send(m.session, { [LOBBY_KEY]: 'room', room: room.view(m) });
|
|
398
|
+
this.checkReady(room);
|
|
399
|
+
}
|
|
400
|
+
checkReady(room) {
|
|
401
|
+
const r = this.options.ready;
|
|
402
|
+
if (!r || room.phase !== 'lobby' || room.countdownEndsAt !== null)
|
|
403
|
+
return;
|
|
404
|
+
const live = [...room.members.values()].filter(m => m.connected);
|
|
405
|
+
if (live.length < Math.max(1, r.minMembers ?? 1) || !live.every(m => m.ready))
|
|
406
|
+
return;
|
|
407
|
+
const ms = r.countdownMs ?? 3000;
|
|
408
|
+
if (ms <= 0) {
|
|
409
|
+
this.startRoom(room);
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
room.countdownEndsAt = performance.now() + ms;
|
|
413
|
+
room.countdown = setTimeout(() => { room.countdown = undefined; if (room.countdownEndsAt !== null)
|
|
414
|
+
this.startRoom(room); }, ms);
|
|
415
|
+
for (const m of room.members.values())
|
|
416
|
+
this.send(m.session, { [LOBBY_KEY]: 'room', room: room.view(m) });
|
|
417
|
+
}
|
|
418
|
+
/** @internal */ cancelCountdown(room) {
|
|
419
|
+
if (room.countdownEndsAt === null)
|
|
420
|
+
return;
|
|
421
|
+
clearTimeout(room.countdown);
|
|
422
|
+
room.countdown = undefined;
|
|
423
|
+
room.countdownEndsAt = null;
|
|
424
|
+
for (const m of room.members.values())
|
|
425
|
+
this.send(m.session, { [LOBBY_KEY]: 'room', room: room.view(m) });
|
|
426
|
+
}
|
|
427
|
+
/** @internal */ startRoom(room) {
|
|
428
|
+
if (room.closed)
|
|
429
|
+
return;
|
|
430
|
+
clearTimeout(room.countdown);
|
|
431
|
+
room.countdown = undefined;
|
|
432
|
+
room.countdownEndsAt = null;
|
|
433
|
+
room.phase = 'playing';
|
|
434
|
+
for (const m of room.members.values())
|
|
435
|
+
m.ready = false;
|
|
436
|
+
this.safe(() => this.onStart(room));
|
|
437
|
+
this.changed(room);
|
|
438
|
+
}
|
|
439
|
+
/** @internal */ closeRoom(room, reason) {
|
|
440
|
+
if (room.closed)
|
|
441
|
+
return;
|
|
442
|
+
clearTimeout(room.countdown);
|
|
443
|
+
for (const m of [...room.members.values()]) {
|
|
444
|
+
room.members.delete(m.session.id);
|
|
445
|
+
this.bySession.delete(m.session.id);
|
|
446
|
+
this.send(m.session, { [LOBBY_KEY]: 'left', reason });
|
|
447
|
+
}
|
|
448
|
+
room.closed = true;
|
|
449
|
+
this.rooms.delete(room.code);
|
|
450
|
+
this.safe(() => this.onClose(room, reason));
|
|
451
|
+
}
|
|
452
|
+
sweep() {
|
|
453
|
+
const now = Date.now();
|
|
454
|
+
for (const r of [...this.rooms.values()])
|
|
455
|
+
if (!r.members.size && r.emptySince !== null && now - r.emptySince >= this.options.emptyCloseMs)
|
|
456
|
+
this.closeRoom(r, 'empty');
|
|
457
|
+
for (const [ip, list] of this.creations)
|
|
458
|
+
if (!list.some(t => now - t < 3600_000))
|
|
459
|
+
this.creations.delete(ip);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
//# sourceMappingURL=lobby.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lobby.js","sourceRoot":"","sources":["../../src/server/lobby.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { RtcCallbacks, RtcPeer } from '../core/rtc.js';
|
|
2
|
+
/** Minimal structural surface used from node-datachannel. The native module is optional and server-only. */
|
|
3
|
+
interface NativeChannel {
|
|
4
|
+
isOpen(): boolean;
|
|
5
|
+
bufferedAmount(): number;
|
|
6
|
+
sendMessageBinary(b: Buffer): boolean;
|
|
7
|
+
close(): void;
|
|
8
|
+
onOpen(cb: () => void): void;
|
|
9
|
+
onClosed(cb: () => void): void;
|
|
10
|
+
onError(cb: (s: string) => void): void;
|
|
11
|
+
onMessage(cb: (m: string | Buffer) => void): void;
|
|
12
|
+
}
|
|
13
|
+
interface NativeConnection {
|
|
14
|
+
setRemoteDescription(sdp: string, type: string): void;
|
|
15
|
+
addRemoteCandidate(candidate: string, mid: string): void;
|
|
16
|
+
createDataChannel(label: string, o: Record<string, unknown>): NativeChannel;
|
|
17
|
+
onLocalDescription(cb: (sdp: string, type: string) => void): void;
|
|
18
|
+
onLocalCandidate(cb: (candidate: string, mid: string) => void): void;
|
|
19
|
+
onStateChange(cb: (state: string) => void): void;
|
|
20
|
+
close(): void;
|
|
21
|
+
}
|
|
22
|
+
interface NativeModule {
|
|
23
|
+
PeerConnection: new (name: string, options: Record<string, unknown>) => NativeConnection;
|
|
24
|
+
}
|
|
25
|
+
export type RtcFactory = (cb: RtcCallbacks) => RtcPeer;
|
|
26
|
+
export interface NativeRtcOptions {
|
|
27
|
+
port?: number;
|
|
28
|
+
publicIp?: string;
|
|
29
|
+
bindAddress?: string;
|
|
30
|
+
iceServers?: string[];
|
|
31
|
+
/** Largest datagram accepted or sent, header included (default 64 KiB + 22). Match the endpoints' maxStateBytes. */
|
|
32
|
+
maxMessageSize?: number;
|
|
33
|
+
}
|
|
34
|
+
/** Load before opening the server. Missing native dependencies fail explicitly, not silently. */
|
|
35
|
+
export declare function createNativeRtcFactory(options?: NativeRtcOptions): Promise<RtcFactory>;
|
|
36
|
+
/** Dependency injection is also used by adapter contract tests. */
|
|
37
|
+
export declare function nativeRtcFactory(native: NativeModule, options?: NativeRtcOptions): RtcFactory;
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/** Load before opening the server. Missing native dependencies fail explicitly, not silently. */
|
|
2
|
+
export async function createNativeRtcFactory(options = {}) {
|
|
3
|
+
const name = 'node-datachannel';
|
|
4
|
+
const imported = await import(name);
|
|
5
|
+
const native = (imported.default ?? imported);
|
|
6
|
+
if (typeof native.PeerConnection !== 'function')
|
|
7
|
+
throw new Error('Unsupported node-datachannel module');
|
|
8
|
+
return nativeRtcFactory(native, options);
|
|
9
|
+
}
|
|
10
|
+
/** Dependency injection is also used by adapter contract tests. */
|
|
11
|
+
export function nativeRtcFactory(native, options = {}) {
|
|
12
|
+
const port = options.port ?? 8788;
|
|
13
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
14
|
+
throw new RangeError('Invalid UDP port');
|
|
15
|
+
if (options.publicIp && (!/^(\d{1,3}\.){3}\d{1,3}$/.test(options.publicIp) || options.publicIp.split('.').some(n => Number(n) > 255)))
|
|
16
|
+
throw new Error('publicIp must be an IPv4 address');
|
|
17
|
+
const maxMessage = options.maxMessageSize ?? 64 * 1024 + 22;
|
|
18
|
+
if (!Number.isInteger(maxMessage) || maxMessage < 1100 || maxMessage > 256 * 1024 + 22)
|
|
19
|
+
throw new RangeError('Invalid maxMessageSize');
|
|
20
|
+
let counter = 0;
|
|
21
|
+
return cb => {
|
|
22
|
+
let alive = true, remote = false, dc;
|
|
23
|
+
const pending = [];
|
|
24
|
+
const cfg = { iceServers: options.iceServers ?? [], enableIceUdpMux: true,
|
|
25
|
+
portRangeBegin: port, portRangeEnd: port, maxMessageSize: maxMessage };
|
|
26
|
+
if (options.bindAddress)
|
|
27
|
+
cfg.bindAddress = options.bindAddress;
|
|
28
|
+
const pc = new native.PeerConnection('twinwire-' + (++counter), cfg);
|
|
29
|
+
const advertised = (s) => options.publicIp
|
|
30
|
+
? s.replace(/(candidate:\S+ \d+ udp \d+ )(\S+)( \d+ typ host)/gi, `$1${options.publicIp}$3`) : s;
|
|
31
|
+
const close = () => { if (!alive)
|
|
32
|
+
return; alive = false; pending.length = 0; try {
|
|
33
|
+
dc?.close();
|
|
34
|
+
pc.close();
|
|
35
|
+
}
|
|
36
|
+
catch { } };
|
|
37
|
+
pc.onLocalDescription((sdp, type) => { if (alive && type.toLowerCase() === 'answer')
|
|
38
|
+
cb.signal({ kind: 'answer', sdp: advertised(sdp) }); });
|
|
39
|
+
pc.onLocalCandidate((candidate, mid) => { if (alive)
|
|
40
|
+
cb.signal({ kind: 'candidate', candidate: advertised(candidate), mid }); });
|
|
41
|
+
pc.onStateChange(state => { if (alive && ['failed', 'closed'].includes(state.toLowerCase())) {
|
|
42
|
+
close();
|
|
43
|
+
cb.closed();
|
|
44
|
+
} });
|
|
45
|
+
return {
|
|
46
|
+
close,
|
|
47
|
+
signal(m) {
|
|
48
|
+
if (!alive)
|
|
49
|
+
return;
|
|
50
|
+
try {
|
|
51
|
+
if (m.kind === 'offer') {
|
|
52
|
+
if (remote)
|
|
53
|
+
throw new Error('Duplicate RTC offer');
|
|
54
|
+
pc.setRemoteDescription(m.sdp, 'offer');
|
|
55
|
+
remote = true;
|
|
56
|
+
dc = pc.createDataChannel('twinwire', { negotiated: true, id: 0, unordered: true, maxRetransmits: 0 });
|
|
57
|
+
const channel = dc;
|
|
58
|
+
channel.onOpen(() => {
|
|
59
|
+
if (alive)
|
|
60
|
+
cb.open({
|
|
61
|
+
get open() { return alive && channel.isOpen(); }, get bufferedAmount() { return channel.bufferedAmount(); },
|
|
62
|
+
send: b => {
|
|
63
|
+
if (!alive || !channel.isOpen())
|
|
64
|
+
return false;
|
|
65
|
+
// libdatachannel returns false when a connected SCTP send was queued.
|
|
66
|
+
// A nonthrowing call is consumed here; Endpoint enforces the queue limit.
|
|
67
|
+
channel.sendMessageBinary(Buffer.from(b));
|
|
68
|
+
return true;
|
|
69
|
+
}, close,
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
channel.onMessage(m => { if (alive && typeof m !== 'string' && m.length <= maxMessage)
|
|
73
|
+
cb.data(new Uint8Array(m)); });
|
|
74
|
+
channel.onClosed(() => { if (alive) {
|
|
75
|
+
close();
|
|
76
|
+
cb.closed();
|
|
77
|
+
} });
|
|
78
|
+
channel.onError(s => { if (alive)
|
|
79
|
+
cb.error(new Error(s)); });
|
|
80
|
+
for (const c of pending)
|
|
81
|
+
pc.addRemoteCandidate(c.candidate, c.mid);
|
|
82
|
+
pending.length = 0;
|
|
83
|
+
}
|
|
84
|
+
else if (m.kind === 'candidate') {
|
|
85
|
+
if (remote)
|
|
86
|
+
pc.addRemoteCandidate(m.candidate, m.mid);
|
|
87
|
+
else {
|
|
88
|
+
if (pending.length >= 64)
|
|
89
|
+
throw new Error('Too many RTC candidates');
|
|
90
|
+
pending.push(m);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
cb.error(error instanceof Error ? error : new Error(String(error)));
|
|
96
|
+
close();
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=rtc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rtc.js","sourceRoot":"","sources":["../../src/server/rtc.ts"],"names":[],"mappings":"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"}
|