From 457d9f51b8998684d0620b76dee081bdb8a73ae3 Mon Sep 17 00:00:00 2001 From: Todd Harris Date: Wed, 2 May 2018 11:41:50 -0700 Subject: [PATCH] Add the "loopback" flag. The "loopback" flag is used to emit messages on the local endpoint of a socket; e.g., allowing the server to send a message to the server's handler directly. This is especially useful in conjunction with rooms, as it allows the server to proactively trigger behavior for each socket in a room without having to maintain a separate list of said sockets or relying on the client endpoint to trigger the behavior. --- lib/client.js | 12 ++++++++++++ lib/namespace.js | 1 + lib/socket.js | 7 ++++++- test/socket.io.js | 33 +++++++++++++++++++++++++++++++-- 4 files changed, 50 insertions(+), 3 deletions(-) diff --git a/lib/client.js b/lib/client.js index 32d179f971..98fb015644 100644 --- a/lib/client.js +++ b/lib/client.js @@ -163,6 +163,18 @@ Client.prototype.packet = function(packet, opts){ opts = opts || {}; var self = this; + // handle loopback packets as though they came in off the wire. + if (opts.loopback) { + if (opts.preEncoded) { // a broadcast pre-encodes a packet + for (var i = 0; i < packet.length; i++) { + this.decoder.add(packet[i]); + } + } else { + this.ondecoded(packet); + } + return; + } + // this writes to the actual connection function writeToEngine(encodedPackets) { if (opts.volatile && !self.conn.transport.writable) return; diff --git a/lib/namespace.js b/lib/namespace.js index 6d0ac17065..85b1090b18 100644 --- a/lib/namespace.js +++ b/lib/namespace.js @@ -30,6 +30,7 @@ exports.events = [ */ exports.flags = [ + 'loopback', 'json', 'volatile', 'local' diff --git a/lib/socket.js b/lib/socket.js index 9a96929728..59f48d3757 100644 --- a/lib/socket.js +++ b/lib/socket.js @@ -37,6 +37,7 @@ exports.events = [ */ var flags = [ + 'loopback', 'json', 'volatile', 'broadcast', @@ -155,6 +156,10 @@ Socket.prototype.emit = function(ev){ throw new Error('Callbacks are not supported when broadcasting'); } + if (this.flags.loopback) { + throw new Error('Callbacks are not supported when emitting loopback messages'); + } + debug('emitting packet with ack id %d', this.nsp.ids); this.acks[this.nsp.ids] = args.pop(); packet.id = this.nsp.ids++; @@ -311,7 +316,7 @@ Socket.prototype.onconnect = function(){ }; /** - * Called with each packet. Called by `Client`. + * Called with each packet. Called by `Client` and `emit` with `loopback` flag. * * @param {Object} packet * @api private diff --git a/test/socket.io.js b/test/socket.io.js index aec781455e..ac0c947562 100644 --- a/test/socket.io.js +++ b/test/socket.io.js @@ -677,7 +677,7 @@ describe('socket.io', function(){ }); }); }); - + it('should not reuse same-namespace connections', function(done){ var srv = http(); var sio = io(srv); @@ -837,6 +837,35 @@ describe('socket.io', function(){ }, 500); }); + it('should emit loopback messages locally', function(done) { + var srv = http(); + var sio = io(srv); + + var local_counter = 0; + var remote_counter = 0; + srv.listen(function(){ + sio.of('/chat').on('connection', function(s){ + setTimeout(function() { + sio.of('/chat').loopback.emit('ev', 'data'); + }, 50); + s.on('ev', function() { + local_counter++; + }); + }); + + var socket = client(srv, '/chat'); + socket.on('ev', function() { + remote_counter++; + }); + }); + + setTimeout(function() { + expect(local_counter).to.be(1); + expect(remote_counter).to.be(0); + done(); + }, 500); + }); + it('should emit volatile event', function(done) { var srv = http(); var sio = io(srv); @@ -1608,7 +1637,7 @@ describe('socket.io', function(){ }); }); }); - + it('should see query parameters sent from secondary namespace connections in handshake object', function(done){ var srv = http(); var sio = io(srv);