--- /dev/null
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+let net = require('net');
+let fs = require('fs');
+let ENABLE_LOGGING = false;
+let log = (function () {
+ if (!ENABLE_LOGGING) {
+ return function () { }; // tslint:disable-line
+ }
+ let isFirst = true;
+ let LOG_LOCATION = 'C:\\stdFork.log';
+ return function log(str) {
+ if (isFirst) {
+ isFirst = false;
+ fs.writeFileSync(LOG_LOCATION, str + '\n');
+ return;
+ }
+ fs.appendFileSync(LOG_LOCATION, str + '\n');
+ };
+})();
+let stdInPipeName = process.env['STDIN_PIPE_NAME']; // tslint:disable-line
+let stdOutPipeName = process.env['STDOUT_PIPE_NAME']; // tslint:disable-line
+let stdErrPipeName = process.env['STDERR_PIPE_NAME']; // tslint:disable-line
+log('STDIN_PIPE_NAME: ' + stdInPipeName);
+log('STDOUT_PIPE_NAME: ' + stdOutPipeName);
+log('STDERR_PIPE_NAME: ' + stdErrPipeName);
+(function () {
+ log('Beginning stdout redirection...');
+ // Create a writing stream to the stdout pipe
+ let stdOutStream = net.connect(stdOutPipeName);
+ // unref stdOutStream to behave like a normal standard out
+ stdOutStream.unref();
+ process.__defineGetter__('stdout', function () {
+ return stdOutStream;
+ });
+ // Create a writing stream to the stderr pipe
+ let stdErrStream = net.connect(stdErrPipeName);
+ // unref stdErrStream to behave like a normal standard out
+ stdErrStream.unref();
+ process.__defineGetter__('stderr', function () {
+ return stdErrStream;
+ });
+ let fsWriteSyncString = function (// tslint:disable-line
+ fd, str, _position, encoding) {
+ // fs.writeSync(fd, string[, position[, encoding]])
+ let buf = Buffer.from(str, encoding || 'utf8');
+ return fsWriteSyncBuffer(fd, buf, 0, buf.length); // tslint:disable-line
+ };
+ let fsWriteSyncBuffer = function (// tslint:disable-line
+ fd, buffer, off, len) {
+ off = Math.abs(off | 0);
+ len = Math.abs(len | 0);
+ // fs.writeSync(fd, buffer, offset, length[, position])
+ let buffer_length = buffer.length;
+ if (off > buffer_length) {
+ throw new Error('offset out of bounds');
+ }
+ if (len > buffer_length) {
+ throw new Error('length out of bounds');
+ }
+ if (((off + len) | 0) < off) {
+ throw new Error('off + len overflow');
+ }
+ if (buffer_length - off < len) {
+ // Asking for more than is left over in the buffer
+ throw new Error('off + len > buffer.length');
+ }
+ let slicedBuffer = buffer;
+ if (off !== 0 || len !== buffer_length) {
+ slicedBuffer = buffer.slice(off, off + len);
+ }
+ if (fd === 1) {
+ stdOutStream.write(slicedBuffer);
+ }
+ else {
+ stdErrStream.write(slicedBuffer);
+ }
+ return slicedBuffer.length;
+ };
+ // handle fs.writeSync(1, ...)
+ let originalWriteSync = fs.writeSync;
+ fs.writeSync = function (// tslint:disable-line
+ fd, data, _position, _encoding) {
+ if (fd !== 1 && fd !== 2) {
+ return originalWriteSync.apply(fs, arguments);
+ }
+ // usage:
+ // fs.writeSync(fd, buffer, offset, length[, position])
+ // OR
+ // fs.writeSync(fd, string[, position[, encoding]])
+ if (data instanceof Buffer) {
+ return fsWriteSyncBuffer.apply(null, arguments);
+ }
+ // For compatibility reasons with fs.writeSync, writing null will write "null", etc
+ if (typeof data !== 'string') {
+ data += '';
+ }
+ return fsWriteSyncString.apply(null, arguments);
+ };
+ log('Finished defining process.stdout, process.stderr and fs.writeSync');
+})();
+(function () {
+ // Begin listening to stdin pipe
+ let server = net.createServer(function (stream) {
+ // Stop accepting new connections, keep the existing one alive
+ server.close();
+ log('Parent process has connected to my stdin. All should be good now.');
+ process.__defineGetter__('stdin', function () {
+ return stream;
+ });
+ // Remove myself from process.argv
+ process.argv.splice(1, 1);
+ // Load the actual program
+ let program = process.argv[1];
+ log('Loading program: ' + program);
+ // Unset the custom environmental variables that should not get inherited
+ delete process.env['STDIN_PIPE_NAME']; // tslint:disable-line
+ delete process.env['STDOUT_PIPE_NAME']; // tslint:disable-line
+ delete process.env['STDERR_PIPE_NAME']; // tslint:disable-line
+ require(program);
+ log('Finished loading program.');
+ let stdinIsReferenced = true;
+ let timer = setInterval(function () {
+ let listenerCount = stream.listeners('data').length +
+ stream.listeners('end').length +
+ stream.listeners('close').length +
+ stream.listeners('error').length;
+ // log('listenerCount: ' + listenerCount)
+ if (listenerCount <= 1) {
+ // No more "actual" listeners, only internal node
+ if (stdinIsReferenced) {
+ stdinIsReferenced = false;
+ // log('unreferencing stream!!!')
+ stream.unref();
+ }
+ }
+ else {
+ // There are "actual" listeners
+ if (!stdinIsReferenced) {
+ stdinIsReferenced = true;
+ stream.ref();
+ }
+ }
+ // log(
+ // '' + stream.listeners('data').length +
+ // ' ' + stream.listeners('end').length +
+ // ' ' + stream.listeners('close').length +
+ // ' ' + stream.listeners('error').length
+ // )
+ }, 1000);
+ if (timer.unref) { // tslint:disable-line
+ timer.unref(); // tslint:disable-line
+ }
+ });
+ server.listen(stdInPipeName, function () {
+ // signal via stdout that the parent process can now begin writing to stdin pipe
+ process.stdout.write('ready');
+ });
+})();