From 8c080de19ed81278e95ecbe71466e256bb7f5bce Mon Sep 17 00:00:00 2001 From: Sebastiaan Marynissen Date: Tue, 2 Feb 2021 11:58:48 +0100 Subject: [PATCH] Exclude specific sockets when emitting --- lib/namespace.ts | 18 ++++++++++++++ lib/socket.ts | 17 ++++++++++++- test/socket.io.ts | 63 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 1 deletion(-) diff --git a/lib/namespace.ts b/lib/namespace.ts index 96b64d2aa7..4aa5abe646 100644 --- a/lib/namespace.ts +++ b/lib/namespace.ts @@ -29,6 +29,9 @@ export class Namespace extends EventEmitter { /** @private */ _rooms: Set = new Set(); + /** @private */ + _except: Set = new Set(); + /** @private */ _flags: any = {}; @@ -123,6 +126,18 @@ export class Namespace extends EventEmitter { return this; } + /** + * Excludes a room when emitting. + * + * @param name + * @return self + * @public + */ + public except(name: Room): Namespace { + this._except.add(name); + return this; + } + /** * Adds a new client. * @@ -203,14 +218,17 @@ export class Namespace extends EventEmitter { const rooms = new Set(this._rooms); const flags = Object.assign({}, this._flags); + const except = new Set(this._except); // reset flags this._rooms.clear(); this._flags = {}; + this._except.clear(); this.adapter.broadcast(packet, { rooms: rooms, flags: flags, + except: except, }); return true; diff --git a/lib/socket.ts b/lib/socket.ts index 6662271bad..4719581f13 100644 --- a/lib/socket.ts +++ b/lib/socket.ts @@ -91,6 +91,7 @@ export class Socket extends EventEmitter { > = []; private flags: BroadcastFlags = {}; private _rooms: Set = new Set(); + private _except: Set = new Set(); private _anyListeners?: Array<(...args: any[]) => void>; /** @@ -165,14 +166,16 @@ export class Socket extends EventEmitter { const rooms = new Set(this._rooms); const flags = Object.assign({}, this.flags); + const except = new Set(this._except); // reset flags this._rooms.clear(); this.flags = {}; + this._except.clear(); if (rooms.size || flags.broadcast) { this.adapter.broadcast(packet, { - except: new Set([this.id]), + except: new Set([this.id, ...except]), rooms: rooms, flags: flags, }); @@ -207,6 +210,18 @@ export class Socket extends EventEmitter { return this; } + /** + * Excludes a room when broadcasting. + * + * @param name + * @return self + * @public + */ + public except(name: Room): Socket { + this._except.add(name); + return this; + } + /** * Sends a `message` event. * diff --git a/test/socket.io.ts b/test/socket.io.ts index 15cb4f3b0c..8dae7ec45a 100644 --- a/test/socket.io.ts +++ b/test/socket.io.ts @@ -823,6 +823,35 @@ describe("socket.io", () => { }); }); + it("should exclude a specific socket when emitting", (done) => { + const srv = createServer(); + const sio = new Server(srv); + + const nsp = sio.of("/nsp"); + + srv.listen(() => { + const socket1 = client(srv, "/nsp"); + const socket2 = client(srv, "/nsp"); + + socket2.on("a", () => { + done(new Error("not")); + }); + socket1.on("a", () => { + done(); + }); + + nsp.on("connection", (socket) => { + socket.on("id", (cb) => { + cb(socket.id); + }); + }); + + socket2.emit("id", (id) => { + nsp.except(id).emit("a"); + }); + }); + }); + describe("dynamic namespaces", () => { it("should allow connections to dynamic namespaces with a regex", (done) => { const srv = createServer(); @@ -2195,6 +2224,40 @@ describe("socket.io", () => { }); }); }); + + it("should exclude specific sockets when broadcasting", (done) => { + const srv = createServer(); + const sio = new Server(srv); + + srv.listen(() => { + const socket1 = client(srv, { multiplex: false }); + const socket2 = client(srv, { multiplex: false }); + const socket3 = client(srv, { multiplex: false }); + + socket2.on("a", () => { + done(new Error("not")); + }); + socket3.on("a", () => { + done(new Error("not")); + }); + socket1.on("a", () => { + done(); + }); + + sio.on("connection", (socket) => { + socket.on("id", (cb) => { + cb(socket.id); + }); + socket.on("exclude", (id) => { + socket.broadcast.except(id).emit("a"); + }); + }); + + socket2.emit("id", (id) => { + socket3.emit("exclude", id); + }); + }); + }); }); describe("middleware", () => {