Child process function not being triggered with no errors - node.js

I'm working on a Node.js app utilizing Electron. I need to access a executable in a certain directory and determine its output. The executable is a simple console application. I read the docs on Child Process and tried to use execFile. However, the callback function doesn't seem to execute.
Here's my code at the moment:
var exec = require('child_process').execFile
exec('E:/SteamLibrary/steamapps/common/GarrysMod/bin/gmad.exe', [], function(err, data) {
console.log(err);
console.log(data);
});
How could I go about fixing this?

Youre using windows so execFile() wouldnt work. It stated on docs.. for convenient I use docs example here with litle change.
const { spawn } = require('child_process');
const bat = spawn('C/steam/steam.exe');
bat.stdout.on('data', (data) => {
console.log(data.toString());
});
bat.stderr.on('data', (data) => {
console.log(data.toString());
});
bat.on('exit', (code) => {
console.log(`Child exited with code ${code}`);
});

Related

Node and talking to child processes

Context
Writing a serial monitor to listen to an Arduino isn't hard. Starting it with command line params for port name and baudrate is straightforward, and thus it's not complicated to configure and launch the monitor from Node:
child_process.exec("./monitor COM6 115200");
This question concerns exec, fork and spawn which are similar but with subtleties I do not yet grasp. As well as launch with parameters, I need to
Capture the output so I can display it in a window
Kill the child process
to re-launch with different parameters
to flash the Arduino and then re-launch after it reboots
I used netcore to write a console app that takes two command line arguments, then connects and listens, echoing to its stdout. I chose netcore because it can run on all three platforms.
Questions
Which should I use of exec, fork and spawn?
How do I kill the child process?
How do I capture the stdout of the child process?
Node documentation talks about a kill method on a subprocess object. The sample code on that page implies this object is returned by spawn but when I use spawn it seems to fail silently. That or it's working but I don't know what I'm doing, which is why I'm posing this question.
All of this Node code will be part of a VSCode extension, so if you also know about those I'd like to pipe stdout to a VSCode OutputChannel if that's possible.
With spawn your are able to listen to stdout.
and then kill process with kill()
From official NodeJS docs:
const { spawn } = require('child_process');
const ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
ls.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
// some logic
ls.kill()
EDIT: a more specific example:
// server.js --------------
const http = require('http');
const server = http.createServer(
(function() {
console.log('Initializing server');
return (req, res) => {
res.end('Hello World');
};
})()
);
server.listen(8080, () => console.log('Server is up on port ' + 8080));
// spawn.js --------------
const { spawn } = require('child_process');
const child = spawn('node', ['./server.js']);
child.stdout.on('data', data => console.log(data.toString()));
child.stderr.on('data', data => console.log('Error: ' + data));
child.on('close', code => console.log(`Process ended with code ${code}`));
child.on('error', err => console.log(err));
setTimeout(() => child.kill(), 2000);

Need to run a NodeJs application from another NodeJs application

I have a NodeJs application running in the following directory
First Application's Path '/users/user1/projects/sampleProject' which is running at 3000 port.
Second Application's Path '/users/user1/demoProjects/demo1' which is going to run at 5000 port on triggering the router function from first application.
The second NodeJs application is not yet started(It will run at port 5000). It need to run independently on hitting a router function in the first NodeJs Application which is running on port 3000 ie(http://localhost:3000/server/startServer). I'm new to NodeJs child processes, Kindly correct me if i'm wrong. And suggest me a right way to do it. Thanks
Start another node application using node.js?
I have tried it like below
// First NodeJs application
import { exec } from "child_process";
router.get('/startServer', async (req, res, next) => {
console.log("Initiated request")
let startServerInstance = 'cd "/users/user1/demoProjects/demo1" && npm run dev'; // path for the second NodeJs application
console.log("Server instance path => " + startServerInstance)
try {
// exec from child process, Spawns a shell then executes the command within that shell
let child = exec(startServerInstance, function (err, stdout, stderr) {
if (err) throw err;
else {
console.log("result ")
res.json({
status: 'success'
});
}
});
} catch (error) {
res.json({
status: 'error',
message: error
});
}
});
The above code executes the command and triggered the second application to run in background but it doesn't return anything. Either error or success result.
You need to use stout and stderror to check other server logs. Also your code is not correct. If you use if without {} it will not go to else statement. That is why you don't see 'result' text in console.
import {
exec
} from "child_process";
router.get('/startServer', async (req, res, next) => {
console.log("Initiated request")
let startServerInstance = 'cd "/users/user1/demoProjects/demo1" && npm run dev'; // path for the second NodeJs application
console.log("Server instance path => " + startServerInstance)
try {
// exec from child process, Spawns a shell then executes the command within that shell
let child = exec(startServerInstance, function(err) {
if (err) throw err;
console.log("Server started");
});
child.stdout.on('data', (data) => {
// this is new server output
console.log(data.toString());
});
child.stderr.on('data', (data) => {
// this is new server error output
console.log(data.toString());
});
res.json({
status: 'success'
});
} catch (error) {
res.json({
status: 'error',
message: error
});
}
});
Child process callback is only called once the process terminates. If the process keeps running, callback is not triggered.
Explained here - https://nodejs.org/docs/latest-v10.x/api/child_process.html#child_process_child_process_exec_command_options_callback

Can't get websocket client to run as child process

I'm looking to build a project based on node that will have a few different websocket connections, I'm fine with the code itself for what I want to do but can't seem to get my head around how to start the websocket modules (code already written and moved to a file named ws.js) to run from the main server.js file.
I have tried spawning as a child process but just get
Error: spawn ws.js ENOENT
I have removed all other code from each file to prevent hidden errors, content of the files are below.
Server.js
var child = require('child_process').spawn('node', ['ws.js']);
child.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
child.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
child.on('exit', function (code) {
console.log('child process exited with code ' + code);
});
setTimeout(function() {
child.stdin.write('echo %PATH%');
}, 2000);
ws.js
const Gdax = require('gdax');
const publicClient = new Gdax.PublicClient();
const websocket = new Gdax.WebsocketClient(['BTC-USD', 'ETH-USD']);
websocket.on('message', data => {
/* work with data */
console.log("data received");
});
websocket.on('error', err => {
/* handle error */
});
websocket.on('close', () => {
/* ... */
});
EDIT --------------------------
Thanks for the response below from Elliot server.js now runs without error however the ws.js child never writes to the console so is either not running or failing silently. Any help is appreciated on getting this working.
Cheers
For the console logs, you have to keep in mind that a child process is a new process and does not share a console. You can make it work with spawn(), however, since you are using a child process to execute a nodeJs file, I recommend using child_process.fork() instead of spawn. It is similar to spawn but is specifically used for other nodeJs processes. The benefit is that it makes it much easier for the two processes to communicate.
With that in mind, you can make the following updates:
Server.js:
var child = require('child_process').fork('./ws.js');
child.on('message', function (data) {
console.log('stdout: ' + data);
});
child.on('error', function (data) {
console.log('stderr: ' + data);
});
child.on('exit', function (code) {
console.log('child process exited with code ' + code);
});
ws.js
const Gdax = require('gdax');
const publicClient = new Gdax.PublicClient();
const websocket = new Gdax.WebsocketClient(['BTC-USD', 'ETH-USD']);
websocket.on('message', data => {
/* work with data */
process.send("data received");
});
websocket.on('error', err => {
/* handle error */
});
websocket.on('close', () => {
/* ... */
});
process.send() sends data to its parent process, where a listener (i.e.
child.on('message', callback)) is waiting to receive it.

node.js: Redirecting stdin,stdout of a (different) console application

I am trying to write an admin tool for Unturned (it's a zombie survival game). The server to that game runs in a terminal. I wanted to somehow get the live output of that console and at the same time being able to write to the terminal so I can control the server with my admin tool written in node.js. I tried to google/search for a solution but am not entirely sure what to look for. So far I tried different things with child_process but to no avail. Is such a thing even possible and when yes how?
const spawn = require('child_process').spawn;
const proc = spawn("Unturned.exe", ["-batchmode", "-nographics", "+secureserver/servername", "", "", "", ]);
proc.stdout.on('data', (data) => {
console.log(data);
});
proc.stderr.on('data', (data) => {
console.log(data);
});
proc.on('exit', (code) => {
console.log(`Child exited with code ${code}`);
});
and another.
const spawn = require('child_process').spawn;
const proc = spawn("Unturned.exe", ["-batchmode", "-nographics", "+secureserver/servername", "", "", "", ], { stdio: ['pipe', 'pipe', 'pipe'] });
proc.stdout.on('data', (data) => {
console.log("stdout: "+data);
});
proc.stderr.on('data', (data) => {
console.log("stderr: "+data);
});
proc.on('exit', (code) => {
console.log(`Child exited with code ${code}`);
});
Both don't work (first one doesn't get input/output, second one doesn't even successfully start the server).
Thanks in advance.
Are you sure that Unturned.exe is sending output to stdout and stderr. Can you do this: Unturned.exe -batchmode -nographics +secureserver/servername >data.txt ?

Node.js detect a child process exit

I am working in node, as it happens via a visual studio code extension. I successfully create child processes and can terminate them on command. I am looking to run code when the process unexpectedly exits, this appears to be what the "exit" event is intended for, but I'm unclear on how to call it, this is the code I am working with, the process runs, but does not detect/log on exit, note that output.append is visual studio code specific version of console.log():
child = exec('mycommand', {cwd: path},
function (error, stdout, stderr) {
output.append('stdout: ' + stdout);
output.append('stderr: ' + stderr);
if (error !== null) {
output.append('exec error: ' + error);
}
});
child.stdout.on('data', function(data) {
output.append(data.toString());
});
Here's four things I have tried that do not work in logging on exit:
child.process.on('exit', function(code) {
output.append("Detected Crash");
});
child.on('exit', function(code) {
output.append("Detected Crash");
});
child.stdout.on('exit', function () {
output.append("Detected Crash");
});
child.stderr.on('exit', function () {
output.append("Detected Crash");
});
Looking at the node.js source code for the child process module, the .exec() method does this itself:
child.addListener('close', exithandler);
child.addListener('error', errorhandler);
And, I think .on() is a shortcut for .addListener(), so you could also do:
child.on('close', exithandler);
child.on('error', errorhandler);

Resources