Passing additional arguments down a callback chain in nodejs - node.js

I'm having difficulties in wrapping my mind around callbacks executed by predefined modules.
I've a socket.io client variable receiving an event, which should trigger a dns lookup of the given server, then send something to it. As far as I understood the whole concept, I execute the dns function, and in the callback execute another function which connects to my server, which in turn triggers another callback and so on, right? So my code looks like ths:
io.sockets.on('connection', function (client) { // comes from socket.io module
client.on('myconnect', function (data) {
doDns(client, data.server);
});
}
var doDns = function (client, server) {
client.emit('status', {m: 'going to resolve domain'});
dns.resolve(server, 'A', doConnectToServer(???)); // comes from dns module
};
var doConnectToServer = function(???) {
client.emit('status', {m: 'going to connect to server now'});
// additional code goes here
}
So here is my problem: how do I pass my client variable down to the next callback, without losing what dns.resolve() will pass to the callback? When I change the line to this...
dns.resolve(server, 'A', doConnectToServer);
... then I have access to the dns results in the callback, but I lose my client variable, "console.log(arguments)" only shows the params passed down from the dns module, obviously. When I do it like this...
dns.resolve(server, 'A', doConnectToServer(client));
... then in my callback I'm missing the vars for the dns result. A "console.log(arguments)" in "doConnectToServer" function only shows the client variable.
So how am I supposed to tackle that?
And in general, am I on the completely wrong boat with my overall call flow (it's my first node.js app), or is this the way you'd design a node.js application?

You're close. Just pass the arguments along from within the doDNS function.
io.sockets.on('connection', function (client) { // comes from socket.io module
client.on('myconnect', function (data) {
doDns(client, data.server);
});
}
var doDns = function (client, server) {
client.emit('status', {m: 'going to resolve domain'});
dns.resolve(server, 'A', function(err, addresses) {
if (err) throw new Error(err);
doConnecToServer(addresses, client);
}); // comes from dns module
};
var doConnectToServer = function(addresses, client) {
client.emit('status', {m: 'going to connect to server now'});
// additional code goes here
}

Related

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!

Node Postgres Module not responding

I have an amazon beanstalk node app that uses the postgres amazon RDS. To interface node with postgres I use node postgres. Code looks like this:
var pg = require('pg'),
done,client;
function DataObject(config,success,error) {
var PG_CONNECT = "postgres://"+config.username+":"+config.password+"#"+
config.server+":"+config.port+"/"+config.database;
self=this;
pg.connect(PG_CONNECT, function(_error, client, done) {
if(_error){ error();}
else
{
self.client = client;
self.done = done;
success();
}
});
}
DataObject.prototype.add_data = function(data,success,error) {
self=this;
this.client.query('INSERT INTO sample (data) VALUES ($1,$2)',
[data], function(_error, result) {
self.done();
success();
});
};
To use it I create my data object and then call add_data every time new data comes along. Within add_data I call 'this/self.done()' to release the connection back to the pool. Now when I repeatedly make those requests the client.query never gets back. Under what circumstance could this lead to a blocking/not responding database interface?
The way you are using pool is incorrect.
You are asking for a connection from pool in the function DataObject. This function acts as a constructor and is executed once per data object. Thus only one connection is asked for from the pool.
When we call add_data the first time, the query is executed and the connection is returned to the pool. Thus the consequent calls are not successful since the connection is already returned.
You can verify this by logging _error:
DataObject.prototype.add_data = function(data,success,error) {
self=this;
this.client.query('INSERT INTO sample (data) VALUES ($1,$2)',
[data], function(_error, result) {
if(_error) console.log(_error); //log the error to console
self.done();
success();
});
};
There are couple of ways you can do it differently:
Ask for a connection for every query made. Thus you'll need to move the code which ask for pool to function add_data.
Release client after performing all queries. This is a tricky way since calls are made asynchronously, you need to be careful that client is not shared i.e. no new request be made until client.query callback function is done.

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;
});
}
}

How to emit an event and pass a function as a parameter with socket.io

I am using socket.io and I am trying to emit an event from my server and pass an object with a function as a parameter. Here is my code:
socket.emit('customEvent', {
name : "Test".
myFunc : function() {
//some logic here
}
});
and then in the client (my app in the browser) I am able to access 'name' property but when I try to access 'myFunc' but I get 'undefined' for it. Here is my code
socket.on('customEvent', function(data){
data.myFunc();
});
What is the correct approach for this (if it is possible at all)?
The data is transmitted as JSON, so it can't contain functions. Maybe you're looking for what's called 'acknowledgments' in socket.io's documentation?
// server
socket.on('customEvent', function (data, fn) {
fn(data.x)
})
// client
socket.emit('customEvent', { x: 1 }, function(){
// ...
})
You can serialize your function, maybe it's a dangerous way for some functions. But socket.io transfers only strings as pure strings or JSON. You can try to eval string function when receive it from server side.
NOTE: Code not tested below:
function hello() {
return "Hello Cruel World";
}
socket.emit('send-function', { myFunc : hello.toString() });
...
on server side:
socket.on('send-function', data) {
console.log(eval(data.myFunc));
}
Try on this code and give us a feedback if it works.

Meteor client synchronous server database calls

I am building an application in Meteor that relies on real time updates from the database. The way Meteor has laid out the examples is to have the database call under the Template call. I've found that when dealing with medium sized datasets this becomes impractical. I am trying to move the request to the server, and have the results passed back to the client.
I have looked at similar questions on SA but have found no immediate answers.
Here is my server side function:
Meteor.methods({
"getTest" : function() {
var res = Data.find({}, { sort : { time : -1 }, limit : 10 });
var r = res.fetch();
return (r);
}
});
And client side:
Template.matches._matches = function() {
var res= {};
Meteor.call("getTest", function (error, result) {
res = result;
});
return res;
}
I have tried variations of the above code - returning in the callback function as one example. As far as I can tell, having a callback makes the function asynchronous, so it cannot be called onload (synchronously) and has to be invoked from the client.
I would like to pass all database queries server side to lighten the front end load. Is this possible in Meteor?
Thanks
The way to do this is to use subscriptions instead of remote method calls. See the counts-by-room example in the docs. So, for every database call you have a collection that exists client-side only. The server then decides the records in the collection using set and unset.

Resources