Skip to content

Instantly share code, notes, and snippets.

@pyhedgehog
Forked from Marak/child.js
Last active October 1, 2015 14:27
Show Gist options
  • Save pyhedgehog/84088623e8afc508d005 to your computer and use it in GitHub Desktop.
Save pyhedgehog/84088623e8afc508d005 to your computer and use it in GitHub Desktop.
Child pipe second attempt

Pros:

  1. (against stdin/stdout usage) Leaves stdin for request data, stdout for response and stderr for logging.
  2. Uses standard Node child_process.spawn options.stdio[3]='ipc' technique.

Cons:

  1. Right now uses '\n' as separator - it's original flaw of Node 'ipc' implementation.
  2. Unportable: Node 'ipc' uses different implementation for different OSes. I.e. on Windows it uses named pipes and I've failed to fix child.py to work on windows. I can't ever imagine what it will be on Mac.
  3. Incompatible: Node 'ipc' can send handle via this socket. I had not yet found how it's implemented.
#!node
var fs = request('fs');
var util = require('util');
var Buffer = request('buffer').Buffer;
var events = request('events');
function PipeParentApi() {
var self = this;
this.waitlen = 0;
this.wait = null;
this.apiin = fs.createReadStream(null, {fd:3, flags:'r', encoding:'binary'});
this.apiout = fs.createWriteStream(null, {fd:4, flags:'w', defaultEncoding:'binary'});
this.apiin.on('data', function(data) {
var pos = 0, datastr, dataobj;
function handleData(buf) {
var datastr = buf.toString('utf-8');
var dataobj = JSON.parse(datastr);
}
while(pos < data.length)
if(self.waitlen == 0) {
self.waitlen = data.readUInt32LE(pos);
pos += 4;
if(data.length-pos>=self.waitlen) {
self.wait = null;
datastr = data.toString('utf-8', pos, pos+self.waitlen);
pos += self.waitlen;
dataobj = JSON.parse(datastr);
self.emit('message', dataobj);
}
}
})
events.EventEmitter.call(this);
}
util.inherits(PipeParentApi, events.EventEmitter);
PipeParentApi.prototype.send = function(data) {
var buf = new Buffer(JSON.stringify(data), 'utf-8');
var lbuf = new Buffer(4);
lbuf.writeUInt32LE(buf.length);
this.apiout.write(lbuf);
this.apiout.write(buf);
}
api = PipeParentApi();
api.on('message', function(json) {
console.log('parent->child message passed', json);
api.send({type:'got', payload:json});
if(json.type === 'exit') process.exit(0);
});
#!/usr/bin/env python
import os
import sys
import socket
import pprint
import json
#pprint.pprint(dict(os.environ))
#print 'NODE_CHANNEL_FD =', os.environ.get('NODE_CHANNEL_FD')
fd = int(os.environ['NODE_CHANNEL_FD'])
if sys.platform == 'win32':
apiin = os.fdopen(fd, 'r')
apiout = os.fdopen(fd+1, 'w')
else:
api = socket.fromfd(fd, socket.AF_UNIX, socket.SOCK_STREAM)
apiin = api.makefile('r')
apiout = api.makefile('w')
while True:
data = apiin.readline()
data = json.loads(data)
print 'parent->child message passed', data
apiout.write(json.dumps({"type":"got", "payload":data})+'\n')
apiout.flush()
if data.get("type") == "exit":
break
#!node
var util = require('util');
var spawn = require('child_process').spawn;
//console.log(process.argv);
var action = process.argv[2]||'py';
//console.log('action =', action);
var child;
if(action === 'py') {
var proc = 'python';
var args = ['child.py'];
if(process.platform == 'win32') {
proc = 'py';
args = ['-2', 'child.py'];
//args = ['-3', 'child.py'];
}
//console.log(proc, args);
child = spawn(proc, args, {stdio:[0, 1, 2, 'ipc']});
} else if(action === 'js') {
child = spawn(process.execPath, ['child.js'], {stdio:[0, 1, 2, 'ipc']});
} else if(action === 'pfiles') {
child = spawn(action, [process.pid], {stdio:[0, 1, 2, 'ipc']});
} else if(action === 'pfiles1') {
child = spawn('sh', ['-c', 'exec pfiles $$'], {stdio:[0, 1, 2, 'ipc']});
} else {
child = spawn(action, [], {stdio:[0, 1, 2, 'ipc']});
}
//child.stdout.on('data', function (data) {
// console.log('stdout: ' + data);
//});
//child.stderr.on('data', function (data) {
// console.log('stderr: ' + data);
//});
child.on('close', function (code) {
console.log('child process exited with code ' + code);
});
child.on('error', function (err) {
console.log('child process not started with error ' + err);
});
child.on('message', function(json) {
console.log('child->parent message passed', json);
});
//console.log('child', child);
//console.log('child.stdio', child.stdio);
child.send({type:'intro'});
setTimeout(function() {
child.send({type:'exit'});
}, 1500);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment