/* -------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. * ------------------------------------------------------------------------------------------ */ 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); const path = require("path"); const os = require("os"); const net = require("net"); const cp = require("child_process"); function makeRandomHexString(length) { let chars = ['0', '1', '2', '3', '4', '5', '6', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; let result = ''; for (let i = 0; i < length; i++) { let idx = Math.floor(chars.length * Math.random()); result += chars[idx]; } return result; } function generatePipeName() { let randomName = 'vscode-lang-' + makeRandomHexString(40); if (process.platform === 'win32') { return '\\\\.\\pipe\\' + randomName + '-sock'; } // Mac/Unix: use socket file return path.join(os.tmpdir(), randomName + '.sock'); } function generatePatchedEnv(env, stdInPipeName, stdOutPipeName) { // Set the two unique pipe names and the electron flag as process env let newEnv = {}; for (let key in env) { newEnv[key] = env[key]; } newEnv['STDIN_PIPE_NAME'] = stdInPipeName; newEnv['STDOUT_PIPE_NAME'] = stdOutPipeName; newEnv['ATOM_SHELL_INTERNAL_RUN_AS_NODE'] = '1'; newEnv['ELECTRON_RUN_AS_NODE'] = '1'; return newEnv; } function fork(modulePath, args, options, callback) { let callbackCalled = false; let resolve = (result) => { if (callbackCalled) { return; } callbackCalled = true; callback(undefined, result); }; let reject = (err) => { if (callbackCalled) { return; } callbackCalled = true; callback(err, undefined); }; // Generate two unique pipe names let stdInPipeName = generatePipeName(); let stdOutPipeName = generatePipeName(); let newEnv = generatePatchedEnv(options.env || process.env, stdInPipeName, stdOutPipeName); let childProcess; // Begin listening to stdout pipe let stdOutServer = net.createServer((stdOutStream) => { // The child process will write exactly one chunk with content `ready` when it has installed a listener to the stdin pipe stdOutStream.once('data', (_chunk) => { // The child process is sending me the `ready` chunk, time to connect to the stdin pipe childProcess.stdin = net.connect(stdInPipeName); // From now on the childProcess.stdout is available for reading childProcess.stdout = stdOutStream; resolve(childProcess); }); }); stdOutServer.listen(stdOutPipeName); let serverClosed = false; let closeServer = () => { if (serverClosed) { return; } serverClosed = true; process.removeListener('exit', closeServer); stdOutServer.close(); }; // Create the process let bootstrapperPath = path.join(__dirname, 'electronForkStart'); childProcess = cp.fork(bootstrapperPath, [modulePath].concat(args), { silent: true, cwd: options.cwd, env: newEnv, execArgv: options.execArgv }); childProcess.once('error', (err) => { closeServer(); reject(err); }); childProcess.once('exit', (err) => { closeServer(); reject(err); }); // On exit still close server process.once('exit', closeServer); } exports.fork = fork;