@baltica/raknet 0.0.6 → 0.0.7

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,7 +45,6 @@ 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);
@@ -55,14 +53,12 @@ class Client extends utils_1.Emitter {
55
53
  try {
56
54
  this.socket.address();
57
55
  this.socket.on("message", (buf) => this.network.receive(buf));
58
- this.tickInterval = setInterval(() => this.network.tick(), 50);
59
56
  resolve();
60
57
  }
61
58
  catch {
62
59
  this.socket.bind();
63
60
  this.socket.on("listening", () => {
64
61
  this.socket.on("message", (buf) => this.network.receive(buf));
65
- this.tickInterval = setInterval(() => this.network.tick(), 50);
66
62
  resolve();
67
63
  });
68
64
  }
@@ -111,10 +107,7 @@ class Client extends utils_1.Emitter {
111
107
  this.network.frameAndSend(data, priority);
112
108
  }
113
109
  close() {
114
- if (this.tickInterval) {
115
- clearInterval(this.tickInterval);
116
- this.tickInterval = undefined;
117
- }
110
+ this.network.destroy();
118
111
  this.network.status = shared_1.Status.Disconnected;
119
112
  this.network.send = () => { };
120
113
  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,14 @@ 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;
43
47
  constructor(mtu: number, client: boolean);
44
48
  sendOfflineWithRetry(data: Buffer): void;
45
49
  private clearOfflineRetry;
50
+ destroy(): void;
46
51
  receive(buffer: Buffer): void;
47
52
  private handleClientOffline;
48
53
  private handleServerOffline;
@@ -42,6 +42,10 @@ 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;
45
49
  constructor(mtu, client) {
46
50
  super();
47
51
  this.mtu = mtu;
@@ -52,9 +56,25 @@ class NetworkSession extends utils_1.Emitter {
52
56
  sendOfflineWithRetry(data) {
53
57
  this.offlineRetry = { data, attempts: 1, maxAttempts: this.maxRetransmit, lastSent: Date.now(), interval: this.retransmitInterval };
54
58
  this.send(data);
59
+ if (!this.retransmitTimer) {
60
+ this.retransmitTimer = setTimeout(() => this.tick(), this.retransmitInterval);
61
+ }
55
62
  }
56
63
  clearOfflineRetry() {
57
64
  this.offlineRetry = null;
65
+ if (this.retransmitTimer) {
66
+ clearTimeout(this.retransmitTimer);
67
+ this.retransmitTimer = undefined;
68
+ }
69
+ }
70
+ destroy() {
71
+ if (this.ackTimer)
72
+ clearTimeout(this.ackTimer);
73
+ if (this.retransmitTimer)
74
+ clearTimeout(this.retransmitTimer);
75
+ if (this.cleanupTimer)
76
+ clearTimeout(this.cleanupTimer);
77
+ this.removeAllListeners();
58
78
  }
59
79
  receive(buffer) {
60
80
  const id = buffer[0];
@@ -231,48 +251,57 @@ class NetworkSession extends utils_1.Emitter {
231
251
  this.offlineRetry = null;
232
252
  this.status = proto_1.Status.Disconnected;
233
253
  this.emit("error", new Error("Connection timed out after " + r.maxAttempts + " attempts"));
254
+ return;
234
255
  }
235
- else {
236
- r.attempts++;
237
- r.lastSent = now;
238
- this.send(r.data);
239
- }
256
+ r.attempts++;
257
+ r.lastSent = now;
258
+ this.send(r.data);
259
+ if (this.retransmitTimer)
260
+ clearTimeout(this.retransmitTimer);
261
+ this.retransmitTimer = setTimeout(() => this.tick(), r.interval);
262
+ return;
240
263
  }
241
264
  }
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());
265
+ if (now - this.lastCleanup > 5000) {
266
+ this.lastCleanup = now;
267
+ const windowStart = this.lastInputSequence - RECEIVE_WINDOW;
268
+ if (windowStart > 0) {
269
+ for (const s of this.receivedFrameSequences)
270
+ if (s < windowStart)
271
+ this.receivedFrameSequences.delete(s);
272
+ for (const s of this.lostFrameSequences)
273
+ if (s < windowStart)
274
+ this.lostFrameSequences.delete(s);
275
+ }
276
+ const relStart = this.highestReliableIndex - RELIABLE_WINDOW;
277
+ if (relStart > 0) {
278
+ for (const i of this.receivedReliableFrameIndices)
279
+ if (i < relStart)
280
+ this.receivedReliableFrameIndices.delete(i);
281
+ }
282
+ for (const [id, entry] of this.fragmentsQueue) {
283
+ if (now - entry.timestamp > FRAGMENT_TIMEOUT)
284
+ this.fragmentsQueue.delete(id);
285
+ }
266
286
  }
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());
287
+ if (this.pendingAcks.size > 0 || this.lostFrameSequences.size > 0) {
288
+ if (this.pendingAcks.size > 0) {
289
+ const ack = new proto_1.Ack();
290
+ ack.sequences = [...this.pendingAcks];
291
+ this.pendingAcks.clear();
292
+ this.send(ack.serialize());
293
+ }
294
+ if (this.lostFrameSequences.size > 0) {
295
+ const nack = new proto_1.Nack();
296
+ nack.sequences = [...this.lostFrameSequences];
297
+ this.lostFrameSequences.clear();
298
+ this.send(nack.serialize());
299
+ }
272
300
  }
273
- // Retransmit unacked frame sets that are older than the retry interval
301
+ let nextRetransmit = Infinity;
274
302
  for (const [seq, sentAt] of this.outputBackupTimestamps) {
275
- if (now - sentAt >= this.retransmitInterval) {
303
+ const age = now - sentAt;
304
+ if (age >= this.retransmitInterval) {
276
305
  const frames = this.outputBackup.get(seq);
277
306
  if (frames) {
278
307
  const fs = new proto_1.FrameSet();
@@ -280,20 +309,33 @@ class NetworkSession extends utils_1.Emitter {
280
309
  fs.frames = frames;
281
310
  this.send(fs.serialize());
282
311
  this.outputBackupTimestamps.set(seq, now);
312
+ nextRetransmit = Math.min(nextRetransmit, this.retransmitInterval);
283
313
  }
284
314
  else {
285
315
  this.outputBackupTimestamps.delete(seq);
286
316
  }
287
317
  }
318
+ else {
319
+ nextRetransmit = Math.min(nextRetransmit, this.retransmitInterval - age);
320
+ }
288
321
  }
289
322
  if (this.outputFrames.size > 0)
290
323
  this.flush();
324
+ if (nextRetransmit < Infinity) {
325
+ if (this.retransmitTimer)
326
+ clearTimeout(this.retransmitTimer);
327
+ this.retransmitTimer = setTimeout(() => this.tick(), nextRetransmit);
328
+ }
291
329
  }
292
330
  onAck(ack) {
293
331
  for (const seq of ack.sequences) {
294
332
  this.outputBackup.delete(seq);
295
333
  this.outputBackupTimestamps.delete(seq);
296
334
  }
335
+ if (this.outputBackupTimestamps.size === 0 && this.retransmitTimer) {
336
+ clearTimeout(this.retransmitTimer);
337
+ this.retransmitTimer = undefined;
338
+ }
297
339
  }
298
340
  onNack(nack) {
299
341
  for (const seq of nack.sequences) {
@@ -371,8 +413,10 @@ class NetworkSession extends utils_1.Emitter {
371
413
  this.outputBackup.set(fs.sequence, fs.frames);
372
414
  this.outputBackupTimestamps.set(fs.sequence, Date.now());
373
415
  this.outputFrames.clear();
374
- const serialized = fs.serialize();
375
- this.send(serialized);
416
+ this.send(fs.serialize());
417
+ if (!this.retransmitTimer) {
418
+ this.retransmitTimer = setTimeout(() => this.tick(), this.retransmitInterval);
419
+ }
376
420
  }
377
421
  onFrameSet(fs) {
378
422
  if (this.receivedFrameSequences.has(fs.sequence))
@@ -389,6 +433,12 @@ class NetworkSession extends utils_1.Emitter {
389
433
  }
390
434
  for (const frame of fs.frames)
391
435
  this.handleFrame(frame);
436
+ if (!this.ackTimer) {
437
+ this.ackTimer = setTimeout(() => {
438
+ this.ackTimer = undefined;
439
+ this.tick();
440
+ }, 10);
441
+ }
392
442
  }
393
443
  handleFrame(frame) {
394
444
  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.7",
4
4
  "description": "RakNet implementation for Baltica",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",