var Consumer = require('vfs-socket/consumer').Consumer; var inherits = require('util').inherits; var spawn = require('child_process').spawn; 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) { try { child = spawn(nodeBin[0], args, options).on("error", tryNext); } catch (e) { return tryNext(e); } child.stdin.readable = true; Consumer.prototype.connect.call(this, [child.stdout, child.stdin], tryNext); child.on("exit", disconnect); child.stdin.resume(); var _self = this; // try all possible locations of node before giving up function tryNext(err, vfs) { if (!child) return; child.removeListener("error", tryNext); child.on("error", function ignore() {}); if (err && err.code == "ENOENT" && nodeBin.length > 1) { child = null; nodeBin.shift(); _self.emit("error", err); _self.connect(callback); } else { callback(err, vfs); } } } // 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);