I'm writing a TCP/IP queue that's supposed to limit maximum connected users to 3 and make any others wait until user disconnects. These are the functions I'm using:
var maxClients = 3;
var currentClients = 0;
var _pending = [];
function process_pending()
{
if (_pending.length > 0) {
var client = _pending.shift();
currentClients++;
client(function()
{
currentClients--;
process.nextTick(process_pending);
});
}
}
function client_limit(client)
{
if (currentClients < maxClients) {
currentClients++;
client(function()
{
currentClients--;
process.nextTick(process_pending);
});
}
else
{
console.log('Overloaded, queuing clients...');
_pending.push(client);
}
}
Whenever three clients are connected and then fourth one tries to connect it displays the Overloaded message and that's okay, but if an existing client disconnects, nobody else can connect. Looks like the
client(function()
{
currentClients--;
process.nextTick(process_pending);
});
Doesn't work properly, how do I fix it?
Related
This is more of a question regarding what to do in the scenario where you want to trigger a socket event for one user, that might be logged into another browser.
I've got a couple of functions that update a users' workstack real-time (in a queue of other workstacks that are assignable by other users); however, if the user is logged into another browser at the same time, and do an update in one browser, it doesn't update in the other (as they have a different socket.id).
I'm not sure what to do with this... I could do it based on the user ID of the person logged in, but at present my socket code does not have scope of any session variables and although there are modules such as session-socket - I'm not sure if that's the right path to go down.
Can anyone advise a way I might approach this please?
If you don't use any cluster you can follow the approach I had in my Miaou chat : I simply set the user as a property of the socket object and I iterate on sockets when necessary. This allow for a few utilitarian functions.
Here's the (simplified) related code.
io.on('connect', function(socket){
...
var userId = session.passport.user;
if (!userId) return die("no authenticated user in socket's session");
...
var shoe = new Shoe(socket, completeUser) // <=== bindind user socket here
// socket event binding here
The Shoe object :
// A shoe embeds a socket and is provided to controlers and plugins.
// It's kept in memory by the closures of the socket event handlers
function Shoe(socket, completeUser){
this.socket = socket;
this.completeUser = completeUser;
this.publicUser = {id:completeUser.id, name:completeUser.name};
this.room;
socket['publicUser'] = this.publicUser;
this.emit = socket.emit.bind(socket);
}
var Shoes = Shoe.prototype;
// emits something to all sockets of a given user. Returns the number of sockets
Shoes.emitToAllSocketsOfUser = function(key, args, onlyOtherSockets){
var currentUserId = this.publicUser.id,
nbs = 0;
for (var clientId in io.sockets.connected) {
var socket = io.sockets.connected[clientId];
if (onlyOtherSockets && socket === this.socket) continue;
if (socket && socket.publicUser && socket.publicUser.id===currentUserId) {
socket.emit(key, args);
nbs++;
}
}
return nbs;
}
// returns the socket of the passed user if he's in the same room
Shoes.userSocket = function(userIdOrName) {
var clients = io.sockets.adapter.rooms[this.room.id],
sockets = [];
for (var clientId in clients) {
var socket = io.sockets.connected[clientId];
if (socket && socket.publicUser && (socket.publicUser.id===userIdOrName||socket.publicUser.name===userIdOrName)) {
return socket;
}
}
}
// returns the ids of the rooms to which the user is currently connected
Shoes.userRooms = function(){
var rooms = [],
uid = this.publicUser.id;
iorooms = io.sockets.adapter.rooms;
for (var roomId in iorooms) {
if (+roomId!=roomId) continue;
var clients = io.sockets.adapter.rooms[roomId];
for (var clientId in clients) {
var socket = io.sockets.connected[clientId];
if (socket && socket.publicUser && socket.publicUser.id===uid) {
rooms.push(roomId);
break;
}
}
}
return rooms;
}
// returns the first found socket of the passed user (may be in another room)
function anyUserSocket(userIdOrName) {
for (var clientId in io.sockets.connected) {
var socket = io.sockets.connected[clientId];
if (socket.publicUser && (socket.publicUser.id===userIdOrName||socket.publicUser.name===userIdOrName)) {
return socket;
}
}
}
// closes all sockets from a user in a given room
exports.throwOut = function(userId, roomId, text){
var clients = io.sockets.adapter.rooms[roomId];;
for (var clientId in clients) {
var socket = io.sockets.connected[clientId];
if (socket.publicUser && socket.publicUser.id===userId) {
if (text) socket.emit('miaou.error', text);
socket.disconnect('unauthorized');
}
}
}
Real code
Now, with ES6 based node versions and WeakMap, I might implement a more direct mapping but the solution I described is robust and efficient enough.
I have made a custom wamp server the code of nodewebkit just triggers processes/worker to launch the apache server which is working really fine. I had to run some cronjobs on pc the cronjob data comes from server when the app first starts. normally my cronjobs are running properly but after sometime the cronjobs just starts and never finishes and i have to restart the app. and then again for few days it keeps running.
function setLoops(i) {
var cron = cron_Jobs[i];
interval_array.push(window.setInterval(function() {
genrate_log("started", cron.url);
ajax_post(app_path + cron.url, function(data) {
genrate_log("completed", cron.url);
}, function(data) {
genrate_log("error", cron.url);
})
}, cron.time))
}
function clear_loops(i) {
clearInterval(interval_array[i]);
}
function cron_jobs(run) {
if (run == false) {
for (var i = 0; i < interval_array.length; i++) {
clear_loops(i);
}
}
if (run == true) {
for (var i = 0; i < cron_Jobs.length; i++) {
setLoops(i);
}
}
}
I thought it has something todo with log file when it become bigger than certain size it stops working. But I confirm that it has nothing todo with log file. I am pretty sure it has something todo with my algorithm or chromium. But not sure on that.
I am trying to implement CometD in our application. But it is taking more time compared to the existing implementation in our project. The existing system is taking time in milliseconds where as CometD is taking 2 seconds to push the message.
I am not sure where I am going wrong. Any guidance will help me lot.
My code:
Java script at client side
(function($)
{
var cometd = $.cometd;
$(document).ready(function()
{
function _connectionEstablished()
{
$('#body').append('<div>CometD Connection Established</div>');
}
function _connectionBroken()
{
$('#body').append('<div>CometD Connection Broken</div>');
}
function _connectionClosed()
{
$('#body').append('<div>CometD Connection Closed</div>');
}
// Function that manages the connection status with the Bayeux server
var _connected = false;
function _metaConnect(message)
{
if (cometd.isDisconnected())
{
_connected = false;
_connectionClosed();
return;
}
var wasConnected = _connected;
_connected = message.successful === true;
if (!wasConnected && _connected)
{
_connectionEstablished();
}
else if (wasConnected && !_connected)
{
_connectionBroken();
}
}
// Function invoked when first contacting the server and
// when the server has lost the state of this client
function _metaHandshake(handshake)
{
if (handshake.successful === true)
{
cometd.batch(function()
{
cometd.subscribe('/java/test', function(message)
{
$('#body').append('<div>Server Says: ' + message.data.eventID + ':'+ message.data.updatedDate + '</div>');
});
});
}
}
// Disconnect when the page unloads
$(window).unload(function()
{
cometd.disconnect(true);
});
var cometURL = "http://localhost:8080/cometd2/cometd";
cometd.configure({
url: cometURL,
logLevel: 'debug'
});
cometd.addListener('/meta/handshake', _metaHandshake);
cometd.addListener('/meta/connect', _metaConnect);
cometd.handshake();
});
})(jQuery);
Comet service class
#Listener("/service/java/*")
public void processMsgFromJava(ServerSession remote, ServerMessage.Mutable message)
{
Map<String, Object> input = message.getDataAsMap();
String eventId = (String)input.get("eventID");
//setting msg id
String channelName = "/java/test";
// Initialize the channel, making it persistent and lazy
bayeux.createIfAbsent(channelName, new ConfigurableServerChannel.Initializer()
{
public void configureChannel(ConfigurableServerChannel channel)
{
channel.setPersistent(true);
channel.setLazy(true);
}
});
// Publish to all subscribers
ServerChannel channel = bayeux.getChannel(channelName);
channel.publish(serverSession, input, null);
}
Is there any thing I need to change in server side code.
You have made your channel lazy, so a delay in message broadcasting is expected (that is what lazy channels are all about).
Please have a look at the documentation for lazy channels.
If you want immediate broadcasting don't set the channel as lazy.
I'm building this function for upload to the server small tile images.
The client builds the tileBuffer and then calls the fireTiles function.
Here I would like to build a loop based on the tileBuffer.length. The server will handle the control. So, i emit StartAddTiles and I immediately called back from the server with the AnotherTile event. The debugger shows me I've been called by the server and I see the code going into the socket.on('AnotherTile'... sentence.
The problem is that when the code reaches the AddTile emit function, it stops there and nothing happens. The server does not receive the request and the loop is terminated there.
Where is the error in my code?
function fireTiles (tileBuffer, mapSelected) {
var tiles = tileBuffer.length;
var tBx = 0;
try
{
var socket = io.connect('http://myweb:8080/');
socket.emit('StartAddTiles', tiles, mapSelected);
socket.on('AnotherTile', function (tlN){
if (tlN < tiles) {
var data = tileBuffer[tlN]; //uso tlN per far comandare il server
tBx++; // debug purpose
socket.emit('AddTile', mapSelected, data, tBx);
} else {
// something went wrong
alert('Error calculating tiles');
return;
}
});
}
catch(err)
{
document.getElementById('status').innerHTML = err.message;
}
}
Here is the server side:
io.sockets.on('connection', function(client) {
console.log('Connecting....');
// controls are limited, this is just a beginning
// Initiate loop
client.on('StartAddTiles', function(tiles, mapSelected) {
var mapId = mapSelected;
mapLoading[mapId] = { //Create a new Entry in The mapLoading Variable
tilesToLoad : tiles,
tilesLoaded : 0
}
console.log('Start loading '+mapLoading[mapId].tilesToLoad+' tiles.');
// Ask for the first tile
client.emit('AnotherTile', mapLoading[mapId].tilesLoaded);
//
});
// client add new Tile/Tiles
client.on('addTile', function(mapSelected, data, tBx) {
var mapId = mapSelected;
mapLoading[mapId].tilesLoaded = ++1;
console.log('Adding tile '+mapLoading[mapId].tilesLoaded+' of '+mapLoading[mapId].tilesToLoad+' tBx '+tBx);
// insert Tile
db_manager.add_tiles(tileBuffer, function(result) {
if (mapLoading[mapId].tilesLoaded == mapLoading[mapId].tilesToLoad) { // full map loaded
mapLoading[mapId] = ""; //reset the buffer
client.emit('TilesOk', mapLoading[mapId].tilesLoaded);
} else {
console.log('requesting tile num: '+mapLoading[mapId].tilesLoaded);
client.emit('AnotherTile', mapLoading[mapId].tilesLoaded);
}
//
});
});
The event names are case sensitive, you should probably use AddTile instead of addTile on the server side too.
I'm working on a chat application with Node.js and Socket.io, and on disconnect, the remaining user receives an alert saying that their partner disconnected.
The problem is that every once in a while, Socket.io automatically disconnects then reconnects. My chat application is triggering the alert, even though the partner hasn't really disconnected.
Code:
var clients = {};
var soloClients = [];
io.sockets.on('connection', function (socket) {
//Session start
socket.on('sessionStart', function () {
clients[socket.id] = socket;
soloClients.push(socket.id);
var searchClients = function(){
if(soloClients.length > 1){
var rand = Math.floor(Math.random() * soloClients.length);
if(soloClients[rand] && soloClients[rand] != socket.id){
if(clients[soloClients[rand]]){
var you = clients[socket.id];
var partner = clients[soloClients[rand]]
clients[partner.id]['partner'] = you.id;
clients[you.id]['partner'] = partner.id;
soloClients.splice(soloClients.indexOf(you.id), 1);
soloClients.splice(soloClients.indexOf(partner.id), 1);
partner.emit('partnerConnect', null);
socket.emit('partnerConnect', null);
}
else{
soloClients.splice(rand, 1);
searchClients;
}
}
else{
searchClients();
}
}
};
searchClients();
});
//On disconnect
socket.on('disconnect', function(){
soloClients.splice(soloClients.indexOf(socket.id), 1);
if(clients[socket.id]){
if(clients[clients[socket.id]['partner']]){
clients[clients[socket.id]['partner']].emit('partnerDisconnect', null);
}
delete clients[socket.id];
}
});
});
I was wondering if there is any way to solve this.
Thanks!
Maybe you should try to find out the real reason why the client gets disconnected? I.e. is it a bad connection, or firewall issues, or something else?
Also, you should check the error you get from the disconnect, if it's a clean disconnect (no error) you do the normal notification, but if it's an error you maybe want to handle it differently.
It turns out that this behavior isn't supposed to happen, it was just a bug in that version. This bug has been fixed in the latest version.