var Consumer = require('vfs-socket/consumer').Consumer; var inherits = require('util').inherits; var spawn = require('child_process').spawn; var fs = require("fs"); exports.Parent = Parent; function Parent(fsOptions) { Consumer.call(this); var options = {}; if (fsOptions.hasOwnProperty("gid")) { options.gid = fsOptions.gid; delete fsOptions.gid; } if (fsOptions.hasOwnProperty("uid")) { options.uid = fsOptions.uid; delete fsOptions.uid; } options.stdio = options.customFds = [-1, -1, 2]; var args = [require.resolve('./child.js'), JSON.stringify(fsOptions)]; var nodeBin = fsOptions.nodeBin || [process.execPath]; var child; // Override Consumer's connect since the transport logic is internal to this module this.connect = connect.bind(this); function connect(callback) { var _self = this; try { if (!fs.existsSync(nodeBin[0])) return tryNext(new Error("Couldn't find valid node binary")); child = spawn(nodeBin[0], args, options).on("error", tryNext); } catch (e) { return done(e); } child.stdin.readable = true; Consumer.prototype.connect.call(this, [child.stdout, child.stdin], done); child.on("exit", disconnect); child.stdin.resume(); function tryNext(err) { if (nodeBin.length > 1) { nodeBin.shift(); _self.emit("error", err); _self.connect(callback); } else { return done(err); } } function done(err, vfs) { if (!callback) return; child.removeListener("error", done); child.on("error", function ignore(err) {}); callback(err, vfs); callback = null; } } // Override Consumer's disconnect to kill the child process afterwards this.disconnect = disconnect.bind(this); function disconnect() { if (!this.transport) return; Consumer.prototype.disconnect.apply(this, arguments); child.kill(); } if (fsOptions.inProcess) { this.connect = function(callback) { var vfs = require('vfs-local')(fsOptions); setImmediate(function(){ callback(null, vfs); }); }; } } inherits(Parent, Consumer);