I am trying to build a client which will send the id ( ex. email ) to nodejs program on server. Email will actually be of the logged-in user.
And nodejs program should keep updating a particular div on client side(say pushing data every 3 seconds) with relevant data for that email address.
Same should be done on multiple machines, wherein every machine has separate person logged-in via email. Something like what happens on gmail.
I have built it as follows, but when i open it from multiple clients, the value of latest client(email) overwrites the value of previous ones and all client show data for latest email only.
Code is as shown below for both server and client.
server.js
var app = require('http').createServer(handler),
io = require('socket.io').listen(app),
fs = require('fs'),
mysql = require('mysql'),
connectionsArray = [],
profile_id,
last_count = 0, //this variable is to check previous count value
connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '', //put your own mysql pwd
database: 'test', //put your database name
port: 3306
}),
POLLING_INTERVAL = 1000,
pollingTimer;
// If there is an error connecting to the database
connection.connect(function(err) {
// connected! (unless `err` is set)
console.log(err);
});
console.log('DB connected');
// creating the server ( localhost:8000 )
app.listen(8000);
// on server started we can load our client.html page
function handler(req, res) {
fs.readFile(__dirname + '/indexnew.html', function(err, data) {
if (err) {
console.log(err);
res.writeHead(500);
return res.end('Error loading client.html');
}
console.log('File loaded');
res.writeHead(200);
res.end(data);
});
}
/*
* HERE IT IS THE COOL PART
* This function loops on itself since there are sockets connected
* to the page. Upon Update it only emits the notification if
* the value has changed.
* Polling the database after a constant interval
*/
var pollingLoop = function() {
sql = "SELECT count(*) as c FROM activity_log WHERE notified=0 and (profile_id = '" + profile_id + "')";
console.log(sql);
// Doing the database query
var query = connection.query(sql),
users = []; // this array will contain the result of our db query
// setting the query listeners
query
.on('error', function(err) {
// Handle error, and 'end' event will be emitted after this as well
console.log(err);
updateSockets(err);
})
.on('result', function(count) {
// it fills our array looping on each user row inside the db
users.push(count);
// loop on itself only if there are sockets still connected
if (connectionsArray.length) {
pollingTimer = setTimeout(pollingLoop, POLLING_INTERVAL);
updateSockets({
users: users,
count: count.c
});
}
})
};
// creating a new websocket to keep the content updated without any AJAX request
io.sockets.on('connection', function(socket) {
console.log('Connected');
//This variable is passed via the client at the time of socket //connection, see "io.connect(..." line in client.html
profile_id = socket.handshake.query.profile_id;
console.log('Number of connections:' + connectionsArray.length);
// starting the loop only if at least there is one user connected
if (!connectionsArray.length) {
pollingLoop();
}
socket.on('disconnect', function() {
var socketIndex = connectionsArray.indexOf(socket);
console.log('socket = ' + socketIndex + ' disconnected');
if (socketIndex >= 0) {
connectionsArray.splice(socketIndex, 1);
}
});
console.log('A new socket is connected!');
connectionsArray.push(socket);
});
var updateSockets = function(data) {
if (last_count != data.count) {
// adding the time of the last update
data.time = new Date();
// sending new data to all the sockets connected
connectionsArray.forEach(function(tmpSocket) {
tmpSocket.volatile.emit('notification', data);
});
}
last_count = data.count;
};
indexnew.html
<html>
<head>
<title>Push notification long polling server streaming on a MySQL db</title>
<style>
dd,
dt {
float: left;
margin: 0;
padding: 5px;
clear: both;
display: block;
width: 100%;
}
dt {
background: #ddd;
}
time {
color: gray;
}
</style>
</head>
<body>
<time></time>
<div id="container">Loading ...</div>
<script src="socket.io.js"></script>
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
var rno = Math.floor((Math.random() * 10) + 1);
// create a new websocket
var socket = io.connect('http://localhost:8000/?profile_id=' + rno);
// on message received we print all the data inside the #container div
socket.on('notification', function(data) {
var usersList = "<dl>";
$.each(data.users, function(index, count) {
usersList += "<dt>" + count.c + "</dt>\n";
});
usersList += "</dl>";
$('#container').html(usersList);
$('time').html('Last Update:' + data.time);
$('sql').html('Last Update:' + data.sql);
});
</script>
</body>
</html>
The way your pollingLoop function and query is structured you will only ever retrieve the last profile_id. Here is why:
The profile_id variable is a global variable, existing on the server thread. The way you've programmed it so far, it seems that you want your pollingLoop to handle all of your sockets at once, but then inside the pollingLoop, you use the global variable profile_id to pull down the information from the database. Every time a new user connects the 'connected' event fires, which updates the profile_id to that user.
Here are some options for what you can do to solve for this:
Construct your query to pull all the profile_id's that are connected,
and build your update_sockets to only send the count for each
profile_id to the appropriate socket.
You can use "group by" to help
with your counts. You could make the pollingLoop run for each
connected user individually. You could keep your query as it is.
Either way you will have to fix your profile_id, because it doesn't make sense to have it contain a single user's unique id in a global setting. If you truly want the profile_id to be a session-based unique ID, doing a random number is a bit dangerous. I would suggest using the socket.id that socket.io exposes for each socket. This way you don't have to worry about it being unique, you don't have to pass it along, and you don't have to store it yourself. The socket.id will be available to you in the connectionsArray since that contains all your sockets. So in the pollingLoop you can loop over the ID's to construct your query, and in the updateSockets you can pair the results back to the socket that needs to receive the data particular to that user.
One more note about a comment in your connection event:
// starting the loop only if at least there is one user connected
This comment is inaccurate, I think it should say:
// starting the loop only if there are no other users connected yet
I hope that helps you!
Related
I'm new in node and socket programming.
In my project Requirement is like this,
One Server which house the set of questions and set of campaigns. campaigns contains questions. And admin will start or stop campaign.
Once Campaign start, Front end of Web Application will display only questions and mobile application display Answer of question and question will automatic reload after every X second in both web and mobile app.
I tried web socket and socket.io this is working fine for web application requirement. But I don't know what for mobile API.
Below is the code for socket.io.
server.js
var mysql = require('mysql');
// Let’s make node/socketio listen on port 3000
var io = require('socket.io').listen(3000);
// Define our db credentials
var db = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '****',
database: 'database_name'
});
// Log any errors connected to the db
db.connect(function (err) {
if (err)
console.log(err);
});
// Define/initialize our global vars
var questions = [];
var total_question = 0;
var isInitNotes = false;
var count = 0;
var sql = "";
// call once per connection, create new connection
io.sockets.on('connection', function (socket) {
console.log((new Date()) + ' Connection from origin ' + socket.handshake.headers.origin);
//io.sockets.emit('users connected', socketCount)
socket.on('disconnect', function () {
console.log((new Date()) + ' Disconnected from origin ' + socket.handshake.headers.origin);
});
db.query('SELECT COUNT(vQuestion) as total_question FROM questions')
.on('result', function (data) {
// Push results onto the questions array
total_question = data.total_question;
});
// select questions from DB
var questionInterval = setInterval(function () {
// check condition for question is over or not
if (count < total_question) {
sql = 'SELECT vQuestion FROM questions LIMIT ' + count + ',1';
console.log(sql);
db.query(sql)
.on('result', function (data) {
// Push results onto the questions array
questions.pop();
questions.push(data);
})
.on('end', function () {
// Only emit questions after query has been completed
socket.emit('get questions', questions);
});
count++;
} else {
clearInterval(questionInterval);
}
}, 5000);
isInitNotes = true;
});
Index.html
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="http://localhost:3000/socket.io/socket.io.js"></script>
<script>
$(document).ready(function(){
// Connect to our node/websockets server
var socket = io.connect('http://localhost:3000');
// Initial set of questions, loop through and add to list
socket.on('get questions', function(data){
var html = ''
for (var i = 0; i < data.length; i++){
// We store html as a var then add to DOM after for efficiency
html += '<li>' + data[i].vQuestion + '</li>'
}
$('#questions').append(html)
})
})
</script>
<ul id="questions"></ul>
<div id="usersConnected"></div>
Commands for server
node server.js
Fri Oct 21 2016 10:30:35 GMT+0530 (IST) Connection from origin http://localhost
Web browser (Web Application)
http://localhost//index.html
display a question every 5 seconds.
In my case, Only one web Application will be there but, More than one mobile users will connect at same time.
When I press F5 repeatedly without stopping the same socket.username enters the room, generating a list of duplicate names. By spending time, this sockets duplicated vain automatically disconnecting .
I tried with these lines after disconnecting and not work!
delete io.sockets.adapter.sids[socket.id];
delete io.sockets.adapter.rooms[socket.id];
How can I avoid this? Tks.
// SERVER.JS
io.set('authorization', function (handshakeData, accept) {
if (handshakeData.headers.cookie) {
handshakeData.cookie = cookie.parse(handshakeData.headers.cookie);
handshakeData.sessionID = cookieParser.signedCookie(handshakeData.cookie['sec_session_id'], 'secret');
if (handshakeData.cookie['sec_session_id'] != handshakeData.sessionID) return accept('Cookie is invalid.', false);
} else return accept('No cookie transmitted.', false);
accept(null, true);
});
io.sockets.on('connection', function(socket) {
socket.on('adduser', function(name, room, picuser, codeuser, operation) {
var handshakeData = socket.request;
var cookies = cookie.parse(handshakeData.headers.cookie);
if(name.length > 0)
{
if (!io.sockets.adapter.sids[socket.id][room]) {
var newCookie = changeCookie(cookies.sec_session_id);
cookiesSockets[cookies.sec_session_id] = newCookie;
cookiesSockets2[newCookie] = socket.id;
socket.color = getRandomColor();
socket.username = name;
socket.room = room;
socket.newid = newCookie;
socket.picuser = picuser;
socket.codeuser = codeuser;
// add the client's username to the global list
usernames[name] = name;
// send client to room
socket.join(room);
// echo to client they've connected
socket.emit('updatechat', socket.picuser, socket.codeuser, socket.color, getClock(), 'You', 'join in '+room+'.', room, 0, 0, getClock2(), operation);
// echo to room 1 that a person has connected to their room
socket.broadcast.to(room).emit('updatechat', socket.picuser, socket.codeuser, socket.color, getClock(), name,'join in room.', room, 0, 0, getClock2(), 3);
//update id's private chats on socket disconnecting and connecting...
if (SocketsUsernames[name])
{
if (SocketsUsernames[name]!=cookies.sec_session_id)
{
var cookieReal = SocketsUsernames[name];
var cookieChanged = cookiesSockets[cookieReal];
delete cookiesSockets[cookieReal];
delete cookiesSockets2[cookieChanged];
socket.broadcast.to(room).emit('updatechatpvt', room, cookieChanged, newCookie);
}
}
SocketsUsernames[name] = cookies.sec_session_id;
updateUsers(room);
}
else
socket.emit('updatechat',null, null, null, null, null, null, room, null, null, null, 7);
}
});
socket.on('disconnect', function(){
if (socket.username)
{
// remove the username from global usernames list
delete usernames[socket.username];
socket.leave('myroom');
}
});
});
//CLIENT.JS
socket.on('connect', function (){
// Retrieve the object from storage CHATROOM!!
var retrievedRooms = localStorage.getItem('myRooms');
console.log('retrievedRooms: ', JSON.parse(retrievedRooms));
if (retrievedRooms && Object.keys(JSON.parse(retrievedRooms)).length>0)
Object.keys(JSON.parse(retrievedRooms)).forEach(function(key) {
if (key)
{
myRooms[key]=key;
socket.emit('checkuser', key, function(callback){
if(!callback) socket.emit('adduser', $('#modalPerfil').attr('data-username'), key, $('#modalPerfil').attr('data-picuser'), $('#modalPerfil').attr('data-userid'), 1);
});
}
});
});
// SOLUTION IN CLIENT.JS - setTimeout
socket.on('connect', function (){
// Retrieve the object from storage CHATROOM!!
var retrievedRooms = localStorage.getItem('myRooms');
console.log('retrievedRooms: ', JSON.parse(retrievedRooms));
if (retrievedRooms && Object.keys(JSON.parse(retrievedRooms)).length>0)
Object.keys(JSON.parse(retrievedRooms)).forEach(function(key) {
if (key)
{
myRooms[key]=key;
setTimeout(function(){
socket.emit('checkuser', key, function(callback){
if(!callback) socket.emit('adduser', $('#modalPerfil').attr('data-username'), key, $('#modalPerfil').attr('data-picuser'), $('#modalPerfil').attr('data-userid'), 1);
});
}, 1000);
}
});
});
This code is causing you a couple problems:
socket.onclose = function (reason) {
roomsToLeaveClient = socket.rooms;
Object.getPrototypeOf(this).onclose.call(this, reason);
});
First off, There's an extra ) at the end that is closing off your .on('connect') block.
That then causes your socket.on('disconnect', ...) code to be outside the scope of socket so it probably isn't getting called appropriately. I'd suggest you don't need to listen for a close event at all. You can just listen for the disconnect event and do any of your cleanup business there.
And, since you're off one set of parens in that code, there's probably a corresponding error somewhere else in your code that still allows things to parse properly. Putting your code in a linter like http://jshint.com shows these types of errors.
Then, if you really did want to override .onclose, you can't just call the prototype version. Instead, you have to save the version that was in place before you assign your override and call that one. That's the only way the is compatible with any other overrides. But, you really ought to just be using .on() with event names to watch socket lifecycle things, then you don't have to worry about proper overrides in any way.
I can't tell right away if there are other issues, but this is a glaring one that needs to be fixed first.
Also, you do not need your roomsToLeaveClient handling. socket.io will automatically remove a disconnecting client from any rooms that it is in. That is not something you need to do.
If you want to know what rooms a socket is in so you can tell the other members of that room that you are leaving, then socket.io has a data structure that tells you exactly what rooms the socket is in and you can just iterate that data structure. You don't have to keep track of that yourself.
I'm trying to learn Socket.io by building a set of dynamically created chatrooms that emit 'connected' and 'disconnected' messages when users enter and leave. After looking at a couple of questions I've put together something functional but most of the response linked are from people who admit they've hacked together answers and I've noticed there's a more general - and recent - discussion about the right way to do this on the Socket.io repo (notably here and here)
As I'm such a novice I don't know if the work below is an acceptable way to do things or it just happens to incidentally function but will cause performance issues or result in too many listeners. If there's an ideal - and official - way to join and leave rooms that feels less clunky than this I'd love to learn about it.
Client
var roomId = ChatRoomData._id // comes from a factory
function init() {
// Make sure the Socket is connected
if (!Socket.socket) {
Socket.connect();
}
// Sends roomId to server
Socket.on('connect', function() {
Socket.emit('room', roomId);
});
// Remove the event listener when the controller instance is destroyed
$scope.$on('$destroy', function () {
Socket.removeListener('connect');
});
}
init();
Server
io.sockets.once('connection', function(socket){
socket.on('room', function(room){ // take room variable from client side
socket.join(room) // and join it
io.sockets.in(room).emit('message', { // Emits a status message to the connect room when a socket client is connected
type: 'status',
text: 'Is now connected',
created: Date.now(),
username: socket.request.user.username
});
socket.on('disconnect', function () { // Emits a status message to the connected room when a socket client is disconnected
io.sockets.in(room).emit({
type: 'status',
text: 'disconnected',
created: Date.now(),
username: socket.request.user.username
});
})
});
Socket.IO : recently released v2.0.3
Regarding joining / leaving rooms [read the docs.]
To join a room is as simple as socket.join('roomName')
//:JOIN:Client Supplied Room
socket.on('subscribe',function(room){
try{
console.log('[socket]','join room :',room)
socket.join(room);
socket.to(room).emit('user joined', socket.id);
}catch(e){
console.log('[error]','join room :',e);
socket.emit('error','couldnt perform requested action');
}
})
and to leave a room, simple as socket.leave('roomName'); :
//:LEAVE:Client Supplied Room
socket.on('unsubscribe',function(room){
try{
console.log('[socket]','leave room :', room);
socket.leave(room);
socket.to(room).emit('user left', socket.id);
}catch(e){
console.log('[error]','leave room :', e);
socket.emit('error','couldnt perform requested action');
}
})
Informing the room that a room user is disconnecting
Not able to get the list of rooms the client is currently in on disconnect event
Has been fixed (Add a 'disconnecting' event to access to socket.rooms upon disconnection)
socket.on('disconnect', function(){(
/*
socket.rooms is empty here
leaveAll() has already been called
*/
});
socket.on('disconnecting', function(){
// socket.rooms should isn't empty here
var rooms = socket.rooms.slice();
/*
here you can iterate over the rooms and emit to each
of those rooms where the disconnecting user was.
*/
});
Now to send to a specific room :
// sending to all clients in 'roomName' room except sender
socket.to('roomName').emit('event', 'content');
Socket.IO Emit Cheatsheet
This is how I inform users of a "disconnecting user"
socket.on('disconnecting', function(){
console.log("disconnecting.. ", socket.id)
notifyFriendOfDisconnect(socket)
});
function notifyFriendOfDisconnect(socket){
var rooms = Object.keys(socket.rooms);
rooms.forEach(function(room){
socket.to(room).emit('connection left', socket.id + ' has left');
});
}
Here is a working method.
I am using socketio "socket.io": "^2.3.0" on server side. On Client side is android
// SocketIO
implementation('io.socket:socket.io-client:1.0.0') {
// excluding org.json which is provided by Android
exclude group: 'org.json', module: 'json'
}
Following is the code that is working for me.
// Join Chat Room
socket.on('ic_join', function(data) {
// Json Parse String To Access Child Elements
let messageJson = JSON.parse(data)
let room1 = messageJson.room1
console.log('======Joined Room========== ')
console.log(room1)
socket.join(room1, function(err) {
console.log(io.sockets.adapter.rooms[room1].length);
console.log(err)
})
})
// Leave Chat Room
socket.on('ic_leave', function(data) {
// Json Parse String To Access Child Elements
let messageJson = JSON.parse(data)
let room1 = messageJson.room1
console.log('======Left Room========== ')
console.log(room1)
socket.leave(room1, function(err) {
if (typeof io.sockets.adapter.rooms[room1] !== 'undefined' && io.sockets.adapter.rooms[room1] != null) {
console.log(io.sockets.adapter.rooms[room1].length);
console.log(err)
} else{
console.log("room is deleted")
}
})
})
For anyone reading this beyond 2/1/2021, using socket.io 3.1.0 and hopefully later, you can reference my example. I have found that the example on how to do this in socket.io's documentation is incorrect. They claim that in the disconnect event that socket.rooms is an object. While is uses the block container and is comma separated, there are no key pairs, meaning their demonstration of const rooms = Object.keys(socket.rooms) returns an empty value. It's creating an array out of an object that is really just an array. To my knowledge {} can only be used for block statements and objects. By some quirk, NodeJS is treating it like a normal array. I assign custom, 4 digit rooms on each connect event. So I have on the disconnect event I have the server skim through all the rooms, and if it encounters a room name with a length of 4, it tells everyone in the room that the size of the room decreased by one. On the client side, I have a socket event listener monitoring for this and when it's detected, updates a innerHTML property so that the clients can display the number of connected users.
//client side code:
socket.on('roomSize', (roomSize) => {
document.getElementById('clientCount').innerHTML = roomSize + ' clients connected';
});
//Server side code:
io.on("connection", (socket) => {
socket.on('createRoom', () => {
let ID = makeID(4)
while (io.sockets.adapter.rooms.has(ID)) {
ID = makeID(4)
}
socket.join(ID);
socket.emit('setID', ID);
});
socket.on("joinRoom", (room) => {
socket.join(room);
let roomSize = io.sockets.adapter.rooms.get(room).size
io.in(room).emit('roomSize', roomSize);
socket.emit('roomJoined', room, roomSize);
});
socket.on('disconnecting', function() {
let rooms = socket.rooms;
rooms.forEach(function(room) {
if (room.length === 4) {
let roomSize = io.sockets.adapter.rooms.get(room).size - 1
io.in(room).emit('roomSize', roomSize);
}
});
});
function makeID(length) {
var result = '';
var characters = '0123456789';
var charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
})
I'm using Heroku + RedisToGo + Express 4.0 + socket.io 1.0.6.
I just recently upgraded to 1.0 from 0.9, and it's half working now. I've hacked together a app from tutorials but my lack of understanding socket.io is showing, so I'm taking a step back. The first question I have is that now socket.on('connect') is happening repeatedly, without stop, even when a connection is successful. My client-side console.log just keeps going and going. Here's client-side:
// Connect the user
socket.on('connect', function(){
var currentUserId = '<%= currentUser.id %>';
// Add user to redis
socket.emit('login', { userID: currentUserId});
// Retrieve presence info
socket.emit('presence');
});
// Show Presence
socket.on('presence', function(data) {
var userID = data.user;
var presence = data.presence;
if (presence) {
$('#red-dot-' + userID).css("display", "none");
$('#green-dot-' + userID).css("display", "inline");
// Show the hangout button
$('#hangout-' + userID).show();
$('#hangout-unavail-' + userID).hide();
}
else {
$('#red-dot-' + userID).css("display", "inline");
$('#green-dot-' + userID).css("display", "none");
}
});
And server-side:
io.sockets.on('connection', function (socket) {
var savedUserID;
socket.on('login', function(data){
var userID = data.userID;
savedUserID = userID;
// add first user
redis.sadd("users", userID);
redis.hmset("users:"+userID, "socketID", socket.id, "userID", userID);
});
socket.on('presence', function(){
// Get the list of online users and show Presence
redis.smembers("users", function(err,results) {
var onlineUsers = results;
for (var i in onlineUsers) {
var userID = redis.hget("users:"+onlineUsers[i],"userID", function(err,reply) {
var userID = reply;
// Emit presence
io.sockets.emit('presence', {
user: userID,
presence: "true"
});
});
}
});
});
As you can see I'm manually adding users to redis.
I found the answer in this Google Group thread.
The problem occurred because I had socket.emit('presence'); in my socket.on('connect', function(){}); client-side.
This in turn called socket.on('presence', function(){}); server-side, which was the problem.
Here are 2 related questions. Posting them together makes more sense.
Question 1
I have a node.js app which emits an event out to all clients, and all current clients will respond with a ready emit. How can I create a list of all the clients that replied to the initial emit, and what kind of identification can be used to distinguish the clients?
Question2:
What I am trying to do after collect a list of connected clients, is to then access a MySQL database table of N number of rows and assign each client X rows each. These rows will be emitted back to their respective clients. How can this be done?
Current Code for Qn 1
Node Code
setInterval(function() {
util.log('Checking for new jobs...');
dbCheckQueue(function(results) { // checks if there are new rows to "distribute" to clients
if (results.length) {
util.log(results.length + ' new jobs found.');
io.sockets.emit('job_available');
}
});
}, 10*1000);
Client-side JS Code
socket.on('job_available', function() {
console.log('Job Available.. Responding with Ready!');
socket.emit('ready');
});
io.sockets.on('connection', function(socket) {
socket.on('ready', function() {
// UPDATE N rows with client_id in column checkout.
// Then SELECTS * from table where checkout = client_id
getListings(client_id, function(listings) {
socket.emit('job', listings); // send jobs
});
});
});
Current Code for Qn 2
The code works for a single client, but how do I loop through all connected clients and perform the same updating of column and selecting of rows?
io.sockets.on('connection', function(socket) {
socket.on('ready', function() {
// UPDATE N rows with client_id in column checkout.
// Then SELECTS * from table where checkout = client_id
getListings(client_id, function(listings) {
socket.emit('job', listings); // send jobs
});
});
});
Socket.io provides you with a public api for that, so instead of hacking something up like Bryan suggest you can use:
io.sockets.clients()
That will returns an array of all connected clients.
If you want all clients connected to a certain namespace:
io.of('/namespace').clients()
But you can even filter it even more.. if you want to have all sockets in a room:
io.sockets.clients('room name here as first argument')
Will return a array of connected sockets for the room room name here as first argument
You will need to keep track of the connected clients yourself. The simple way to do that would be to use an array:
var clients = [];
io.sockets.on('connect', function(client) {
clients.push(client);
client.on('disconnect', function() {
clients.splice(clients.indexOf(client), 1);
});
});
Then you can references that clients array on the server wherever you need to, in your ready event handler or whatever. Something like:
io.sockets.on('connection', function(socket) {
socket.on('ready', function() {
// UPDATE N rows with client_id in column checkout.
// Then SELECTS * from table where checkout = client_id
clients.forEach(function(client, index) {
var client_id = index; // Just use the index in the clients array for now
getListings(client_id, function(listings) {
socket.emit('job', listings); // send jobs
});
});
});
});