Socket.io Duplicate clients on a namespace - node.js

Hi I'm trying to use dynamic namespace to create them on demand.
It's working except that I get duplicate or more client for some reason
Server side :
io.of("/" + group ).on("connection", function(socket_group) {
socket_group.groupId = group;
socket_group.on("infos", function(){
console.log("on the group !");
})
socket_group.on('list', function () {
Urls.find({'group' : '...'}).sort({ '_id' : -1 }).limit(10).exec(function(err, data){
socket_group.emit('links', data);
});
})
[...]
})
Client Side :
socket.emit('list', { ... });
On the client side only one command is sent but the server is always responding with 2 or more responses. Every time I close/open my app the response is incremented.
Thanks if you find out.

This could be correct behavior; just like if you were to stack event handlers in any other environment. To ensure you only execute the attachment of your function to the namespace once, check for its presence first (or define this someplace in your program that only runs once as needed).
Try the condition (!io.namespaces["/" + group])

Related

How can i pause or cancel a Loop in NodeJs from Angular Client

I am wondering if it is possible to cancel or pause a loop which runs in NodeJs. In my case i have a function which the User calls via the angular client and kicks of a mail to a list of people.
In NodeJs there is a function that loops over the list and sends the email. I also provide progress via socket.io which all works fine. The question is, is there a way to interrupt, cancel this loop from the client once it is kicked off.
Below is my code which i currently use to update client of progress etc.
campRoutes.post('/sendEmail/:socketid?', token_check, async(req, res) => {
try {
// Get Socket info
const socketid = req.params.socketid
let emails
if (req.body.massEmailType == 'Farm') {
emails = await bulk.getEmails(req.body.tractList)
let recCount = emails[0].length
// Calculate the delay timer based on record count
// If the client send SocketID we will update via socket
if (socketid) {
console.log(socketid)
io.to(`${socketid}`).emit('emailCount', {count: recCount})
}
let i = 1
while (i <= recCount){
if (socketid) {
//TODO: Add Email Send Code
io.to(`${socketid}`).emit('emailProcessed', {count: i})
io.to(`${socketid}`).emit('massEmailSend', {name : emails[0][i-1].name , address :emails[0][i-1].address})
console.log('Sending Message ' + emails[0][i-1].address)
i++
await sleep(150)
}
}
}
res.json({ Success: true , Error: "", Message:"", Data:emails})
} catch (error) {
console.log(error)
res.json({ Success: false , Error: error.Error, Message:error.Error})
}
})
If it's a loop, I guess you can listen for SIGTERM for your specific pid using
process.on('SIGTERM', () => {...
Technique documented in https://hackernoon.com/graceful-shutdown-in-nodejs-2f8f59d1c357
For now i solved this not using socket.io to stop the loop but http.get
i created a mailStop Array on my controller which the user calls
to call the Mail Loop function
after user calls the function I return via socket.io a
mailingID which is then set on the angular client.
if the user clicks stop process will make a call to api and
push the mailingID into the mailStop Array.
In my loop i check if the mailingID is in the mailStop Array
and if it is exit the loop.
For good housekeeping i remove the mailingID from the mailStop
Array
This works and will also handle multiple users making call to same function and getting wrong result as each click will have its own mailingId.
Onlything which would be great is to figure out a way how to set this message from client to server via socket.io

kurento-utils, multiple WebRtcPeer's in one client

I have an application where I'm sharing both my desktop and my webcam to my Kurento Server (two different endpoints in the same pipeline), starting a recording endpoint for both and then alerting the client on the other hand that they're both ready to consume.
My issue comes with having two WebRtcPeerRecvonly peers on my client, if one doesn't finish before the other one makes a request to consume I either get videos of the same Desktop endpoint or two videos of the same Webcam endpoint.
webcam peer
initWebcamUser(id){
let options = {
onicecandidate: (candidate) => {
socket.emit('onWebcamIceCandidate',{
candidate : candidate,
socket_id : id,
});
}
};
webRtcWebcamPeer = new kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly(options, function(error) {
this.generateOffer((error, offerSdp) => {
socket.emit('viewerWebcam',{
sdpOffer : offerSdp,
socket_id : id
});
});
});
}
and my desktop peer.
initDesktop(socket_id){
let options = {
onicecandidate: (candidate) => {
socket.emit('onDesktopIceCandidate',{
candidate : candidate,
socket_id : socket_id,
});
}
}
webRtcDesktopPeer = new kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly(options, function(error) {
this.generateOffer((error, offerSdp) => {
socket.emit('viewerDesktop',{
sdpOffer : offerSdp,
socket_id : socket_id
});
});
});
}
I've come to the conclusion that they're both sharing the same kurentoUtils.WebRtcPeer as if I set a delay of 2 seconds before invoking initDesktop after calling initWebcamUser I get the correct streams 100% of the time.
I guess this boils down to the question of is there anyway to do this concurrently? Or should I set up a promise based system on when the WebcamPeer is complete, if so where would I put this in this process, when iceCandidates are added?
Edit: I feel it's important to note that I am assigning these peers to their respective 'participants' in my webcamViewerResponse / desktopViewerResponse respectively so they wouldn't be referenced from those temp webRtcWebcamPeer/webRtcDesktopPeer variables when I'm having this issue.
Thanks in advance.
If anyone is looking for an answer for this, I found a solution. Not the most elegant but it works 100% of the time.
endpoint.on('OnIceComponentStateChanged', function(event) {
if(event.state==='CONNECTED'){
//resolve your promise to continue on with your next connection here.
}
});

How to deal with events in nodejs/node-red

I work with node-red and develop a custom node at the moment that uses websockets to connect to a device and request data from it.
function query(node, msg, callback) {
var uri = 'ws://' + node.config.host + ':' + node.config.port;
var protocol = 'Lux_WS';
node.ws = new WebSocket(uri, protocol);
var login = "LOGIN;" + node.config.password;
node.ws.on('open', function open() {
node.status({fill:"green",shape:"dot",text:"connected"});
node.ws.send(login);
node.ws.send("REFRESH");
});
node.ws.on('message', function (data, flags) {
processResponse(data, node);
});
node.ws.on('close', function(code, reason) {
node.status({fill:"grey",shape:"dot",text:"disconnected"});
});
node.ws.on('error', function(error) {
node.status({fill:"red",shape:"dot",text:"Error " + error});
});
}
In the processResponse function I need process the first response. It gives me an XML with several ids that I need to request further data.
I plan to set up a structure that holds all the data from the first request, and populate it further with the data that results from the id requests.
And that's where my problem starts, whenever I send a query from within the processResponse function, I trigger an event that results in the same function getting called again, but then my structure is empty.
I know that this is due to the async nature of nodejs and the event system, but I simply don't see how to circumvent this behavior or do my code in the right way.
If anybody can recommend examples on how to deal with situations like this or even better could give an example, that would be great!

nodejs socket.io emit is not executed

I've got the problem that the second emit() in the following code (I have picked the important part if there is more needed just ask), which is sending a "stateChange"-Event, seems not to be executed. The "ID"-Event is received by the Server.
this.socket = io.connect('...');
this.socket.emit("ID", {canvasID: this.ID});
this.socket.on(PLACE_BUBBLE, function(data){
var node = uCanvas.placeBubble(data.x1, data.y1);
this.socket.emit("stateChange",
{action : PLACE_BUBBLE, canvasID : this.ID, nodeID : node.nodeID, x : node.x, y : node.y});
});
The server is looking like this:
socketio.sockets.on("connection", function(socket){
socket.on("ID", function(data){
...
});
socket.on("stateChange", function(data){
...
});
});
placeBubble() is executed but there is simply no information send back to the server.
/solved: Problem was "this" in this.socket.emit which should be uCanvas.socket.emit(). This was the object holding the socket.
Solved: Problem was "this" in this.socket.emit which should be uCanvas.socket.emit(). This was the object holding the socket.

socket.io data seems to be sent multiple times(nodejs and craftyjs)

I am following this tutorial on making HTML5 games. I wanted to try and mix node in to make it multiplayer. I am using node.js(v0.10.4) on server and crafty.js on front end.
I am using socket.io to send and receive messages. For now it's just me(not multiple clients). The weird thing that happens is that the message that comes from the server seems to be sent multiple times. I turned on debug mode in socket.io but it only seems to be sending the data once, yet on the front end the data seems to be coming in, in multiples. I set an incrementor on the data and it seems as if the incrementor is not incrementing multiple times but instead I am getting multiple copies of the same data.
here's node code:
var http = require('http').createServer(handler),
static = require('node-static'),
io = require('socket.io').listen(http);
io.set('log level', 3);
http.listen(80);
//attach the socket to our server
var file = new static.Server(); //Create a file object so we can server the files in the correct folder
function handler(req, res) {
req.addListener('end', function() {
file.serve(req, res);
}).resume();
}
io.sockets.on('connection', function (socket) { //listen for any sockets that will come from the client
socket.on('collected', function(data) {
/**** here's where the data is being sent back to the client *****/
socket.emit('messageFromServer', { data: data.number });
});
});
and here's front end code:
//messenger entity
Crafty.c('SendRecieveMessages',{
count: 0,
sendMessageToServer : function() {
console.log('got a village');
/**** Here's where we send the message to the server ****/
socket.emit('collected', { village : "The message went to the server and back. it's collected", number : this.count });
this.count++;
},
recieveMessageFromServer : function() {
socket.on('messageFromServer', function(data) {
/*** This data seems to be coming back or logging multiple times? ***/
console.log(data);
});
}
});
Lastly here's a screenshot of the debug in process. As you can see number is not always incrementing, it almost looks like the data is getting stored. Thanks!
http://cl.ly/image/0i3H0q2P1X0S
It looks like every time you call Crafty.c, recieveMessageFromServer() is getting called too. Every time recieveMessageFromServer is invoked, it attaches an additional event listener on the socket. That's why the first time data comes back you get one copy, then the second time you get two, the third time you get three, and so on.
You either need to prevent recieveMessageFromServer from being called multiple times, or use removeListener or removeAllListeners to remove the previously attached listeners.
Thanks to #Bret Copeland for helping me figure this one out. As he pointed out, every time socket.on() is called, it seems to add another listener. To prevent this...
I declared a global variable:
I declared a variable as a property in my Game object(in craftyjs, so use whatever you want in your setup)
Game = {
//lots of other code here...
//need this to use later for socket.io
send_message : true
}
then edited my recieveMessageFromServer() function to check whether its ok to send the message or not:
recieveMessageFromServer : function() {
console.log('does this show up multiple times?');
/* Check whether the send_message is true before sending */
if (Game.send_message) {
socket.on('messageFromServer', function(data) {
console.log(data);
Game.send_message = false;
});
}
}

Resources