Skip to content

Commit 5f7b47d

Browse files
perf: precompute the WebSocket frames when broadcasting
Note: - only packets without binary attachments are affected - the permessage-deflate extension must be disabled (which is the default) Previous attempt: - wsPreEncoded option: 5579d40 - fix for binary packets: a33e42b - revert: 88eee59
1 parent 6fffc2c commit 5f7b47d

File tree

4 files changed

+98
-2
lines changed

4 files changed

+98
-2
lines changed

lib/index.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { EventEmitter } from "events";
22
import { yeast } from "./contrib/yeast";
3+
import { WebSocket } from "ws";
34

45
/**
56
* A public ID, sent by the server at the beginning of the Socket.IO session and which can be used for private messaging
@@ -164,7 +165,7 @@ export class Adapter extends EventEmitter {
164165
};
165166

166167
packet.nsp = this.nsp.name;
167-
const encodedPackets = this.encoder.encode(packet);
168+
const encodedPackets = this._encode(packet, packetOpts);
168169

169170
this.apply(opts, (socket) => {
170171
if (typeof socket.notifyOutgoingListeners === "function") {
@@ -207,7 +208,7 @@ export class Adapter extends EventEmitter {
207208
// we can use the same id for each packet, since the _ids counter is common (no duplicate)
208209
packet.id = this.nsp._ids++;
209210

210-
const encodedPackets = this.encoder.encode(packet);
211+
const encodedPackets = this._encode(packet, packetOpts);
211212

212213
let clientCount = 0;
213214

@@ -227,6 +228,25 @@ export class Adapter extends EventEmitter {
227228
clientCountCallback(clientCount);
228229
}
229230

231+
private _encode(packet: unknown, packetOpts: Record<string, unknown>) {
232+
const encodedPackets = this.encoder.encode(packet);
233+
234+
if (encodedPackets.length === 1 && typeof encodedPackets[0] === "string") {
235+
// "4" being the "message" packet type in the Engine.IO protocol
236+
const data = Buffer.from("4" + encodedPackets[0]);
237+
// see https://github.com/websockets/ws/issues/617#issuecomment-283002469
238+
packetOpts.wsPreEncodedFrame = WebSocket.Sender.frame(data, {
239+
readOnly: false,
240+
mask: false,
241+
rsv1: false,
242+
opcode: 1,
243+
fin: true,
244+
});
245+
}
246+
247+
return encodedPackets;
248+
}
249+
230250
/**
231251
* Gets a list of sockets by sid.
232252
*

package-lock.json

Lines changed: 31 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
"main": "./dist/index.js",
1313
"types": "./dist/index.d.ts",
1414
"description": "default socket.io in-memory adapter",
15+
"peerDependencies": {
16+
"ws": "*"
17+
},
1518
"devDependencies": {
1619
"@types/mocha": "^10.0.1",
1720
"@types/node": "^14.11.2",

test/index.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,48 @@ describe("socket.io-adapter", () => {
140140
expect(ids).to.eql(["s3"]);
141141
});
142142

143+
it("should precompute the WebSocket frames when broadcasting", () => {
144+
function socket(id) {
145+
return [
146+
id,
147+
{
148+
id,
149+
client: {
150+
writeToEngine(payload, opts) {
151+
expect(payload).to.eql(["123"]);
152+
expect(opts.preEncoded).to.eql(true);
153+
expect(opts.wsPreEncodedFrame.length).to.eql(2);
154+
expect(opts.wsPreEncodedFrame[0]).to.eql(Buffer.from([129, 4]));
155+
expect(opts.wsPreEncodedFrame[1]).to.eql(
156+
Buffer.from([52, 49, 50, 51])
157+
);
158+
},
159+
},
160+
},
161+
];
162+
}
163+
const nsp = {
164+
server: {
165+
encoder: {
166+
encode() {
167+
return ["123"];
168+
},
169+
},
170+
},
171+
// @ts-ignore
172+
sockets: new Map([socket("s1"), socket("s2"), socket("s3")]),
173+
};
174+
const adapter = new Adapter(nsp);
175+
adapter.addAll("s1", new Set());
176+
adapter.addAll("s2", new Set());
177+
adapter.addAll("s3", new Set());
178+
179+
adapter.broadcast([], {
180+
rooms: new Set(),
181+
except: new Set(),
182+
});
183+
});
184+
143185
describe("utility methods", () => {
144186
let adapter;
145187

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy