I use Node.js to create a microservice for downloading multimedia. This service works by taking the binary download data to the buffer, and then using the S3 npm package to load into the S3 bucket. I am trying to use the eventEmitter present in this package, which shows the amount of data uploaded to S3, and sends it back to the client that is loading (so that they can see the download progress). I use socket.io to send progress data to the client.
The problem I encountered is that the .emit event in socket.io will send download progress data to all connected clients, not just the client that initiated the download. As I understand it, the socket connects to the default room on the โconnectionโ, which mirrors the โidโ on the client side. According to official docs, using socket.to (id) .emit () should send data that is bound only to this client, but this does not work for me.
UPDATED Code example:
server.js:
var http = require('http'), users = require('./data'), app = require('./app')(users); var server = http.createServer(app); server.listen(app.get('port'), function(){ console.log('Express server listening on port ' + app.get('port')); }); var io = require('./socket.js').listen(server);
socket.js:
var socketio = require('socket.io'); var socketConnection = exports = module.exports = {}; socketConnection.listen = function listen(app) { io = socketio.listen(app); exports.sockets = io.sockets; io.sockets.on('connection', function (socket) { socket.join(socket.id); socket.on('disconnect', function(){ console.log("device "+socket.id+" disconnected"); }); socketConnection.upload = function upload (data) { socket.to(socket.id).emit('progress', {progress:(data.progressAmount/data.progressTotal)*100}); }; }); return io; };
s3upload.js:
var config = require('../config/aws.json'); var s3 = require('s3'); var path = require('path'); var fs = require('fs'); var Busboy = require('busboy'); var inspect = require('util').inspect; var io = require('../socket.js'); ... var S3Upload = exports = module.exports = {}; .... S3Upload.upload = function upload(params) {
When using DEBUG = * node myapp.js, I see that socket.io-parser accepts this information but does not pass it to the client:
socket.io-parser encoding packet {"type":2,"data":["progress",{"progress":95.79422221709825}],"nsp":"/"} +0ms socket.io-parser encoded {"type":2,"data":["progress",{"progress":95.79422221709825}],"nsp":"/"} as 2["progress",{"progress":95.79422221709825}] +0ms
However, if I delete the .to part of this code, it will send data to the client (although to all clients, which will not help at all):
io.sockets.on('connection', function(socket) { socket.join(socket.id); socket.emit('progress', {progress: (data.progressAmount/data.progressTotal)*100}); });
DEBUG = * node myapp.js:
socket.io:client writing packet {"type":2,"data":["progress",{"progress":99.93823786632886}],"nsp":"/"} +1ms socket.io-parser encoding packet {"type":2,"data":["progress",{"progress":99.93823786632886}],"nsp":"/"} +1ms socket.io-parser encoded {"type":2,"data":["progress",{"progress":99.93823786632886}],"nsp":"/"} as 2["progress",{"progress":99.93823786632886}] +0ms engine:socket sending packet "message" (2["progress",{"progress":99.93823786632886}]) +0ms engine:socket flushing buffer to transport +0ms engine:ws writing "42["progress",{"progress":99.84186540937002}]" +0ms engine:ws writing "42["progress",{"progress":99.93823786632886}]" +0ms
What am I doing wrong here? Is there any other way to emit events from the server only to specific clients that I miss?