node-pty 0.10.1 → 0.11.0-beta12
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.
- package/README.md +8 -8
- package/binding.gyp +45 -27
- package/lib/eventEmitter2.js +2 -1
- package/lib/eventEmitter2.js.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/shared/conout.js +11 -0
- package/lib/shared/conout.js.map +1 -0
- package/lib/terminal.js +9 -6
- package/lib/terminal.js.map +1 -1
- package/lib/terminal.test.js +3 -3
- package/lib/testUtils.test.js +1 -0
- package/lib/testUtils.test.js.map +1 -1
- package/lib/unixTerminal.js +13 -4
- package/lib/unixTerminal.js.map +1 -1
- package/lib/unixTerminal.test.js +31 -0
- package/lib/unixTerminal.test.js.map +1 -1
- package/lib/utils.js +1 -0
- package/lib/utils.js.map +1 -1
- package/lib/windowsConoutConnection.js +122 -0
- package/lib/windowsConoutConnection.js.map +1 -0
- package/lib/windowsPtyAgent.js +16 -15
- package/lib/windowsPtyAgent.js.map +1 -1
- package/lib/windowsTerminal.js +4 -3
- package/lib/windowsTerminal.js.map +1 -1
- package/lib/worker/conoutSocketWorker.js +19 -0
- package/lib/worker/conoutSocketWorker.js.map +1 -0
- package/package.json +6 -6
- package/scripts/post-install.js +1 -0
- package/src/interfaces.ts +3 -4
- package/src/native.d.ts +1 -1
- package/src/shared/conout.ts +15 -0
- package/src/terminal.ts +3 -1
- package/src/unix/comms.h +5 -0
- package/src/unix/pty.cc +148 -175
- package/src/unix/spawn-helper.cc +70 -0
- package/src/unixTerminal.test.ts +28 -0
- package/src/unixTerminal.ts +11 -2
- package/src/win/conpty.cc +34 -22
- package/src/win/path_util.cc +1 -1
- package/src/windowsConoutConnection.ts +79 -0
- package/src/windowsPtyAgent.ts +10 -10
- package/src/worker/conoutSocketWorker.ts +18 -0
- package/typings/node-pty.d.ts +9 -3
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2020, Microsoft Corporation (MIT License).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Worker } from 'worker_threads';
|
|
6
|
+
import { Socket } from 'net';
|
|
7
|
+
import { IDisposable } from './types';
|
|
8
|
+
import { IWorkerData, ConoutWorkerMessage, getWorkerPipeName } from './shared/conout';
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
import { IEvent, EventEmitter2 } from './eventEmitter2';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The amount of time to wait for additional data after the conpty shell process has exited before
|
|
14
|
+
* shutting down the worker and sockets. The timer will be reset if a new data event comes in after
|
|
15
|
+
* the timer has started.
|
|
16
|
+
*/
|
|
17
|
+
const FLUSH_DATA_INTERVAL = 1000;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Connects to and manages the lifecycle of the conout socket. This socket must be drained on
|
|
21
|
+
* another thread in order to avoid deadlocks where Conpty waits for the out socket to drain
|
|
22
|
+
* when `ClosePseudoConsole` is called. This happens when data is being written to the terminal when
|
|
23
|
+
* the pty is closed.
|
|
24
|
+
*
|
|
25
|
+
* See also:
|
|
26
|
+
* - https://github.com/microsoft/node-pty/issues/375
|
|
27
|
+
* - https://github.com/microsoft/vscode/issues/76548
|
|
28
|
+
* - https://github.com/microsoft/terminal/issues/1810
|
|
29
|
+
* - https://docs.microsoft.com/en-us/windows/console/closepseudoconsole
|
|
30
|
+
*/
|
|
31
|
+
export class ConoutConnection implements IDisposable {
|
|
32
|
+
private _worker: Worker;
|
|
33
|
+
private _drainTimeout: NodeJS.Timeout;
|
|
34
|
+
private _isDisposed: boolean = false;
|
|
35
|
+
|
|
36
|
+
private _onReady = new EventEmitter2<void>();
|
|
37
|
+
public get onReady(): IEvent<void> { return this._onReady.event; }
|
|
38
|
+
|
|
39
|
+
constructor(
|
|
40
|
+
private _conoutPipeName: string
|
|
41
|
+
) {
|
|
42
|
+
const workerData: IWorkerData = { conoutPipeName: _conoutPipeName };
|
|
43
|
+
const scriptPath = __dirname.replace('node_modules.asar', 'node_modules.asar.unpacked');
|
|
44
|
+
this._worker = new Worker(join(scriptPath, 'worker/conoutSocketWorker.js'), { workerData });
|
|
45
|
+
this._worker.on('message', (message: ConoutWorkerMessage) => {
|
|
46
|
+
switch (message) {
|
|
47
|
+
case ConoutWorkerMessage.READY:
|
|
48
|
+
this._onReady.fire();
|
|
49
|
+
return;
|
|
50
|
+
default:
|
|
51
|
+
console.warn('Unexpected ConoutWorkerMessage', message);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
dispose(): void {
|
|
57
|
+
if (this._isDisposed) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
this._isDisposed = true;
|
|
61
|
+
// Drain all data from the socket before closing
|
|
62
|
+
this._drainDataAndClose();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
connectSocket(socket: Socket): void {
|
|
66
|
+
socket.connect(getWorkerPipeName(this._conoutPipeName));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private _drainDataAndClose(): void {
|
|
70
|
+
if (this._drainTimeout) {
|
|
71
|
+
clearTimeout(this._drainTimeout);
|
|
72
|
+
}
|
|
73
|
+
this._drainTimeout = setTimeout(() => this._destroySocket(), FLUSH_DATA_INTERVAL);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private async _destroySocket(): Promise<void> {
|
|
77
|
+
await this._worker.terminate();
|
|
78
|
+
}
|
|
79
|
+
}
|
package/src/windowsPtyAgent.ts
CHANGED
|
@@ -10,6 +10,7 @@ import * as path from 'path';
|
|
|
10
10
|
import { Socket } from 'net';
|
|
11
11
|
import { ArgvOrCommandLine } from './types';
|
|
12
12
|
import { fork } from 'child_process';
|
|
13
|
+
import { ConoutConnection } from './windowsConoutConnection';
|
|
13
14
|
|
|
14
15
|
let conptyNative: IConptyNative;
|
|
15
16
|
let winptyNative: IWinptyNative;
|
|
@@ -19,7 +20,7 @@ let winptyNative: IWinptyNative;
|
|
|
19
20
|
* shutting down the socket. The timer will be reset if a new data event comes in after the timer
|
|
20
21
|
* has started.
|
|
21
22
|
*/
|
|
22
|
-
const FLUSH_DATA_INTERVAL =
|
|
23
|
+
const FLUSH_DATA_INTERVAL = 1000;
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* This agent sits between the WindowsTerminal class and provides a common interface for both conpty
|
|
@@ -33,6 +34,7 @@ export class WindowsPtyAgent {
|
|
|
33
34
|
private _innerPidHandle: number;
|
|
34
35
|
private _closeTimeout: NodeJS.Timer;
|
|
35
36
|
private _exitCode: number | undefined;
|
|
37
|
+
private _conoutSocketWorker: ConoutConnection;
|
|
36
38
|
|
|
37
39
|
private _fd: any;
|
|
38
40
|
private _pty: number;
|
|
@@ -116,10 +118,12 @@ export class WindowsPtyAgent {
|
|
|
116
118
|
// Create terminal pipe IPC channel and forward to a local unix socket.
|
|
117
119
|
this._outSocket = new Socket();
|
|
118
120
|
this._outSocket.setEncoding('utf8');
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
// The conout socket must be ready out on another thread to avoid deadlocks
|
|
122
|
+
this._conoutSocketWorker = new ConoutConnection(term.conout);
|
|
123
|
+
this._conoutSocketWorker.onReady(() => {
|
|
124
|
+
this._conoutSocketWorker.connectSocket(this._outSocket);
|
|
125
|
+
});
|
|
126
|
+
this._outSocket.on('connect', () => {
|
|
123
127
|
this._outSocket.emit('ready_datapipe');
|
|
124
128
|
});
|
|
125
129
|
|
|
@@ -130,7 +134,6 @@ export class WindowsPtyAgent {
|
|
|
130
134
|
writable: true
|
|
131
135
|
});
|
|
132
136
|
this._inSocket.setEncoding('utf8');
|
|
133
|
-
// TODO: Wait for ready event?
|
|
134
137
|
|
|
135
138
|
if (this._useConpty) {
|
|
136
139
|
const connect = (this._ptyNative as IConptyNative).connect(this._pty, commandLine, cwd, env, c => this._$onProcessExit(c));
|
|
@@ -151,9 +154,7 @@ export class WindowsPtyAgent {
|
|
|
151
154
|
|
|
152
155
|
public kill(): void {
|
|
153
156
|
this._inSocket.readable = false;
|
|
154
|
-
this._inSocket.writable = false;
|
|
155
157
|
this._outSocket.readable = false;
|
|
156
|
-
this._outSocket.writable = false;
|
|
157
158
|
// Tell the agent to kill the pty, this releases handles to the process
|
|
158
159
|
if (this._useConpty) {
|
|
159
160
|
this._getConsoleProcessList().then(consoleProcessList => {
|
|
@@ -183,6 +184,7 @@ export class WindowsPtyAgent {
|
|
|
183
184
|
}
|
|
184
185
|
});
|
|
185
186
|
}
|
|
187
|
+
this._conoutSocketWorker.dispose();
|
|
186
188
|
}
|
|
187
189
|
|
|
188
190
|
private _getConsoleProcessList(): Promise<number[]> {
|
|
@@ -238,9 +240,7 @@ export class WindowsPtyAgent {
|
|
|
238
240
|
|
|
239
241
|
private _cleanUpProcess(): void {
|
|
240
242
|
this._inSocket.readable = false;
|
|
241
|
-
this._inSocket.writable = false;
|
|
242
243
|
this._outSocket.readable = false;
|
|
243
|
-
this._outSocket.writable = false;
|
|
244
244
|
this._outSocket.destroy();
|
|
245
245
|
}
|
|
246
246
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2020, Microsoft Corporation (MIT License).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { parentPort, workerData } from 'worker_threads';
|
|
6
|
+
import { Socket, createServer } from 'net';
|
|
7
|
+
import { ConoutWorkerMessage, IWorkerData, getWorkerPipeName } from '../shared/conout';
|
|
8
|
+
|
|
9
|
+
const conoutPipeName = (workerData as IWorkerData).conoutPipeName;
|
|
10
|
+
const conoutSocket = new Socket();
|
|
11
|
+
conoutSocket.setEncoding('utf8');
|
|
12
|
+
conoutSocket.connect(conoutPipeName, () => {
|
|
13
|
+
const server = createServer(workerSocket => {
|
|
14
|
+
conoutSocket.pipe(workerSocket);
|
|
15
|
+
});
|
|
16
|
+
server.listen(getWorkerPipeName(conoutPipeName));
|
|
17
|
+
parentPort.postMessage(ConoutWorkerMessage.READY);
|
|
18
|
+
});
|
package/typings/node-pty.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ declare module 'node-pty' {
|
|
|
42
42
|
/**
|
|
43
43
|
* Environment to be set for the child program.
|
|
44
44
|
*/
|
|
45
|
-
env?: { [key: string]: string };
|
|
45
|
+
env?: { [key: string]: string | undefined };
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* String encoding of the underlying pty.
|
|
@@ -78,11 +78,17 @@ declare module 'node-pty' {
|
|
|
78
78
|
|
|
79
79
|
export interface IPtyForkOptions extends IBasePtyForkOptions {
|
|
80
80
|
/**
|
|
81
|
-
* Security warning: use this option with great caution
|
|
82
|
-
* with higher privileges might leak to the child program.
|
|
81
|
+
* Security warning: use this option with great caution unless `closeFDs` is also set,
|
|
82
|
+
* as opened file descriptors with higher privileges might leak to the child program.
|
|
83
83
|
*/
|
|
84
84
|
uid?: number;
|
|
85
85
|
gid?: number;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Close all open file after spawning the child process (UNIX only).
|
|
89
|
+
* Carries a performance penalty on Linux.
|
|
90
|
+
*/
|
|
91
|
+
closeFDs?: boolean;
|
|
86
92
|
}
|
|
87
93
|
|
|
88
94
|
export interface IWindowsPtyForkOptions extends IBasePtyForkOptions {
|