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", () => {