So what I'm trying to do is loop over an array of javascript objects (sensors
), each with cmd
and parser
attributes, run each cmd
in the system shell, parse its output with the appropriate parser
function, and append the resulting string to the server's res
object.
The first issue is that I get an error claiming the current object has no method parser
. I've tried a few different things and still can't get it to recognize that attribute of the object.
The second issue, when I gave up and hardcoded the parse function inside the loop (which destroys my ability to add commands that need a different parser), is that because the output of each command is read in a callback function, the server runs res.end()
before the callbacks return, causing an empty response to the browser.
I'm quite new to node and javascript, so I'm sure I've made some beginner mistakes, I just can't seem to sort them out in my head. Any help would be appreciated.
// requires
var http = require('http');
var exec = require('child_process').exec;
// parsers
var parseTemp = function(str) {
return ((parseInt(str, 16) / 50 - 273.15).toFixed(2));
};
// sensors
var sensors = [
{
label: "Object temp",
cmd: "i2cget -y 3 0x5a 0x07 w",
parser: parseTemp,
units: " degrees C"
},
{
label: "Ambient temp",
cmd: "i2cget -y 3 0x5a 0x06 w",
parser: parseTemp,
units: " degrees C"
}
];
// server
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
for (var s in sensors) {
exec(s.cmd, function (error, stdout, stderr) {
res.write( s.label + ': ' + s.parser(stdout) + s.units + '\n' );
});
}
res.end();
}).listen(1337, '');
console.log('Server running on port 1337');
Your first issue is a result of each callback function referencing the same s
variable. You can easily solve this by changing the for(s in sensors)
loop into a sensors.forEach(function(s){...})
. That will close over (google javascript closure) the s and make it the right one for each callback when the time comes. There might be other problems - I didn't look all that hard once I saw this issue.
Your second issue is precisely what you said. The res.end()
is being called before the callbacks - since they're asynchronous, so at best will be called after the current "thread" of execution is finished. You can solve that with a simple counter: increment before every exec
call, and on each callback decrement and check if the counter has reached its initial value - if so, then run res.end()
.