fix: properly track events with acknowledgement

"event_received" events did include the acknowledgement function, which
would break during encoding.

Related:

- https://github.com/socketio/socket.io-admin-ui/issues/48
- https://github.com/socketio/socket.io-admin-ui/issues/54
This commit is contained in:
Damien Arrachequesne 2022-10-06 07:46:56 +02:00
parent a8ce5262d5
commit 6d58a755b4
No known key found for this signature in database
GPG Key ID: 544D14663E7F7CF0
4 changed files with 182 additions and 1 deletions

View File

@ -368,6 +368,10 @@ const registerVerboseListeners = (
if (nsp !== adminNamespace) {
if (typeof socket.onAny === "function") {
socket.onAny((...args: any[]) => {
const withAck = typeof args[args.length - 1] === "function";
if (withAck) {
args = args.slice(0, -1);
}
adminNamespace.emit(
"event_received",
nsp.name,

View File

@ -11,7 +11,7 @@
"scripts": {
"compile": "tsc",
"test": "npm run format:check && npm run compile && npm run test:unit",
"test:unit": "nyc mocha --require ts-node/register --timeout 5000 test/index.ts --quit",
"test:unit": "nyc mocha --require ts-node/register --timeout 5000 test/*.ts --quit",
"format:check": "prettier --parser typescript --check 'lib/**/*.ts' 'test/**/*.ts'",
"format:fix": "prettier --parser typescript --write 'lib/**/*.ts' 'test/**/*.ts'",
"prepack": "npm run compile"

167
test/events.ts Normal file
View File

@ -0,0 +1,167 @@
import { Server } from "socket.io";
import { createServer } from "http";
import { AddressInfo } from "net";
import { instrument } from "../lib";
import { io as ioc } from "socket.io-client";
import expect = require("expect.js");
import { createPartialDone } from "./util";
describe("events", () => {
let port: number, io: Server;
beforeEach((done) => {
const httpServer = createServer();
io = new Server(httpServer);
httpServer.listen(() => {
port = (httpServer.address() as AddressInfo).port;
done();
});
});
afterEach(() => {
io.close();
});
it("should track events sent to the client", (done) => {
instrument(io, {
auth: false,
});
const adminSocket = ioc(`http://localhost:${port}/admin`);
const clientSocket = ioc(`http://localhost:${port}`, {
forceNew: true,
});
const partialDone = createPartialDone(2, () => {
adminSocket.disconnect();
clientSocket.disconnect();
done();
});
io.on("connection", (socket) => {
socket.emit("hello", 1, "2", Buffer.from([3]));
});
clientSocket.on("hello", partialDone);
adminSocket.on("event_sent", (arg1, arg2, arg3, arg4) => {
expect(arg1).to.eql("/");
expect(arg2).to.eql(clientSocket.id);
expect(arg3).to.eql(["hello", 1, "2", Buffer.from([3])]);
expect(new Date(arg4).toISOString()).to.eql(arg4);
partialDone();
});
});
it("should track events sent to the client (with ack)", (done) => {
instrument(io, {
auth: false,
});
const adminSocket = ioc(`http://localhost:${port}/admin`);
const clientSocket = ioc(`http://localhost:${port}`, {
forceNew: true,
});
const partialDone = createPartialDone(2, () => {
adminSocket.disconnect();
clientSocket.disconnect();
done();
});
io.on("connection", (socket) => {
socket.emit("hello", (arg: string) => {
expect(arg).to.eql("world");
partialDone();
});
});
clientSocket.on("hello", (cb) => {
cb("world");
});
adminSocket.on("event_sent", (arg1, arg2, arg3, arg4) => {
expect(arg1).to.eql("/");
expect(arg2).to.eql(clientSocket.id);
expect(arg3).to.eql(["hello"]);
expect(new Date(arg4).toISOString()).to.eql(arg4);
partialDone();
});
});
it("should track events received from the client", (done) => {
instrument(io, {
auth: false,
});
const adminSocket = ioc(`http://localhost:${port}/admin`);
const clientSocket = ioc(`http://localhost:${port}`, {
forceNew: true,
});
const partialDone = createPartialDone(2, () => {
adminSocket.disconnect();
clientSocket.disconnect();
done();
});
io.on("connection", (socket) => {
socket.on("hello", partialDone);
});
adminSocket.on("event_received", (arg1, arg2, arg3, arg4) => {
expect(arg1).to.eql("/");
expect(arg2).to.eql(clientSocket.id);
expect(arg3).to.eql(["hello", 1, "2", Buffer.from([3])]);
expect(new Date(arg4).toISOString()).to.eql(arg4);
partialDone();
});
clientSocket.emit("hello", 1, "2", Buffer.from([3]));
});
it("should track events received from the client (with ack)", (done) => {
instrument(io, {
auth: false,
});
const adminSocket = ioc(`http://localhost:${port}/admin`);
const clientSocket = ioc(`http://localhost:${port}`, {
forceNew: true,
});
const partialDone = createPartialDone(2, () => {
adminSocket.disconnect();
clientSocket.disconnect();
done();
});
io.on("connection", (socket) => {
socket.on("hello", (arg, cb) => {
expect(arg).to.eql("world");
cb("123");
});
});
adminSocket.on("event_received", (arg1, arg2, arg3, arg4) => {
expect(arg1).to.eql("/");
expect(arg2).to.eql(clientSocket.id);
expect(arg3).to.eql(["hello", "world"]);
expect(new Date(arg4).toISOString()).to.eql(arg4);
partialDone();
});
clientSocket.emit("hello", "world", (arg: string) => {
expect(arg).to.eql("123");
partialDone();
});
});
});

10
test/util.ts Normal file
View File

@ -0,0 +1,10 @@
export function createPartialDone(count: number, done: (err?: Error) => void) {
let i = 0;
return () => {
if (++i === count) {
done();
} else if (i > count) {
done(new Error(`partialDone() called too many times: ${i} > ${count}`));
}
};
}