node-pty 1.2.0-beta.7 → 1.2.0-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/binding.gyp +20 -18
  2. package/lib/unixTerminal.js +5 -2
  3. package/lib/windowsTerminal.js +1 -1
  4. package/package.json +6 -5
  5. package/prebuilds/darwin-arm64/pty.node +0 -0
  6. package/prebuilds/darwin-arm64/spawn-helper +0 -0
  7. package/prebuilds/darwin-x64/pty.node +0 -0
  8. package/prebuilds/darwin-x64/spawn-helper +0 -0
  9. package/prebuilds/linux-arm64/pty.node +0 -0
  10. package/prebuilds/linux-x64/pty.node +0 -0
  11. package/prebuilds/win32-arm64/conpty.node +0 -0
  12. package/prebuilds/win32-arm64/conpty.pdb +0 -0
  13. package/prebuilds/win32-arm64/conpty_console_list.node +0 -0
  14. package/prebuilds/win32-arm64/conpty_console_list.pdb +0 -0
  15. package/prebuilds/win32-x64/conpty.node +0 -0
  16. package/prebuilds/win32-x64/conpty.pdb +0 -0
  17. package/prebuilds/win32-x64/conpty_console_list.node +0 -0
  18. package/prebuilds/win32-x64/conpty_console_list.pdb +0 -0
  19. package/src/unix/pty.cc +7 -5
  20. package/typings/node-pty.d.ts +4 -1
  21. package/deps/.editorconfig +0 -2
  22. package/lib/conpty_console_list_agent.js.map +0 -1
  23. package/lib/eventEmitter2.js.map +0 -1
  24. package/lib/eventEmitter2.test.js +0 -30
  25. package/lib/eventEmitter2.test.js.map +0 -1
  26. package/lib/index.js.map +0 -1
  27. package/lib/interfaces.js.map +0 -1
  28. package/lib/shared/conout.js.map +0 -1
  29. package/lib/terminal.js.map +0 -1
  30. package/lib/terminal.test.js +0 -139
  31. package/lib/terminal.test.js.map +0 -1
  32. package/lib/testUtils.test.js +0 -28
  33. package/lib/testUtils.test.js.map +0 -1
  34. package/lib/types.js.map +0 -1
  35. package/lib/unixTerminal.js.map +0 -1
  36. package/lib/unixTerminal.test.js +0 -383
  37. package/lib/unixTerminal.test.js.map +0 -1
  38. package/lib/utils.js.map +0 -1
  39. package/lib/windowsConoutConnection.js.map +0 -1
  40. package/lib/windowsPtyAgent.js.map +0 -1
  41. package/lib/windowsPtyAgent.test.js +0 -90
  42. package/lib/windowsPtyAgent.test.js.map +0 -1
  43. package/lib/windowsTerminal.js.map +0 -1
  44. package/lib/windowsTerminal.test.js +0 -218
  45. package/lib/windowsTerminal.test.js.map +0 -1
  46. package/lib/worker/conoutSocketWorker.js.map +0 -1
  47. package/scripts/gen-compile-commands.js +0 -8
  48. package/scripts/increment-version.js +0 -54
  49. package/scripts/linux/checksums.txt +0 -2
  50. package/scripts/linux/install-sysroot.js +0 -158
  51. package/scripts/linux/verify-glibc-requirements.sh +0 -36
  52. package/src/conpty_console_list_agent.ts +0 -15
  53. package/src/eventEmitter2.test.ts +0 -30
  54. package/src/eventEmitter2.ts +0 -48
  55. package/src/index.ts +0 -52
  56. package/src/interfaces.ts +0 -138
  57. package/src/native.d.ts +0 -37
  58. package/src/shared/conout.ts +0 -15
  59. package/src/terminal.test.ts +0 -119
  60. package/src/terminal.ts +0 -211
  61. package/src/testUtils.test.ts +0 -23
  62. package/src/tsconfig.json +0 -22
  63. package/src/types.ts +0 -15
  64. package/src/unixTerminal.test.ts +0 -402
  65. package/src/unixTerminal.ts +0 -388
  66. package/src/utils.ts +0 -29
  67. package/src/windowsConoutConnection.ts +0 -82
  68. package/src/windowsPtyAgent.test.ts +0 -94
  69. package/src/windowsPtyAgent.ts +0 -261
  70. package/src/windowsTerminal.test.ts +0 -229
  71. package/src/windowsTerminal.ts +0 -203
  72. package/src/worker/conoutSocketWorker.ts +0 -22
@@ -1,261 +0,0 @@
1
- /**
2
- * Copyright (c) 2012-2015, Christopher Jeffrey, Peter Sunde (MIT License)
3
- * Copyright (c) 2016, Daniel Imms (MIT License).
4
- * Copyright (c) 2018, Microsoft Corporation (MIT License).
5
- */
6
-
7
- import * as fs from 'fs';
8
- import * as path from 'path';
9
- import { fork } from 'child_process';
10
- import { Socket } from 'net';
11
- import { ArgvOrCommandLine } from './types';
12
- import { ConoutConnection } from './windowsConoutConnection';
13
- import { loadNativeModule } from './utils';
14
-
15
- let conptyNative: IConptyNative;
16
-
17
- /**
18
- * The amount of time to wait for additional data after the conpty shell process has exited before
19
- * shutting down the socket. The timer will be reset if a new data event comes in after the timer
20
- * has started.
21
- */
22
- const FLUSH_DATA_INTERVAL = 1000;
23
-
24
- /**
25
- * This agent sits between the WindowsTerminal class and provides an interface for conpty.
26
- */
27
- export class WindowsPtyAgent {
28
- private _inSocket: Socket;
29
- private _outSocket: Socket;
30
- private _innerPid: number = 0;
31
- private _closeTimeout: NodeJS.Timer | undefined;
32
- private _exitCode: number | undefined;
33
- private _conoutSocketWorker: ConoutConnection;
34
-
35
- private _fd: any;
36
- private _pty: number;
37
- private _ptyNative: IConptyNative;
38
-
39
- public get inSocket(): Socket { return this._inSocket; }
40
- public get outSocket(): Socket { return this._outSocket; }
41
- public get fd(): any { return this._fd; }
42
- public get innerPid(): number { return this._innerPid; }
43
- public get pty(): number { return this._pty; }
44
-
45
- constructor(
46
- file: string,
47
- args: ArgvOrCommandLine,
48
- env: string[],
49
- cwd: string,
50
- cols: number,
51
- rows: number,
52
- debug: boolean,
53
- private _useConptyDll: boolean = false,
54
- conptyInheritCursor: boolean = false
55
- ) {
56
- if (!conptyNative) {
57
- conptyNative = loadNativeModule('conpty').module;
58
- }
59
- this._ptyNative = conptyNative;
60
-
61
- // Sanitize input variable.
62
- cwd = path.resolve(cwd);
63
-
64
- // Compose command line
65
- const commandLine = argsToCommandLine(file, args);
66
-
67
- // Open pty session.
68
- const term: IConptyProcess = conptyNative.startProcess(file, cols, rows, debug, this._generatePipeName(), conptyInheritCursor, this._useConptyDll);
69
-
70
- // Not available on windows.
71
- this._fd = term.fd;
72
-
73
- // Generated incremental number that has no real purpose besides using it
74
- // as a terminal id.
75
- this._pty = term.pty;
76
-
77
- // Create terminal pipe IPC channel and forward to a local unix socket.
78
- this._outSocket = new Socket();
79
- this._outSocket.setEncoding('utf8');
80
- // The conout socket must be ready out on another thread to avoid deadlocks
81
- this._conoutSocketWorker = new ConoutConnection(term.conout, this._useConptyDll);
82
- this._conoutSocketWorker.onReady(() => {
83
- this._conoutSocketWorker.connectSocket(this._outSocket);
84
- });
85
- this._outSocket.on('connect', () => {
86
- this._outSocket.emit('ready_datapipe');
87
- });
88
-
89
- const inSocketFD = fs.openSync(term.conin, 'w');
90
- this._inSocket = new Socket({
91
- fd: inSocketFD,
92
- readable: false,
93
- writable: true
94
- });
95
- this._inSocket.setEncoding('utf8');
96
-
97
- const connect = conptyNative.connect(this._pty, commandLine, cwd, env, this._useConptyDll, c => this._$onProcessExit(c));
98
- this._innerPid = connect.pid;
99
- }
100
-
101
- public resize(cols: number, rows: number): void {
102
- if (this._exitCode !== undefined) {
103
- throw new Error('Cannot resize a pty that has already exited');
104
- }
105
- this._ptyNative.resize(this._pty, cols, rows, this._useConptyDll);
106
- }
107
-
108
- public clear(): void {
109
- this._ptyNative.clear(this._pty, this._useConptyDll);
110
- }
111
-
112
- public kill(): void {
113
- // Tell the agent to kill the pty, this releases handles to the process
114
- if (!this._useConptyDll) {
115
- this._inSocket.readable = false;
116
- this._outSocket.readable = false;
117
- this._getConsoleProcessList().then(consoleProcessList => {
118
- consoleProcessList.forEach((pid: number) => {
119
- try {
120
- process.kill(pid);
121
- } catch (e) {
122
- // Ignore if process cannot be found (kill ESRCH error)
123
- }
124
- });
125
- });
126
- this._ptyNative.kill(this._pty, this._useConptyDll);
127
- this._conoutSocketWorker.dispose();
128
- } else {
129
- // Close the input write handle to signal the end of session.
130
- this._inSocket.destroy();
131
- this._ptyNative.kill(this._pty, this._useConptyDll);
132
- this._outSocket.on('data', () => {
133
- this._conoutSocketWorker.dispose();
134
- });
135
- }
136
- }
137
-
138
- private _getConsoleProcessList(): Promise<number[]> {
139
- return new Promise<number[]>(resolve => {
140
- const agent = fork(path.join(__dirname, 'conpty_console_list_agent'), [ this._innerPid.toString() ]);
141
- agent.on('message', message => {
142
- clearTimeout(timeout);
143
- resolve(message.consoleProcessList);
144
- });
145
- const timeout = setTimeout(() => {
146
- // Something went wrong, just send back the shell PID
147
- agent.kill();
148
- resolve([ this._innerPid ]);
149
- }, 5000);
150
- });
151
- }
152
-
153
- public get exitCode(): number | undefined {
154
- return this._exitCode;
155
- }
156
-
157
- private _generatePipeName(): string {
158
- return `conpty-${Math.random() * 10000000}`;
159
- }
160
-
161
- /**
162
- * Triggered from the native side when a contpy process exits.
163
- */
164
- private _$onProcessExit(exitCode: number): void {
165
- this._exitCode = exitCode;
166
- if (!this._useConptyDll) {
167
- this._flushDataAndCleanUp();
168
- this._outSocket.on('data', () => this._flushDataAndCleanUp());
169
- }
170
- }
171
-
172
- private _flushDataAndCleanUp(): void {
173
- if (this._useConptyDll) {
174
- return;
175
- }
176
- if (this._closeTimeout) {
177
- clearTimeout(this._closeTimeout);
178
- }
179
- this._closeTimeout = setTimeout(() => this._cleanUpProcess(), FLUSH_DATA_INTERVAL);
180
- }
181
-
182
- private _cleanUpProcess(): void {
183
- if (this._useConptyDll) {
184
- return;
185
- }
186
- this._inSocket.readable = false;
187
- this._outSocket.readable = false;
188
- this._outSocket.destroy();
189
- }
190
- }
191
-
192
- // Convert argc/argv into a Win32 command-line following the escaping convention
193
- // documented on MSDN (e.g. see CommandLineToArgvW documentation). Copied from
194
- // winpty project.
195
- export function argsToCommandLine(file: string, args: ArgvOrCommandLine): string {
196
- if (isCommandLine(args)) {
197
- if (args.length === 0) {
198
- return file;
199
- }
200
- return `${argsToCommandLine(file, [])} ${args}`;
201
- }
202
- const argv = [file];
203
- Array.prototype.push.apply(argv, args);
204
- let result = '';
205
- for (let argIndex = 0; argIndex < argv.length; argIndex++) {
206
- if (argIndex > 0) {
207
- result += ' ';
208
- }
209
- const arg = argv[argIndex];
210
- // if it is empty or it contains whitespace and is not already quoted
211
- const hasLopsidedEnclosingQuote = xOr((arg[0] !== '"'), (arg[arg.length - 1] !== '"'));
212
- const hasNoEnclosingQuotes = ((arg[0] !== '"') && (arg[arg.length - 1] !== '"'));
213
- const quote =
214
- arg === '' ||
215
- (arg.indexOf(' ') !== -1 ||
216
- arg.indexOf('\t') !== -1) &&
217
- ((arg.length > 1) &&
218
- (hasLopsidedEnclosingQuote || hasNoEnclosingQuotes));
219
- if (quote) {
220
- result += '\"';
221
- }
222
- let bsCount = 0;
223
- for (let i = 0; i < arg.length; i++) {
224
- const p = arg[i];
225
- if (p === '\\') {
226
- bsCount++;
227
- } else if (p === '"') {
228
- result += repeatText('\\', bsCount * 2 + 1);
229
- result += '"';
230
- bsCount = 0;
231
- } else {
232
- result += repeatText('\\', bsCount);
233
- bsCount = 0;
234
- result += p;
235
- }
236
- }
237
- if (quote) {
238
- result += repeatText('\\', bsCount * 2);
239
- result += '\"';
240
- } else {
241
- result += repeatText('\\', bsCount);
242
- }
243
- }
244
- return result;
245
- }
246
-
247
- function isCommandLine(args: ArgvOrCommandLine): args is string {
248
- return typeof args === 'string';
249
- }
250
-
251
- function repeatText(text: string, count: number): string {
252
- let result = '';
253
- for (let i = 0; i < count; i++) {
254
- result += text;
255
- }
256
- return result;
257
- }
258
-
259
- function xOr(arg1: boolean, arg2: boolean): boolean {
260
- return ((arg1 && !arg2) || (!arg1 && arg2));
261
- }
@@ -1,229 +0,0 @@
1
- /**
2
- * Copyright (c) 2017, Daniel Imms (MIT License).
3
- * Copyright (c) 2018, Microsoft Corporation (MIT License).
4
- */
5
-
6
- import * as fs from 'fs';
7
- import * as assert from 'assert';
8
- import { WindowsTerminal } from './windowsTerminal';
9
- import * as path from 'path';
10
- import * as psList from 'ps-list';
11
-
12
- interface IProcessState {
13
- // Whether the PID must exist or must not exist
14
- [pid: number]: boolean;
15
- }
16
-
17
- interface IWindowsProcessTreeResult {
18
- name: string;
19
- pid: number;
20
- }
21
-
22
- function pollForProcessState(desiredState: IProcessState, intervalMs: number = 100, timeoutMs: number = 2000): Promise<void> {
23
- return new Promise<void>(resolve => {
24
- let tries = 0;
25
- const interval = setInterval(() => {
26
- psList({ all: true }).then(ps => {
27
- let success = true;
28
- const pids = Object.keys(desiredState).map(k => parseInt(k, 10));
29
- console.log('expected pids', JSON.stringify(pids));
30
- pids.forEach(pid => {
31
- if (desiredState[pid]) {
32
- if (!ps.some(p => p.pid === pid)) {
33
- console.log(`pid ${pid} does not exist`);
34
- success = false;
35
- }
36
- } else {
37
- if (ps.some(p => p.pid === pid)) {
38
- console.log(`pid ${pid} still exists`);
39
- success = false;
40
- }
41
- }
42
- });
43
- if (success) {
44
- clearInterval(interval);
45
- resolve();
46
- return;
47
- }
48
- tries++;
49
- if (tries * intervalMs >= timeoutMs) {
50
- clearInterval(interval);
51
- const processListing = pids.map(k => `${k}: ${desiredState[k]}`).join('\n');
52
- assert.fail(`Bad process state, expected:\n${processListing}`);
53
- resolve();
54
- }
55
- });
56
- }, intervalMs);
57
- });
58
- }
59
-
60
- function pollForProcessTreeSize(pid: number, size: number, intervalMs: number = 100, timeoutMs: number = 2000): Promise<IWindowsProcessTreeResult[]> {
61
- return new Promise<IWindowsProcessTreeResult[]>(resolve => {
62
- let tries = 0;
63
- const interval = setInterval(() => {
64
- psList({ all: true }).then(ps => {
65
- const openList: IWindowsProcessTreeResult[] = [];
66
- openList.push(ps.filter(p => p.pid === pid).map(p => {
67
- return { name: p.name, pid: p.pid };
68
- })[0]);
69
- const list: IWindowsProcessTreeResult[] = [];
70
- while (openList.length) {
71
- const current = openList.shift()!;
72
- ps.filter(p => p.ppid === current.pid).map(p => {
73
- return { name: p.name, pid: p.pid };
74
- }).forEach(p => openList.push(p));
75
- list.push(current);
76
- }
77
- console.log('list', JSON.stringify(list));
78
- const success = list.length === size;
79
- if (success) {
80
- clearInterval(interval);
81
- resolve(list);
82
- return;
83
- }
84
- tries++;
85
- if (tries * intervalMs >= timeoutMs) {
86
- clearInterval(interval);
87
- assert.fail(`Bad process state, expected: ${size}, actual: ${list.length}`);
88
- }
89
- });
90
- }, intervalMs);
91
- });
92
- }
93
-
94
- if (process.platform === 'win32') {
95
- [false, true].forEach((useConptyDll) => {
96
- describe(`WindowsTerminal (useConptyDll = ${useConptyDll})`, () => {
97
- describe('kill', () => {
98
- it('should not crash parent process', function (done) {
99
- this.timeout(20000);
100
- const term = new WindowsTerminal('cmd.exe', [], { useConptyDll });
101
- term.on('exit', () => done());
102
- term.kill();
103
- });
104
- it('should kill the process tree', function (done: Mocha.Done): void {
105
- this.timeout(20000);
106
- const term = new WindowsTerminal('cmd.exe', [], { useConptyDll });
107
- // Start sub-processes
108
- term.write('powershell.exe\r');
109
- term.write('node.exe\r');
110
- console.log('start poll for tree size');
111
- pollForProcessTreeSize(term.pid, 3, 500, 5000).then(list => {
112
- assert.strictEqual(list[0].name.toLowerCase(), 'cmd.exe');
113
- assert.strictEqual(list[1].name.toLowerCase(), 'powershell.exe');
114
- assert.strictEqual(list[2].name.toLowerCase(), 'node.exe');
115
- term.kill();
116
- const desiredState: IProcessState = {};
117
- desiredState[list[0].pid] = false;
118
- desiredState[list[1].pid] = false;
119
- desiredState[list[2].pid] = false;
120
- term.on('exit', () => {
121
- pollForProcessState(desiredState, 1000, 5000).then(() => {
122
- done();
123
- }).catch(done);
124
- });
125
- }).catch(done);
126
- });
127
- });
128
-
129
- describe('resize', () => {
130
- it('should throw a non-native exception when resizing an invalid value', function(done) {
131
- this.timeout(20000);
132
- const term = new WindowsTerminal('cmd.exe', [], { useConptyDll });
133
- assert.throws(() => term.resize(-1, -1));
134
- assert.throws(() => term.resize(0, 0));
135
- assert.doesNotThrow(() => term.resize(1, 1));
136
- term.on('exit', () => {
137
- done();
138
- });
139
- term.kill();
140
- });
141
- it('should throw a non-native exception when resizing a killed terminal', function(done) {
142
- this.timeout(20000);
143
- const term = new WindowsTerminal('cmd.exe', [], { useConptyDll });
144
- (<any>term)._defer(() => {
145
- term.once('exit', () => {
146
- assert.throws(() => term.resize(1, 1));
147
- done();
148
- });
149
- term.destroy();
150
- });
151
- });
152
- });
153
-
154
- describe('Args as CommandLine', () => {
155
- it('should not fail running a file containing a space in the path', function (done) {
156
- this.timeout(10000);
157
- const spaceFolder = path.resolve(__dirname, '..', 'fixtures', 'space folder');
158
- if (!fs.existsSync(spaceFolder)) {
159
- fs.mkdirSync(spaceFolder);
160
- }
161
-
162
- const cmdCopiedPath = path.resolve(spaceFolder, 'cmd.exe');
163
- const data = fs.readFileSync(`${process.env.windir}\\System32\\cmd.exe`);
164
- fs.writeFileSync(cmdCopiedPath, data);
165
-
166
- if (!fs.existsSync(cmdCopiedPath)) {
167
- // Skip test if git bash isn't installed
168
- return;
169
- }
170
- const term = new WindowsTerminal(cmdCopiedPath, '/c echo "hello world"', { useConptyDll });
171
- let result = '';
172
- term.on('data', (data) => {
173
- result += data;
174
- });
175
- term.on('exit', () => {
176
- assert.ok(result.indexOf('hello world') >= 1);
177
- done();
178
- });
179
- });
180
- });
181
-
182
- describe('env', () => {
183
- it('should set environment variables of the shell', function (done) {
184
- this.timeout(10000);
185
- const term = new WindowsTerminal('cmd.exe', '/C echo %FOO%', { useConptyDll, env: { FOO: 'BAR' }});
186
- let result = '';
187
- term.on('data', (data) => {
188
- result += data;
189
- });
190
- term.on('exit', () => {
191
- assert.ok(result.indexOf('BAR') >= 0);
192
- done();
193
- });
194
- });
195
- });
196
-
197
- describe('On close', () => {
198
- it('should return process zero exit codes', function (done) {
199
- this.timeout(10000);
200
- const term = new WindowsTerminal('cmd.exe', '/C exit', { useConptyDll });
201
- term.on('exit', (code) => {
202
- assert.strictEqual(code, 0);
203
- done();
204
- });
205
- });
206
-
207
- it('should return process non-zero exit codes', function (done) {
208
- this.timeout(10000);
209
- const term = new WindowsTerminal('cmd.exe', '/C exit 2', { useConptyDll });
210
- term.on('exit', (code) => {
211
- assert.strictEqual(code, 2);
212
- done();
213
- });
214
- });
215
- });
216
-
217
- describe('Write', () => {
218
- it('should accept input', function (done) {
219
- this.timeout(10000);
220
- const term = new WindowsTerminal('cmd.exe', '', { useConptyDll });
221
- term.write('exit\r');
222
- term.on('exit', () => {
223
- done();
224
- });
225
- });
226
- });
227
- });
228
- });
229
- }
@@ -1,203 +0,0 @@
1
- /**
2
- * Copyright (c) 2012-2015, Christopher Jeffrey, Peter Sunde (MIT License)
3
- * Copyright (c) 2016, Daniel Imms (MIT License).
4
- * Copyright (c) 2018, Microsoft Corporation (MIT License).
5
- */
6
-
7
- import { Socket } from 'net';
8
- import { Terminal, DEFAULT_COLS, DEFAULT_ROWS } from './terminal';
9
- import { WindowsPtyAgent } from './windowsPtyAgent';
10
- import { IPtyOpenOptions, IWindowsPtyForkOptions } from './interfaces';
11
- import { ArgvOrCommandLine } from './types';
12
- import { assign } from './utils';
13
-
14
- const DEFAULT_FILE = 'cmd.exe';
15
- const DEFAULT_NAME = 'Windows Shell';
16
-
17
- export class WindowsTerminal extends Terminal {
18
- private _isReady: boolean;
19
- private _deferreds: { run: () => void }[];
20
- private _agent: WindowsPtyAgent;
21
-
22
- constructor(file?: string, args?: ArgvOrCommandLine, opt?: IWindowsPtyForkOptions) {
23
- super(opt);
24
-
25
- this._checkType('args', args, 'string', true);
26
-
27
- // Initialize arguments
28
- args = args || [];
29
- file = file || DEFAULT_FILE;
30
- opt = opt || {};
31
- opt.env = opt.env || process.env;
32
-
33
- if (opt.encoding) {
34
- console.warn('Setting encoding on Windows is not supported');
35
- }
36
-
37
- const env = assign({}, opt.env);
38
- this._cols = opt.cols || DEFAULT_COLS;
39
- this._rows = opt.rows || DEFAULT_ROWS;
40
- const cwd = opt.cwd || process.cwd();
41
- const name = opt.name || env.TERM || DEFAULT_NAME;
42
- const parsedEnv = this._parseEnv(env);
43
-
44
- // If the terminal is ready
45
- this._isReady = false;
46
-
47
- // Functions that need to run after `ready` event is emitted.
48
- this._deferreds = [];
49
-
50
- // Create new termal.
51
- this._agent = new WindowsPtyAgent(file, args, parsedEnv, cwd, this._cols, this._rows, false, opt.useConptyDll, opt.conptyInheritCursor);
52
- this._socket = this._agent.outSocket;
53
-
54
- // Not available until `ready` event emitted.
55
- this._pid = this._agent.innerPid;
56
- this._fd = this._agent.fd;
57
- this._pty = this._agent.pty;
58
-
59
- // The forked windows terminal is not available until `ready` event is
60
- // emitted.
61
- this._socket.on('ready_datapipe', () => {
62
-
63
- // Run deferreds and set ready state once the first data event is received.
64
- this._socket.once('data', () => {
65
- // Wait until the first data event is fired then we can run deferreds.
66
- if (!this._isReady) {
67
- // Terminal is now ready and we can avoid having to defer method
68
- // calls.
69
- this._isReady = true;
70
-
71
- // Execute all deferred methods
72
- this._deferreds.forEach(fn => {
73
- // NB! In order to ensure that `this` has all its references
74
- // updated any variable that need to be available in `this` before
75
- // the deferred is run has to be declared above this forEach
76
- // statement.
77
- fn.run();
78
- });
79
-
80
- // Reset
81
- this._deferreds = [];
82
- }
83
- });
84
-
85
- // Shutdown if `error` event is emitted.
86
- this._socket.on('error', err => {
87
- // Close terminal session.
88
- this._close();
89
-
90
- // EIO, happens when someone closes our child process: the only process
91
- // in the terminal.
92
- // node < 0.6.14: errno 5
93
- // node >= 0.6.14: read EIO
94
- if ((<any>err).code) {
95
- if (~(<any>err).code.indexOf('errno 5') || ~(<any>err).code.indexOf('EIO')) return;
96
- }
97
-
98
- // Throw anything else.
99
- if (this.listeners('error').length < 2) {
100
- throw err;
101
- }
102
- });
103
-
104
- // Cleanup after the socket is closed.
105
- this._socket.on('close', () => {
106
- this.emit('exit', this._agent.exitCode);
107
- this._close();
108
- });
109
-
110
- });
111
-
112
- this._file = file;
113
- this._name = name;
114
-
115
- this._readable = true;
116
- this._writable = true;
117
-
118
- this._forwardEvents();
119
- }
120
-
121
- protected _write(data: string | Buffer): void {
122
- this._defer(this._doWrite, data);
123
- }
124
-
125
- private _doWrite(data: string | Buffer): void {
126
- this._agent.inSocket.write(data);
127
- }
128
-
129
- /**
130
- * openpty
131
- */
132
-
133
- public static open(options?: IPtyOpenOptions): void {
134
- throw new Error('open() not supported on windows, use Fork() instead.');
135
- }
136
-
137
- /**
138
- * TTY
139
- */
140
-
141
- public resize(cols: number, rows: number): void {
142
- if (cols <= 0 || rows <= 0 || isNaN(cols) || isNaN(rows) || cols === Infinity || rows === Infinity) {
143
- throw new Error('resizing must be done using positive cols and rows');
144
- }
145
- this._deferNoArgs(() => {
146
- this._agent.resize(cols, rows);
147
- this._cols = cols;
148
- this._rows = rows;
149
- });
150
- }
151
-
152
- public clear(): void {
153
- this._deferNoArgs(() => {
154
- this._agent.clear();
155
- });
156
- }
157
-
158
- public destroy(): void {
159
- this._deferNoArgs(() => {
160
- this.kill();
161
- });
162
- }
163
-
164
- public kill(signal?: string): void {
165
- this._deferNoArgs(() => {
166
- if (signal) {
167
- throw new Error('Signals not supported on windows.');
168
- }
169
- this._close();
170
- this._agent.kill();
171
- });
172
- }
173
-
174
- private _deferNoArgs<A>(deferredFn: () => void): void {
175
- // If the terminal is ready, execute.
176
- if (this._isReady) {
177
- deferredFn.call(this);
178
- return;
179
- }
180
-
181
- // Queue until terminal is ready.
182
- this._deferreds.push({
183
- run: () => deferredFn.call(this)
184
- });
185
- }
186
-
187
- private _defer<A>(deferredFn: (arg: A) => void, arg: A): void {
188
- // If the terminal is ready, execute.
189
- if (this._isReady) {
190
- deferredFn.call(this, arg);
191
- return;
192
- }
193
-
194
- // Queue until terminal is ready.
195
- this._deferreds.push({
196
- run: () => deferredFn.call(this, arg)
197
- });
198
- }
199
-
200
- public get process(): string { return this._name; }
201
- public get master(): Socket { throw new Error('master is not supported on Windows'); }
202
- public get slave(): Socket { throw new Error('slave is not supported on Windows'); }
203
- }