I want to pass a command to a python child process and then get the result. I would use exec, but I want to keep the child process open so that I don't have to open it every time I do a new command. Here is my code that currently does nothing:
var connect = require('connect'),
io = require("socket.io").listen(1032),
util = require("util"),
child = require('child_process'),
python = child.spawn("python");
var app = connect()
.use(connect.static(__dirname + '/www'))
.use(connect.logger('dev'))
.listen(3000);
io.sockets.on('connection', function (socket) {
console.log("Socket " + socket.id + " opened");
python.stdout.on('data', function (data) {
console.log("computed", data.toString("utf-8"));
socket.emit("python", { result : data.toString("utf-8") });
});
socket.on('python', function (data) {
console.log("received data" + data.cmd);
python.stdin.resume();
python.stdin.write(data.cmd);
python.stdin.end();
});
});
Does your python code contain any non-ascii characters?
This works fine:
var
spawn = require('child_process').spawn,
python = spawn('python');
python.stdin.write('print ("a")');
python.stdin.end();
python.stdout.on('data', function (data) {
console.log(data.toString());
});
But if I change the letter "a" to a russian letter "п" it stops working. Event not fired.
But it works perfect with node interpreter (with any utf8 characters).
var
spawn = require('child_process').spawn,
node = spawn('node');
node.stdin.write('console.log("п");');
node.stdin.end();
node.stdout.on('data', function (data) {
console.log(data.toString());
});
I think you need to ask about it in python section.
Related
On Mac OS using Node, I would like to:
Copy a code snippet from Stack Overflow e.g. console.log('hello world')
Access code snippet console.log('hello world') in running Node program
This is how I imagined it would work
var child_process = require('child_process');
var child = child_process.spawn('pbcopy');
child.stdin.on('data', function (data) {
// runs every time I copy something to my clipboard
console.log('data' + data);
});
This doesn't work. Nor does 'readable' event.
I have seen this example to write to the clipboard using pbcopy https://stackoverflow.com/a/13735363/3893510
Thanks for your help
Edit: I have a very crude way to do it using node copy-paste and a timeout
var ncp = require("copy-paste");
const listOfCopiedItems = []
function trackAllCopiedText (prev = "") {
const text = ncp.paste()
if (prev !== text){
listOfCopiedItems.push({
text,
dateTime: new Date()
})
}
setTimeout(() => {
trackAllCopiedText(text)
}, 1000);
}
trackAllCopiedText()
I'm trying to run a command (aws configure) from a .js file called with node. I've been using child_process which allows me to execute a command or batch file. However when that file would normally prompt the user for something like a username and password, I am unable to have that interaction take place.
I tried using process.stdin with node in order to perhaps use node as the middle man of a user's input, but I am unable to link the two together.
If anyone has any ideas that would be great!
var spawn = require('child_process').spawn;
var mystdin = process.stdin;
var conf = spawn('aws configure', {input: mystdin, shell: true});
//When command returns
conf.stdout.on('data', function(data) {
console.log('stdout: ' + data);
//prompt for input
mystdin.resume();
mystdin.setEncoding('utf8');
var util = require('util');
mystdin.on('data', function (text) {
//INSERT ANSWER HERE
console.log('received data:', util.inspect(text));
if (text === 'quit\n') {
done();
}
});
function done() {
console.log('Now that process.stdin is paused, there is nothing more to do.');
process.exit();
}
});
conf.stderr.on('data', function(data) {
console.log('stdout: ' + data);
});
conf.on('close', function(code) {
console.log('child precess exited with code ' + code);
});
This is just the path I was currently going down. If anyone has a better suggestion let me know!
Thanks
Two ideas: first, I think the arguments are supposed to be in the second parameters. Second, maybe the aws command doesn't realize it is an interactive terminal or something. You may try with child_process like that, or if that doesn't work, with pty.js:
var pty = require('pty.js');
var term = pty.spawn('aws', ['configure'], {
name: 'xterm-color',
cols: 80,
rows: 30,
cwd: process.env.HOME,
env: process.env
});
term.on('data', function(data) {
console.log(data);
});
I have a node.js server, which will print out some message in the console and then start the server.
I am creating a automation test by using tap to check the message in the console.log and check if server is started, i.e. there is a PID generated.
I tried 2 different methods -child_process.exec and child_process.spawn
1. Use child_process.exec with a call back function.
This does not work as the server is long running and will not even
go to the call back, so I cannot even check for any stdout.
Then I use child_process.exec without call back, this solves the
first issue where I can now get the message back from stdout.
The second issue is that the test will hang since the server is long running and will not terminate by itself.
code snippet:
var exec = require('child_process').exec;
tap.test('test server start', function(t) {
childProcess= exec('node',['server']);
console.log('[exec] childProcess.pid: ', childProcess.pid);
t.notEqual(childProcess.pid, undefined);
childProcess.stdout.on('data', function (data) {
console.log('[exec] stdout: ', data.toString());
t.match(data.toString(), "Example app listening at http://:::3000");
t.end();
childProcess.kill('SIGTERM');
});
childProcess.stderr.on('data', function (data) {
console.log('[exec] stderr: ', data.toString());
});
childProcess.on('close', function (code) {
if (code!=null)
console.log('child process exited with code '+ code);
});
});
use child_process.spawn -code snippet
var spawn = require('child_process').spawn;
tap.test('test server start', function(t) {
childProcess= spawn('node',['server']);
console.log('[spawn] childProcess.pid: ', childProcess.pid);
t.notEqual(childProcess.pid, undefined);
childProcess.stdout.on('data', function (data) {
console.log('[spawn] stdout: ', data.toString());
t.match(data.toString(), "Example app listening at http://:::3000");
t.end();
childProcess.kill('SIGTERM');
});
childProcess.stderr.on('data', function (data) {
console.log('[spawn] stderr: ', data.toString());
});
childProcess.on('close', function (code) {
if (code!=null)
console.log('child process exited with code '+ code);
});
});
In both 1 & 2, the test will hang since the server is long running,
I need to use child_process.kill() to terminate the test
Is there a better method to achieve this?
Thanks in advance for any improvements.
Well, I think that you can check if the server is alive in a different way (without spawning a new process).
For example, you can start your server waiting for connections:
const net = require('net');
var connections = {};
var server = net.createServer(function(conn) { });
server.listen(3333);
server.on('connection',function(conn) {
var key = conn.remoteAddress + ':' + conn.remotePort;
connections[key] = conn;
conn.on('close',function() {
delete connections[key];
});
});
Then, connect some clients (or just one) to the server:
var connected = 0;
for (var i = 0;i < 10;i++) {
var client = net.connect(3333);
client.on('connect',function() {
connected++;
console.log(connected);
});
}
So, if you are be able to connect to the server, then your server is alive.
And finally, when you want to close the server, just create a new function like this one:
var destroy = function ()
{
server.close(function() {
console.log('ok');
});
for (var key in connections) {
connections[key].destroy();
}
}
Call it for example after 10 successful connections to the server. Inside the for loop:
for (var i = 0; i < 10; i++) {
var client = net.connect(3333);
client.on('connect',function() {
connected++;
if (connected === 10) {
destroy();
}
});
}
This is a very basic example, but I think that it's enough to understand another way to do what you want to do.
I.
My situation is as follows: there's an array of IP address. I will test each IP to connect to a remote server. If one IP connects, the rest IPs are ignored and not going to be connected.
I used the following Node.JS codes to do the work, but it seems not working. Please give some hints. Thanks!
// serverip is a var of string splitted by ";", e.g. "ip1;ip2;ip3"
var aryServerIP = serverip.split(";");
console.log(aryServerIP);
var ipcnt = aryServerIP.length; // ipcnt = 3, for example
for (ip in aryServerIP)
{
console.log("to process: " + ipcnt); // error here: always print 3
var net = require('net');
var client = new net.Socket();
var rdpport = 3389;
client.connect(rdpport, aryServerIP[ip], function(){
console.log("socket connected to " + aryServerIP[ip] + ":" + rdpport);
client.destroy();
if (0 != ipcnt)
{
// do some real connection work about aryServerIP[ip].
ipcnt--;
}
});
client.on('error', function(){
console.log("fail to connect to " + aryServerIP[ip] + ":" + rdpport);
ipcnt--;
});
}
I know using ipcnt count to control the loop is bad, but I don't know how to control the Node.JS loop, when there's async function called in the loop...
Because your connect and error callbacks are both asynchronous, so they will both run after the for loop has completely finished.
What you need to do is set up a set of callbacks. For instance, rather than use a for loop, wrap your entire loop body in a function. If connect succeeds, then just do what you normally would, and if the error callback is called, then execute the wrapping function again. Something like this:
var async = require('async');
var net = require('net');
var rdpport = 3389;
function tryConnections(aryServerIP, callback){
function connect(i){
if (i === aryServerIP.length) return callback();
var client = new net.Socket();
client.connect(rdpport, aryServerIP[i], function(){
callback(client);
});
client.on('error', function(){
connect(i + 1)
});
}
connect(0)
}
tryConnections(serverip.split(";"), function(client){
if (client) // Successfully connected to something
else // all ips failed
});
Another solution would be to use the Async library.
function tryConnections(aryServerIP, callback){
async.detectSeries(aryServerIP, function(ip, cb){
var client = new net.Socket();
client.connect(rdpport, ip, function(){
cb(client);
});
client.on('error', function(){
cb();
});
}, callback);
}
I have a node.js server that pretty much runs a child process and sends the stdout from the process to connected clients via sockets. It is working just fine but when a client disconnects I cannot close the childprocess due to the var being outside the scope. Here is my sample code
var sys = require('sys'),
ws = require('./ws');
var server = ws.createServer(function (socket) {
socket.addListener("connect", function (resource) {
var counter = 0;
sys.puts("client connected from " + resource);
var spawn = require('child_process').spawn, tail = spawn('app');
sys.puts("Spawned child pid: "+ tail.pid);
tail.stdout.addListener('data', function(data) {
socket.write(JSON.stringify(data));
});
})
socket.addListener("close", function () {
//
// need to access the tail var here!!!
//
sys.puts("quit");
})
})
server.listen(3656)
In my close listener I need to access the tail variable so I can kill the process.
Move tail declaration one level up, from onConnect to createServer, since it is still the same instance:
ws.createServer(function(socket){
var tail;
socket.addListener("connect", function(resource){
tail = spawn("app");
...
});
socket.addListener("close", function(){
if(tail)
tail = null;
});
});