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

+22-2
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

+31
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3
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

+42
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)