@sanctumterra/raknet 1.3.61 → 1.3.64

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.
Files changed (42) hide show
  1. package/dist/client/client-events.d.ts +2 -4
  2. package/dist/client/client-events.d.ts.map +1 -1
  3. package/dist/client/client-options.d.ts +23 -0
  4. package/dist/client/client-options.d.ts.map +1 -0
  5. package/dist/client/client-options.js +24 -0
  6. package/dist/client/client.d.ts +26 -11
  7. package/dist/client/client.d.ts.map +1 -1
  8. package/dist/client/client.js +222 -102
  9. package/dist/client/framer.d.ts +49 -0
  10. package/dist/client/framer.d.ts.map +1 -0
  11. package/dist/client/framer.js +368 -0
  12. package/dist/client/index.d.ts +2 -2
  13. package/dist/client/index.d.ts.map +1 -1
  14. package/dist/client/index.js +2 -2
  15. package/dist/index.d.ts +2 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +2 -1
  18. package/dist/proto/packets/index.d.ts +0 -1
  19. package/dist/proto/packets/index.d.ts.map +1 -1
  20. package/dist/proto/packets/index.js +0 -1
  21. package/dist/proto/types/valid.d.ts +1 -2
  22. package/dist/proto/types/valid.d.ts.map +1 -1
  23. package/dist/tests/benchmark.d.ts +2 -0
  24. package/dist/tests/benchmark.d.ts.map +1 -0
  25. package/dist/tests/benchmark.js +71 -0
  26. package/dist/tests/localhost.js +3 -1
  27. package/dist/tests/test.d.ts +2 -0
  28. package/dist/tests/test.d.ts.map +1 -0
  29. package/dist/tests/test.js +49 -0
  30. package/dist/utils/Logger.d.ts +14 -0
  31. package/dist/utils/Logger.d.ts.map +1 -0
  32. package/dist/utils/Logger.js +98 -0
  33. package/dist/utils/buffer-pool.d.ts +5 -0
  34. package/dist/utils/buffer-pool.d.ts.map +1 -0
  35. package/dist/utils/buffer-pool.js +22 -0
  36. package/dist/utils/decorators.d.ts +3 -0
  37. package/dist/utils/decorators.d.ts.map +1 -0
  38. package/dist/utils/decorators.js +62 -0
  39. package/dist/utils/index.d.ts +4 -0
  40. package/dist/utils/index.d.ts.map +1 -0
  41. package/dist/utils/index.js +19 -0
  42. package/package.json +4 -7
@@ -1,4 +1,5 @@
1
- import type { Ack, ConnectedPing, ConnectionRequest, NewIncomingConnection, OpenConnectionReplyOne, OpenConnectionReplyTwo, OpenConnectionRequestOne, OpenConnectionRequestTwo, UnconnectedPing, UnconnectedPong, Frameset, Nack, ConnectedPong, ConnectionRequestAccepted } from "../proto";
1
+ import type { Ack, ConnectedPing, ConnectionRequest, NewIncomingConnection, OpenConnectionReplyOne, OpenConnectionReplyTwo, OpenConnectionRequestOne, OpenConnectionRequestTwo, UnconnectedPing, UnconnectedPong } from "../proto";
2
+ import type { Frameset } from "../proto/packets/frameset";
2
3
  export interface ClientEvents {
3
4
  "open-connection-reply-one": [OpenConnectionReplyOne];
4
5
  "open-connection-reply-two": [OpenConnectionReplyTwo];
@@ -10,11 +11,8 @@ export interface ClientEvents {
10
11
  "connected-ping": [ConnectedPing];
11
12
  "connection-request": [ConnectionRequest];
12
13
  "new-incoming-connection": [NewIncomingConnection];
13
- "connection-request-accepted": [ConnectionRequestAccepted];
14
- "connected-pong": [ConnectedPong];
15
14
  encapsulated: [Buffer];
16
15
  ack: [Ack];
17
- nack: [Nack];
18
16
  error: [Error];
19
17
  close: [];
20
18
  connect: [];
@@ -1 +1 @@
1
- {"version":3,"file":"client-events.d.ts","sourceRoot":"","sources":["../../src/client/client-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,GAAG,EACH,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,wBAAwB,EACxB,eAAe,EACf,eAAe,EACf,QAAQ,EACR,IAAI,EACJ,aAAa,EACb,yBAAyB,EACzB,MAAM,UAAU,CAAC;AAElB,MAAM,WAAW,YAAY;IAC5B,2BAA2B,EAAE,CAAC,sBAAsB,CAAC,CAAC;IACtD,2BAA2B,EAAE,CAAC,sBAAsB,CAAC,CAAC;IACtD,6BAA6B,EAAE,CAAC,wBAAwB,CAAC,CAAC;IAC1D,6BAA6B,EAAE,CAAC,wBAAwB,CAAC,CAAC;IAC1D,kBAAkB,EAAE,CAAC,eAAe,CAAC,CAAC;IACtC,kBAAkB,EAAE,CAAC,eAAe,CAAC,CAAC;IACtC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC;IACrB,gBAAgB,EAAE,CAAC,aAAa,CAAC,CAAC;IAClC,oBAAoB,EAAE,CAAC,iBAAiB,CAAC,CAAC;IAC1C,yBAAyB,EAAE,CAAC,qBAAqB,CAAC,CAAC;IACnD,6BAA6B,EAAE,CAAC,yBAAyB,CAAC,CAAC;IAC3D,gBAAgB,EAAE,CAAC,aAAa,CAAC,CAAC;IAClC,YAAY,EAAE,CAAC,MAAM,CAAC,CAAC;IACvB,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;IACX,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;IACb,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;IACf,KAAK,EAAE,EAAE,CAAC;IACV,OAAO,EAAE,EAAE,CAAC;IACZ,IAAI,EAAE,EAAE,CAAC;CACT"}
1
+ {"version":3,"file":"client-events.d.ts","sourceRoot":"","sources":["../../src/client/client-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,GAAG,EACH,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,wBAAwB,EACxB,eAAe,EACf,eAAe,EACf,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC5B,2BAA2B,EAAE,CAAC,sBAAsB,CAAC,CAAC;IACtD,2BAA2B,EAAE,CAAC,sBAAsB,CAAC,CAAC;IACtD,6BAA6B,EAAE,CAAC,wBAAwB,CAAC,CAAC;IAC1D,6BAA6B,EAAE,CAAC,wBAAwB,CAAC,CAAC;IAC1D,kBAAkB,EAAE,CAAC,eAAe,CAAC,CAAC;IACtC,kBAAkB,EAAE,CAAC,eAAe,CAAC,CAAC;IACtC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC;IACrB,gBAAgB,EAAE,CAAC,aAAa,CAAC,CAAC;IAClC,oBAAoB,EAAE,CAAC,iBAAiB,CAAC,CAAC;IAC1C,yBAAyB,EAAE,CAAC,qBAAqB,CAAC,CAAC;IACnD,YAAY,EAAE,CAAC,MAAM,CAAC,CAAC;IACvB,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;IACX,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;IACf,KAAK,EAAE,EAAE,CAAC;IACV,OAAO,EAAE,EAAE,CAAC;IACZ,IAAI,EAAE,EAAE,CAAC;CACT"}
@@ -0,0 +1,23 @@
1
+ type ClientOptions = {
2
+ address: string;
3
+ port: number;
4
+ protocolVersion: number;
5
+ mtuSize: number;
6
+ clientId: bigint;
7
+ debug: boolean;
8
+ timeout: number;
9
+ maxFrameQueueSize: number;
10
+ fragmentTimeout: number;
11
+ enableBufferPooling: boolean;
12
+ gcInterval: number;
13
+ socketBufferMultiplier: number;
14
+ tickInterval: number;
15
+ connectionRetryInterval: number;
16
+ initialConnectionTimeout: number;
17
+ batchSize: number;
18
+ maxPipelineStages: number;
19
+ fastPathEnabled: boolean;
20
+ };
21
+ declare const defaultClientOptions: ClientOptions;
22
+ export { type ClientOptions, defaultClientOptions };
23
+ //# sourceMappingURL=client-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-options.d.ts","sourceRoot":"","sources":["../../src/client/client-options.ts"],"names":[],"mappings":"AAAA,KAAK,aAAa,GAAG;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,uBAAuB,EAAE,MAAM,CAAC;IAChC,wBAAwB,EAAE,MAAM,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,QAAA,MAAM,oBAAoB,EAAE,aAmB3B,CAAC;AAEF,OAAO,EAAE,KAAK,aAAa,EAAE,oBAAoB,EAAE,CAAC"}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultClientOptions = void 0;
4
+ const defaultClientOptions = {
5
+ address: "127.0.0.1",
6
+ port: 19132,
7
+ protocolVersion: 11,
8
+ mtuSize: 1492,
9
+ clientId: BigInt(Math.floor(Math.random() * 1000000000000000000)),
10
+ debug: false,
11
+ timeout: 3000,
12
+ maxFrameQueueSize: 1000,
13
+ fragmentTimeout: 10000,
14
+ enableBufferPooling: true,
15
+ gcInterval: 60000,
16
+ socketBufferMultiplier: 2048,
17
+ tickInterval: 8,
18
+ connectionRetryInterval: 100,
19
+ initialConnectionTimeout: 800,
20
+ batchSize: 16,
21
+ maxPipelineStages: 2,
22
+ fastPathEnabled: true,
23
+ };
24
+ exports.defaultClientOptions = defaultClientOptions;
@@ -1,17 +1,32 @@
1
- import Emitter from "@serenityjs/emitter";
2
- import { type ClientOptions } from "./client_options";
1
+ import { Emitter } from "@serenityjs/emitter";
3
2
  import type { ClientEvents } from "./client-events";
4
- import { type Advertisement } from "../proto";
3
+ import { type Socket } from "node:dgram";
4
+ import { Framer } from "./framer";
5
+ import { Address, type Advertisement, type Frame, Priority } from "../proto";
6
+ import { type ClientOptions } from "./client-options";
5
7
  export declare class Client extends Emitter<ClientEvents> {
6
- private rakSocket;
8
+ socket: Socket;
9
+ framer: Framer;
7
10
  options: ClientOptions;
8
- ticker: NodeJS.Timeout;
9
- tick: number;
10
- private advertisement;
11
- constructor(options: Partial<ClientOptions>);
11
+ private timer;
12
+ private timeout;
13
+ serverAddress: Address;
14
+ private isConnecting;
15
+ private packetHandlers;
16
+ private fastPathPackets;
17
+ constructor(options?: Partial<ClientOptions>);
18
+ initSocket(): void;
19
+ ping(): Promise<Advertisement | null>;
12
20
  connect(): Promise<Advertisement>;
13
- ping(): Promise<Advertisement>;
14
- frameAndSend(buffer: Buffer): void;
15
- private handleData;
21
+ private setupConnection;
22
+ sendFrame(frame: Frame, priority: Priority): void;
23
+ send(buffer: Buffer): void;
24
+ private onMessage;
25
+ private cleanup;
26
+ private handleAck;
27
+ private handleUnconnectedPong;
28
+ private handleOpenConnectionReplyOne;
29
+ private handleOpenConnectionReplyTwo;
30
+ private handleFrameSet;
16
31
  }
17
32
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,qBAAqB,CAAC;AAC1C,OAAO,EAAE,KAAK,aAAa,EAAwB,MAAM,kBAAkB,CAAC;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD,OAAO,EAaN,KAAK,aAAa,EAClB,MAAM,UAAU,CAAC;AAElB,qBAAa,MAAO,SAAQ,OAAO,CAAC,YAAY,CAAC;IAChD,OAAO,CAAC,SAAS,CAAY;IAEtB,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAG,MAAM,CAAC,OAAO,CAAC;IACxB,IAAI,SAAK;IAChB,OAAO,CAAC,aAAa,CAAiB;gBAE1B,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC;IAW9B,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC;IAoBjC,IAAI,IAAI,OAAO,CAAC,aAAa,CAAC;IAwBpC,YAAY,CAAC,MAAM,EAAE,MAAM;IAIlC,OAAO,CAAC,UAAU;CAqElB"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAmB,KAAK,MAAM,EAAgB,MAAM,YAAY,CAAC;AACxE,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAEN,OAAO,EACP,KAAK,aAAa,EAElB,KAAK,KAAK,EAOV,QAAQ,EAGR,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,KAAK,aAAa,EAAwB,MAAM,kBAAkB,CAAC;AAK5E,qBAAa,MAAO,SAAQ,OAAO,CAAC,YAAY,CAAC;IACzC,MAAM,EAAG,MAAM,CAAC;IAChB,MAAM,EAAG,MAAM,CAAC;IAChB,OAAO,EAAE,aAAa,CAAC;IAC9B,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,OAAO,CAAkB;IAC1B,aAAa,EAAG,OAAO,CAAC;IAC/B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,cAAc,CAAwD;IAC9E,OAAO,CAAC,eAAe,CAKpB;gBAES,OAAO,GAAE,OAAO,CAAC,aAAa,CAAwB;IAmB3D,UAAU;IAaJ,IAAI,IAAI,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IA2BrC,OAAO,IAAI,OAAO,CAAC,aAAa,CAAC;YAmBhC,eAAe;IAyDtB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAIjD,IAAI,CAAC,MAAM,EAAE,MAAM;IAe1B,OAAO,CAAC,SAAS;IAyBjB,OAAO,CAAC,OAAO;IASf,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,4BAA4B;IAkBpC,OAAO,CAAC,4BAA4B;IAuCpC,OAAO,CAAC,cAAc;CAKtB"}
@@ -1,129 +1,249 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4
10
  };
5
11
  Object.defineProperty(exports, "__esModule", { value: true });
6
12
  exports.Client = void 0;
7
- const emitter_1 = __importDefault(require("@serenityjs/emitter"));
8
- const client_options_1 = require("./client_options");
9
- const rs_rak_client_1 = require("@sanctumterra/rs-rak-client");
13
+ const emitter_1 = require("@serenityjs/emitter");
14
+ const node_dgram_1 = require("node:dgram");
15
+ const framer_1 = require("./framer");
10
16
  const proto_1 = require("../proto");
11
- class Client extends emitter_1.default {
12
- rakSocket;
17
+ const client_options_1 = require("./client-options");
18
+ const utils_1 = require("../utils");
19
+ const frameset_1 = require("../proto/packets/frameset");
20
+ const decorators_1 = require("../utils/decorators");
21
+ class Client extends emitter_1.Emitter {
22
+ socket;
23
+ framer;
13
24
  options;
14
- ticker;
15
- tick = 0;
16
- advertisement;
17
- constructor(options) {
25
+ timer;
26
+ timeout;
27
+ serverAddress;
28
+ isConnecting = false;
29
+ packetHandlers;
30
+ fastPathPackets = new Set([
31
+ proto_1.Packet.Ack,
32
+ proto_1.Packet.Nack,
33
+ proto_1.Packet.ConnectedPing,
34
+ proto_1.Packet.ConnectedPong,
35
+ ]);
36
+ constructor(options = client_options_1.defaultClientOptions) {
18
37
  super();
19
38
  this.options = { ...client_options_1.defaultClientOptions, ...options };
20
- this.rakSocket = new rs_rak_client_1.RaknetClient(this.options.address, this.options.port);
39
+ this.maxListeners = 20;
40
+ this.packetHandlers = new Map([
41
+ [proto_1.Packet.Ack, this.handleAck.bind(this)],
42
+ [proto_1.Packet.UnconnectedPong, this.handleUnconnectedPong.bind(this)],
43
+ [
44
+ proto_1.Packet.OpenConnectionReplyOne,
45
+ this.handleOpenConnectionReplyOne.bind(this),
46
+ ],
47
+ [
48
+ proto_1.Packet.OpenConnectionReplyTwo,
49
+ this.handleOpenConnectionReplyTwo.bind(this),
50
+ ],
51
+ [proto_1.Packet.FrameSet, this.handleFrameSet.bind(this)],
52
+ ]);
21
53
  }
22
- async connect() {
23
- this.ticker = setInterval(() => {
24
- this.rakSocket.receive();
25
- this.rakSocket.tick();
26
- const data = this.rakSocket.onEvent();
27
- if (data) {
28
- this.handleData(Buffer.from(data.data));
29
- }
30
- this.tick++;
31
- }, 20);
32
- await this.ping();
33
- this.rakSocket.connect();
54
+ initSocket() {
55
+ try {
56
+ this.socket = (0, node_dgram_1.createSocket)("udp4");
57
+ this.framer = new framer_1.Framer(this);
58
+ this.remove("tick", () => this.framer.tick());
59
+ this.on("tick", () => this.framer.tick());
60
+ this.socket.removeAllListeners("message");
61
+ this.socket.on("message", this.onMessage.bind(this));
62
+ }
63
+ catch (error) {
64
+ utils_1.Logger.error(`Failed to create socket: ${error}`);
65
+ }
66
+ }
67
+ async ping() {
34
68
  return new Promise((resolve, reject) => {
35
- this.once("ack", () => {
36
- this.emit("connect");
37
- resolve(this.advertisement);
69
+ const timeoutId = setTimeout(() => {
70
+ this.removeAll("unconnected-pong");
71
+ reject(new Error("Ping timed out"));
72
+ }, this.options.initialConnectionTimeout);
73
+ const sendPing = () => {
74
+ const unconnectedPing = new proto_1.UnconnectedPing();
75
+ unconnectedPing.guid = this.options.clientId;
76
+ unconnectedPing.clientTimestamp = BigInt(Date.now());
77
+ this.send(unconnectedPing.serialize());
78
+ };
79
+ sendPing();
80
+ const pingInterval = setInterval(sendPing, 50);
81
+ this.once("unconnected-pong", (packet) => {
82
+ clearTimeout(timeoutId);
83
+ clearInterval(pingInterval);
84
+ resolve((0, proto_1.fromString)(packet.message));
38
85
  });
39
86
  });
40
87
  }
41
- async ping() {
88
+ async connect() {
89
+ if (this.isConnecting)
90
+ throw new Error("Connection attempt already in progress");
91
+ try {
92
+ this.isConnecting = true;
93
+ this.initSocket();
94
+ const [advertisement] = await Promise.all([
95
+ this.ping(),
96
+ this.setupConnection(),
97
+ ]);
98
+ if (!advertisement)
99
+ throw new Error("Failed to get server advertisement");
100
+ return advertisement;
101
+ }
102
+ catch (error) {
103
+ this.isConnecting = false;
104
+ throw error;
105
+ }
106
+ }
107
+ async setupConnection() {
108
+ this.timer = setInterval(() => this.emit("tick"), this.options.tickInterval);
109
+ const request = new proto_1.OpenConnectionRequestOne();
110
+ request.mtu = this.options.mtuSize;
111
+ request.protocol = this.options.protocolVersion;
42
112
  return new Promise((resolve, reject) => {
43
- const timeout = setTimeout(() => {
44
- cleanup();
45
- reject(new Error("Ping timeout"));
46
- }, 5000);
47
- const pongHandler = (pong) => {
48
- this.advertisement = (0, proto_1.fromString)(pong.message);
49
- cleanup();
50
- resolve((0, proto_1.fromString)(pong.message));
51
- };
113
+ let connectionAttempts = 0;
114
+ const maxAttempts = 3;
115
+ let isResolved = false;
116
+ let timeoutId;
52
117
  const cleanup = () => {
53
- clearTimeout(timeout);
54
- this.remove("unconnected-pong", pongHandler);
118
+ clearTimeout(timeoutId);
119
+ this.removeAll("open-connection-reply-one");
120
+ this.removeAll("new-incoming-connection");
121
+ };
122
+ const attemptConnection = () => {
123
+ if (isResolved)
124
+ return;
125
+ if (connectionAttempts >= maxAttempts) {
126
+ cleanup();
127
+ reject(new Error("Connection timed out"));
128
+ return;
129
+ }
130
+ connectionAttempts++;
131
+ this.emit("open-connection-request-one", request);
132
+ this.send(request.serialize());
133
+ const delay = connectionAttempts === 1
134
+ ? 50
135
+ : Math.min(75 * 1.5 ** (connectionAttempts - 1), 200);
136
+ timeoutId = setTimeout(attemptConnection, delay);
55
137
  };
56
- this.rakSocket.ping();
57
- this.once("unconnected-pong", pongHandler);
138
+ // biome-ignore lint/suspicious/noAssignInExpressions: <explanation>
139
+ this.once("open-connection-reply-one", () => (connectionAttempts = 0));
140
+ this.onceAfter("new-incoming-connection", () => {
141
+ if (!isResolved) {
142
+ isResolved = true;
143
+ cleanup();
144
+ this.emit("connect");
145
+ this.isConnecting = false;
146
+ resolve();
147
+ }
148
+ });
149
+ attemptConnection();
58
150
  });
59
151
  }
60
- frameAndSend(buffer) {
61
- this.rakSocket.frameAndSend(buffer);
152
+ sendFrame(frame, priority) {
153
+ this.framer.sendFrame(frame, priority);
62
154
  }
63
- handleData(data) {
64
- if (!data || data.length === 0) {
65
- // console.log("Received empty data buffer");
66
- return;
155
+ send(buffer) {
156
+ if (this.options.debug) {
157
+ utils_1.Logger.debug(`Sending ${buffer[0]}, ${buffer.length} bytes to ${this.options.address}:${this.options.port}`);
67
158
  }
68
- let packetId = data[0];
69
- if ((packetId & 0xf0) === 0x80)
70
- packetId = 0x80;
71
- switch (packetId) {
72
- case 254: {
73
- this.emit("encapsulated", data);
74
- break;
75
- }
76
- case proto_1.Packet.Ack: {
77
- const ack = new proto_1.Ack(data).deserialize();
78
- this.emit("ack", ack);
79
- break;
80
- }
81
- case proto_1.Packet.FrameSet: {
82
- const frameset = new proto_1.Frameset(data).deserialize();
83
- this.emit("frameset", frameset);
84
- break;
85
- }
86
- case proto_1.Packet.ConnectedPing: {
87
- const connectedPing = new proto_1.ConnectedPing(data).deserialize();
88
- this.emit("connected-ping", connectedPing);
89
- break;
90
- }
91
- case proto_1.Packet.ConnectionRequest: {
92
- const connectionRequest = new proto_1.ConnectionRequest(data).deserialize();
93
- this.emit("connection-request", connectionRequest);
94
- break;
95
- }
96
- case proto_1.Packet.NewIncomingConnection: {
97
- const newIncomingConnection = new proto_1.NewIncomingConnection(data).deserialize();
98
- this.emit("new-incoming-connection", newIncomingConnection);
99
- break;
100
- }
101
- case proto_1.Packet.UnconnectedPing: {
102
- const unconnectedPing = new proto_1.UnconnectedPing(data).deserialize();
103
- this.emit("unconnected-ping", unconnectedPing);
104
- break;
105
- }
106
- case proto_1.Packet.UnconnectedPong: {
107
- const unconnectedPong = new proto_1.UnconnectedPong(data).deserialize();
108
- this.emit("unconnected-pong", unconnectedPong);
109
- break;
110
- }
111
- case proto_1.Packet.Nack: {
112
- const nack = new proto_1.Nack(data).deserialize();
113
- this.emit("nack", nack);
114
- break;
159
+ this.socket.send(buffer, 0, buffer.length, this.options.port, this.options.address);
160
+ }
161
+ onMessage(msg, rinfo) {
162
+ try {
163
+ const packetId = (msg[0] & 0xf0) === 0x80 ? 0x80 : msg[0];
164
+ if (this.fastPathPackets.has(packetId)) {
165
+ this.packetHandlers.get(packetId)?.(msg, rinfo);
166
+ return;
115
167
  }
116
- case proto_1.Packet.ConnectedPong: {
117
- const connectedPong = new proto_1.ConnectedPong(data).deserialize();
118
- this.emit("connected-pong", connectedPong);
119
- break;
168
+ const handler = this.packetHandlers.get(packetId);
169
+ if (handler) {
170
+ handler(msg, rinfo);
171
+ return;
120
172
  }
121
- case proto_1.Packet.ConnectionRequestAccepted: {
122
- const connectionRequestAccepted = new proto_1.ConnectionRequestAccepted(data).deserialize();
123
- this.emit("connection-request-accepted", connectionRequestAccepted);
124
- break;
173
+ if (this.options.debug) {
174
+ utils_1.Logger.debug(`Unhandled packet ${packetId} from ${rinfo.address}:${rinfo.port}`);
125
175
  }
126
176
  }
177
+ catch (error) {
178
+ utils_1.Logger.error("Failed to handle packet", { error: error });
179
+ }
180
+ }
181
+ cleanup() {
182
+ this.removeAll();
183
+ this.socket.removeAllListeners();
184
+ this.socket.close();
185
+ clearInterval(this.timer);
186
+ clearTimeout(this.timeout);
187
+ this.isConnecting = false;
188
+ }
189
+ handleAck(msg, _rinfo) {
190
+ this.emit("ack", new proto_1.Ack(msg).deserialize());
191
+ }
192
+ handleUnconnectedPong(msg, _rinfo) {
193
+ this.emit("unconnected-pong", new proto_1.UnconnectedPong(msg).deserialize());
194
+ }
195
+ handleOpenConnectionReplyOne(msg, rinfo) {
196
+ const packet = new proto_1.OpenConnectionReplyOne(msg).deserialize();
197
+ this.emit("open-connection-reply-one", packet);
198
+ this.serverAddress = new proto_1.Address(rinfo.address, rinfo.port, rinfo.family === "IPv4" ? 4 : 6);
199
+ const request = new proto_1.OpenConnectionRequestTwo();
200
+ request.mtu = packet.mtu;
201
+ request.address = this.serverAddress;
202
+ request.clientGuid = this.options.clientId;
203
+ this.emit("open-connection-request-two", request);
204
+ this.send(request.serialize());
205
+ }
206
+ handleOpenConnectionReplyTwo(msg, _rinfo) {
207
+ const packet = new proto_1.OpenConnectionReplyTwo(msg).deserialize();
208
+ this.emit("open-connection-reply-two", packet);
209
+ this.options.mtuSize = packet.mtu;
210
+ const conReq = new proto_1.ConnectionRequest();
211
+ conReq.clientGuid = this.options.clientId;
212
+ conReq.timestamp = BigInt(Date.now());
213
+ conReq.useSecurity = false;
214
+ let connectionAttempts = 0;
215
+ let lastAttemptTime = 0;
216
+ this.emit("connection-request", conReq);
217
+ this.framer.frameAndSend(conReq.serialize(), proto_1.Priority.Immediate);
218
+ lastAttemptTime = Date.now();
219
+ const connectionInterval = setInterval(() => {
220
+ const now = Date.now();
221
+ if (now - lastAttemptTime < 100)
222
+ return;
223
+ if (connectionAttempts >= 3) {
224
+ clearInterval(connectionInterval);
225
+ this.cleanup();
226
+ this.emit("error", new Error("Connection request timed out"));
227
+ return;
228
+ }
229
+ lastAttemptTime = now;
230
+ connectionAttempts++;
231
+ this.emit("connection-request", conReq);
232
+ this.framer.frameAndSend(conReq.serialize(), proto_1.Priority.Immediate);
233
+ }, 100);
234
+ this.once("new-incoming-connection", () => clearInterval(connectionInterval));
235
+ }
236
+ handleFrameSet(msg, _rinfo) {
237
+ const frameset = new frameset_1.Frameset(msg).deserialize();
238
+ this.emit("frameset", frameset);
239
+ this.framer.handle(frameset);
127
240
  }
128
241
  }
129
242
  exports.Client = Client;
243
+ __decorate([
244
+ decorators_1.measureExecutionTime,
245
+ decorators_1.optimizeConnection,
246
+ __metadata("design:type", Function),
247
+ __metadata("design:paramtypes", []),
248
+ __metadata("design:returntype", Promise)
249
+ ], Client.prototype, "connect", null);
@@ -0,0 +1,49 @@
1
+ import { Frame, Priority } from "../proto";
2
+ import { Frameset } from "../proto";
3
+ import type { Client } from "./client";
4
+ interface FragmentInfo {
5
+ frame: Frame;
6
+ timestamp: number;
7
+ }
8
+ export declare class Framer {
9
+ private static readonly BUFFER_SIZES;
10
+ private bufferPools;
11
+ private client;
12
+ private lastInputSequence;
13
+ private receivedFrameSequences;
14
+ private lostFrameSequences;
15
+ private inputHighestSequenceIndex;
16
+ private inputOrderIndex;
17
+ protected inputOrderingQueue: Map<number, Map<number, Frame>>;
18
+ protected readonly fragmentsQueue: Map<number, Map<number, FragmentInfo>>;
19
+ outputOrderIndex: number[];
20
+ outputSequenceIndex: number[];
21
+ outputFrameQueue: Frameset;
22
+ protected outputSequence: number;
23
+ protected outputSplitIndex: number;
24
+ protected outputReliableIndex: number;
25
+ protected outputFrames: Frame[];
26
+ outputBackup: Map<number, Frame[]>;
27
+ constructor(client: Client);
28
+ tick(): void;
29
+ private processFrame;
30
+ private processBatch;
31
+ handle(frameSet: Frameset): void;
32
+ private handleFrame;
33
+ private handleOrdered;
34
+ private processOrderedFrames;
35
+ private handleSequenced;
36
+ private handleSplit;
37
+ private reassembleAndProcessFragment;
38
+ frameAndSend(payload: Buffer, priority?: Priority): void;
39
+ sendFrame(frame: Frame, priority: Priority): void;
40
+ private handleLargePayload;
41
+ private createSplitFrame;
42
+ private queueFrame;
43
+ sendQueue(amount: number): void;
44
+ private cleanupStaleFragments;
45
+ private getOptimalBuffer;
46
+ private releaseBuffer;
47
+ }
48
+ export {};
49
+ //# sourceMappingURL=framer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"framer.d.ts","sourceRoot":"","sources":["../../src/client/framer.ts"],"names":[],"mappings":"AACA,OAAO,EAIN,KAAK,EAGL,QAAQ,EAIR,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGvC,UAAU,YAAY;IACrB,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,MAAM;IAClB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAA4B;IAChE,OAAO,CAAC,WAAW,CAAoC;IAEvD,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO,CAAC,iBAAiB,CAAM;IAC/B,OAAO,CAAC,sBAAsB,CAA0B;IACxD,OAAO,CAAC,kBAAkB,CAA0B;IACpD,OAAO,CAAC,yBAAyB,CAAmC;IACpE,OAAO,CAAC,eAAe,CAAmC;IAC1D,SAAS,CAAC,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAa;IAC1E,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAC9D;IAEJ,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,gBAAgB,EAAE,QAAQ,CAAC;IAClC,SAAS,CAAC,cAAc,SAAK;IAC7B,SAAS,CAAC,gBAAgB,SAAK;IAC/B,SAAS,CAAC,mBAAmB,SAAK;IAClC,SAAS,CAAC,YAAY,EAAE,KAAK,EAAE,CAAM;IAC9B,YAAY,uBAA8B;gBAErC,MAAM,EAAE,MAAM;IAmBnB,IAAI;IAqBX,OAAO,CAAC,YAAY;IAuDpB,OAAO,CAAC,YAAY;IAcb,MAAM,CAAC,QAAQ,EAAE,QAAQ;IAyChC,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,oBAAoB;IAkB5B,OAAO,CAAC,eAAe;IAoBvB,OAAO,CAAC,WAAW;IAkBnB,OAAO,CAAC,4BAA4B;IA8C7B,YAAY,CAClB,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,QAA0B,GAClC,IAAI;IAQA,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAuBxD,OAAO,CAAC,kBAAkB;IAkB1B,OAAO,CAAC,gBAAgB;IAwBxB,OAAO,CAAC,UAAU;IAuBX,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAatC,OAAO,CAAC,qBAAqB;IAa7B,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,aAAa;CAUrB"}