I wondered if someone could help figure out what I am doing wrong:
My client web page initiates a connection with my server, and listens to a long running process whose state is getting updated in the db by a worker process on another thread, emitting updates back to the browser. I define a socket.io connection in the app.post() method. This is handled by the poll() function below (scroll down a bit past the invite checking code)
However, when a new web client connects, it's messages get added to the previous client's as if there were just one channel. Why isn't there a separate unique channel for each browser?
//Create server
var express = require('express'),
app = express(),
http = require('http'),
server = http.createServer(app),
io = require('socket.io').listen(server);
io.set('log level', 1); // reduce logging
io.configure(function () {
io.set("transports", ["xhr-polling"]);
io.set("polling duration", 10);
});
app.post('/api/users', function (req, res) {
if (!req.body.auth.accessToken) {
req.body.auth.accessToken = req.body.auth.authResponse.accessToken;
} //fb return object is different depending on whether it is a first login or subsequent
logger.log('debug', '/api/users:POST', req.body);
io.sockets.on('connection', function (socket) {
socket = socket;
socket.emit('update', {
status: 200 //send initialization ping
});
//check if user has valid invite, if not try to invite
db.getTotalUserInvites(function (err_inv, res_total) {
db.getUserInvite(req.body.fid, function (err_check, res_check) {
logger.log('debug', 'Total invites issued=' + res_total);
//process report - all we need is accesToken, processReport will do the rest
mine_fb.processUser(req.body.auth.accessToken, socket, function (User,socket) { //pass channel properly
db.getReportStatus(User.fid,socket, function (result,socket) {
logger.log('debug', 'report status', result);
if (result) {
if (socket && (result.report_status == -1)) {
logger.log('debug', 'report already processed. retrieving uniq_id ' + result.uniq_id);
socket.emit('update', {
status: -1,
uniq_id: result.uniq_id
});
return true;
} else {
if (socket && (result.report_status >= 0)) {
logger.log('debug', 'we are in the middle of processing report ' + result.uniq_id);
//in this case we become a listener and not a speaker
function poll(socket) {
db.getReportStatus(User.fid, socket,function (r,socket) {
socket.emit('update', { //!!!! THIS EMITS TO ALL CONNECTED BROWSERS
status: r.report_status,
uniq_id: r.uniq_id
}); //...socket
if ((r.report_status >= 0) && (socket)) {
logger.log('debug', 'polling...');
_.delay(poll, 2000, socket);
}
}); //get rerpot
}; //end poll
socket.on('disconnect', function () {
socket=null;
});
poll(socket);
} // else we're in the middle
} //done checking status
} //end of seq
});
return res.send();
});
});
});
});
});
While it is not clear how to help you I can tell what's going on in your code:
app.post('/api/users', function (req, res) {
// some code
io.sockets.on('connection', function (socket) {
// some code
});
});
Whenever a user POSTs something to /api/users a new handler is attached to io.sockets (that's what .on does). But these handlers are never removed, so each time a new connection is established all attached handlers fire. That's where your broadcasting comes from.
You have to separate app.post(...) from io.sockets.on('connection',...) (they should be independent, both defined at module level, not nested). I'm sure it won't be easy (you will probably have to authenticate a user twice for example) but that's the only reasonable way.
You shouldn't put your io.sockets.on('connection', function (socket) inside the app.post scope.
Just put it outside and try again, it will probably work correctly.
Listening to connexion should be done once when the server starts, not each time a client hits some URL.