kill() function is not recognized for child_process - javascript

Using node js I'm calling external script in MATLAB and Python
That is working well using terminal commands to run the scripts using those application ('start')
But when I'm trying to close them using kill() ('stop') I get an error:
TypeError: exec.kill is not a function
I'm using MAC OS and this is my code:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var fs = require('fs');
var path = require('path');
const exec = require('child_process').exec;
var cmd1 =
'/Applications/MATLAB_R2016b.app/bin/matlab -nojvm < /Users/dorsimon/Desktop/liftrack/Testing_Classifier.m';
var cmd2 = 'python /Users/dorsimon/Desktop/liftrack/arduino_sampling_for_workout.py';
app.get('/', function(req, res) {
res.sendfile('index.html');
});
//Whenever someone connects this gets executed
io.on('connection', function(socket) {
console.log('A user connected');
fs.watch('/Users/dorsimon/Desktop/liftrack/result/', function(event, test) {
console.log('event is: ' + event);
fs.readFile('/Users/dorsimon/Desktop/liftrack/result/results.csv', 'utf-8', function read(
err,
data
) {
if (err) {
console.log('err');
throw err;
}
console.log(data);
socket.send(data);
});
});
fs.watch('/Users/dorsimon/Desktop/liftrack/go', function(event, test) {
console.log('event is: ' + event);
fs.readFile('/Users/dorsimon/Desktop/liftrack/go/go.csv', 'utf-8', function read(err, data) {
if (err) {
console.log('err');
throw err;
}
console.log(data);
socket.send(data);
});
});
//Whenever someone disconnects this piece of code executed
socket.on('disconnect', function() {
console.log('A user disconnected');
});
socket.on('start', function() {
exec(cmd1, function(error, stdout, stderr) {
// command output is in stdout
});
exec(cmd2, function(error, stdout, stderr) {
// command output is in stdout
});
});
socket.on('stop', function() {
exec.kill();
});
});
http.listen(3000, function() {
console.log('listening on *:3000');
});
How can I kill those child_process that I started?
Thanks
Dor

You need to store the return value of exec and call kill on that. You can store those values as properties on socket for convenience:
socket.on('start', function() {
socket.child1 = exec(cmd1, function(error, stdout, stderr) {
// command output is in stdout
});
socket.child2 = exec(cmd2, function(error, stdout, stderr) {
// command output is in stdout
});
});
socket.on('stop', function() {
socket.child1.kill();
socket.child2.kill();
});
FWIW, you probably have to do the same with the return values of fs.watch(), and call close() on them when the socket gets closed, otherwise you'll probably run into issues after your server has been running for a while (it creates two watchers for each socket.io connection, but doesn't remove them, so they'll linger).

Related

Having difficulty returning a value from an async function

I'm new to Node and have previously just written Javascript for simple browser extensions. What I'm trying to do is run a shell script and then return the text for it on a get request (simplified version).
I've tried looking at callbacks and can't seem to get my head around it or even adapt another example to what I'm trying to do. My main problem is either that the I'm receiving the error "first argument must be one of type string or buffer. received type undefined" or "received type function" (when I tried to implement a callback, which is what I believe I need to do here?).
I've looked at a few examples of callbacks and promises and seeing them in abstraction (or other contexts) just isn't making sense to me so was hoping someone could help direct me in the right direction?
The code is very crude, but just trying to get some basic functionality before expanding it any further.
var express = require("express");
var app = express();
const { exec } = require("child_process");
var ifcfg = function(callback) {
exec("ifconfig", (error, stdout, stderr) => {
if (error) {
console.log(`error: ${error.message}`);
return error;
}
if (stderr) {
console.log(`stderr: ${stderr}`);
return err;
} else {
var output = stdout.toString();
return callback(output);
}
});
}
app.get("/ifconfig", (req, res) => res.write(ifcfg(data)));
var port = process.env.PORT || 8080;
app.listen(port, function() {
console.log("Listening on " + port);
});
In JavaScript, a callback is a function passed into another function as an argument to be executed later.
Since the command is executed asynchronously you will want to use a callback to handle the return value once the command has finished executing:
var express = require("express");
var app = express();
const { exec } = require("child_process");
function os_func() {
this.execCommand = function(cmd, callback) {
exec(cmd, (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
callback(stdout);
});
}
}
app.get("/", (req, res) => {
console.log("InsideGetss");
var os = new os_func();
os.execCommand('ifconfig', function (returnvalue) {
res.end(returnvalue)
});
});

Raspberry serial port automatically stops after some time

I am using neo 6m gps module with raspberry pi 3 , i have attached it on serial port ttyAMA0 , but it reads data for only small time and then port closes automatically , and sometime the data is also corrupt which causes gps.js module to throw an error.
Execution Demo screenshot.
Below is my node js script:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var file = '/dev/ttyAMA0';
const SerialPort = require('serialport');
const parsers = SerialPort.parsers;
const parser = new parsers.Readline({
delimiter: '\r\n'
});
const port = new SerialPort(file, {
baudRate: 9600
});
port.pipe(parser);
var GPS = require('../../gps.js');
var gps = new GPS;
gps.on('GGA', function(data) {
io.emit('position', data);
console.log("Latitiude :", data.lat);
console.log("Longitude :", data.lon);
});
app.get('/', function(req, res) {
res.sendFile(__dirname + '/maps.html');
});
http.listen(3000, function() {
console.log('listening on *:3000');
});
port.on('data', function(data) {
gps.updatePartial(data);
});
process.on('unhandledRejection', function (reason, p) {
//I just caught an unhandled promise rejection, since we already have fallback handler for unhandled errors (see below), let throw and let him handle that
console.log("=============");
console.log(reason);
console.log("=============");
return;
});
process.on('rejectionHandled', () => {});
process.on('uncaughtException', function (error) {
console.log(error);
});
port.on('close', function(data) {
console.log("Port closed");
console.log(port.binding);
});
Output screenshot
I solved the problem by reinstalling the raspbian, OS was closing the port for some reason

saving a file when server is terminated

I'm try to save a content to a file when my node js (express) server is terminated, somehow the file is empty.
function exitHandler() {
//.......
fs.writeFile('graph.txt', Graph, 'utf8', (err) => {
if (err != null) {
console.error(err);
}
});
}
// Bring in our dependencies
const express = require('express');
global.fs = require('fs');
// Connect all our routes to our application.
app = express();
// Turn on the server!
app.listen(3000, () => {
console.log('App listening on port 3000');.
});
// Catches exit event
process.on('exit', exitHandler.bind(null));
// Catches ctrl+c event
process.on('SIGINT', () => {
exitHandler();
process.exit(-1);
});
// Catches "kill pid" (for example: nodemon restart)
process.on('SIGUSR1', exitHandler.bind(null));
process.on('SIGUSR2', exitHandler.bind(null));
// Catches uncaught exceptions
process.on('uncaughtException', exitHandler.bind(null)
);
If I delete the process.exit(-1) it save content to the file, but never exit the program, and call the event of 'exit'.
thanks
The exitHandler function is asynchronous. You're calling process.exit before the file gets saved. You should use a callback function:
function exitHandler(callback) {
//.......
fs.writeFile('graph.txt', Graph, 'utf8', (err) => {
if (err != null) {
console.error(err);
} else {
callback();
}
});
}
// ...
process.on('SIGINT', () => {
exitHandler(() => process.exit(-1));
});
Or, as schroffl suggested in comments, you can use fs.writeFileSync instead of fs.writeFile:
function exitHandler() {
//.......
fs.writeFileSync('graph.txt', Graph, 'utf8');
}

display ssh2 stdout and stderr in textarea

I'm building a node.js application to manage servers.
In this application, I can create some shell scripts and execute them on a server by clicking on a button.
Here is what I have in my routes.js file for this action :
app.get('/exec', isLoggedIn, function(req, res) {
var url = require('url');
var url_parts = url.parse(req.url, true);
var query = url_parts.query;
var Server = require('../app/models/server');
var Script = require('../app/models/script');
var async = require('async');
var scriptId = query.scriptId;
var userId = query.userId;
var serverId = query.serverId;
var stdout = "";
var stderr = "";
async.parallel({
servers: function(callback){
Server.find({"_id" : serverId}).exec(callback);
},
scripts: function(callback){
Script.find({"_id" : scriptId}).exec(callback);
}
}, function(err, results) {
if (err)
res.send(err);
var selectedServer = results.servers;
var selectedScript = results.scripts;
var serverIp = selectedServer[0].serverDetails.serverAddress;
var serverPort = selectedServer[0].serverDetails.serverPort;
var serverUsername = selectedServer[0].serverDetails.serverUsername;
var scriptContent = selectedScript[0].scriptDetails.scriptContent;
var Connection = require('ssh2');
var conn = new Connection();
conn.on('ready', function() {
//console.log('Connection :: ready');
conn.exec(scriptContent, function(err, stream) {
if (err) throw err;
stream.on('exit', function(code, signal) {
//console.log('Stream :: exit :: code: ' + code + ', signal: ' + signal);
}).on('close', function() {
//console.log('Stream :: close');
conn.end();
}).on('data', function(data_out) {
console.log('STDOUT: \n' + data_out);
stdout = stdout + data_out;
res.render('execresults.ejs', {
stdout : stdout
});
}).stderr.on('data', function(data_err) {
console.log('STDERR: \n' + data_err);
});
});
}).connect({
host: serverIp,
port: serverPort,
username: serverUsername,
privateKey: require('fs').readFileSync('id_rsa')
});
conn.on('error', function(e) { console.log("Connection failed or timed out")});
});
});
It works fine and I have the results of the execution in the console. But I would like to display both stdout and stderr results in two textarea of an ejs page.
The problem is that when I run a simple command like "uptime", it works, I will have the stdout result displayed in my textarea.
But when the shell script returns both stdout and stderr, or if stdout is a large amount of text, I don't have everything passed to my ejs page because of this error I think : Error: Can't set headers after they are sent.
My question is : How can I send both stdout and stderr to my ejs page, only when the script is completely executed ? I tried to build a "stdout" variable by concatenating all stdout output but it doesn't seem to work...
Can someone help me ?
thanks a lot
Assuming the process eventually ends on its own and it does not output a lot of data, you could probably just buffer the data and then render when the process closes:
conn.exec(scriptContent, function(err, stream) {
if (err)
return res.send(err);
var stdout = '',
stderr = '';
stream.on('close', function() {
conn.end();
res.render('execresults.ejs', {
stdout: stdout,
stderr: stderr
});
}).on('data', function(data) {
stdout += data;
}).stderr.on('data', function(data) {
stderr += data;
});
});
Secondly,
if (err)
res.send(err);
should really have a return:
if (err)
return res.send(err);
to prevent further execution on errors.

Asynchronous function not returning callback for MongoDB connect

I have a MongoDB connect call that crashes a heroku app..
I have been editing what was originally localHost code (was working perfectly) to work with Heroku MongoDb addons (like MongoLab), but how do I get someDBcollectionVariable to work with someDBcollectionVariable.find()
//MongoDB
var mongodb = require('mongodb');
var db;
var MONGODB_URI = process.env.MONGOLAB_URI;
var PORT = process.env.PORT;
var testColl;
function dbConnect() {
return mongodb.MongoClient.connect(MONGODB_URI, function(err, database) {
if(err) throw err;
db = database;
var testColl = db.collection('test');
app.listen(PORT);
console.log('Listening on port ' + PORT);
return testColl;
});
}
//calls then look like
app.post('/add', function (req, res) {
testColl.insert(
{
"title" : req.body.title,
"quantity" : parseInt(req.body.quantity)
},
function (err, doc) {
getAll(res);
});
});
//and getAll looks like this
function getAll(res) {
testColl.find().sort( { value: 1 } ).toArray(function (err, docs) {
res.json({docs: docs});
});
}
Before moving that code inside dbConnect(), testColl.find.. was generating a ResponseError because the connect code was completing before the variable could be set?
Returning a value from an asynchronous function makes no sense. To use the a value, you need to pass it to a callback function. The same goes for errors (you can't throw asynchronously). A fixed version of your code could look like:
//MongoDB
var mongodb = require('mongodb');
var db;
var MONGODB_URI = process.env.MONGOLAB_URI;
var PORT = process.env.PORT;
var testColl;
function dbConnect(callback) {
mongodb.MongoClient.connect(MONGODB_URI, function (err, database) {
if (err) {
return callback(err);
}
db = database;
database.collection('test', function (err, testColl) {
if (err) {
return callback(err);
}
app.listen(PORT);
console.log('Listening on port ' + PORT);
callback(null, testColl);
});
});
}
//calls then look like
dbConnect(function (err, testColl) {
if (err) {
return console.error(err.stack || err.message);
}
testColl.find...
});

Categories

Resources