@baltica/raknet 0.0.6 → 0.0.8

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.
@@ -4,7 +4,6 @@ import { ClientEvents, ClientOptions } from "./types";
4
4
  export declare class Client extends Emitter<ClientEvents> {
5
5
  private socket;
6
6
  private network;
7
- private tickInterval?;
8
7
  private relay?;
9
8
  options: ClientOptions;
10
9
  constructor(options?: Partial<ClientOptions>);
@@ -10,7 +10,6 @@ const types_1 = require("./types");
10
10
  class Client extends utils_1.Emitter {
11
11
  socket;
12
12
  network;
13
- tickInterval;
14
13
  relay;
15
14
  options;
16
15
  constructor(options = {}) {
@@ -46,23 +45,21 @@ class Client extends utils_1.Emitter {
46
45
  const targetPort = this.network.address.port;
47
46
  this.network.send = (data) => this.relay.send(data, targetAddress, targetPort);
48
47
  this.relay.onMessage((data) => this.network.receive(data));
49
- this.tickInterval = setInterval(() => this.network.tick(), 50);
50
48
  }
51
49
  initDirect() {
52
50
  this.socket = (0, node_dgram_1.createSocket)(this.options.family);
51
+ this.socket.ref();
53
52
  this.network.send = (data) => this.socket.send(data, this.options.port, this.options.address);
54
53
  return new Promise((resolve) => {
55
54
  try {
56
55
  this.socket.address();
57
56
  this.socket.on("message", (buf) => this.network.receive(buf));
58
- this.tickInterval = setInterval(() => this.network.tick(), 50);
59
57
  resolve();
60
58
  }
61
59
  catch {
62
60
  this.socket.bind();
63
61
  this.socket.on("listening", () => {
64
62
  this.socket.on("message", (buf) => this.network.receive(buf));
65
- this.tickInterval = setInterval(() => this.network.tick(), 50);
66
63
  resolve();
67
64
  });
68
65
  }
@@ -111,10 +108,7 @@ class Client extends utils_1.Emitter {
111
108
  this.network.frameAndSend(data, priority);
112
109
  }
113
110
  close() {
114
- if (this.tickInterval) {
115
- clearInterval(this.tickInterval);
116
- this.tickInterval = undefined;
117
- }
111
+ this.network.destroy();
118
112
  this.network.status = shared_1.Status.Disconnected;
119
113
  this.network.send = () => { };
120
114
  this.network.removeAllListeners();
@@ -4,7 +4,6 @@ import { ServerEvents, ServerOptions } from "./types";
4
4
  import { Connection } from "./connection";
5
5
  export declare class Server extends Emitter<ServerEvents> {
6
6
  private socket;
7
- private tickInterval?;
8
7
  private connections;
9
8
  options: ServerOptions;
10
9
  constructor(options?: Partial<ServerOptions>);
@@ -10,7 +10,6 @@ const connection_1 = require("./connection");
10
10
  const RAKNET_PROTOCOL = 11;
11
11
  class Server extends utils_1.Emitter {
12
12
  socket;
13
- tickInterval;
14
13
  connections = new Map();
15
14
  options;
16
15
  constructor(options = {}) {
@@ -26,14 +25,11 @@ class Server extends utils_1.Emitter {
26
25
  this.socket.bind(this.options.port, this.options.address);
27
26
  this.socket.on("listening", () => {
28
27
  this.socket.on("message", (buffer, rinfo) => this.handleMessage(buffer, rinfo));
29
- this.tickInterval = setInterval(() => this.tick(), 50);
30
28
  resolve();
31
29
  });
32
30
  });
33
31
  }
34
32
  stop() {
35
- if (this.tickInterval)
36
- clearInterval(this.tickInterval);
37
33
  for (const conn of this.connections.values())
38
34
  conn.disconnect();
39
35
  this.connections.clear();
@@ -40,9 +40,16 @@ export declare class NetworkSession extends Emitter<NetworkEvents> {
40
40
  private highestReliableIndex;
41
41
  private offlineRetry;
42
42
  private outputBackupTimestamps;
43
+ private ackTimer?;
44
+ private retransmitTimer?;
45
+ private cleanupTimer?;
46
+ private lastCleanup;
47
+ private keepaliveTimer?;
43
48
  constructor(mtu: number, client: boolean);
49
+ private startKeepalive;
44
50
  sendOfflineWithRetry(data: Buffer): void;
45
51
  private clearOfflineRetry;
52
+ destroy(): void;
46
53
  receive(buffer: Buffer): void;
47
54
  private handleClientOffline;
48
55
  private handleServerOffline;
@@ -42,19 +42,56 @@ class NetworkSession extends utils_1.Emitter {
42
42
  highestReliableIndex = -1;
43
43
  offlineRetry = null;
44
44
  outputBackupTimestamps = new Map();
45
+ ackTimer;
46
+ retransmitTimer;
47
+ cleanupTimer;
48
+ lastCleanup = 0;
49
+ keepaliveTimer;
45
50
  constructor(mtu, client) {
46
51
  super();
47
52
  this.mtu = mtu;
48
53
  this.client = client;
49
54
  for (let i = 0; i < 32; i++)
50
55
  this.inputOrderingQueue.set(i, new Map());
56
+ this.startKeepalive();
57
+ }
58
+ startKeepalive() {
59
+ if (this.keepaliveTimer)
60
+ clearTimeout(this.keepaliveTimer);
61
+ const interval = this.status === proto_1.Status.Connected ? 10 :
62
+ this.status === proto_1.Status.Connecting ? 10 : 100;
63
+ this.keepaliveTimer = setTimeout(() => {
64
+ this.tick();
65
+ this.startKeepalive();
66
+ }, interval);
67
+ this.keepaliveTimer.ref();
51
68
  }
52
69
  sendOfflineWithRetry(data) {
53
70
  this.offlineRetry = { data, attempts: 1, maxAttempts: this.maxRetransmit, lastSent: Date.now(), interval: this.retransmitInterval };
54
71
  this.send(data);
72
+ if (!this.retransmitTimer) {
73
+ this.retransmitTimer = setTimeout(() => this.tick(), this.retransmitInterval);
74
+ this.retransmitTimer.ref();
75
+ }
55
76
  }
56
77
  clearOfflineRetry() {
57
78
  this.offlineRetry = null;
79
+ if (this.retransmitTimer) {
80
+ clearTimeout(this.retransmitTimer);
81
+ this.retransmitTimer = undefined;
82
+ }
83
+ }
84
+ destroy() {
85
+ this.status = proto_1.Status.Disconnected;
86
+ if (this.ackTimer)
87
+ clearTimeout(this.ackTimer);
88
+ if (this.retransmitTimer)
89
+ clearTimeout(this.retransmitTimer);
90
+ if (this.cleanupTimer)
91
+ clearTimeout(this.cleanupTimer);
92
+ if (this.keepaliveTimer)
93
+ clearTimeout(this.keepaliveTimer);
94
+ this.removeAllListeners();
58
95
  }
59
96
  receive(buffer) {
60
97
  const id = buffer[0];
@@ -221,7 +258,7 @@ class NetworkSession extends utils_1.Emitter {
221
258
  }
222
259
  }
223
260
  tick() {
224
- if (this.status === proto_1.Status.Disconnected)
261
+ if (this.status === proto_1.Status.Disconnected || !this.send)
225
262
  return;
226
263
  const now = Date.now();
227
264
  if (this.offlineRetry) {
@@ -231,48 +268,58 @@ class NetworkSession extends utils_1.Emitter {
231
268
  this.offlineRetry = null;
232
269
  this.status = proto_1.Status.Disconnected;
233
270
  this.emit("error", new Error("Connection timed out after " + r.maxAttempts + " attempts"));
271
+ return;
234
272
  }
235
- else {
236
- r.attempts++;
237
- r.lastSent = now;
238
- this.send(r.data);
239
- }
273
+ r.attempts++;
274
+ r.lastSent = now;
275
+ this.send(r.data);
276
+ if (this.retransmitTimer)
277
+ clearTimeout(this.retransmitTimer);
278
+ this.retransmitTimer = setTimeout(() => this.tick(), r.interval);
279
+ this.retransmitTimer.ref();
280
+ return;
240
281
  }
241
282
  }
242
- const windowStart = this.lastInputSequence - RECEIVE_WINDOW;
243
- if (windowStart > 0) {
244
- for (const s of this.receivedFrameSequences)
245
- if (s < windowStart)
246
- this.receivedFrameSequences.delete(s);
247
- for (const s of this.lostFrameSequences)
248
- if (s < windowStart)
249
- this.lostFrameSequences.delete(s);
250
- }
251
- const relStart = this.highestReliableIndex - RELIABLE_WINDOW;
252
- if (relStart > 0) {
253
- for (const i of this.receivedReliableFrameIndices)
254
- if (i < relStart)
255
- this.receivedReliableFrameIndices.delete(i);
256
- }
257
- for (const [id, entry] of this.fragmentsQueue) {
258
- if (now - entry.timestamp > FRAGMENT_TIMEOUT)
259
- this.fragmentsQueue.delete(id);
260
- }
261
- if (this.pendingAcks.size > 0) {
262
- const ack = new proto_1.Ack();
263
- ack.sequences = [...this.pendingAcks];
264
- this.pendingAcks.clear();
265
- this.send(ack.serialize());
283
+ if (now - this.lastCleanup > 5000) {
284
+ this.lastCleanup = now;
285
+ const windowStart = this.lastInputSequence - RECEIVE_WINDOW;
286
+ if (windowStart > 0) {
287
+ for (const s of this.receivedFrameSequences)
288
+ if (s < windowStart)
289
+ this.receivedFrameSequences.delete(s);
290
+ for (const s of this.lostFrameSequences)
291
+ if (s < windowStart)
292
+ this.lostFrameSequences.delete(s);
293
+ }
294
+ const relStart = this.highestReliableIndex - RELIABLE_WINDOW;
295
+ if (relStart > 0) {
296
+ for (const i of this.receivedReliableFrameIndices)
297
+ if (i < relStart)
298
+ this.receivedReliableFrameIndices.delete(i);
299
+ }
300
+ for (const [id, entry] of this.fragmentsQueue) {
301
+ if (now - entry.timestamp > FRAGMENT_TIMEOUT)
302
+ this.fragmentsQueue.delete(id);
303
+ }
266
304
  }
267
- if (this.lostFrameSequences.size > 0) {
268
- const nack = new proto_1.Nack();
269
- nack.sequences = [...this.lostFrameSequences];
270
- this.lostFrameSequences.clear();
271
- this.send(nack.serialize());
305
+ if (this.pendingAcks.size > 0 || this.lostFrameSequences.size > 0) {
306
+ if (this.pendingAcks.size > 0) {
307
+ const ack = new proto_1.Ack();
308
+ ack.sequences = [...this.pendingAcks];
309
+ this.pendingAcks.clear();
310
+ this.send(ack.serialize());
311
+ }
312
+ if (this.lostFrameSequences.size > 0) {
313
+ const nack = new proto_1.Nack();
314
+ nack.sequences = [...this.lostFrameSequences];
315
+ this.lostFrameSequences.clear();
316
+ this.send(nack.serialize());
317
+ }
272
318
  }
273
- // Retransmit unacked frame sets that are older than the retry interval
319
+ let nextRetransmit = Infinity;
274
320
  for (const [seq, sentAt] of this.outputBackupTimestamps) {
275
- if (now - sentAt >= this.retransmitInterval) {
321
+ const age = now - sentAt;
322
+ if (age >= this.retransmitInterval) {
276
323
  const frames = this.outputBackup.get(seq);
277
324
  if (frames) {
278
325
  const fs = new proto_1.FrameSet();
@@ -280,20 +327,34 @@ class NetworkSession extends utils_1.Emitter {
280
327
  fs.frames = frames;
281
328
  this.send(fs.serialize());
282
329
  this.outputBackupTimestamps.set(seq, now);
330
+ nextRetransmit = Math.min(nextRetransmit, this.retransmitInterval);
283
331
  }
284
332
  else {
285
333
  this.outputBackupTimestamps.delete(seq);
286
334
  }
287
335
  }
336
+ else {
337
+ nextRetransmit = Math.min(nextRetransmit, this.retransmitInterval - age);
338
+ }
288
339
  }
289
340
  if (this.outputFrames.size > 0)
290
341
  this.flush();
342
+ if (nextRetransmit < Infinity) {
343
+ if (this.retransmitTimer)
344
+ clearTimeout(this.retransmitTimer);
345
+ this.retransmitTimer = setTimeout(() => this.tick(), nextRetransmit);
346
+ this.retransmitTimer.ref();
347
+ }
291
348
  }
292
349
  onAck(ack) {
293
350
  for (const seq of ack.sequences) {
294
351
  this.outputBackup.delete(seq);
295
352
  this.outputBackupTimestamps.delete(seq);
296
353
  }
354
+ if (this.outputBackupTimestamps.size === 0 && this.retransmitTimer) {
355
+ clearTimeout(this.retransmitTimer);
356
+ this.retransmitTimer = undefined;
357
+ }
297
358
  }
298
359
  onNack(nack) {
299
360
  for (const seq of nack.sequences) {
@@ -363,7 +424,7 @@ class NetworkSession extends utils_1.Emitter {
363
424
  this.flush();
364
425
  }
365
426
  flush() {
366
- if (this.outputFrames.size === 0)
427
+ if (this.outputFrames.size === 0 || !this.send)
367
428
  return;
368
429
  const fs = new proto_1.FrameSet();
369
430
  fs.sequence = this.outputSequence++;
@@ -371,8 +432,11 @@ class NetworkSession extends utils_1.Emitter {
371
432
  this.outputBackup.set(fs.sequence, fs.frames);
372
433
  this.outputBackupTimestamps.set(fs.sequence, Date.now());
373
434
  this.outputFrames.clear();
374
- const serialized = fs.serialize();
375
- this.send(serialized);
435
+ this.send(fs.serialize());
436
+ if (!this.retransmitTimer) {
437
+ this.retransmitTimer = setTimeout(() => this.tick(), this.retransmitInterval);
438
+ this.retransmitTimer.ref();
439
+ }
376
440
  }
377
441
  onFrameSet(fs) {
378
442
  if (this.receivedFrameSequences.has(fs.sequence))
@@ -389,6 +453,13 @@ class NetworkSession extends utils_1.Emitter {
389
453
  }
390
454
  for (const frame of fs.frames)
391
455
  this.handleFrame(frame);
456
+ if (!this.ackTimer) {
457
+ this.ackTimer = setTimeout(() => {
458
+ this.ackTimer = undefined;
459
+ this.tick();
460
+ }, 10);
461
+ this.ackTimer.ref();
462
+ }
392
463
  }
393
464
  handleFrame(frame) {
394
465
  if (frame.isReliable()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@baltica/raknet",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "RakNet implementation for Baltica",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",