-"use strict";
-/**
- * Copyright (c) 2012-2015, Christopher Jeffrey, Peter Sunde (MIT License)
- * Copyright (c) 2016, Daniel Imms (MIT License).
- * Copyright (c) 2018, Microsoft Corporation (MIT License).
- */
-Object.defineProperty(exports, "__esModule", { value: true });
-var os = require("os");
-var path = require("path");
-var net_1 = require("net");
-var child_process_1 = require("child_process");
-var conptyNative;
-var winptyNative;
-/**
- * The amount of time to wait for additional data after the conpty shell process has exited before
- * shutting down the socket. The timer will be reset if a new data event comes in after the timer
- * has started.
- */
-var FLUSH_DATA_INTERVAL = 20;
-/**
- * This agent sits between the WindowsTerminal class and provides a common interface for both conpty
- * and winpty.
- */
-var WindowsPtyAgent = /** @class */ (function () {
- function WindowsPtyAgent(file, args, env, cwd, cols, rows, debug, _useConpty, conptyInheritCursor) {
- var _this = this;
- if (conptyInheritCursor === void 0) { conptyInheritCursor = false; }
- this._useConpty = _useConpty;
- if (this._useConpty === undefined || this._useConpty === true) {
- this._useConpty = this._getWindowsBuildNumber() >= 18309;
- }
- if (this._useConpty) {
- if (!conptyNative) {
- try {
- conptyNative = require('../build/Release/conpty.node');
- }
- catch (outerError) {
- try {
- conptyNative = require('../build/Debug/conpty.node');
- }
- catch (innerError) {
- console.error('innerError', innerError);
- // Re-throw the exception from the Release require if the Debug require fails as well
- throw outerError;
- }
- }
- }
- }
- else {
- if (!winptyNative) {
- try {
- winptyNative = require('../build/Release/pty.node');
- }
- catch (outerError) {
- try {
- winptyNative = require('../build/Debug/pty.node');
- }
- catch (innerError) {
- console.error('innerError', innerError);
- // Re-throw the exception from the Release require if the Debug require fails as well
- throw outerError;
- }
- }
- }
- }
- this._ptyNative = this._useConpty ? conptyNative : winptyNative;
- // Sanitize input variable.
- cwd = path.resolve(cwd);
- // Compose command line
- var commandLine = argsToCommandLine(file, args);
- // Open pty session.
- var term;
- if (this._useConpty) {
- term = this._ptyNative.startProcess(file, cols, rows, debug, this._generatePipeName(), conptyInheritCursor);
- }
- else {
- term = this._ptyNative.startProcess(file, commandLine, env, cwd, cols, rows, debug);
- this._pid = term.pid;
- this._innerPid = term.innerPid;
- this._innerPidHandle = term.innerPidHandle;
- }
- // Not available on windows.
- this._fd = term.fd;
- // Generated incremental number that has no real purpose besides using it
- // as a terminal id.
- this._pty = term.pty;
- // Create terminal pipe IPC channel and forward to a local unix socket.
- this._outSocket = new net_1.Socket();
- this._outSocket.setEncoding('utf8');
- this._outSocket.connect(term.conout, function () {
- // TODO: Emit event on agent instead of socket?
- // Emit ready event.
- _this._outSocket.emit('ready_datapipe');
- });
- this._inSocket = new net_1.Socket();
- this._inSocket.setEncoding('utf8');
- this._inSocket.connect(term.conin);
- // TODO: Wait for ready event?
- if (this._useConpty) {
- var connect = this._ptyNative.connect(this._pty, commandLine, cwd, env, function (c) { return _this._$onProcessExit(c); });
- this._innerPid = connect.pid;
- }
- }
- Object.defineProperty(WindowsPtyAgent.prototype, "inSocket", {
- get: function () { return this._inSocket; },
- enumerable: true,
- configurable: true
- });
- Object.defineProperty(WindowsPtyAgent.prototype, "outSocket", {
- get: function () { return this._outSocket; },
- enumerable: true,
- configurable: true
- });
- Object.defineProperty(WindowsPtyAgent.prototype, "fd", {
- get: function () { return this._fd; },
- enumerable: true,
- configurable: true
- });
- Object.defineProperty(WindowsPtyAgent.prototype, "innerPid", {
- get: function () { return this._innerPid; },
- enumerable: true,
- configurable: true
- });
- Object.defineProperty(WindowsPtyAgent.prototype, "pty", {
- get: function () { return this._pty; },
- enumerable: true,
- configurable: true
- });
- WindowsPtyAgent.prototype.resize = function (cols, rows) {
- if (this._useConpty) {
- if (this._exitCode !== undefined) {
- throw new Error('Cannot resize a pty that has already exited');
- }
- this._ptyNative.resize(this._pty, cols, rows);
- return;
- }
- this._ptyNative.resize(this._pid, cols, rows);
- };
- WindowsPtyAgent.prototype.kill = function () {
- var _this = this;
- this._inSocket.readable = false;
- this._inSocket.writable = false;
- this._outSocket.readable = false;
- this._outSocket.writable = false;
- // Tell the agent to kill the pty, this releases handles to the process
- if (this._useConpty) {
- this._getConsoleProcessList().then(function (consoleProcessList) {
- consoleProcessList.forEach(function (pid) {
- try {
- process.kill(pid);
- }
- catch (e) {
- // Ignore if process cannot be found (kill ESRCH error)
- }
- });
- _this._ptyNative.kill(_this._pty);
- });
- }
- else {
- this._ptyNative.kill(this._pid, this._innerPidHandle);
- // Since pty.kill closes the handle it will kill most processes by itself
- // and process IDs can be reused as soon as all handles to them are
- // dropped, we want to immediately kill the entire console process list.
- // If we do not force kill all processes here, node servers in particular
- // seem to become detached and remain running (see
- // Microsoft/vscode#26807).
- var processList = this._ptyNative.getProcessList(this._pid);
- processList.forEach(function (pid) {
- try {
- process.kill(pid);
- }
- catch (e) {
- // Ignore if process cannot be found (kill ESRCH error)
- }
- });
- }
- };
- WindowsPtyAgent.prototype._getConsoleProcessList = function () {
- var _this = this;
- return new Promise(function (resolve) {
- var agent = child_process_1.fork(path.join(__dirname, 'conpty_console_list_agent'), [_this._innerPid.toString()]);
- agent.on('message', function (message) {
- clearTimeout(timeout);
- resolve(message.consoleProcessList);
- });
- var timeout = setTimeout(function () {
- // Something went wrong, just send back the shell PID
- agent.kill();
- resolve([_this._innerPid]);
- }, 5000);
- });
- };
- Object.defineProperty(WindowsPtyAgent.prototype, "exitCode", {
- get: function () {
- if (this._useConpty) {
- return this._exitCode;
- }
- return this._ptyNative.getExitCode(this._innerPidHandle);
- },
- enumerable: true,
- configurable: true
- });
- WindowsPtyAgent.prototype._getWindowsBuildNumber = function () {
- var osVersion = (/(\d+)\.(\d+)\.(\d+)/g).exec(os.release());
- var buildNumber = 0;
- if (osVersion && osVersion.length === 4) {
- buildNumber = parseInt(osVersion[3]);
- }
- return buildNumber;
- };
- WindowsPtyAgent.prototype._generatePipeName = function () {
- return "conpty-" + Math.random() * 10000000;
- };
- /**
- * Triggered from the native side when a contpy process exits.
- */
- WindowsPtyAgent.prototype._$onProcessExit = function (exitCode) {
- var _this = this;
- this._exitCode = exitCode;
- this._flushDataAndCleanUp();
- this._outSocket.on('data', function () { return _this._flushDataAndCleanUp(); });
- };
- WindowsPtyAgent.prototype._flushDataAndCleanUp = function () {
- var _this = this;
- if (this._closeTimeout) {
- clearTimeout(this._closeTimeout);
- }
- this._closeTimeout = setTimeout(function () { return _this._cleanUpProcess(); }, FLUSH_DATA_INTERVAL);
- };
- WindowsPtyAgent.prototype._cleanUpProcess = function () {
- this._inSocket.readable = false;
- this._inSocket.writable = false;
- this._outSocket.readable = false;
- this._outSocket.writable = false;
- this._outSocket.destroy();
- };
- return WindowsPtyAgent;
-}());
-exports.WindowsPtyAgent = WindowsPtyAgent;
-// Convert argc/argv into a Win32 command-line following the escaping convention
-// documented on MSDN (e.g. see CommandLineToArgvW documentation). Copied from
-// winpty project.
-function argsToCommandLine(file, args) {
- if (isCommandLine(args)) {
- if (args.length === 0) {
- return file;
- }
- return argsToCommandLine(file, []) + " " + args;
- }
- var argv = [file];
- Array.prototype.push.apply(argv, args);
- var result = '';
- for (var argIndex = 0; argIndex < argv.length; argIndex++) {
- if (argIndex > 0) {
- result += ' ';
- }
- var arg = argv[argIndex];
- // if it is empty or it contains whitespace and is not already quoted
- var hasLopsidedEnclosingQuote = xOr((arg[0] !== '"'), (arg[arg.length - 1] !== '"'));
- var hasNoEnclosingQuotes = ((arg[0] !== '"') && (arg[arg.length - 1] !== '"'));
- var quote = arg === '' ||
- (arg.indexOf(' ') !== -1 ||
- arg.indexOf('\t') !== -1) &&
- ((arg.length > 1) &&
- (hasLopsidedEnclosingQuote || hasNoEnclosingQuotes));
- if (quote) {
- result += '\"';
- }
- var bsCount = 0;
- for (var i = 0; i < arg.length; i++) {
- var p = arg[i];
- if (p === '\\') {
- bsCount++;
- }
- else if (p === '"') {
- result += repeatText('\\', bsCount * 2 + 1);
- result += '"';
- bsCount = 0;
- }
- else {
- result += repeatText('\\', bsCount);
- bsCount = 0;
- result += p;
- }
- }
- if (quote) {
- result += repeatText('\\', bsCount * 2);
- result += '\"';
- }
- else {
- result += repeatText('\\', bsCount);
- }
- }
- return result;
-}
-exports.argsToCommandLine = argsToCommandLine;
-function isCommandLine(args) {
- return typeof args === 'string';
-}
-function repeatText(text, count) {
- var result = '';
- for (var i = 0; i < count; i++) {
- result += text;
- }
- return result;
-}
-function xOr(arg1, arg2) {
- return ((arg1 && !arg2) || (!arg1 && arg2));
-}
-//# sourceMappingURL=windowsPtyAgent.js.map
\ No newline at end of file