1 /*---------------------------------------------------------------------------------------------
2 * Copyright (c) Microsoft Corporation. All rights reserved.
3 * Licensed under the MIT License. See License.txt in the project root for license information.
4 *--------------------------------------------------------------------------------------------*/
5 let net = require('net');
6 let fs = require('fs');
7 let ENABLE_LOGGING = false;
8 let log = (function () {
10 return function () { }; // tslint:disable-line
13 let LOG_LOCATION = 'C:\\stdFork.log';
14 return function log(str) {
17 fs.writeFileSync(LOG_LOCATION, str + '\n');
20 fs.appendFileSync(LOG_LOCATION, str + '\n');
23 let stdInPipeName = process.env['STDIN_PIPE_NAME']; // tslint:disable-line
24 let stdOutPipeName = process.env['STDOUT_PIPE_NAME']; // tslint:disable-line
25 let stdErrPipeName = process.env['STDERR_PIPE_NAME']; // tslint:disable-line
26 log('STDIN_PIPE_NAME: ' + stdInPipeName);
27 log('STDOUT_PIPE_NAME: ' + stdOutPipeName);
28 log('STDERR_PIPE_NAME: ' + stdErrPipeName);
30 log('Beginning stdout redirection...');
31 // Create a writing stream to the stdout pipe
32 let stdOutStream = net.connect(stdOutPipeName);
33 // unref stdOutStream to behave like a normal standard out
35 process.__defineGetter__('stdout', function () {
38 // Create a writing stream to the stderr pipe
39 let stdErrStream = net.connect(stdErrPipeName);
40 // unref stdErrStream to behave like a normal standard out
42 process.__defineGetter__('stderr', function () {
45 let fsWriteSyncString = function (// tslint:disable-line
46 fd, str, _position, encoding) {
47 // fs.writeSync(fd, string[, position[, encoding]])
48 let buf = Buffer.from(str, encoding || 'utf8');
49 return fsWriteSyncBuffer(fd, buf, 0, buf.length); // tslint:disable-line
51 let fsWriteSyncBuffer = function (// tslint:disable-line
52 fd, buffer, off, len) {
53 off = Math.abs(off | 0);
54 len = Math.abs(len | 0);
55 // fs.writeSync(fd, buffer, offset, length[, position])
56 let buffer_length = buffer.length;
57 if (off > buffer_length) {
58 throw new Error('offset out of bounds');
60 if (len > buffer_length) {
61 throw new Error('length out of bounds');
63 if (((off + len) | 0) < off) {
64 throw new Error('off + len overflow');
66 if (buffer_length - off < len) {
67 // Asking for more than is left over in the buffer
68 throw new Error('off + len > buffer.length');
70 let slicedBuffer = buffer;
71 if (off !== 0 || len !== buffer_length) {
72 slicedBuffer = buffer.slice(off, off + len);
75 stdOutStream.write(slicedBuffer);
78 stdErrStream.write(slicedBuffer);
80 return slicedBuffer.length;
82 // handle fs.writeSync(1, ...)
83 let originalWriteSync = fs.writeSync;
84 fs.writeSync = function (// tslint:disable-line
85 fd, data, _position, _encoding) {
86 if (fd !== 1 && fd !== 2) {
87 return originalWriteSync.apply(fs, arguments);
90 // fs.writeSync(fd, buffer, offset, length[, position])
92 // fs.writeSync(fd, string[, position[, encoding]])
93 if (data instanceof Buffer) {
94 return fsWriteSyncBuffer.apply(null, arguments);
96 // For compatibility reasons with fs.writeSync, writing null will write "null", etc
97 if (typeof data !== 'string') {
100 return fsWriteSyncString.apply(null, arguments);
102 log('Finished defining process.stdout, process.stderr and fs.writeSync');
105 // Begin listening to stdin pipe
106 let server = net.createServer(function (stream) {
107 // Stop accepting new connections, keep the existing one alive
109 log('Parent process has connected to my stdin. All should be good now.');
110 process.__defineGetter__('stdin', function () {
113 // Remove myself from process.argv
114 process.argv.splice(1, 1);
115 // Load the actual program
116 let program = process.argv[1];
117 log('Loading program: ' + program);
118 // Unset the custom environmental variables that should not get inherited
119 delete process.env['STDIN_PIPE_NAME']; // tslint:disable-line
120 delete process.env['STDOUT_PIPE_NAME']; // tslint:disable-line
121 delete process.env['STDERR_PIPE_NAME']; // tslint:disable-line
123 log('Finished loading program.');
124 let stdinIsReferenced = true;
125 let timer = setInterval(function () {
126 let listenerCount = stream.listeners('data').length +
127 stream.listeners('end').length +
128 stream.listeners('close').length +
129 stream.listeners('error').length;
130 // log('listenerCount: ' + listenerCount)
131 if (listenerCount <= 1) {
132 // No more "actual" listeners, only internal node
133 if (stdinIsReferenced) {
134 stdinIsReferenced = false;
135 // log('unreferencing stream!!!')
140 // There are "actual" listeners
141 if (!stdinIsReferenced) {
142 stdinIsReferenced = true;
147 // '' + stream.listeners('data').length +
148 // ' ' + stream.listeners('end').length +
149 // ' ' + stream.listeners('close').length +
150 // ' ' + stream.listeners('error').length
153 if (timer.unref) { // tslint:disable-line
154 timer.unref(); // tslint:disable-line
157 server.listen(stdInPipeName, function () {
158 // signal via stdout that the parent process can now begin writing to stdin pipe
159 process.stdout.write('ready');