onelobby 0.2.0 → 0.2.1
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/README.md +2 -2
- package/dist/direct/hub.js +23 -5
- package/dist/direct/hub.js.map +1 -1
- package/dist/direct/index.d.ts +8 -1
- package/dist/direct/index.js +17 -8
- package/dist/direct/index.js.map +1 -1
- package/dist/lobby.d.ts +41 -4
- package/dist/lobby.js +73 -15
- package/dist/lobby.js.map +1 -1
- package/dist/onelobby.bundle.mjs +5 -5
- package/dist/onelobby.bundle.mjs.map +3 -3
- package/dist/onelobby.d.ts +1 -1
- package/dist/onelobby.global.js +129 -25
- package/dist/onelobby.global.js.map +2 -2
- package/dist/onelobby.global.min.js +5 -5
- package/dist/onelobby.global.min.js.map +3 -3
- package/dist/onelobby.js +17 -3
- package/dist/onelobby.js.map +1 -1
- package/dist/socket.d.ts +11 -5
- package/dist/socket.js +34 -10
- package/dist/socket.js.map +1 -1
- package/dist/testing.js +13 -3
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
package/dist/lobby.d.ts
CHANGED
|
@@ -8,6 +8,20 @@ import type { ChannelName, IceServer, LinkFactory, PeerLink } from "./transport.
|
|
|
8
8
|
import { Voice, type VoiceDeps } from "./voice.js";
|
|
9
9
|
import { type LobbySocket, type LobbySocketOptions } from "./socket.js";
|
|
10
10
|
export type Phase = "lobby" | "in_game";
|
|
11
|
+
/** The close code and reason a host chose with `kick()` / `disconnect()`, passed to the removed player's sockets. */
|
|
12
|
+
export interface CloseInfo {
|
|
13
|
+
code?: number;
|
|
14
|
+
reason?: string;
|
|
15
|
+
}
|
|
16
|
+
/** Options for `lobby.kick()`. */
|
|
17
|
+
export interface KickOptions {
|
|
18
|
+
/** Default true: the player's address cannot rejoin this lobby while it lasts. false = `disconnect()`. */
|
|
19
|
+
ban?: boolean;
|
|
20
|
+
/** Close code for the player's `asWebSocket()` onclose: 1000 or 3000-4999. */
|
|
21
|
+
code?: number;
|
|
22
|
+
/** Close reason for that onclose, at most 120 characters. */
|
|
23
|
+
reason?: string;
|
|
24
|
+
}
|
|
11
25
|
export type Peer = PeerInfo;
|
|
12
26
|
export type LobbyEvents = {
|
|
13
27
|
peerJoined: [Peer];
|
|
@@ -15,12 +29,14 @@ export type LobbyEvents = {
|
|
|
15
29
|
peerReady: [Peer];
|
|
16
30
|
/** Joiner: the link to the host is open (the host itself is ready from the start). Also available as `lobby.ready`. */
|
|
17
31
|
ready: [];
|
|
18
|
-
|
|
32
|
+
/** reason "left", "kicked", "disconnected" (kick with ban false), "timeout", ...; `close` when the host gave one. */
|
|
33
|
+
peerLeft: [Peer, reason: string, close?: CloseInfo];
|
|
19
34
|
joinRequested: [Peer];
|
|
20
35
|
hostChanged: [hostId: number];
|
|
21
36
|
phase: [Phase];
|
|
22
37
|
message: [from: number, bytes: Uint8Array, channel: ChannelName];
|
|
23
|
-
|
|
38
|
+
/** `close` is the code and reason the host gave when it removed this player (`kick()` / `disconnect()`). */
|
|
39
|
+
sessionEnded: [reason: string, close?: CloseInfo];
|
|
24
40
|
/** The signaling server went away. The game continues on the data channels (s.9). */
|
|
25
41
|
serverLost: [];
|
|
26
42
|
metaChanged: [Record<string, string>];
|
|
@@ -64,6 +80,8 @@ export interface RateLimit {
|
|
|
64
80
|
}
|
|
65
81
|
/** The smallest `peerTimeoutMs` honoured: three missed pings. */
|
|
66
82
|
export declare const MIN_PEER_TIMEOUT_MS = 6000;
|
|
83
|
+
/** Host: how long a kicked / disconnected peer's link stays open for the hub's notice to reach it first. */
|
|
84
|
+
export declare const KICK_LINGER_MS = 3000;
|
|
67
85
|
/** The name shown for a peer that chose none: "Player N", N = its seat (peer id, join order). */
|
|
68
86
|
export declare function seatName(p: PeerInfo): PeerInfo;
|
|
69
87
|
/** One joined lobby: roster, star of peer links, and the lockstep/chat/voice engines riding on them. */
|
|
@@ -115,12 +133,14 @@ export declare class Lobby extends Emitter<LobbyEvents> {
|
|
|
115
133
|
private relayRetry;
|
|
116
134
|
/** clock.now() of the last frame from each peer (peerTimeoutMs). */
|
|
117
135
|
private lastHeard;
|
|
136
|
+
/** Host: links of kicked / disconnected peers, kept open briefly (removePeer `linger`). */
|
|
137
|
+
private readonly lingering;
|
|
118
138
|
/** Host: per-peer fixed window for rateLimit. */
|
|
119
139
|
private rate;
|
|
120
140
|
/**
|
|
121
141
|
* Resolves when this peer can exchange data: immediately for the host, once the link to the host is open for a
|
|
122
142
|
* joiner. Rejects with OneLobbyError("ice_failed") when the joiner cannot reach the host in `readyTimeoutMs`
|
|
123
|
-
* (or with "closed"/"kicked" when the lobby ends first).
|
|
143
|
+
* (or with "closed"/"kicked" when the lobby ends first; "closed" also when the host disconnected it).
|
|
124
144
|
*/
|
|
125
145
|
readonly ready: Promise<void>;
|
|
126
146
|
constructor(cfg: LobbyConfig);
|
|
@@ -147,7 +167,18 @@ export declare class Lobby extends Emitter<LobbyEvents> {
|
|
|
147
167
|
_begin(): void;
|
|
148
168
|
start(): Promise<void>;
|
|
149
169
|
setMeta(meta: Record<string, string>): Promise<void>;
|
|
150
|
-
|
|
170
|
+
/**
|
|
171
|
+
* Host: removes a player. By default it is a ban: the hub refuses that player's address for the rest of this lobby
|
|
172
|
+
* (a new tab or a reload included). `{ ban: false }` is `disconnect()`. `code` / `reason` reach the player's
|
|
173
|
+
* `asWebSocket()` onclose (and `sessionEnded`'s second argument); without them its socket closes with 4000 "kicked".
|
|
174
|
+
*/
|
|
175
|
+
kick(peerId: number, opts?: KickOptions): Promise<void>;
|
|
176
|
+
/**
|
|
177
|
+
* Host: ends one player's connection without a ban, like a server closing one WebSocket. The player's
|
|
178
|
+
* `asWebSocket()` gets onclose with `code` (default 1000) and `reason` (default "disconnected"), its lobby ends with
|
|
179
|
+
* `sessionEnded("disconnected")`, and it may join again (a new tab, a reload). Same as `kick(peerId, { ban: false, code, reason })`.
|
|
180
|
+
*/
|
|
181
|
+
disconnect(peerId: number, code?: number, reason?: string): Promise<void>;
|
|
151
182
|
approve(peerId: number, ok: boolean): Promise<void>;
|
|
152
183
|
leave(): Promise<void>;
|
|
153
184
|
/** raw mode (and any extra game data): to one peer. */
|
|
@@ -188,7 +219,13 @@ export declare class Lobby extends Emitter<LobbyEvents> {
|
|
|
188
219
|
private onHostClaim;
|
|
189
220
|
private onSignaling;
|
|
190
221
|
private onSignal;
|
|
222
|
+
/**
|
|
223
|
+
* `linger` (host kick / disconnect): stop using the peer's link at once but leave it open until that peer closes it
|
|
224
|
+
* or KICK_LINGER_MS pass. The hub tells the peer over its WebSocket; closing the data link first would make it look
|
|
225
|
+
* like the host vanished (a migration and a 1001 instead of the host's close code).
|
|
226
|
+
*/
|
|
191
227
|
private removePeer;
|
|
228
|
+
/** Lockstep drops (stalled, desynced): removed without a ban, so the player can come back (a rejoin resyncs). */
|
|
192
229
|
private dropPeer;
|
|
193
230
|
private setPhase;
|
|
194
231
|
private onServerClosed;
|
package/dist/lobby.js
CHANGED
|
@@ -9,6 +9,8 @@ import { Voice } from "./voice.js";
|
|
|
9
9
|
import { hostConnections, joinerSocket } from "./socket.js";
|
|
10
10
|
/** The smallest `peerTimeoutMs` honoured: three missed pings. */
|
|
11
11
|
export const MIN_PEER_TIMEOUT_MS = 6000;
|
|
12
|
+
/** Host: how long a kicked / disconnected peer's link stays open for the hub's notice to reach it first. */
|
|
13
|
+
export const KICK_LINGER_MS = 3000;
|
|
12
14
|
/** The name shown for a peer that chose none: "Player N", N = its seat (peer id, join order). */
|
|
13
15
|
export function seatName(p) {
|
|
14
16
|
const n = typeof p.name === "string" ? p.name.trim() : "";
|
|
@@ -71,12 +73,14 @@ export class Lobby extends Emitter {
|
|
|
71
73
|
relayRetry = false;
|
|
72
74
|
/** clock.now() of the last frame from each peer (peerTimeoutMs). */
|
|
73
75
|
lastHeard = new Map();
|
|
76
|
+
/** Host: links of kicked / disconnected peers, kept open briefly (removePeer `linger`). */
|
|
77
|
+
lingering = new Set();
|
|
74
78
|
/** Host: per-peer fixed window for rateLimit. */
|
|
75
79
|
rate = new Map();
|
|
76
80
|
/**
|
|
77
81
|
* Resolves when this peer can exchange data: immediately for the host, once the link to the host is open for a
|
|
78
82
|
* joiner. Rejects with OneLobbyError("ice_failed") when the joiner cannot reach the host in `readyTimeoutMs`
|
|
79
|
-
* (or with "closed"/"kicked" when the lobby ends first).
|
|
83
|
+
* (or with "closed"/"kicked" when the lobby ends first; "closed" also when the host disconnected it).
|
|
80
84
|
*/
|
|
81
85
|
ready = new Promise((res, rej) => {
|
|
82
86
|
this.markReady = () => {
|
|
@@ -205,11 +209,37 @@ export class Lobby extends Emitter {
|
|
|
205
209
|
this.signaling.send({ t: "meta", meta });
|
|
206
210
|
this.emit("metaChanged", this.meta);
|
|
207
211
|
}
|
|
208
|
-
|
|
212
|
+
/**
|
|
213
|
+
* Host: removes a player. By default it is a ban: the hub refuses that player's address for the rest of this lobby
|
|
214
|
+
* (a new tab or a reload included). `{ ban: false }` is `disconnect()`. `code` / `reason` reach the player's
|
|
215
|
+
* `asWebSocket()` onclose (and `sessionEnded`'s second argument); without them its socket closes with 4000 "kicked".
|
|
216
|
+
*/
|
|
217
|
+
async kick(peerId, opts = {}) {
|
|
209
218
|
if (!this.isHost)
|
|
210
219
|
throw new Error("only the host can kick");
|
|
211
|
-
|
|
212
|
-
|
|
220
|
+
const { ban = true, code, reason } = opts;
|
|
221
|
+
if (code !== undefined && !(code === 1000 || (Number.isInteger(code) && code >= 3000 && code <= 4999)))
|
|
222
|
+
throw new RangeError("close code must be 1000 or 3000-4999");
|
|
223
|
+
if (reason !== undefined && reason.length > 120)
|
|
224
|
+
throw new RangeError("close reason must be at most 120 characters");
|
|
225
|
+
const msg = { t: "kick", peerId };
|
|
226
|
+
if (!ban)
|
|
227
|
+
msg.ban = false;
|
|
228
|
+
if (code !== undefined)
|
|
229
|
+
msg.closeCode = code;
|
|
230
|
+
if (reason !== undefined)
|
|
231
|
+
msg.closeReason = reason;
|
|
232
|
+
this.signaling.send(msg);
|
|
233
|
+
const close = code !== undefined || reason !== undefined ? { code, reason } : undefined;
|
|
234
|
+
this.removePeer(peerId, ban ? "kicked" : "disconnected", close, true);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Host: ends one player's connection without a ban, like a server closing one WebSocket. The player's
|
|
238
|
+
* `asWebSocket()` gets onclose with `code` (default 1000) and `reason` (default "disconnected"), its lobby ends with
|
|
239
|
+
* `sessionEnded("disconnected")`, and it may join again (a new tab, a reload). Same as `kick(peerId, { ban: false, code, reason })`.
|
|
240
|
+
*/
|
|
241
|
+
disconnect(peerId, code, reason) {
|
|
242
|
+
return this.kick(peerId, { ban: false, code, reason });
|
|
213
243
|
}
|
|
214
244
|
async approve(peerId, ok) {
|
|
215
245
|
if (!this.isHost)
|
|
@@ -691,8 +721,15 @@ export class Lobby extends Emitter {
|
|
|
691
721
|
void this.onSignal(Number(m.from), m);
|
|
692
722
|
break;
|
|
693
723
|
case "error":
|
|
694
|
-
if (m.code === "kicked")
|
|
695
|
-
|
|
724
|
+
if (m.code === "kicked") {
|
|
725
|
+
const d = (m.data ?? {});
|
|
726
|
+
const close = {};
|
|
727
|
+
if (typeof d.closeCode === "number")
|
|
728
|
+
close.code = d.closeCode;
|
|
729
|
+
if (typeof d.closeReason === "string")
|
|
730
|
+
close.reason = d.closeReason;
|
|
731
|
+
this.teardown(d.ban === false ? "disconnected" : "kicked", close.code !== undefined || close.reason !== undefined ? close : undefined);
|
|
732
|
+
}
|
|
696
733
|
else
|
|
697
734
|
this.reportError(new OneLobbyError(String(m.code), String(m.msg ?? ""), m.data));
|
|
698
735
|
break;
|
|
@@ -713,7 +750,12 @@ export class Lobby extends Emitter {
|
|
|
713
750
|
payload.ice = s.ice;
|
|
714
751
|
await link.handleSignal(payload);
|
|
715
752
|
}
|
|
716
|
-
|
|
753
|
+
/**
|
|
754
|
+
* `linger` (host kick / disconnect): stop using the peer's link at once but leave it open until that peer closes it
|
|
755
|
+
* or KICK_LINGER_MS pass. The hub tells the peer over its WebSocket; closing the data link first would make it look
|
|
756
|
+
* like the host vanished (a migration and a 1001 instead of the host's close code).
|
|
757
|
+
*/
|
|
758
|
+
removePeer(peerId, reason, close, linger = false) {
|
|
717
759
|
const peer = this.roster.get(peerId);
|
|
718
760
|
if (peerId === this.localPeerId) {
|
|
719
761
|
this.teardown(reason === "kicked" ? "kicked" : reason);
|
|
@@ -723,11 +765,25 @@ export class Lobby extends Emitter {
|
|
|
723
765
|
this.roster.delete(peerId);
|
|
724
766
|
const link = this.links.get(peerId);
|
|
725
767
|
if (link && peerId !== this.hostPeerId) {
|
|
726
|
-
link.onClose = null;
|
|
727
768
|
link.onMessage = null;
|
|
728
|
-
link.close();
|
|
729
769
|
this.links.delete(peerId);
|
|
730
770
|
this.hiSentTo.delete(link);
|
|
771
|
+
if (linger) {
|
|
772
|
+
this.lingering.add(link);
|
|
773
|
+
const done = () => {
|
|
774
|
+
if (!this.lingering.delete(link))
|
|
775
|
+
return;
|
|
776
|
+
cancel();
|
|
777
|
+
link.onClose = null;
|
|
778
|
+
link.close();
|
|
779
|
+
};
|
|
780
|
+
const cancel = this.cfg.clock.setTimeout(done, KICK_LINGER_MS);
|
|
781
|
+
link.onClose = done;
|
|
782
|
+
}
|
|
783
|
+
else {
|
|
784
|
+
link.onClose = null;
|
|
785
|
+
link.close();
|
|
786
|
+
}
|
|
731
787
|
}
|
|
732
788
|
this.connected.delete(peerId);
|
|
733
789
|
this.outbox.delete(peerId);
|
|
@@ -737,14 +793,15 @@ export class Lobby extends Emitter {
|
|
|
737
793
|
this.chat.onPeerLeft(peerId);
|
|
738
794
|
this.voice.onPeerLeft(peerId);
|
|
739
795
|
if (peer)
|
|
740
|
-
this.emit("peerLeft", peer, reason);
|
|
796
|
+
this.emit("peerLeft", peer, reason, close);
|
|
741
797
|
if (peerId === this.hostPeerId && !this.isHost) {
|
|
742
798
|
this.handleHostLost(reason);
|
|
743
799
|
}
|
|
744
800
|
}
|
|
801
|
+
/** Lockstep drops (stalled, desynced): removed without a ban, so the player can come back (a rejoin resyncs). */
|
|
745
802
|
dropPeer(peerId, reason) {
|
|
746
|
-
this.signaling.send({ t: "kick", peerId });
|
|
747
|
-
this.removePeer(peerId, reason);
|
|
803
|
+
this.signaling.send({ t: "kick", peerId, ban: false, closeReason: reason });
|
|
804
|
+
this.removePeer(peerId, reason, undefined, true);
|
|
748
805
|
}
|
|
749
806
|
setPhase(p) {
|
|
750
807
|
if (p !== "lobby" && p !== "in_game")
|
|
@@ -807,7 +864,7 @@ export class Lobby extends Emitter {
|
|
|
807
864
|
return;
|
|
808
865
|
this.sendTo(this.hostPeerId, { type: "ping", n: ++this.pingN, t: this.cfg.clock.now() >>> 0 }, 0, "fast");
|
|
809
866
|
}
|
|
810
|
-
teardown(reason) {
|
|
867
|
+
teardown(reason, close) {
|
|
811
868
|
if (this.ended)
|
|
812
869
|
return;
|
|
813
870
|
this.ended = true;
|
|
@@ -820,16 +877,17 @@ export class Lobby extends Emitter {
|
|
|
820
877
|
this.cancelPing?.();
|
|
821
878
|
this.lockstep.stop();
|
|
822
879
|
this.voice.close();
|
|
823
|
-
for (const l of this.links.values()) {
|
|
880
|
+
for (const l of [...this.links.values(), ...this.lingering]) {
|
|
824
881
|
l.onClose = null;
|
|
825
882
|
l.onMessage = null;
|
|
826
883
|
l.close();
|
|
827
884
|
}
|
|
828
885
|
this.links.clear();
|
|
886
|
+
this.lingering.clear();
|
|
829
887
|
this.signaling.onClose = null;
|
|
830
888
|
this.signaling.onMessage = null;
|
|
831
889
|
this.signaling.close();
|
|
832
|
-
this.emit("sessionEnded", reason);
|
|
890
|
+
this.emit("sessionEnded", reason, close);
|
|
833
891
|
}
|
|
834
892
|
/** Total in-flight links (diagnostics and tests). */
|
|
835
893
|
get linkCount() {
|
package/dist/lobby.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lobby.js","sourceRoot":"","sources":["../src/lobby.ts"],"names":[],"mappings":"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","sourcesContent":["import { Chat } from \"./chat.js\";\nimport type { Clock } from \"./clock.js\";\nimport {\n CodecError,\n MAX_FRAME_BYTES,\n MODE_LOCKSTEP,\n MODE_RAW,\n PROTO,\n decodeMessage,\n encodeMessage,\n type Message,\n} from \"./codec.js\";\nimport { Reassembler, splitChunks } from \"./chunking.js\";\nimport { Emitter } from \"./emitter.js\";\nimport type { Hub } from \"./hub.js\";\nimport { Lockstep } from \"./lockstep.js\";\nimport { claimWinsWrapped, pickNewHost } from \"./migration.js\";\nimport { OneLobbyError, type LobbyState, type PeerInfo, type SignalingClient, type ServerMsg } from \"./signaling.js\";\nimport type { ChannelName, IceServer, LinkFactory, PeerLink, SignalPayload } from \"./transport.js\";\nimport { Voice, type VoiceDeps } from \"./voice.js\";\nimport { hostConnections, joinerSocket, type LobbySocket, type LobbySocketOptions } from \"./socket.js\";\n\nexport type Phase = \"lobby\" | \"in_game\";\nexport type Peer = PeerInfo;\n\nexport type LobbyEvents = {\n peerJoined: [Peer];\n /** The peer's data channels are open and the handshake is done: reliable sends reach it now (earlier ones were queued and flushed). */\n peerReady: [Peer];\n /** Joiner: the link to the host is open (the host itself is ready from the start). Also available as `lobby.ready`. */\n ready: [];\n peerLeft: [Peer, reason: string];\n joinRequested: [Peer];\n hostChanged: [hostId: number];\n phase: [Phase];\n message: [from: number, bytes: Uint8Array, channel: ChannelName];\n sessionEnded: [reason: string];\n /** The signaling server went away. The game continues on the data channels (s.9). */\n serverLost: [];\n metaChanged: [Record<string, string>];\n};\n\nexport interface LobbyConfig {\n signaling: SignalingClient;\n state: LobbyState;\n ice: IceServer[];\n links: LinkFactory;\n clock: Clock;\n wall: () => number;\n hashEveryTicks: number;\n relayOnly: boolean;\n voice: VoiceDeps;\n displayName: string;\n /**\n * Joiner: give up on reaching the host after this many ms (0 or absent: wait forever). When the ICE list has a\n * TURN server and the lobby is not relay-only already, the second half of the budget is a relay-only retry.\n * On failure `ready` rejects with OneLobbyError(\"ice_failed\"), the error is reported and the lobby is left.\n */\n readyTimeoutMs?: number;\n /**\n * Direct IP (docs/direct-ip.md): the hub lives in the host, so there is no migration. A joiner that loses the host\n * (link, peer_left, a host_changed from the hub as it shuts down, or the signaling socket) ends with \"host_left\".\n */\n direct?: boolean;\n /**\n * Treat a peer as gone after this many ms without hearing anything from it (0 or absent: off, and a silent peer\n * surfaces only when its link or signaling socket times out, about 30 s). Joiners ping the host every 2 s and the\n * host answers, so the host drops a silent joiner (`peerLeft`, \"timeout\") and a joiner handles a silent host as\n * lost (a direct lobby ends with \"host_left\"). Values under 6000 are raised to 6000.\n */\n peerTimeoutMs?: number;\n /** Host: per-peer cap on incoming raw messages; the excess is dropped before `message` fires or is relayed. */\n rateLimit?: RateLimit;\n}\n\n/** At most `messages` raw messages per peer in any `perMs` window (a fixed window, reset every `perMs`). */\nexport interface RateLimit {\n messages: number;\n perMs: number;\n}\n\n/** The smallest `peerTimeoutMs` honoured: three missed pings. */\nexport const MIN_PEER_TIMEOUT_MS = 6000;\n\n/** The name shown for a peer that chose none: \"Player N\", N = its seat (peer id, join order). */\nexport function seatName(p: PeerInfo): PeerInfo {\n const n = typeof p.name === \"string\" ? p.name.trim() : \"\";\n // \"Player\" is onelobby-server's stand-in for an empty name\n if (n && n !== \"Player\") return p;\n return { ...p, name: `Player ${p.peerId}` };\n}\n\nfunction hasRelay(ice: IceServer[]): boolean {\n return ice.some((s) => (Array.isArray(s.urls) ? s.urls : [s.urls]).some((u) => /^turns?:/i.test(String(u))));\n}\n\nconst HOST_WATCHDOG_MS = 250;\nconst PING_EVERY_MS = 2000;\n\n/** One joined lobby: roster, star of peer links, and the lockstep/chat/voice engines riding on them. */\nexport class Lobby extends Emitter<LobbyEvents> {\n readonly code: string;\n readonly mode: \"lockstep\" | \"raw\";\n readonly tickRate: number;\n readonly lockstep: Lockstep;\n readonly chat: Chat;\n readonly voice: Voice;\n\n localPeerId: number;\n hostPeerId: number;\n phase: Phase;\n meta: Record<string, string>;\n resumeToken: string;\n /** Last measured round trip to the host in ms (joiners), or 0. */\n rtt = 0;\n /**\n * Direct-IP host only (onelobby/direct): the code friends paste to join, e.g. \"6B01-RGFE-P2B\" (docs/direct-ip.md\n * s.2a). Show it with joinCodeKind. Empty when the machine has no IPv4 address, and on joiners.\n */\n joinCode = \"\";\n /** \"internet\": the router forwarded the port and the code carries its public address; \"same_network\": the LAN address. */\n joinCodeKind: \"internet\" | \"same_network\" | \"none\" = \"none\";\n /** Direct-IP host only: this machine's addresses with the port, for an \"Advanced\" fold-out. */\n directAddresses: string[] = [];\n /** Direct-IP host only: how the router port-open went (\"UPnP\", \"no UPnP gateway answered; ...\", \"off\"). */\n portMapping = \"\";\n\n private signaling: SignalingClient;\n private cfg: LobbyConfig;\n private roster = new Map<number, Peer>();\n private links = new Map<number, PeerLink>();\n private connected = new Set<number>(); // host: peers that said hi\n private hiSentTo = new Set<PeerLink>();\n private epoch = 0;\n private ended = false;\n private serverUp = true;\n private cancelWatchdog: (() => void) | null = null;\n private cancelPing: (() => void) | null = null;\n private pingN = 0;\n private chunkId = 1;\n private reassemblers = new Map<number, Reassembler>();\n private hub: Hub;\n private outbox = new Map<number, { msg: Message; route: number; channel?: ChannelName }[]>();\n private markReady: () => void = () => {};\n private failReady: (e: Error) => void = () => {};\n private isReady = false;\n private cancelReadyTimer: (() => void) | null = null;\n private relayRetry = false;\n /** clock.now() of the last frame from each peer (peerTimeoutMs). */\n private lastHeard = new Map<number, number>();\n /** Host: per-peer fixed window for rateLimit. */\n private rate = new Map<number, { start: number; n: number }>();\n /**\n * Resolves when this peer can exchange data: immediately for the host, once the link to the host is open for a\n * joiner. Rejects with OneLobbyError(\"ice_failed\") when the joiner cannot reach the host in `readyTimeoutMs`\n * (or with \"closed\"/\"kicked\" when the lobby ends first).\n */\n readonly ready: Promise<void> = new Promise<void>((res, rej) => {\n this.markReady = () => {\n if (this.isReady) return;\n this.isReady = true;\n this.cancelReadyTimer?.();\n this.cancelReadyTimer = null;\n res();\n };\n this.failReady = rej;\n });\n\n constructor(cfg: LobbyConfig) {\n super();\n this.cfg = cfg;\n this.signaling = cfg.signaling;\n const st = cfg.state;\n this.code = st.code;\n this.mode = st.mode;\n this.tickRate = st.tickRate;\n this.localPeerId = st.you;\n this.hostPeerId = st.hostId;\n this.phase = st.phase;\n this.meta = { ...st.meta };\n this.resumeToken = st.resumeToken;\n for (const p of st.peers) this.roster.set(p.peerId, seatName(p));\n this.ready.catch(() => {}); // a rejection is also reported through errorSink; awaiting `ready` stays optional\n\n const self = this;\n this.hub = {\n get clock() { return self.cfg.clock; },\n get localPeerId() { return self.localPeerId; },\n get hostPeerId() { return self.hostPeerId; },\n get isHost() { return self.isHost; },\n get tickRate() { return self.tickRate; },\n connectedPeers: () => self.connectedPeerIds(),\n sendTo: (peerId, msg, route, channel) => self.sendTo(peerId, msg, route ?? 0, channel),\n sendToHost: (msg, route, channel) => {\n if (!self.isHost) self.sendTo(self.hostPeerId, msg, route ?? 0, channel);\n },\n dropPeer: (peerId, reason) => self.dropPeer(peerId, reason),\n reportError: (e) => self.reportError(e),\n nextChunkId: () => self.chunkId++ >>> 0,\n };\n\n this.lockstep = new Lockstep(this.hub, { hashEveryTicks: cfg.hashEveryTicks });\n this.chat = new Chat(this.hub, cfg.wall, (id) => this.voice.isMutedPeer(id));\n this.voice = new Voice(this.hub, cfg.voice);\n this.lockstep.on(\"started\", () => this.setPhase(\"in_game\"));\n this.lockstep.on(\"error\", (e) => this.reportError(e));\n\n this.signaling.onMessage = (m) => this.onSignaling(m);\n this.signaling.onClose = () => this.onServerClosed();\n\n if (this.isHost) this.markReady();\n else this.armReadyTimer();\n if (this.isHost && this.mode === \"lockstep\") {\n if (this.phase === \"in_game\") this.lockstep.hostStart();\n else this.lockstep.hostIdle();\n }\n this.cancelWatchdog = cfg.clock.setInterval(() => this.watchdog(), HOST_WATCHDOG_MS);\n this.cancelPing = cfg.clock.setInterval(() => this.pingHost(), PING_EVERY_MS);\n }\n\n // ---- state -----------------------------------------------------------------------------------------------------\n\n get isHost(): boolean {\n return this.localPeerId === this.hostPeerId;\n }\n get peers(): Peer[] {\n return [...this.roster.values()].sort((a, b) => a.peerId - b.peerId);\n }\n peer(peerId: number): Peer | undefined {\n return this.roster.get(peerId);\n }\n /** Peers whose link is open and handshake done (host: the ready joiners; joiner: the host once ready). */\n get connectedPeers(): number[] {\n return this.connectedPeerIds();\n }\n\n /**\n * Joiner: the link to the host as a WebSocket-shaped object (text by default), so WebSocket client code runs\n * unchanged. It opens when `ready` resolves and closes when the session ends (`host_left` gives code 1001).\n */\n asWebSocket(opts?: LobbySocketOptions): LobbySocket {\n return joinerSocket(this, opts);\n }\n\n /** Host: `handler(conn)` once per joiner (a WebSocket-shaped connection), the server-side mirror of asWebSocket(). */\n onConnection(handler: (conn: LobbySocket) => void, opts?: LobbySocketOptions): () => void {\n return hostConnections(this, handler, opts);\n }\n\n set snapshotChunkSize(n: number) {\n this.lockstep.chunkSize = n;\n }\n\n /** Current migration epoch (0 until the first host change). */\n get hostEpoch(): number {\n return this.epoch;\n }\n\n /** @internal Host role: create the link to `peerId` and start negotiating (adapters and tests). */\n _offer(peerId: number): PeerLink {\n this.offerTo(peerId);\n return this.links.get(peerId)!;\n }\n\n /** @internal Joiner role: create the answering link to `peerId` (adapters and tests). */\n _answer(peerId: number): PeerLink {\n return this.makeLink(peerId);\n }\n\n /** @internal Called by OneLobby right after construction: the host waits for joiners, a joiner waits for the host's offer. */\n _begin(): void {\n /* joiners are passive until the host offers; hosts create links on peer_joined */\n }\n\n // ---- game-facing actions ---------------------------------------------------------------------------------------\n\n async start(): Promise<void> {\n if (!this.isHost) throw new Error(\"only the host can start the game\");\n if (this.phase === \"in_game\") return;\n this.signaling.send({ t: \"phase\", phase: \"in_game\" });\n this.setPhase(\"in_game\");\n if (this.mode === \"lockstep\") this.lockstep.hostStart();\n }\n\n async setMeta(meta: Record<string, string>): Promise<void> {\n if (!this.isHost) throw new Error(\"only the host can set metadata\");\n this.meta = { ...meta };\n this.signaling.send({ t: \"meta\", meta });\n this.emit(\"metaChanged\", this.meta);\n }\n\n async kick(peerId: number): Promise<void> {\n if (!this.isHost) throw new Error(\"only the host can kick\");\n this.signaling.send({ t: \"kick\", peerId });\n this.removePeer(peerId, \"kicked\");\n }\n\n async approve(peerId: number, ok: boolean): Promise<void> {\n if (!this.isHost) throw new Error(\"only the host can approve joins\");\n this.signaling.send({ t: \"approve\", peerId, ok });\n }\n\n async leave(): Promise<void> {\n if (this.ended) return;\n this.signaling.send({ t: \"leave\" });\n this.teardown(\"left\");\n }\n\n /** raw mode (and any extra game data): to one peer. */\n send(peerId: number, bytes: Uint8Array, opts: { channel?: \"reliable\" | \"fast\" } = {}): void {\n const channel = opts.channel ?? \"reliable\";\n if (this.isHost) this.sendTo(peerId, { type: \"raw\", bytes }, this.localPeerId, channel);\n else this.sendTo(this.hostPeerId, { type: \"raw\", bytes }, peerId, channel);\n }\n\n /** To everyone else in the lobby. */\n broadcast(bytes: Uint8Array, opts: { channel?: \"reliable\" | \"fast\" } = {}): void {\n const channel = opts.channel ?? \"reliable\";\n if (this.isHost) {\n // peers whose channels are not open yet get reliable broadcasts queued and flushed in order\n for (const p of this.roster.keys()) if (p !== this.localPeerId) this.sendTo(p, { type: \"raw\", bytes }, this.localPeerId, channel);\n } else {\n this.sendTo(this.hostPeerId, { type: \"raw\", bytes }, 0, channel);\n }\n }\n\n // ---- sending ---------------------------------------------------------------------------------------------------\n\n private channelFor(msg: Message): ChannelName {\n if (msg.type === \"voice\") return \"voice\";\n if (msg.type === \"ping\" || msg.type === \"pong\") return \"fast\";\n return \"reliable\";\n }\n\n private sendTo(peerId: number, msg: Message, route: number, channel?: ChannelName): void {\n const link = this.links.get(peerId);\n const ch0 = channel ?? this.channelFor(msg);\n const queueable = msg.type === \"raw\" || msg.type === \"chat\" || msg.type === \"cmd\";\n // game data to a host-side peer waits for its `hi`; protocol messages only need the link\n const ready = !!link?.isOpen && (!queueable || !this.isHost || this.connected.has(peerId));\n if (!ready) {\n // Reliable game data for a peer that is in the roster (or is the host) but not connected yet waits for its handshake.\n const known = this.roster.has(peerId) || peerId === this.hostPeerId;\n if (queueable && ch0 === \"reliable\" && known && !this.ended) {\n let q = this.outbox.get(peerId);\n if (!q) this.outbox.set(peerId, (q = []));\n if (q.length >= 1000) q.shift();\n q.push({ msg, route, channel });\n }\n return;\n }\n if (!link) return;\n try {\n const ch = ch0;\n let bytes: Uint8Array;\n try {\n bytes = encodeMessage(msg, route);\n } catch (e) {\n if (!(e instanceof CodecError) || e.code !== \"too_long\") throw e;\n bytes = encodeMessage(msg, route, true);\n }\n if (bytes.length > MAX_FRAME_BYTES) {\n // Oversized frame: send the whole inner frame as a chunk set (spec/binary.md \"Large non-snapshot frames\").\n for (const c of splitChunks(this.chunkId++ >>> 0, bytes)) link.send(ch, encodeMessage(c, route));\n } else {\n link.send(ch, bytes);\n }\n } catch (e) {\n this.reportError(e instanceof Error ? e : new Error(String(e)));\n }\n }\n\n private connectedPeerIds(): number[] {\n if (this.isHost) return [...this.connected].filter((id) => this.links.get(id)?.isOpen).sort((a, b) => a - b);\n const l = this.links.get(this.hostPeerId);\n return l?.isOpen ? [this.hostPeerId] : [];\n }\n\n private reportError(e: Error): void {\n this.errorSink?.(e);\n }\n /** @internal set by OneLobby so lobby errors reach `kit.on(\"error\")`. */\n errorSink: ((e: Error) => void) | null = null;\n /** @internal set by OneLobby: the server issued a new resume token (rememberSeat). */\n seatSink: ((token: string) => void) | null = null;\n\n // ---- joiner connect timeout -------------------------------------------------------------------------------------\n\n private armReadyTimer(): void {\n const total = this.cfg.readyTimeoutMs ?? 0;\n if (!(total > 0)) return;\n const canRelay = !this.cfg.relayOnly && hasRelay(this.cfg.ice);\n const first = canRelay ? Math.ceil(total / 2) : total;\n this.cancelReadyTimer = this.cfg.clock.setTimeout(() => {\n if (this.isReady || this.ended) return;\n if (canRelay) this.retryRelayed(total - first);\n else this.giveUpConnecting();\n }, first);\n }\n\n /** The direct attempt stalled: dial the host ourselves through the TURN relay (a host answers any offer). */\n private retryRelayed(budget: number): void {\n this.relayRetry = true;\n const link = this.makeLink(this.hostPeerId, true);\n link.startOffer();\n this.cancelReadyTimer = this.cfg.clock.setTimeout(() => {\n if (!this.isReady && !this.ended) this.giveUpConnecting();\n }, budget);\n }\n\n private giveUpConnecting(): void {\n const err = new OneLobbyError(\"ice_failed\", `could not open a connection to the host${this.relayRetry ? \" (direct or relayed)\" : \"\"}`);\n this.failReady(err);\n this.reportError(err);\n if (this.ended) return;\n this.signaling.send({ t: \"leave\" });\n this.teardown(\"ice_failed\");\n }\n\n // ---- links -----------------------------------------------------------------------------------------------------\n\n private makeLink(peerId: number, relayOnly = this.cfg.relayOnly): PeerLink {\n const old = this.links.get(peerId);\n if (old) {\n old.onClose = null;\n old.onMessage = null;\n old.close();\n }\n const link = this.cfg.links.create({ remoteId: peerId, iceServers: this.cfg.ice, relayOnly });\n this.links.set(peerId, link);\n link.onSignal = (s) => this.signaling.send({ t: \"signal\", to: peerId, ...s });\n link.onOpen = () => this.onLinkOpen(peerId, link);\n link.onClose = (reason) => this.onLinkClosed(peerId, link, reason);\n link.onMessage = (ch, bytes) => this.onData(peerId, ch, bytes);\n link.onPath = (path) => this.signaling.send({ t: \"path\", path });\n return link;\n }\n\n /** Host side: offer to a joiner. */\n private offerTo(peerId: number): void {\n const link = this.makeLink(peerId);\n link.startOffer();\n }\n\n private onLinkOpen(peerId: number, link: PeerLink): void {\n if (this.isHost) {\n // Joiner speaks first (`hi`). After a migration the new host announces itself so the joiner knows who won.\n if (this.epoch > 0) this.sendTo(peerId, { type: \"host_claim\", epoch: this.epoch, hostId: this.localPeerId, tick: this.lockstep.lastTick }, 0);\n return;\n }\n if (peerId === this.hostPeerId) this.sendHi(link);\n // else: an unexpected offerer; wait for its host_claim before trusting it\n }\n\n private sendHi(link: PeerLink): void {\n if (this.hiSentTo.has(link)) return;\n this.hiSentTo.add(link);\n this.lockstep.touch();\n link.send(\"reliable\", encodeMessage(this.lockstep.hiMessage(this.localPeerId)));\n this.markReady();\n this.emit(\"ready\");\n this.emit(\"peerReady\", this.roster.get(link.remoteId) ?? { peerId: link.remoteId, name: \"\" });\n this.flush(link.remoteId);\n }\n\n private onLinkClosed(peerId: number, link: PeerLink, _reason: string): void {\n if (this.links.get(peerId) !== link) return; // replaced\n this.links.delete(peerId);\n this.hiSentTo.delete(link);\n if (this.ended) return;\n if (this.isHost) {\n this.connected.delete(peerId);\n this.lockstep.onPeerLeft(peerId);\n this.voice.onPeerLeft(peerId);\n // The server announces the departure; if it is gone, drop the peer ourselves.\n if (!this.serverUp && this.roster.has(peerId)) this.removePeer(peerId, \"timeout\");\n } else if (peerId === this.hostPeerId) {\n // Never connected yet (ICE failed): not a host loss. The ready timer retries over the relay or gives up.\n if (!this.isReady && this.cancelReadyTimer) return;\n this.handleHostLost(\"link closed\");\n }\n }\n\n // ---- data channel dispatch -------------------------------------------------------------------------------------\n\n private onData(from: number, channel: ChannelName, bytes: Uint8Array, reassembled = false): void {\n let d;\n try {\n d = decodeMessage(bytes, reassembled);\n } catch (e) {\n this.reportError(e instanceof Error ? e : new Error(String(e)));\n return;\n }\n if (!d) return;\n if (!reassembled) this.lastHeard.set(from, this.cfg.clock.now());\n const { msg, route } = d;\n switch (msg.type) {\n case \"hi\":\n if (this.isHost) this.onHi(from, msg.lastTick);\n break;\n case \"welcome_dc\":\n if (!this.isHost) {\n if (msg.hostId !== this.hostPeerId) this.setHost(msg.hostId);\n this.lockstep.touch();\n }\n break;\n case \"cmd\": case \"frame\": case \"hash\": case \"desync\":\n case \"snapshot_req\": case \"snapshot\":\n if (from === this.hostPeerId || this.isHost) this.lockstep.handle(from, msg);\n break;\n case \"chunk\": {\n if (reassembled) break; // a chunk set never nests another\n let r = this.reassemblers.get(from);\n if (!r) this.reassemblers.set(from, (r = new Reassembler()));\n let whole;\n try {\n whole = r.push(msg);\n } catch (e) {\n this.reportError(e instanceof Error ? e : new Error(String(e)));\n break;\n }\n if (!whole) break;\n if (this.lockstep.snapshotPending && from === this.hostPeerId) this.lockstep.onSnapshotPayload(whole);\n else this.onData(from, channel, whole, true); // an oversized inner frame\n break;\n }\n case \"chat\": case \"chat_history\": case \"chat_reject\":\n this.chat.handle(from, route, msg);\n break;\n case \"voice\":\n if (channel === \"voice\") this.voice.handle(from, route, msg); // a voice frame on another channel is ignored\n break;\n case \"raw\":\n this.onRaw(from, route, msg.bytes, channel);\n break;\n case \"ping\":\n this.sendTo(from, { type: \"pong\", n: msg.n, t: msg.t }, 0, \"fast\");\n break;\n case \"pong\":\n this.rtt = Math.max(0, (this.cfg.clock.now() >>> 0) - msg.t);\n break;\n case \"host_claim\":\n this.onHostClaim(from, msg.epoch, msg.hostId);\n break;\n }\n }\n\n private onHi(from: number, lastTick: number): void {\n this.connected.add(from);\n this.sendTo(from, {\n type: \"welcome_dc\",\n // the tick the snapshot will carry (the game's applied tick), so welcome_dc.tick == snapshot.tick even when\n // the game loop has not yet consumed every emitted frame; 0 before the game starts\n tick: this.mode === \"lockstep\" ? this.lockstep.currentTick : 0,\n tickRate: this.tickRate,\n mode: this.mode === \"lockstep\" ? MODE_LOCKSTEP : MODE_RAW,\n hostId: this.localPeerId,\n }, 0);\n this.chat.sendHistory(from);\n if (this.mode === \"lockstep\") this.lockstep.onPeerHi(from, lastTick);\n this.emit(\"peerReady\", this.roster.get(from) ?? { peerId: from, name: \"\" });\n this.flush(from);\n }\n\n private flush(peerId: number): void {\n const q = this.outbox.get(peerId);\n if (!q) return;\n this.outbox.delete(peerId);\n for (const m of q) this.sendTo(peerId, m.msg, m.route, m.channel);\n }\n\n private onRaw(from: number, route: number, bytes: Uint8Array, channel: ChannelName): void {\n if (!this.isHost) {\n this.emit(\"message\", route, bytes, channel);\n return;\n }\n if (!this.allowRaw(from)) return;\n if (route === 0 || route === this.localPeerId) {\n this.emit(\"message\", from, bytes, channel);\n }\n if (route === 0) {\n for (const p of this.connectedPeerIds()) if (p !== from) this.sendTo(p, { type: \"raw\", bytes }, from, channel);\n } else if (route !== this.localPeerId) {\n this.sendTo(route, { type: \"raw\", bytes }, from, channel);\n }\n }\n\n private allowRaw(from: number): boolean {\n const lim = this.cfg.rateLimit;\n if (!lim || !(lim.messages > 0) || !(lim.perMs > 0)) return true;\n const now = this.cfg.clock.now();\n let w = this.rate.get(from);\n if (!w || now - w.start >= lim.perMs) this.rate.set(from, (w = { start: now, n: 0 }));\n return ++w.n <= lim.messages;\n }\n\n // ---- migration -------------------------------------------------------------------------------------------------\n\n private setHost(hostId: number): void {\n if (hostId === this.hostPeerId) return;\n this.hostPeerId = hostId;\n this.emit(\"hostChanged\", hostId);\n }\n\n /** The host is gone (link closed, no frames for 3 s, or the server said so): run the s.9 rule. */\n private handleHostLost(reason: string): void {\n if (this.isHost || this.ended) return;\n if (this.cfg.direct) {\n this.teardown(\"host_left\");\n return;\n }\n const failed = this.hostPeerId;\n const gone = this.roster.get(failed);\n if (gone) {\n this.roster.delete(failed);\n this.emit(\"peerLeft\", gone, reason === \"link closed\" ? \"timeout\" : reason);\n }\n const old = this.links.get(failed);\n if (old) {\n old.onClose = null;\n old.onMessage = null;\n old.close();\n this.links.delete(failed);\n this.hiSentTo.delete(old);\n }\n const candidate = pickNewHost([...this.roster.keys(), this.localPeerId], failed) ?? this.localPeerId;\n if (candidate === this.localPeerId) this.becomeHost();\n // else: wait for the candidate's host_claim (or the server's host_changed); it offers to us and we answer with hi\n }\n\n private becomeHost(): void {\n this.epoch = (this.epoch + 1) & 0xffff;\n this.hostPeerId = this.localPeerId;\n this.markReady();\n this.connected.clear();\n this.hiSentTo.clear();\n this.lastHeard.clear(); // joiners spoke to the old host; their clocks start when they say hi to us\n this.lockstep.becomeHost();\n this.emit(\"hostChanged\", this.localPeerId);\n if (this.serverUp) this.signaling.send({ t: \"host_changed\", hostId: this.localPeerId, epoch: this.epoch });\n for (const p of this.roster.keys()) {\n if (p !== this.localPeerId) this.offerTo(p);\n }\n }\n\n private onHostClaim(from: number, epoch: number, hostId: number): void {\n const mine = { epoch: this.epoch, hostId: this.hostPeerId };\n const theirs = { epoch, hostId };\n if (hostId === this.hostPeerId && epoch === this.epoch && !this.isHost) {\n const l = this.links.get(from);\n if (l) this.sendHi(l);\n return;\n }\n if (!claimWinsWrapped(theirs, mine)) return; // we hold the better claim\n const wasHost = this.isHost;\n this.epoch = epoch;\n if (wasHost) {\n // We lose: demote. Everyone else will be offered to by the winner.\n for (const [id, l] of this.links) {\n if (id === from) continue;\n l.onClose = null;\n l.onMessage = null;\n l.close();\n this.links.delete(id);\n }\n this.connected.clear();\n this.lockstep.becomeJoiner();\n }\n this.setHost(hostId);\n const link = this.links.get(from);\n if (link && from === hostId) this.sendHi(link);\n }\n\n // ---- signaling -------------------------------------------------------------------------------------------------\n\n private onSignaling(m: ServerMsg): void {\n switch (m.t) {\n case \"peer_joined\": {\n if (!m.peer || this.roster.has((m.peer as Peer).peerId)) return;\n const peer = seatName(m.peer as Peer);\n this.roster.set(peer.peerId, peer);\n this.emit(\"peerJoined\", peer);\n if (this.isHost) this.offerTo(peer.peerId);\n break;\n }\n case \"peer_left\":\n this.removePeer(Number(m.peerId), String(m.reason ?? \"left\"));\n break;\n case \"host_changed\": {\n if (this.cfg.direct) {\n // the hub promotes a joiner as the host leaves; in direct mode the hub is going with it\n if (!this.isHost) this.teardown(\"host_left\");\n break;\n }\n const id = Number(m.hostId);\n if (typeof m.epoch === \"number\" && m.epoch > this.epoch) this.epoch = m.epoch & 0xffff;\n if (id === this.hostPeerId) break;\n if (id === this.localPeerId && !this.isHost) {\n const failed = this.hostPeerId;\n this.roster.delete(failed);\n this.becomeHost();\n } else {\n this.setHost(id);\n }\n break;\n }\n case \"join_request\":\n this.emit(\"joinRequested\", seatName(m.peer as Peer));\n break;\n case \"lobby\": {\n const st = m as unknown as LobbyState;\n this.meta = { ...st.meta };\n if (st.resumeToken && st.resumeToken !== this.resumeToken) {\n this.resumeToken = st.resumeToken;\n this.seatSink?.(this.resumeToken);\n }\n this.roster = new Map(st.peers.map((p) => [p.peerId, seatName(p)]));\n if (st.hostId !== this.hostPeerId && !this.isHost) this.setHost(st.hostId);\n this.setPhase(st.phase);\n break;\n }\n case \"meta\":\n this.meta = { ...(m.meta as Record<string, string>) };\n this.emit(\"metaChanged\", this.meta);\n break;\n case \"phase\":\n this.setPhase(m.phase as Phase);\n break;\n case \"signal\":\n void this.onSignal(Number(m.from), m as unknown as SignalPayload);\n break;\n case \"error\":\n if (m.code === \"kicked\") this.teardown(\"kicked\");\n else this.reportError(new OneLobbyError(String(m.code), String(m.msg ?? \"\"), m.data as Record<string, unknown> | undefined));\n break;\n }\n }\n\n private async onSignal(from: number, s: SignalPayload): Promise<void> {\n let link = this.links.get(from);\n if (s.sdp?.type === \"offer\") {\n // We are the answerer; an offer always comes from the (new) host.\n link = this.makeLink(from);\n }\n if (!link) return;\n const payload: SignalPayload = {};\n if (s.sdp) payload.sdp = s.sdp;\n if (s.ice) payload.ice = s.ice;\n await link.handleSignal(payload);\n }\n\n private removePeer(peerId: number, reason: string): void {\n const peer = this.roster.get(peerId);\n if (peerId === this.localPeerId) {\n this.teardown(reason === \"kicked\" ? \"kicked\" : reason);\n return;\n }\n if (peer) this.roster.delete(peerId);\n const link = this.links.get(peerId);\n if (link && peerId !== this.hostPeerId) {\n link.onClose = null;\n link.onMessage = null;\n link.close();\n this.links.delete(peerId);\n this.hiSentTo.delete(link);\n }\n this.connected.delete(peerId);\n this.outbox.delete(peerId);\n this.lastHeard.delete(peerId);\n this.rate.delete(peerId);\n this.lockstep.onPeerLeft(peerId);\n this.chat.onPeerLeft(peerId);\n this.voice.onPeerLeft(peerId);\n if (peer) this.emit(\"peerLeft\", peer, reason);\n if (peerId === this.hostPeerId && !this.isHost) {\n this.handleHostLost(reason);\n }\n }\n\n private dropPeer(peerId: number, reason: string): void {\n this.signaling.send({ t: \"kick\", peerId });\n this.removePeer(peerId, reason);\n }\n\n private setPhase(p: Phase): void {\n if (p !== \"lobby\" && p !== \"in_game\") return;\n if (this.phase === p) return;\n this.phase = p;\n if (p === \"in_game\" && !this.lockstep.started) this.lockstep.markStarted();\n this.emit(\"phase\", p);\n }\n\n private onServerClosed(): void {\n if (this.ended) return;\n if (this.cfg.direct && !this.isHost) {\n this.teardown(\"host_left\");\n return;\n }\n this.serverUp = false;\n this.emit(\"serverLost\");\n // Alone with no peers: nothing keeps this session alive.\n if (this.links.size === 0 && this.roster.size <= 1) this.teardown(\"server_lost\");\n }\n\n // ---- housekeeping ----------------------------------------------------------------------------------------------\n\n private watchdog(): void {\n if (this.ended) return;\n const timeout = this.cfg.peerTimeoutMs ?? 0;\n if (timeout > 0) this.dropSilent(Math.max(timeout, MIN_PEER_TIMEOUT_MS));\n if (this.ended || this.isHost) return;\n if (this.mode === \"lockstep\" && this.lockstep.hostSilent()) {\n this.lockstep.touch();\n this.lockstep.pokeHost(); // a live-but-stalled host answers with a snapshot; a dead one is replaced below\n this.handleHostLost(\"timeout\");\n }\n }\n\n /** peerTimeoutMs: the host drops joiners it has not heard from; a joiner handles a silent host as lost. */\n private dropSilent(timeout: number): void {\n const now = this.cfg.clock.now();\n if (this.isHost) {\n for (const id of [...this.connected]) {\n const last = this.lastHeard.get(id);\n if (last !== undefined && now - last > timeout) this.removePeer(id, \"timeout\");\n }\n } else if (this.isReady) {\n const last = this.lastHeard.get(this.hostPeerId);\n if (last !== undefined && now - last > timeout) {\n this.lastHeard.delete(this.hostPeerId);\n this.handleHostLost(\"timeout\");\n }\n }\n }\n\n private pingHost(): void {\n if (this.ended || this.isHost) return;\n this.sendTo(this.hostPeerId, { type: \"ping\", n: ++this.pingN, t: this.cfg.clock.now() >>> 0 }, 0, \"fast\");\n }\n\n private teardown(reason: string): void {\n if (this.ended) return;\n this.ended = true;\n this.cancelReadyTimer?.();\n if (!this.isReady) {\n const code = reason === \"ice_failed\" || reason === \"kicked\" ? reason : \"closed\";\n this.failReady(new OneLobbyError(code, `the lobby ended before connecting (${reason})`));\n }\n this.cancelWatchdog?.();\n this.cancelPing?.();\n this.lockstep.stop();\n this.voice.close();\n for (const l of this.links.values()) {\n l.onClose = null;\n l.onMessage = null;\n l.close();\n }\n this.links.clear();\n this.signaling.onClose = null;\n this.signaling.onMessage = null;\n this.signaling.close();\n this.emit(\"sessionEnded\", reason);\n }\n\n /** Total in-flight links (diagnostics and tests). */\n get linkCount(): number {\n return this.links.size;\n }\n}\n\nexport { PROTO };\n"]}
|
|
1
|
+
{"version":3,"file":"lobby.js","sourceRoot":"","sources":["../src/lobby.ts"],"names":[],"mappings":"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","sourcesContent":["import { Chat } from \"./chat.js\";\nimport type { Clock } from \"./clock.js\";\nimport {\n CodecError,\n MAX_FRAME_BYTES,\n MODE_LOCKSTEP,\n MODE_RAW,\n PROTO,\n decodeMessage,\n encodeMessage,\n type Message,\n} from \"./codec.js\";\nimport { Reassembler, splitChunks } from \"./chunking.js\";\nimport { Emitter } from \"./emitter.js\";\nimport type { Hub } from \"./hub.js\";\nimport { Lockstep } from \"./lockstep.js\";\nimport { claimWinsWrapped, pickNewHost } from \"./migration.js\";\nimport { OneLobbyError, type LobbyState, type PeerInfo, type SignalingClient, type ServerMsg } from \"./signaling.js\";\nimport type { ChannelName, IceServer, LinkFactory, PeerLink, SignalPayload } from \"./transport.js\";\nimport { Voice, type VoiceDeps } from \"./voice.js\";\nimport { hostConnections, joinerSocket, type LobbySocket, type LobbySocketOptions } from \"./socket.js\";\n\nexport type Phase = \"lobby\" | \"in_game\";\n/** The close code and reason a host chose with `kick()` / `disconnect()`, passed to the removed player's sockets. */\nexport interface CloseInfo {\n code?: number;\n reason?: string;\n}\n/** Options for `lobby.kick()`. */\nexport interface KickOptions {\n /** Default true: the player's address cannot rejoin this lobby while it lasts. false = `disconnect()`. */\n ban?: boolean;\n /** Close code for the player's `asWebSocket()` onclose: 1000 or 3000-4999. */\n code?: number;\n /** Close reason for that onclose, at most 120 characters. */\n reason?: string;\n}\nexport type Peer = PeerInfo;\n\nexport type LobbyEvents = {\n peerJoined: [Peer];\n /** The peer's data channels are open and the handshake is done: reliable sends reach it now (earlier ones were queued and flushed). */\n peerReady: [Peer];\n /** Joiner: the link to the host is open (the host itself is ready from the start). Also available as `lobby.ready`. */\n ready: [];\n /** reason \"left\", \"kicked\", \"disconnected\" (kick with ban false), \"timeout\", ...; `close` when the host gave one. */\n peerLeft: [Peer, reason: string, close?: CloseInfo];\n joinRequested: [Peer];\n hostChanged: [hostId: number];\n phase: [Phase];\n message: [from: number, bytes: Uint8Array, channel: ChannelName];\n /** `close` is the code and reason the host gave when it removed this player (`kick()` / `disconnect()`). */\n sessionEnded: [reason: string, close?: CloseInfo];\n /** The signaling server went away. The game continues on the data channels (s.9). */\n serverLost: [];\n metaChanged: [Record<string, string>];\n};\n\nexport interface LobbyConfig {\n signaling: SignalingClient;\n state: LobbyState;\n ice: IceServer[];\n links: LinkFactory;\n clock: Clock;\n wall: () => number;\n hashEveryTicks: number;\n relayOnly: boolean;\n voice: VoiceDeps;\n displayName: string;\n /**\n * Joiner: give up on reaching the host after this many ms (0 or absent: wait forever). When the ICE list has a\n * TURN server and the lobby is not relay-only already, the second half of the budget is a relay-only retry.\n * On failure `ready` rejects with OneLobbyError(\"ice_failed\"), the error is reported and the lobby is left.\n */\n readyTimeoutMs?: number;\n /**\n * Direct IP (docs/direct-ip.md): the hub lives in the host, so there is no migration. A joiner that loses the host\n * (link, peer_left, a host_changed from the hub as it shuts down, or the signaling socket) ends with \"host_left\".\n */\n direct?: boolean;\n /**\n * Treat a peer as gone after this many ms without hearing anything from it (0 or absent: off, and a silent peer\n * surfaces only when its link or signaling socket times out, about 30 s). Joiners ping the host every 2 s and the\n * host answers, so the host drops a silent joiner (`peerLeft`, \"timeout\") and a joiner handles a silent host as\n * lost (a direct lobby ends with \"host_left\"). Values under 6000 are raised to 6000.\n */\n peerTimeoutMs?: number;\n /** Host: per-peer cap on incoming raw messages; the excess is dropped before `message` fires or is relayed. */\n rateLimit?: RateLimit;\n}\n\n/** At most `messages` raw messages per peer in any `perMs` window (a fixed window, reset every `perMs`). */\nexport interface RateLimit {\n messages: number;\n perMs: number;\n}\n\n/** The smallest `peerTimeoutMs` honoured: three missed pings. */\nexport const MIN_PEER_TIMEOUT_MS = 6000;\n/** Host: how long a kicked / disconnected peer's link stays open for the hub's notice to reach it first. */\nexport const KICK_LINGER_MS = 3000;\n\n/** The name shown for a peer that chose none: \"Player N\", N = its seat (peer id, join order). */\nexport function seatName(p: PeerInfo): PeerInfo {\n const n = typeof p.name === \"string\" ? p.name.trim() : \"\";\n // \"Player\" is onelobby-server's stand-in for an empty name\n if (n && n !== \"Player\") return p;\n return { ...p, name: `Player ${p.peerId}` };\n}\n\nfunction hasRelay(ice: IceServer[]): boolean {\n return ice.some((s) => (Array.isArray(s.urls) ? s.urls : [s.urls]).some((u) => /^turns?:/i.test(String(u))));\n}\n\nconst HOST_WATCHDOG_MS = 250;\nconst PING_EVERY_MS = 2000;\n\n/** One joined lobby: roster, star of peer links, and the lockstep/chat/voice engines riding on them. */\nexport class Lobby extends Emitter<LobbyEvents> {\n readonly code: string;\n readonly mode: \"lockstep\" | \"raw\";\n readonly tickRate: number;\n readonly lockstep: Lockstep;\n readonly chat: Chat;\n readonly voice: Voice;\n\n localPeerId: number;\n hostPeerId: number;\n phase: Phase;\n meta: Record<string, string>;\n resumeToken: string;\n /** Last measured round trip to the host in ms (joiners), or 0. */\n rtt = 0;\n /**\n * Direct-IP host only (onelobby/direct): the code friends paste to join, e.g. \"6B01-RGFE-P2B\" (docs/direct-ip.md\n * s.2a). Show it with joinCodeKind. Empty when the machine has no IPv4 address, and on joiners.\n */\n joinCode = \"\";\n /** \"internet\": the router forwarded the port and the code carries its public address; \"same_network\": the LAN address. */\n joinCodeKind: \"internet\" | \"same_network\" | \"none\" = \"none\";\n /** Direct-IP host only: this machine's addresses with the port, for an \"Advanced\" fold-out. */\n directAddresses: string[] = [];\n /** Direct-IP host only: how the router port-open went (\"UPnP\", \"no UPnP gateway answered; ...\", \"off\"). */\n portMapping = \"\";\n\n private signaling: SignalingClient;\n private cfg: LobbyConfig;\n private roster = new Map<number, Peer>();\n private links = new Map<number, PeerLink>();\n private connected = new Set<number>(); // host: peers that said hi\n private hiSentTo = new Set<PeerLink>();\n private epoch = 0;\n private ended = false;\n private serverUp = true;\n private cancelWatchdog: (() => void) | null = null;\n private cancelPing: (() => void) | null = null;\n private pingN = 0;\n private chunkId = 1;\n private reassemblers = new Map<number, Reassembler>();\n private hub: Hub;\n private outbox = new Map<number, { msg: Message; route: number; channel?: ChannelName }[]>();\n private markReady: () => void = () => {};\n private failReady: (e: Error) => void = () => {};\n private isReady = false;\n private cancelReadyTimer: (() => void) | null = null;\n private relayRetry = false;\n /** clock.now() of the last frame from each peer (peerTimeoutMs). */\n private lastHeard = new Map<number, number>();\n /** Host: links of kicked / disconnected peers, kept open briefly (removePeer `linger`). */\n private readonly lingering = new Set<PeerLink>();\n /** Host: per-peer fixed window for rateLimit. */\n private rate = new Map<number, { start: number; n: number }>();\n /**\n * Resolves when this peer can exchange data: immediately for the host, once the link to the host is open for a\n * joiner. Rejects with OneLobbyError(\"ice_failed\") when the joiner cannot reach the host in `readyTimeoutMs`\n * (or with \"closed\"/\"kicked\" when the lobby ends first; \"closed\" also when the host disconnected it).\n */\n readonly ready: Promise<void> = new Promise<void>((res, rej) => {\n this.markReady = () => {\n if (this.isReady) return;\n this.isReady = true;\n this.cancelReadyTimer?.();\n this.cancelReadyTimer = null;\n res();\n };\n this.failReady = rej;\n });\n\n constructor(cfg: LobbyConfig) {\n super();\n this.cfg = cfg;\n this.signaling = cfg.signaling;\n const st = cfg.state;\n this.code = st.code;\n this.mode = st.mode;\n this.tickRate = st.tickRate;\n this.localPeerId = st.you;\n this.hostPeerId = st.hostId;\n this.phase = st.phase;\n this.meta = { ...st.meta };\n this.resumeToken = st.resumeToken;\n for (const p of st.peers) this.roster.set(p.peerId, seatName(p));\n this.ready.catch(() => {}); // a rejection is also reported through errorSink; awaiting `ready` stays optional\n\n const self = this;\n this.hub = {\n get clock() { return self.cfg.clock; },\n get localPeerId() { return self.localPeerId; },\n get hostPeerId() { return self.hostPeerId; },\n get isHost() { return self.isHost; },\n get tickRate() { return self.tickRate; },\n connectedPeers: () => self.connectedPeerIds(),\n sendTo: (peerId, msg, route, channel) => self.sendTo(peerId, msg, route ?? 0, channel),\n sendToHost: (msg, route, channel) => {\n if (!self.isHost) self.sendTo(self.hostPeerId, msg, route ?? 0, channel);\n },\n dropPeer: (peerId, reason) => self.dropPeer(peerId, reason),\n reportError: (e) => self.reportError(e),\n nextChunkId: () => self.chunkId++ >>> 0,\n };\n\n this.lockstep = new Lockstep(this.hub, { hashEveryTicks: cfg.hashEveryTicks });\n this.chat = new Chat(this.hub, cfg.wall, (id) => this.voice.isMutedPeer(id));\n this.voice = new Voice(this.hub, cfg.voice);\n this.lockstep.on(\"started\", () => this.setPhase(\"in_game\"));\n this.lockstep.on(\"error\", (e) => this.reportError(e));\n\n this.signaling.onMessage = (m) => this.onSignaling(m);\n this.signaling.onClose = () => this.onServerClosed();\n\n if (this.isHost) this.markReady();\n else this.armReadyTimer();\n if (this.isHost && this.mode === \"lockstep\") {\n if (this.phase === \"in_game\") this.lockstep.hostStart();\n else this.lockstep.hostIdle();\n }\n this.cancelWatchdog = cfg.clock.setInterval(() => this.watchdog(), HOST_WATCHDOG_MS);\n this.cancelPing = cfg.clock.setInterval(() => this.pingHost(), PING_EVERY_MS);\n }\n\n // ---- state -----------------------------------------------------------------------------------------------------\n\n get isHost(): boolean {\n return this.localPeerId === this.hostPeerId;\n }\n get peers(): Peer[] {\n return [...this.roster.values()].sort((a, b) => a.peerId - b.peerId);\n }\n peer(peerId: number): Peer | undefined {\n return this.roster.get(peerId);\n }\n /** Peers whose link is open and handshake done (host: the ready joiners; joiner: the host once ready). */\n get connectedPeers(): number[] {\n return this.connectedPeerIds();\n }\n\n /**\n * Joiner: the link to the host as a WebSocket-shaped object (text by default), so WebSocket client code runs\n * unchanged. It opens when `ready` resolves and closes when the session ends (`host_left` gives code 1001).\n */\n asWebSocket(opts?: LobbySocketOptions): LobbySocket {\n return joinerSocket(this, opts);\n }\n\n /** Host: `handler(conn)` once per joiner (a WebSocket-shaped connection), the server-side mirror of asWebSocket(). */\n onConnection(handler: (conn: LobbySocket) => void, opts?: LobbySocketOptions): () => void {\n return hostConnections(this, handler, opts);\n }\n\n set snapshotChunkSize(n: number) {\n this.lockstep.chunkSize = n;\n }\n\n /** Current migration epoch (0 until the first host change). */\n get hostEpoch(): number {\n return this.epoch;\n }\n\n /** @internal Host role: create the link to `peerId` and start negotiating (adapters and tests). */\n _offer(peerId: number): PeerLink {\n this.offerTo(peerId);\n return this.links.get(peerId)!;\n }\n\n /** @internal Joiner role: create the answering link to `peerId` (adapters and tests). */\n _answer(peerId: number): PeerLink {\n return this.makeLink(peerId);\n }\n\n /** @internal Called by OneLobby right after construction: the host waits for joiners, a joiner waits for the host's offer. */\n _begin(): void {\n /* joiners are passive until the host offers; hosts create links on peer_joined */\n }\n\n // ---- game-facing actions ---------------------------------------------------------------------------------------\n\n async start(): Promise<void> {\n if (!this.isHost) throw new Error(\"only the host can start the game\");\n if (this.phase === \"in_game\") return;\n this.signaling.send({ t: \"phase\", phase: \"in_game\" });\n this.setPhase(\"in_game\");\n if (this.mode === \"lockstep\") this.lockstep.hostStart();\n }\n\n async setMeta(meta: Record<string, string>): Promise<void> {\n if (!this.isHost) throw new Error(\"only the host can set metadata\");\n this.meta = { ...meta };\n this.signaling.send({ t: \"meta\", meta });\n this.emit(\"metaChanged\", this.meta);\n }\n\n /**\n * Host: removes a player. By default it is a ban: the hub refuses that player's address for the rest of this lobby\n * (a new tab or a reload included). `{ ban: false }` is `disconnect()`. `code` / `reason` reach the player's\n * `asWebSocket()` onclose (and `sessionEnded`'s second argument); without them its socket closes with 4000 \"kicked\".\n */\n async kick(peerId: number, opts: KickOptions = {}): Promise<void> {\n if (!this.isHost) throw new Error(\"only the host can kick\");\n const { ban = true, code, reason } = opts;\n if (code !== undefined && !(code === 1000 || (Number.isInteger(code) && code >= 3000 && code <= 4999)))\n throw new RangeError(\"close code must be 1000 or 3000-4999\");\n if (reason !== undefined && reason.length > 120) throw new RangeError(\"close reason must be at most 120 characters\");\n const msg: Record<string, unknown> = { t: \"kick\", peerId };\n if (!ban) msg.ban = false;\n if (code !== undefined) msg.closeCode = code;\n if (reason !== undefined) msg.closeReason = reason;\n this.signaling.send(msg as { t: \"kick\"; peerId: number });\n const close: CloseInfo | undefined = code !== undefined || reason !== undefined ? { code, reason } : undefined;\n this.removePeer(peerId, ban ? \"kicked\" : \"disconnected\", close, true);\n }\n\n /**\n * Host: ends one player's connection without a ban, like a server closing one WebSocket. The player's\n * `asWebSocket()` gets onclose with `code` (default 1000) and `reason` (default \"disconnected\"), its lobby ends with\n * `sessionEnded(\"disconnected\")`, and it may join again (a new tab, a reload). Same as `kick(peerId, { ban: false, code, reason })`.\n */\n disconnect(peerId: number, code?: number, reason?: string): Promise<void> {\n return this.kick(peerId, { ban: false, code, reason });\n }\n\n async approve(peerId: number, ok: boolean): Promise<void> {\n if (!this.isHost) throw new Error(\"only the host can approve joins\");\n this.signaling.send({ t: \"approve\", peerId, ok });\n }\n\n async leave(): Promise<void> {\n if (this.ended) return;\n this.signaling.send({ t: \"leave\" });\n this.teardown(\"left\");\n }\n\n /** raw mode (and any extra game data): to one peer. */\n send(peerId: number, bytes: Uint8Array, opts: { channel?: \"reliable\" | \"fast\" } = {}): void {\n const channel = opts.channel ?? \"reliable\";\n if (this.isHost) this.sendTo(peerId, { type: \"raw\", bytes }, this.localPeerId, channel);\n else this.sendTo(this.hostPeerId, { type: \"raw\", bytes }, peerId, channel);\n }\n\n /** To everyone else in the lobby. */\n broadcast(bytes: Uint8Array, opts: { channel?: \"reliable\" | \"fast\" } = {}): void {\n const channel = opts.channel ?? \"reliable\";\n if (this.isHost) {\n // peers whose channels are not open yet get reliable broadcasts queued and flushed in order\n for (const p of this.roster.keys()) if (p !== this.localPeerId) this.sendTo(p, { type: \"raw\", bytes }, this.localPeerId, channel);\n } else {\n this.sendTo(this.hostPeerId, { type: \"raw\", bytes }, 0, channel);\n }\n }\n\n // ---- sending ---------------------------------------------------------------------------------------------------\n\n private channelFor(msg: Message): ChannelName {\n if (msg.type === \"voice\") return \"voice\";\n if (msg.type === \"ping\" || msg.type === \"pong\") return \"fast\";\n return \"reliable\";\n }\n\n private sendTo(peerId: number, msg: Message, route: number, channel?: ChannelName): void {\n const link = this.links.get(peerId);\n const ch0 = channel ?? this.channelFor(msg);\n const queueable = msg.type === \"raw\" || msg.type === \"chat\" || msg.type === \"cmd\";\n // game data to a host-side peer waits for its `hi`; protocol messages only need the link\n const ready = !!link?.isOpen && (!queueable || !this.isHost || this.connected.has(peerId));\n if (!ready) {\n // Reliable game data for a peer that is in the roster (or is the host) but not connected yet waits for its handshake.\n const known = this.roster.has(peerId) || peerId === this.hostPeerId;\n if (queueable && ch0 === \"reliable\" && known && !this.ended) {\n let q = this.outbox.get(peerId);\n if (!q) this.outbox.set(peerId, (q = []));\n if (q.length >= 1000) q.shift();\n q.push({ msg, route, channel });\n }\n return;\n }\n if (!link) return;\n try {\n const ch = ch0;\n let bytes: Uint8Array;\n try {\n bytes = encodeMessage(msg, route);\n } catch (e) {\n if (!(e instanceof CodecError) || e.code !== \"too_long\") throw e;\n bytes = encodeMessage(msg, route, true);\n }\n if (bytes.length > MAX_FRAME_BYTES) {\n // Oversized frame: send the whole inner frame as a chunk set (spec/binary.md \"Large non-snapshot frames\").\n for (const c of splitChunks(this.chunkId++ >>> 0, bytes)) link.send(ch, encodeMessage(c, route));\n } else {\n link.send(ch, bytes);\n }\n } catch (e) {\n this.reportError(e instanceof Error ? e : new Error(String(e)));\n }\n }\n\n private connectedPeerIds(): number[] {\n if (this.isHost) return [...this.connected].filter((id) => this.links.get(id)?.isOpen).sort((a, b) => a - b);\n const l = this.links.get(this.hostPeerId);\n return l?.isOpen ? [this.hostPeerId] : [];\n }\n\n private reportError(e: Error): void {\n this.errorSink?.(e);\n }\n /** @internal set by OneLobby so lobby errors reach `kit.on(\"error\")`. */\n errorSink: ((e: Error) => void) | null = null;\n /** @internal set by OneLobby: the server issued a new resume token (rememberSeat). */\n seatSink: ((token: string) => void) | null = null;\n\n // ---- joiner connect timeout -------------------------------------------------------------------------------------\n\n private armReadyTimer(): void {\n const total = this.cfg.readyTimeoutMs ?? 0;\n if (!(total > 0)) return;\n const canRelay = !this.cfg.relayOnly && hasRelay(this.cfg.ice);\n const first = canRelay ? Math.ceil(total / 2) : total;\n this.cancelReadyTimer = this.cfg.clock.setTimeout(() => {\n if (this.isReady || this.ended) return;\n if (canRelay) this.retryRelayed(total - first);\n else this.giveUpConnecting();\n }, first);\n }\n\n /** The direct attempt stalled: dial the host ourselves through the TURN relay (a host answers any offer). */\n private retryRelayed(budget: number): void {\n this.relayRetry = true;\n const link = this.makeLink(this.hostPeerId, true);\n link.startOffer();\n this.cancelReadyTimer = this.cfg.clock.setTimeout(() => {\n if (!this.isReady && !this.ended) this.giveUpConnecting();\n }, budget);\n }\n\n private giveUpConnecting(): void {\n const err = new OneLobbyError(\"ice_failed\", `could not open a connection to the host${this.relayRetry ? \" (direct or relayed)\" : \"\"}`);\n this.failReady(err);\n this.reportError(err);\n if (this.ended) return;\n this.signaling.send({ t: \"leave\" });\n this.teardown(\"ice_failed\");\n }\n\n // ---- links -----------------------------------------------------------------------------------------------------\n\n private makeLink(peerId: number, relayOnly = this.cfg.relayOnly): PeerLink {\n const old = this.links.get(peerId);\n if (old) {\n old.onClose = null;\n old.onMessage = null;\n old.close();\n }\n const link = this.cfg.links.create({ remoteId: peerId, iceServers: this.cfg.ice, relayOnly });\n this.links.set(peerId, link);\n link.onSignal = (s) => this.signaling.send({ t: \"signal\", to: peerId, ...s });\n link.onOpen = () => this.onLinkOpen(peerId, link);\n link.onClose = (reason) => this.onLinkClosed(peerId, link, reason);\n link.onMessage = (ch, bytes) => this.onData(peerId, ch, bytes);\n link.onPath = (path) => this.signaling.send({ t: \"path\", path });\n return link;\n }\n\n /** Host side: offer to a joiner. */\n private offerTo(peerId: number): void {\n const link = this.makeLink(peerId);\n link.startOffer();\n }\n\n private onLinkOpen(peerId: number, link: PeerLink): void {\n if (this.isHost) {\n // Joiner speaks first (`hi`). After a migration the new host announces itself so the joiner knows who won.\n if (this.epoch > 0) this.sendTo(peerId, { type: \"host_claim\", epoch: this.epoch, hostId: this.localPeerId, tick: this.lockstep.lastTick }, 0);\n return;\n }\n if (peerId === this.hostPeerId) this.sendHi(link);\n // else: an unexpected offerer; wait for its host_claim before trusting it\n }\n\n private sendHi(link: PeerLink): void {\n if (this.hiSentTo.has(link)) return;\n this.hiSentTo.add(link);\n this.lockstep.touch();\n link.send(\"reliable\", encodeMessage(this.lockstep.hiMessage(this.localPeerId)));\n this.markReady();\n this.emit(\"ready\");\n this.emit(\"peerReady\", this.roster.get(link.remoteId) ?? { peerId: link.remoteId, name: \"\" });\n this.flush(link.remoteId);\n }\n\n private onLinkClosed(peerId: number, link: PeerLink, _reason: string): void {\n if (this.links.get(peerId) !== link) return; // replaced\n this.links.delete(peerId);\n this.hiSentTo.delete(link);\n if (this.ended) return;\n if (this.isHost) {\n this.connected.delete(peerId);\n this.lockstep.onPeerLeft(peerId);\n this.voice.onPeerLeft(peerId);\n // The server announces the departure; if it is gone, drop the peer ourselves.\n if (!this.serverUp && this.roster.has(peerId)) this.removePeer(peerId, \"timeout\");\n } else if (peerId === this.hostPeerId) {\n // Never connected yet (ICE failed): not a host loss. The ready timer retries over the relay or gives up.\n if (!this.isReady && this.cancelReadyTimer) return;\n this.handleHostLost(\"link closed\");\n }\n }\n\n // ---- data channel dispatch -------------------------------------------------------------------------------------\n\n private onData(from: number, channel: ChannelName, bytes: Uint8Array, reassembled = false): void {\n let d;\n try {\n d = decodeMessage(bytes, reassembled);\n } catch (e) {\n this.reportError(e instanceof Error ? e : new Error(String(e)));\n return;\n }\n if (!d) return;\n if (!reassembled) this.lastHeard.set(from, this.cfg.clock.now());\n const { msg, route } = d;\n switch (msg.type) {\n case \"hi\":\n if (this.isHost) this.onHi(from, msg.lastTick);\n break;\n case \"welcome_dc\":\n if (!this.isHost) {\n if (msg.hostId !== this.hostPeerId) this.setHost(msg.hostId);\n this.lockstep.touch();\n }\n break;\n case \"cmd\": case \"frame\": case \"hash\": case \"desync\":\n case \"snapshot_req\": case \"snapshot\":\n if (from === this.hostPeerId || this.isHost) this.lockstep.handle(from, msg);\n break;\n case \"chunk\": {\n if (reassembled) break; // a chunk set never nests another\n let r = this.reassemblers.get(from);\n if (!r) this.reassemblers.set(from, (r = new Reassembler()));\n let whole;\n try {\n whole = r.push(msg);\n } catch (e) {\n this.reportError(e instanceof Error ? e : new Error(String(e)));\n break;\n }\n if (!whole) break;\n if (this.lockstep.snapshotPending && from === this.hostPeerId) this.lockstep.onSnapshotPayload(whole);\n else this.onData(from, channel, whole, true); // an oversized inner frame\n break;\n }\n case \"chat\": case \"chat_history\": case \"chat_reject\":\n this.chat.handle(from, route, msg);\n break;\n case \"voice\":\n if (channel === \"voice\") this.voice.handle(from, route, msg); // a voice frame on another channel is ignored\n break;\n case \"raw\":\n this.onRaw(from, route, msg.bytes, channel);\n break;\n case \"ping\":\n this.sendTo(from, { type: \"pong\", n: msg.n, t: msg.t }, 0, \"fast\");\n break;\n case \"pong\":\n this.rtt = Math.max(0, (this.cfg.clock.now() >>> 0) - msg.t);\n break;\n case \"host_claim\":\n this.onHostClaim(from, msg.epoch, msg.hostId);\n break;\n }\n }\n\n private onHi(from: number, lastTick: number): void {\n this.connected.add(from);\n this.sendTo(from, {\n type: \"welcome_dc\",\n // the tick the snapshot will carry (the game's applied tick), so welcome_dc.tick == snapshot.tick even when\n // the game loop has not yet consumed every emitted frame; 0 before the game starts\n tick: this.mode === \"lockstep\" ? this.lockstep.currentTick : 0,\n tickRate: this.tickRate,\n mode: this.mode === \"lockstep\" ? MODE_LOCKSTEP : MODE_RAW,\n hostId: this.localPeerId,\n }, 0);\n this.chat.sendHistory(from);\n if (this.mode === \"lockstep\") this.lockstep.onPeerHi(from, lastTick);\n this.emit(\"peerReady\", this.roster.get(from) ?? { peerId: from, name: \"\" });\n this.flush(from);\n }\n\n private flush(peerId: number): void {\n const q = this.outbox.get(peerId);\n if (!q) return;\n this.outbox.delete(peerId);\n for (const m of q) this.sendTo(peerId, m.msg, m.route, m.channel);\n }\n\n private onRaw(from: number, route: number, bytes: Uint8Array, channel: ChannelName): void {\n if (!this.isHost) {\n this.emit(\"message\", route, bytes, channel);\n return;\n }\n if (!this.allowRaw(from)) return;\n if (route === 0 || route === this.localPeerId) {\n this.emit(\"message\", from, bytes, channel);\n }\n if (route === 0) {\n for (const p of this.connectedPeerIds()) if (p !== from) this.sendTo(p, { type: \"raw\", bytes }, from, channel);\n } else if (route !== this.localPeerId) {\n this.sendTo(route, { type: \"raw\", bytes }, from, channel);\n }\n }\n\n private allowRaw(from: number): boolean {\n const lim = this.cfg.rateLimit;\n if (!lim || !(lim.messages > 0) || !(lim.perMs > 0)) return true;\n const now = this.cfg.clock.now();\n let w = this.rate.get(from);\n if (!w || now - w.start >= lim.perMs) this.rate.set(from, (w = { start: now, n: 0 }));\n return ++w.n <= lim.messages;\n }\n\n // ---- migration -------------------------------------------------------------------------------------------------\n\n private setHost(hostId: number): void {\n if (hostId === this.hostPeerId) return;\n this.hostPeerId = hostId;\n this.emit(\"hostChanged\", hostId);\n }\n\n /** The host is gone (link closed, no frames for 3 s, or the server said so): run the s.9 rule. */\n private handleHostLost(reason: string): void {\n if (this.isHost || this.ended) return;\n if (this.cfg.direct) {\n this.teardown(\"host_left\");\n return;\n }\n const failed = this.hostPeerId;\n const gone = this.roster.get(failed);\n if (gone) {\n this.roster.delete(failed);\n this.emit(\"peerLeft\", gone, reason === \"link closed\" ? \"timeout\" : reason);\n }\n const old = this.links.get(failed);\n if (old) {\n old.onClose = null;\n old.onMessage = null;\n old.close();\n this.links.delete(failed);\n this.hiSentTo.delete(old);\n }\n const candidate = pickNewHost([...this.roster.keys(), this.localPeerId], failed) ?? this.localPeerId;\n if (candidate === this.localPeerId) this.becomeHost();\n // else: wait for the candidate's host_claim (or the server's host_changed); it offers to us and we answer with hi\n }\n\n private becomeHost(): void {\n this.epoch = (this.epoch + 1) & 0xffff;\n this.hostPeerId = this.localPeerId;\n this.markReady();\n this.connected.clear();\n this.hiSentTo.clear();\n this.lastHeard.clear(); // joiners spoke to the old host; their clocks start when they say hi to us\n this.lockstep.becomeHost();\n this.emit(\"hostChanged\", this.localPeerId);\n if (this.serverUp) this.signaling.send({ t: \"host_changed\", hostId: this.localPeerId, epoch: this.epoch });\n for (const p of this.roster.keys()) {\n if (p !== this.localPeerId) this.offerTo(p);\n }\n }\n\n private onHostClaim(from: number, epoch: number, hostId: number): void {\n const mine = { epoch: this.epoch, hostId: this.hostPeerId };\n const theirs = { epoch, hostId };\n if (hostId === this.hostPeerId && epoch === this.epoch && !this.isHost) {\n const l = this.links.get(from);\n if (l) this.sendHi(l);\n return;\n }\n if (!claimWinsWrapped(theirs, mine)) return; // we hold the better claim\n const wasHost = this.isHost;\n this.epoch = epoch;\n if (wasHost) {\n // We lose: demote. Everyone else will be offered to by the winner.\n for (const [id, l] of this.links) {\n if (id === from) continue;\n l.onClose = null;\n l.onMessage = null;\n l.close();\n this.links.delete(id);\n }\n this.connected.clear();\n this.lockstep.becomeJoiner();\n }\n this.setHost(hostId);\n const link = this.links.get(from);\n if (link && from === hostId) this.sendHi(link);\n }\n\n // ---- signaling -------------------------------------------------------------------------------------------------\n\n private onSignaling(m: ServerMsg): void {\n switch (m.t) {\n case \"peer_joined\": {\n if (!m.peer || this.roster.has((m.peer as Peer).peerId)) return;\n const peer = seatName(m.peer as Peer);\n this.roster.set(peer.peerId, peer);\n this.emit(\"peerJoined\", peer);\n if (this.isHost) this.offerTo(peer.peerId);\n break;\n }\n case \"peer_left\":\n this.removePeer(Number(m.peerId), String(m.reason ?? \"left\"));\n break;\n case \"host_changed\": {\n if (this.cfg.direct) {\n // the hub promotes a joiner as the host leaves; in direct mode the hub is going with it\n if (!this.isHost) this.teardown(\"host_left\");\n break;\n }\n const id = Number(m.hostId);\n if (typeof m.epoch === \"number\" && m.epoch > this.epoch) this.epoch = m.epoch & 0xffff;\n if (id === this.hostPeerId) break;\n if (id === this.localPeerId && !this.isHost) {\n const failed = this.hostPeerId;\n this.roster.delete(failed);\n this.becomeHost();\n } else {\n this.setHost(id);\n }\n break;\n }\n case \"join_request\":\n this.emit(\"joinRequested\", seatName(m.peer as Peer));\n break;\n case \"lobby\": {\n const st = m as unknown as LobbyState;\n this.meta = { ...st.meta };\n if (st.resumeToken && st.resumeToken !== this.resumeToken) {\n this.resumeToken = st.resumeToken;\n this.seatSink?.(this.resumeToken);\n }\n this.roster = new Map(st.peers.map((p) => [p.peerId, seatName(p)]));\n if (st.hostId !== this.hostPeerId && !this.isHost) this.setHost(st.hostId);\n this.setPhase(st.phase);\n break;\n }\n case \"meta\":\n this.meta = { ...(m.meta as Record<string, string>) };\n this.emit(\"metaChanged\", this.meta);\n break;\n case \"phase\":\n this.setPhase(m.phase as Phase);\n break;\n case \"signal\":\n void this.onSignal(Number(m.from), m as unknown as SignalPayload);\n break;\n case \"error\":\n if (m.code === \"kicked\") {\n const d = (m.data ?? {}) as { ban?: unknown; closeCode?: unknown; closeReason?: unknown };\n const close: CloseInfo = {};\n if (typeof d.closeCode === \"number\") close.code = d.closeCode;\n if (typeof d.closeReason === \"string\") close.reason = d.closeReason;\n this.teardown(d.ban === false ? \"disconnected\" : \"kicked\", close.code !== undefined || close.reason !== undefined ? close : undefined);\n }\n else this.reportError(new OneLobbyError(String(m.code), String(m.msg ?? \"\"), m.data as Record<string, unknown> | undefined));\n break;\n }\n }\n\n private async onSignal(from: number, s: SignalPayload): Promise<void> {\n let link = this.links.get(from);\n if (s.sdp?.type === \"offer\") {\n // We are the answerer; an offer always comes from the (new) host.\n link = this.makeLink(from);\n }\n if (!link) return;\n const payload: SignalPayload = {};\n if (s.sdp) payload.sdp = s.sdp;\n if (s.ice) payload.ice = s.ice;\n await link.handleSignal(payload);\n }\n\n /**\n * `linger` (host kick / disconnect): stop using the peer's link at once but leave it open until that peer closes it\n * or KICK_LINGER_MS pass. The hub tells the peer over its WebSocket; closing the data link first would make it look\n * like the host vanished (a migration and a 1001 instead of the host's close code).\n */\n private removePeer(peerId: number, reason: string, close?: CloseInfo, linger = false): void {\n const peer = this.roster.get(peerId);\n if (peerId === this.localPeerId) {\n this.teardown(reason === \"kicked\" ? \"kicked\" : reason);\n return;\n }\n if (peer) this.roster.delete(peerId);\n const link = this.links.get(peerId);\n if (link && peerId !== this.hostPeerId) {\n link.onMessage = null;\n this.links.delete(peerId);\n this.hiSentTo.delete(link);\n if (linger) {\n this.lingering.add(link);\n const done = () => {\n if (!this.lingering.delete(link)) return;\n cancel();\n link.onClose = null;\n link.close();\n };\n const cancel = this.cfg.clock.setTimeout(done, KICK_LINGER_MS);\n link.onClose = done;\n } else {\n link.onClose = null;\n link.close();\n }\n }\n this.connected.delete(peerId);\n this.outbox.delete(peerId);\n this.lastHeard.delete(peerId);\n this.rate.delete(peerId);\n this.lockstep.onPeerLeft(peerId);\n this.chat.onPeerLeft(peerId);\n this.voice.onPeerLeft(peerId);\n if (peer) this.emit(\"peerLeft\", peer, reason, close);\n if (peerId === this.hostPeerId && !this.isHost) {\n this.handleHostLost(reason);\n }\n }\n\n /** Lockstep drops (stalled, desynced): removed without a ban, so the player can come back (a rejoin resyncs). */\n private dropPeer(peerId: number, reason: string): void {\n this.signaling.send({ t: \"kick\", peerId, ban: false, closeReason: reason } as { t: \"kick\"; peerId: number });\n this.removePeer(peerId, reason, undefined, true);\n }\n\n private setPhase(p: Phase): void {\n if (p !== \"lobby\" && p !== \"in_game\") return;\n if (this.phase === p) return;\n this.phase = p;\n if (p === \"in_game\" && !this.lockstep.started) this.lockstep.markStarted();\n this.emit(\"phase\", p);\n }\n\n private onServerClosed(): void {\n if (this.ended) return;\n if (this.cfg.direct && !this.isHost) {\n this.teardown(\"host_left\");\n return;\n }\n this.serverUp = false;\n this.emit(\"serverLost\");\n // Alone with no peers: nothing keeps this session alive.\n if (this.links.size === 0 && this.roster.size <= 1) this.teardown(\"server_lost\");\n }\n\n // ---- housekeeping ----------------------------------------------------------------------------------------------\n\n private watchdog(): void {\n if (this.ended) return;\n const timeout = this.cfg.peerTimeoutMs ?? 0;\n if (timeout > 0) this.dropSilent(Math.max(timeout, MIN_PEER_TIMEOUT_MS));\n if (this.ended || this.isHost) return;\n if (this.mode === \"lockstep\" && this.lockstep.hostSilent()) {\n this.lockstep.touch();\n this.lockstep.pokeHost(); // a live-but-stalled host answers with a snapshot; a dead one is replaced below\n this.handleHostLost(\"timeout\");\n }\n }\n\n /** peerTimeoutMs: the host drops joiners it has not heard from; a joiner handles a silent host as lost. */\n private dropSilent(timeout: number): void {\n const now = this.cfg.clock.now();\n if (this.isHost) {\n for (const id of [...this.connected]) {\n const last = this.lastHeard.get(id);\n if (last !== undefined && now - last > timeout) this.removePeer(id, \"timeout\");\n }\n } else if (this.isReady) {\n const last = this.lastHeard.get(this.hostPeerId);\n if (last !== undefined && now - last > timeout) {\n this.lastHeard.delete(this.hostPeerId);\n this.handleHostLost(\"timeout\");\n }\n }\n }\n\n private pingHost(): void {\n if (this.ended || this.isHost) return;\n this.sendTo(this.hostPeerId, { type: \"ping\", n: ++this.pingN, t: this.cfg.clock.now() >>> 0 }, 0, \"fast\");\n }\n\n private teardown(reason: string, close?: CloseInfo): void {\n if (this.ended) return;\n this.ended = true;\n this.cancelReadyTimer?.();\n if (!this.isReady) {\n const code = reason === \"ice_failed\" || reason === \"kicked\" ? reason : \"closed\";\n this.failReady(new OneLobbyError(code, `the lobby ended before connecting (${reason})`));\n }\n this.cancelWatchdog?.();\n this.cancelPing?.();\n this.lockstep.stop();\n this.voice.close();\n for (const l of [...this.links.values(), ...this.lingering]) {\n l.onClose = null;\n l.onMessage = null;\n l.close();\n }\n this.links.clear();\n this.lingering.clear();\n this.signaling.onClose = null;\n this.signaling.onMessage = null;\n this.signaling.close();\n this.emit(\"sessionEnded\", reason, close);\n }\n\n /** Total in-flight links (diagnostics and tests). */\n get linkCount(): number {\n return this.links.size;\n }\n}\n\nexport { PROTO };\n"]}
|