@sanctumterra/raknet 1.4.11 → 1.4.12
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/dist/client/client.d.ts +1 -0
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/client.js +11 -12
- package/dist/server/connection.d.ts.map +1 -1
- package/dist/server/connection.js +7 -11
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +2 -5
- package/dist/server/types/server-events.d.ts +5 -1
- package/dist/server/types/server-events.d.ts.map +1 -1
- package/dist/shared/network_session.d.ts +12 -2
- package/dist/shared/network_session.d.ts.map +1 -1
- package/dist/shared/network_session.js +136 -60
- package/package.json +1 -1
package/dist/client/client.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export declare class Client extends EventEmitter<ClientEvents> {
|
|
|
20
20
|
private resolvedAddress;
|
|
21
21
|
private proxyReady;
|
|
22
22
|
private lastPongTime;
|
|
23
|
+
private lastActivityTime;
|
|
23
24
|
private isDisconnected;
|
|
24
25
|
constructor(options?: Partial<ClientOptions>);
|
|
25
26
|
private setupProxy;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,YAAY,EAWZ,QAAQ,EAIR,KAAK,KAAK,EAKV,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EACN,KAAK,aAAa,EAElB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAgB,KAAK,UAAU,EAAe,MAAM,YAAY,CAAC;AAKxE,qBAAa,MAAO,SAAQ,YAAY,CAAC,YAAY,CAAC;IACrD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAiC;IACnE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAO;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAO;IAE3C,OAAO,EAAE,aAAa,CAAC;IAC9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,MAAM,CAAmB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,SAAS,CAAS;IAE1B,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,cAAc,CAAS;gBAEnB,OAAO,GAAE,OAAO,CAAC,aAAa,CAAM;YAmBlC,UAAU;IAoGxB,OAAO,CAAC,wBAAwB;IAIhC,OAAO,CAAC,iBAAiB;IAuBzB,OAAO,CAAC,qBAAqB;IA4B7B,OAAO,CAAC,oBAAoB;IA2Bf,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAiD9B,MAAM,IAAI,IAAI;IA6BrB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,OAAO;IAgBR,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,YAAY,EAWZ,QAAQ,EAIR,KAAK,KAAK,EAKV,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EACN,KAAK,aAAa,EAElB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAgB,KAAK,UAAU,EAAe,MAAM,YAAY,CAAC;AAKxE,qBAAa,MAAO,SAAQ,YAAY,CAAC,YAAY,CAAC;IACrD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAiC;IACnE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAO;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAO;IAE3C,OAAO,EAAE,aAAa,CAAC;IAC9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,MAAM,CAAmB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,SAAS,CAAS;IAE1B,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,gBAAgB,CAAsB;IAC9C,OAAO,CAAC,cAAc,CAAS;gBAEnB,OAAO,GAAE,OAAO,CAAC,aAAa,CAAM;YAmBlC,UAAU;IAoGxB,OAAO,CAAC,wBAAwB;IAIhC,OAAO,CAAC,iBAAiB;IAuBzB,OAAO,CAAC,qBAAqB;IA4B7B,OAAO,CAAC,oBAAoB;IA2Bf,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAiD9B,MAAM,IAAI,IAAI;IA6BrB,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,OAAO;IAgBR,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAmEhD,YAAY,CAAC,IAAI,EAAE,MAAM;IAkDzB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,GAAE,QAA0B;IAI5D,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,QAA0B;IAI/D,IAAI,IAAI,IAAI;IAOZ,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAWxB,UAAU,IAAI,IAAI;CAWzB"}
|
package/dist/client/client.js
CHANGED
|
@@ -25,6 +25,7 @@ class Client extends shared_1.EventEmitter {
|
|
|
25
25
|
resolvedAddress = null;
|
|
26
26
|
proxyReady = false;
|
|
27
27
|
lastPongTime = Date.now();
|
|
28
|
+
lastActivityTime = Date.now();
|
|
28
29
|
isDisconnected = false;
|
|
29
30
|
constructor(options = {}) {
|
|
30
31
|
super();
|
|
@@ -255,9 +256,9 @@ class Client extends shared_1.EventEmitter {
|
|
|
255
256
|
if (this.tick % Client.PING_INTERVAL_TICKS === 0) {
|
|
256
257
|
this.sendConnectedPing();
|
|
257
258
|
}
|
|
258
|
-
// Check for stale connection
|
|
259
|
-
const
|
|
260
|
-
if (
|
|
259
|
+
// Check for stale connection (no activity at all)
|
|
260
|
+
const timeSinceLastActivity = Date.now() - this.lastActivityTime;
|
|
261
|
+
if (timeSinceLastActivity > Client.STALE_TIMEOUT_MS) {
|
|
261
262
|
this.handleDisconnect("Connection timed out (stale)");
|
|
262
263
|
return;
|
|
263
264
|
}
|
|
@@ -337,23 +338,19 @@ class Client extends shared_1.EventEmitter {
|
|
|
337
338
|
break;
|
|
338
339
|
}
|
|
339
340
|
case shared_1.Packets.FrameSet: {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
}
|
|
344
|
-
catch (error) {
|
|
345
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
346
|
-
shared_2.Logger.error(`Frame set error: ${message}`);
|
|
347
|
-
this.handleDisconnect(`Frame set error: ${message}`);
|
|
348
|
-
}
|
|
341
|
+
this.lastActivityTime = Date.now();
|
|
342
|
+
const frameSet = new shared_1.FrameSet(actualData).deserialize();
|
|
343
|
+
this.session.onFrameSet(frameSet);
|
|
349
344
|
break;
|
|
350
345
|
}
|
|
351
346
|
case shared_1.Packets.Ack: {
|
|
347
|
+
this.lastActivityTime = Date.now();
|
|
352
348
|
const ack = new shared_1.Ack(actualData).deserialize();
|
|
353
349
|
this.session.onAck(ack);
|
|
354
350
|
break;
|
|
355
351
|
}
|
|
356
352
|
case shared_1.Packets.Nack: {
|
|
353
|
+
this.lastActivityTime = Date.now();
|
|
357
354
|
const nack = new shared_1.Ack(actualData).deserialize();
|
|
358
355
|
this.session.onNack(nack);
|
|
359
356
|
break;
|
|
@@ -397,7 +394,9 @@ class Client extends shared_1.EventEmitter {
|
|
|
397
394
|
this.frameAndSend(nic.serialize(), shared_1.Priority.High);
|
|
398
395
|
this.status = shared_1.ConnectionStatus.Connected;
|
|
399
396
|
this.lastPongTime = Date.now(); // Reset stale timer on connect
|
|
397
|
+
this.lastActivityTime = Date.now();
|
|
400
398
|
this.emit("connect");
|
|
399
|
+
console.log("Raknet Connected");
|
|
401
400
|
break;
|
|
402
401
|
}
|
|
403
402
|
default: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/server/connection.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,GAAG,EAOR,YAAY,EACZ,KAAK,KAAK,EACV,KAAK,QAAQ,EAIb,QAAQ,EACR,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,qBAAa,UAAW,SAAQ,YAAY,CAAC,gBAAgB,CAAC;IAS5D,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,IAAI;IAXb,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAO;IAElD,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,gBAAgB,CAAsB;IAC9C,OAAO,CAAC,cAAc,CAAS;gBAGtB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM;IAQd,MAAM,CAAC,IAAI,EAAE,MAAM;IAoBnB,UAAU,CAAC,MAAM,SAAiB,GAAG,IAAI;IAYzC,OAAO,IAAI,OAAO;IAIlB,UAAU,CAAC,QAAQ,EAAE,QAAQ;
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../src/server/connection.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,GAAG,EAOR,YAAY,EACZ,KAAK,KAAK,EACV,KAAK,QAAQ,EAIb,QAAQ,EACR,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,qBAAa,UAAW,SAAQ,YAAY,CAAC,gBAAgB,CAAC;IAS5D,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,GAAG;IACX,OAAO,CAAC,IAAI;IAXb,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IACjD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAO;IAElD,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,gBAAgB,CAAsB;IAC9C,OAAO,CAAC,cAAc,CAAS;gBAGtB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM;IAQd,MAAM,CAAC,IAAI,EAAE,MAAM;IAoBnB,UAAU,CAAC,MAAM,SAAiB,GAAG,IAAI;IAYzC,OAAO,IAAI,OAAO;IAIlB,UAAU,CAAC,QAAQ,EAAE,QAAQ;IAK7B,UAAU,IAAI,UAAU;IAIxB,SAAS,CAAC,IAAI,EAAE,MAAM;IA8DtB,KAAK,CAAC,OAAO,EAAE,GAAG;IAIzB,uFAAuF;IAChF,MAAM,CAAC,OAAO,EAAE,GAAG;IAInB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,GAAE,QAAwB;IAI1D,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,QAAwB;IAIhE,IAAI,CAAC,IAAI,EAAE,MAAM;CAGxB"}
|
|
@@ -46,22 +46,15 @@ class Connection extends shared_1.EventEmitter {
|
|
|
46
46
|
// Send disconnect packet to client
|
|
47
47
|
const disconnect = new shared_1.DisconnectMessage();
|
|
48
48
|
this.session.frameAndSend(disconnect.serialize(), shared_1.Priority.High);
|
|
49
|
-
// Emit disconnect event
|
|
50
|
-
this.server.emit("disconnect", this);
|
|
49
|
+
// Emit disconnect event with reason
|
|
50
|
+
this.server.emit("disconnect", { connection: this, reason });
|
|
51
51
|
}
|
|
52
52
|
isStale() {
|
|
53
53
|
return this.isDisconnected;
|
|
54
54
|
}
|
|
55
55
|
onFrameSet(frameSet) {
|
|
56
56
|
this.lastActivityTime = Date.now();
|
|
57
|
-
|
|
58
|
-
this.session.onFrameSet(frameSet);
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
62
|
-
shared_1.Logger.error(`Frame set error: ${message}`);
|
|
63
|
-
this.disconnect(`Frame set error: ${message}`);
|
|
64
|
-
}
|
|
57
|
+
this.session.onFrameSet(frameSet);
|
|
65
58
|
}
|
|
66
59
|
getAddress() {
|
|
67
60
|
return this.rinfo;
|
|
@@ -88,7 +81,10 @@ class Connection extends shared_1.EventEmitter {
|
|
|
88
81
|
}
|
|
89
82
|
case shared_1.Packets.Disconnect: {
|
|
90
83
|
this.isDisconnected = true;
|
|
91
|
-
this.server.emit("disconnect",
|
|
84
|
+
this.server.emit("disconnect", {
|
|
85
|
+
connection: this,
|
|
86
|
+
reason: "Client disconnected",
|
|
87
|
+
});
|
|
92
88
|
break;
|
|
93
89
|
}
|
|
94
90
|
case shared_1.Packets.ConnectedPing: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,YAAY,EAQZ,MAAM,WAAW,CAAC;AAEnB,OAAO,EACN,KAAK,aAAa,EAElB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EAExB,MAAM,SAAS,CAAC;AAGjB,qBAAa,MAAO,SAAQ,YAAY,CAAC,kBAAkB,CAAC;IAC3D,OAAO,CAAC,MAAM,CAAS;IACvB,SAAgB,OAAO,EAAE,mBAAmB,CAAC;IACtC,aAAa,EAAE,aAAa,CAAC;IACpC,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAAiB;gBAEzB,OAAO,GAAE,OAAO,CAAC,mBAAmB,CAAM;IAuB/C,IAAI;IAOJ,MAAM;IAab,OAAO,CAAC,YAAY;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,YAAY,EAQZ,MAAM,WAAW,CAAC;AAEnB,OAAO,EACN,KAAK,aAAa,EAElB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EAExB,MAAM,SAAS,CAAC;AAGjB,qBAAa,MAAO,SAAQ,YAAY,CAAC,kBAAkB,CAAC;IAC3D,OAAO,CAAC,MAAM,CAAS;IACvB,SAAgB,OAAO,EAAE,mBAAmB,CAAC;IACtC,aAAa,EAAE,aAAa,CAAC;IACpC,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAAiB;gBAEzB,OAAO,GAAE,OAAO,CAAC,mBAAmB,CAAM;IAuB/C,IAAI;IAOJ,MAAM;IAab,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,SAAS;IA6EV,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAGzD"}
|
package/dist/server/server.js
CHANGED
|
@@ -47,15 +47,12 @@ class Server extends shared_1.EventEmitter {
|
|
|
47
47
|
this.socket.on("message", this.onMessage.bind(this));
|
|
48
48
|
this.on("disconnect", this.onDisconnect.bind(this));
|
|
49
49
|
}
|
|
50
|
-
onDisconnect(connection,
|
|
50
|
+
onDisconnect({ connection, reason, }) {
|
|
51
51
|
const address = connection.getAddress();
|
|
52
52
|
this.connections.delete(`${address.address}:${address.port}`);
|
|
53
53
|
this.advertisement.playerCount = this.connections.size;
|
|
54
|
-
if (executedByServer) {
|
|
55
|
-
this.emit("disconnect", connection);
|
|
56
|
-
}
|
|
57
54
|
if (this.options.enableServerLogs) {
|
|
58
|
-
shared_1.Logger.info(`Client disconnected ${address.address}:${address.port}`);
|
|
55
|
+
shared_1.Logger.info(`Client disconnected ${address.address}:${address.port} - ${reason}`);
|
|
59
56
|
}
|
|
60
57
|
}
|
|
61
58
|
onMessage(message, rinfo) {
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { Connection } from "../connection";
|
|
2
|
+
export interface DisconnectEvent {
|
|
3
|
+
connection: Connection;
|
|
4
|
+
reason: string;
|
|
5
|
+
}
|
|
2
6
|
export interface RaknetServerEvents {
|
|
3
7
|
listening: undefined;
|
|
4
8
|
connect: Connection;
|
|
5
|
-
disconnect:
|
|
9
|
+
disconnect: DisconnectEvent;
|
|
6
10
|
}
|
|
7
11
|
//# sourceMappingURL=server-events.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-events.d.ts","sourceRoot":"","sources":["../../../src/server/types/server-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,UAAU,CAAC;IACpB,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"server-events.d.ts","sourceRoot":"","sources":["../../../src/server/types/server-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,WAAW,eAAe;IAC/B,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,kBAAkB;IAClC,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,UAAU,CAAC;IACpB,UAAU,EAAE,eAAe,CAAC;CAC5B"}
|
|
@@ -12,13 +12,23 @@ export declare class NetworkSession {
|
|
|
12
12
|
outputBackup: Map<number, Frame[]>;
|
|
13
13
|
receivedFrameSequences: Set<number>;
|
|
14
14
|
lostFrameSequences: Set<number>;
|
|
15
|
+
pendingAcks: Set<number>;
|
|
15
16
|
lastInputSequence: number;
|
|
16
|
-
fragmentsQueue: Map<number,
|
|
17
|
+
fragmentsQueue: Map<number, {
|
|
18
|
+
frames: Map<number, Frame>;
|
|
19
|
+
timestamp: number;
|
|
20
|
+
}>;
|
|
17
21
|
inputHighestSequenceIndex: Array<number>;
|
|
18
22
|
inputOrderIndex: Array<number>;
|
|
19
23
|
protected inputOrderingQueue: Map<number, Map<number, Frame>>;
|
|
24
|
+
private receivedReliableFrameIndices;
|
|
25
|
+
private highestReliableIndex;
|
|
26
|
+
private static readonly RECEIVE_WINDOW_SIZE;
|
|
27
|
+
private static readonly RELIABLE_WINDOW_SIZE;
|
|
28
|
+
private static readonly FRAGMENT_TIMEOUT_MS;
|
|
29
|
+
private static readonly ORDER_QUEUE_MAX_SIZE;
|
|
20
30
|
constructor(mtu: number);
|
|
21
|
-
onTick(): void;
|
|
31
|
+
onTick(_tick?: number): void;
|
|
22
32
|
onAck(ack: Ack): void;
|
|
23
33
|
onNack(nack: Ack): void;
|
|
24
34
|
frameAndSend(data: Buffer, priority?: Priority): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network_session.d.ts","sourceRoot":"","sources":["../../src/shared/network_session.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAW,QAAQ,EAAe,MAAM,SAAS,CAAC;AAK/E,qBAAa,cAAc;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,MAAM,EAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAGhC,mBAAmB,SAAK;IACxB,gBAAgB,SAAK;IAC5B,SAAS,CAAC,cAAc,SAAK;IACtB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,YAAY,EAAE,GAAG,CAAC,KAAK,CAAC,CAAa;IACrC,YAAY,uBAA8B;IAG1C,sBAAsB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;IAChD,kBAAkB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;IAC5C,iBAAiB,SAAM;IACvB,cAAc,EAAE,GAAG,
|
|
1
|
+
{"version":3,"file":"network_session.d.ts","sourceRoot":"","sources":["../../src/shared/network_session.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAW,QAAQ,EAAe,MAAM,SAAS,CAAC;AAK/E,qBAAa,cAAc;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,MAAM,EAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAGhC,mBAAmB,SAAK;IACxB,gBAAgB,SAAK;IAC5B,SAAS,CAAC,cAAc,SAAK;IACtB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,YAAY,EAAE,GAAG,CAAC,KAAK,CAAC,CAAa;IACrC,YAAY,uBAA8B;IAG1C,sBAAsB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;IAChD,kBAAkB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;IAC5C,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;IACrC,iBAAiB,SAAM;IACvB,cAAc,EAAE,GAAG,CACzB,MAAM,EACN;QAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CACjD,CAAa;IACP,yBAAyB,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACzC,eAAe,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACtC,SAAS,CAAC,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAa;IAE1E,OAAO,CAAC,4BAA4B,CAA0B;IAC9D,OAAO,CAAC,oBAAoB,CAAM;IAGlC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAQ;IACnD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAQ;IACpD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAS;IACpD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAO;gBAEvC,GAAG,EAAE,MAAM;IAUvB,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM;IAsDrB,KAAK,CAAC,GAAG,EAAE,GAAG;IAMd,MAAM,CAAC,IAAI,EAAE,GAAG;IAeT,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,QAA0B;IAQ/D,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,GAAE,QAA0B;IA8C5D,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ;IAW3C,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAiB/B,UAAU,CAAC,QAAQ,EAAE,QAAQ;IAgD7B,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAwB/B,gBAAgB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IA0CpC,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAenC,aAAa,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;CAwCxC"}
|
|
@@ -20,11 +20,19 @@ class NetworkSession {
|
|
|
20
20
|
// Input
|
|
21
21
|
receivedFrameSequences = new Set();
|
|
22
22
|
lostFrameSequences = new Set();
|
|
23
|
+
pendingAcks = new Set();
|
|
23
24
|
lastInputSequence = -1;
|
|
24
25
|
fragmentsQueue = new Map();
|
|
25
26
|
inputHighestSequenceIndex;
|
|
26
27
|
inputOrderIndex;
|
|
27
28
|
inputOrderingQueue = new Map();
|
|
29
|
+
receivedReliableFrameIndices = new Set();
|
|
30
|
+
highestReliableIndex = -1;
|
|
31
|
+
// goofy ahh geyser stuff
|
|
32
|
+
static RECEIVE_WINDOW_SIZE = 2048;
|
|
33
|
+
static RELIABLE_WINDOW_SIZE = 4096;
|
|
34
|
+
static FRAGMENT_TIMEOUT_MS = 30000;
|
|
35
|
+
static ORDER_QUEUE_MAX_SIZE = 256;
|
|
28
36
|
constructor(mtu) {
|
|
29
37
|
this.mtu = mtu;
|
|
30
38
|
this.outputOrderIndex = new Array(32).fill(0);
|
|
@@ -34,10 +42,35 @@ class NetworkSession {
|
|
|
34
42
|
for (let index = 0; index < 32; index++)
|
|
35
43
|
this.inputOrderingQueue.set(index, new Map());
|
|
36
44
|
}
|
|
37
|
-
onTick() {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
45
|
+
onTick(_tick) {
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
const windowStart = this.lastInputSequence - NetworkSession.RECEIVE_WINDOW_SIZE;
|
|
48
|
+
if (windowStart > 0) {
|
|
49
|
+
for (const seq of this.receivedFrameSequences) {
|
|
50
|
+
if (seq < windowStart)
|
|
51
|
+
this.receivedFrameSequences.delete(seq);
|
|
52
|
+
}
|
|
53
|
+
for (const seq of this.lostFrameSequences) {
|
|
54
|
+
if (seq < windowStart)
|
|
55
|
+
this.lostFrameSequences.delete(seq);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const reliableWindowStart = this.highestReliableIndex - NetworkSession.RELIABLE_WINDOW_SIZE;
|
|
59
|
+
if (reliableWindowStart > 0) {
|
|
60
|
+
for (const idx of this.receivedReliableFrameIndices) {
|
|
61
|
+
if (idx < reliableWindowStart)
|
|
62
|
+
this.receivedReliableFrameIndices.delete(idx);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
for (const [splitId, entry] of this.fragmentsQueue) {
|
|
66
|
+
if (now - entry.timestamp > NetworkSession.FRAGMENT_TIMEOUT_MS) {
|
|
67
|
+
logger_1.Logger.warn(`Fragment queue ${splitId} timed out, dropping ${entry.frames.size} fragments`);
|
|
68
|
+
this.fragmentsQueue.delete(splitId);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (this.pendingAcks.size > 0) {
|
|
72
|
+
const ackSeqs = Array.from(this.pendingAcks);
|
|
73
|
+
this.pendingAcks.clear();
|
|
41
74
|
const ack = new proto_1.Ack();
|
|
42
75
|
ack.sequences = ackSeqs;
|
|
43
76
|
this.send(ack.serialize());
|
|
@@ -145,27 +178,51 @@ class NetworkSession {
|
|
|
145
178
|
this.send(buffer);
|
|
146
179
|
}
|
|
147
180
|
onFrameSet(frameSet) {
|
|
181
|
+
// Already received this exact sequence so ignore duplicate
|
|
148
182
|
if (this.receivedFrameSequences.has(frameSet.sequence)) {
|
|
149
|
-
|
|
183
|
+
logger_1.Logger.warn(`Duplicate frame set received: sequence ${frameSet.sequence}`);
|
|
184
|
+
return;
|
|
150
185
|
}
|
|
186
|
+
// Remove from lost if we finally got it
|
|
151
187
|
this.lostFrameSequences.delete(frameSet.sequence);
|
|
152
|
-
|
|
153
|
-
const isEqual = frameSet.sequence === this.lastInputSequence;
|
|
154
|
-
if (isLess || isEqual) {
|
|
155
|
-
throw new Error("Frame set received is out of order");
|
|
156
|
-
}
|
|
188
|
+
// Track this sequence as received and queue ACK
|
|
157
189
|
this.receivedFrameSequences.add(frameSet.sequence);
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
190
|
+
this.pendingAcks.add(frameSet.sequence);
|
|
191
|
+
// If this is a newer sequence than we've seen, update tracking
|
|
192
|
+
if (frameSet.sequence > this.lastInputSequence) {
|
|
193
|
+
const diff = frameSet.sequence - this.lastInputSequence;
|
|
194
|
+
// Mark any gaps as lost (for NACK)
|
|
195
|
+
if (diff > 1) {
|
|
196
|
+
for (let index = this.lastInputSequence + 1; index < frameSet.sequence; index++) {
|
|
197
|
+
// Only mark as lost if we haven't already received it
|
|
198
|
+
if (!this.receivedFrameSequences.has(index)) {
|
|
199
|
+
this.lostFrameSequences.add(index);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
this.lastInputSequence = frameSet.sequence;
|
|
162
204
|
}
|
|
163
|
-
|
|
205
|
+
else {
|
|
206
|
+
// zOut-of-order packet (arrived late but still valid)
|
|
207
|
+
logger_1.Logger.warn(`Out-of-order frame set received: sequence ${frameSet.sequence} (expected > ${this.lastInputSequence})`);
|
|
208
|
+
}
|
|
209
|
+
// Process all frames
|
|
164
210
|
for (const frame of frameSet.frames) {
|
|
165
211
|
this.handleFrame(frame);
|
|
166
212
|
}
|
|
167
213
|
}
|
|
168
214
|
handleFrame(frame) {
|
|
215
|
+
// Duplicate detection for reliable frames
|
|
216
|
+
if (frame.isReliable()) {
|
|
217
|
+
if (this.receivedReliableFrameIndices.has(frame.reliableFrameIndex)) {
|
|
218
|
+
// Already processed tsis reliable frame, skip
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
this.receivedReliableFrameIndices.add(frame.reliableFrameIndex);
|
|
222
|
+
if (frame.reliableFrameIndex > this.highestReliableIndex) {
|
|
223
|
+
this.highestReliableIndex = frame.reliableFrameIndex;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
169
226
|
if (frame.isSplit()) {
|
|
170
227
|
this.handleSplitFrame(frame);
|
|
171
228
|
}
|
|
@@ -183,38 +240,48 @@ class NetworkSession {
|
|
|
183
240
|
const splitId = frame.splitId;
|
|
184
241
|
let entry = this.fragmentsQueue.get(splitId);
|
|
185
242
|
if (!entry) {
|
|
186
|
-
entry = new Map();
|
|
243
|
+
entry = { frames: new Map(), timestamp: Date.now() };
|
|
187
244
|
this.fragmentsQueue.set(splitId, entry);
|
|
188
245
|
}
|
|
189
|
-
entry.set(frame.splitFrameIndex, frame);
|
|
190
|
-
if (entry.size === frame.splitSize) {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
stream.write(sframe.payload);
|
|
246
|
+
entry.frames.set(frame.splitFrameIndex, frame);
|
|
247
|
+
if (entry.frames.size === frame.splitSize) {
|
|
248
|
+
const stream = new binarystream_1.BinaryStream();
|
|
249
|
+
for (let index = 0; index < frame.splitSize; index++) {
|
|
250
|
+
const sframe = entry.frames.get(index);
|
|
251
|
+
if (!sframe) {
|
|
252
|
+
logger_1.Logger.warn(`Missing fragment at index ${index} for splitId=${frame.splitId}`);
|
|
253
|
+
this.fragmentsQueue.delete(splitId);
|
|
254
|
+
return;
|
|
199
255
|
}
|
|
200
|
-
|
|
201
|
-
reassembledFrame.reliability = frame.reliability;
|
|
202
|
-
reassembledFrame.reliableFrameIndex = frame.reliableFrameIndex;
|
|
203
|
-
reassembledFrame.sequenceFrameIndex = frame.sequenceFrameIndex;
|
|
204
|
-
reassembledFrame.orderedFrameIndex = frame.orderedFrameIndex;
|
|
205
|
-
reassembledFrame.orderChannel = frame.orderChannel;
|
|
206
|
-
reassembledFrame.payload = stream.getBuffer();
|
|
207
|
-
this.handleFrame(reassembledFrame);
|
|
256
|
+
stream.write(sframe.payload);
|
|
208
257
|
}
|
|
258
|
+
const reassembledFrame = new proto_1.Frame();
|
|
259
|
+
reassembledFrame.reliability = frame.reliability;
|
|
260
|
+
reassembledFrame.reliableFrameIndex = frame.reliableFrameIndex;
|
|
261
|
+
reassembledFrame.sequenceFrameIndex = frame.sequenceFrameIndex;
|
|
262
|
+
reassembledFrame.orderedFrameIndex = frame.orderedFrameIndex;
|
|
263
|
+
reassembledFrame.orderChannel = frame.orderChannel;
|
|
264
|
+
reassembledFrame.payload = stream.getBuffer();
|
|
209
265
|
this.fragmentsQueue.delete(splitId);
|
|
266
|
+
// Process the reassembled frame (but skip split handling since it's no longer split)
|
|
267
|
+
if (reassembledFrame.isSequenced()) {
|
|
268
|
+
this.handleSequenced(reassembledFrame);
|
|
269
|
+
}
|
|
270
|
+
else if (reassembledFrame.isOrdered()) {
|
|
271
|
+
this.handleOrdered(reassembledFrame);
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
this.handle(reassembledFrame.payload);
|
|
275
|
+
}
|
|
210
276
|
}
|
|
211
277
|
}
|
|
212
278
|
handleSequenced(frame) {
|
|
213
279
|
const channel = frame.orderChannel;
|
|
214
|
-
const currentHighestSequence = this.inputHighestSequenceIndex[channel];
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
280
|
+
const currentHighestSequence = this.inputHighestSequenceIndex[channel] ?? 0;
|
|
281
|
+
// Sequenced frames: drop if older than what we've seen, otherwise process immediately
|
|
282
|
+
// They don't need ordering, just drop stale ones
|
|
283
|
+
if (frame.sequenceFrameIndex < currentHighestSequence) {
|
|
284
|
+
// Old sequenced frame, drop it
|
|
218
285
|
return;
|
|
219
286
|
}
|
|
220
287
|
this.inputHighestSequenceIndex[channel] = frame.sequenceFrameIndex + 1;
|
|
@@ -222,32 +289,41 @@ class NetworkSession {
|
|
|
222
289
|
}
|
|
223
290
|
handleOrdered(frame) {
|
|
224
291
|
const channel = frame.orderChannel;
|
|
225
|
-
const expectedOrderIndex = this.inputOrderIndex[channel];
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
292
|
+
const expectedOrderIndex = this.inputOrderIndex[channel] ?? 0;
|
|
293
|
+
if (frame.orderedFrameIndex === expectedOrderIndex) {
|
|
294
|
+
// This is the frame we're waiting for - process it
|
|
295
|
+
this.inputHighestSequenceIndex[channel] = 0;
|
|
296
|
+
this.inputOrderIndex[channel] = expectedOrderIndex + 1;
|
|
297
|
+
this.handle(frame.payload);
|
|
298
|
+
// Now flush any queued frames that are now in order
|
|
299
|
+
const outOfOrderQueue = this.inputOrderingQueue.get(channel);
|
|
300
|
+
if (outOfOrderQueue) {
|
|
301
|
+
let nextIndex = expectedOrderIndex + 1;
|
|
302
|
+
while (outOfOrderQueue.has(nextIndex)) {
|
|
303
|
+
const queuedFrame = outOfOrderQueue.get(nextIndex);
|
|
304
|
+
if (queuedFrame) {
|
|
305
|
+
this.handle(queuedFrame.payload);
|
|
306
|
+
outOfOrderQueue.delete(nextIndex);
|
|
307
|
+
}
|
|
308
|
+
nextIndex++;
|
|
309
|
+
}
|
|
310
|
+
this.inputOrderIndex[channel] = nextIndex;
|
|
232
311
|
}
|
|
233
|
-
unordered.set(frame.orderedFrameIndex, frame);
|
|
234
312
|
}
|
|
235
|
-
else if (
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
outOfOrderQueue.delete(index);
|
|
313
|
+
else if (frame.orderedFrameIndex > expectedOrderIndex) {
|
|
314
|
+
// Future frame n queue it for later
|
|
315
|
+
const outOfOrderQueue = this.inputOrderingQueue.get(channel);
|
|
316
|
+
if (outOfOrderQueue) {
|
|
317
|
+
// Prevent unbounded queue growth
|
|
318
|
+
if (outOfOrderQueue.size < NetworkSession.ORDER_QUEUE_MAX_SIZE) {
|
|
319
|
+
outOfOrderQueue.set(frame.orderedFrameIndex, frame);
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
logger_1.Logger.warn(`Order queue for channel ${channel} is full, dropping frame ${frame.orderedFrameIndex}`);
|
|
323
|
+
}
|
|
247
324
|
}
|
|
248
|
-
this.inputOrderingQueue.set(frame.orderChannel, outOfOrderQueue);
|
|
249
|
-
this.inputOrderIndex[frame.orderChannel] = index;
|
|
250
325
|
}
|
|
326
|
+
// If frame.orderedFrameIndex < expectedOrderIndex, it's a duplicate/old frame - ignore it
|
|
251
327
|
}
|
|
252
328
|
}
|
|
253
329
|
exports.NetworkSession = NetworkSession;
|