From 121fd7c73df1f1e32bf6d3d6308e6a8aaad2dc4d Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Mon, 20 Feb 2023 17:31:02 +0100 Subject: [PATCH] refactor: do not reuse the same packet ID for retries The packet ID cannot be used for deduplication, because it's only unique for the given session. If you reconnect on another server and try to resend a packet, then the server won't be able to know whether the packet has already been processed or not. --- lib/socket.ts | 17 ++++++++++++----- test/retry.ts | 6 +++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/socket.ts b/lib/socket.ts index 1a92f073..8a992e10 100644 --- a/lib/socket.ts +++ b/lib/socket.ts @@ -70,6 +70,12 @@ export interface SocketOptions { } type QueuedPacket = { + /** + * Only used for debugging purposes. To allow deduplication on the server side, one should include a unique offset in + * the packet, for example with crypto.randomUUID(). + * + * @see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID + */ id: number; args: unknown[]; flags: Flags; @@ -225,6 +231,11 @@ export class Socket< * @private */ private _queue: Array = []; + /** + * A sequence to generate the ID of the {@link QueuedPacket}. + * @private + */ + private _queueSeq: number = 0; private readonly nsp: string; private readonly _opts: SocketOptions; @@ -501,7 +512,7 @@ export class Socket< } const packet = { - id: this.ids++, + id: this._queueSeq++, tryCount: 0, pending: false, args, @@ -563,12 +574,8 @@ export class Socket< packet.pending = true; packet.tryCount++; debug("sending packet [%d] (try n°%d)", packet.id, packet.tryCount); - const currentId = this.ids; - this.ids = packet.id; // the same id is reused for consecutive retries, in order to allow deduplication on the server side this.flags = packet.flags; - this.emit.apply(this, packet.args); - this.ids = currentId; // restore offset } /** diff --git a/test/retry.ts b/test/retry.ts index e356b589..bf791925 100644 --- a/test/retry.ts +++ b/test/retry.ts @@ -68,9 +68,9 @@ describe("retry", () => { const expected = [ "0", '20["ack"]', - '20["ack"]', - '20["ack"]', - '20["ack"]', + '21["ack"]', + '22["ack"]', + '23["ack"]', "1", ];