-
Notifications
You must be signed in to change notification settings - Fork 5.9k
/
Copy pathchild_process.ts
105 lines (84 loc) · 3.1 KB
/
child_process.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import * as cp from "child_process";
import { ServerProxy } from "../../common/proxy";
import { preserveEnv } from "../../common/util";
import { WritableProxy, ReadableProxy } from "./stream";
// tslint:disable completed-docs
export type ForkProvider = (modulePath: string, args?: string[], options?: cp.ForkOptions) => cp.ChildProcess;
export class ChildProcessProxy implements ServerProxy {
public constructor(private readonly process: cp.ChildProcess) {}
public async kill(signal?: string): Promise<void> {
this.process.kill(signal);
}
public async disconnect(): Promise<void> {
this.process.disconnect();
}
public async ref(): Promise<void> {
this.process.ref();
}
public async unref(): Promise<void> {
this.process.unref();
}
// tslint:disable-next-line no-any
public async send(message: any): Promise<void> {
return new Promise((resolve, reject): void => {
this.process.send(message, (error) => {
if (error) {
reject(error);
} else {
resolve();
}
});
});
}
public async getPid(): Promise<number> {
return this.process.pid;
}
public async onDone(cb: () => void): Promise<void> {
this.process.on("close", cb);
}
public async dispose(): Promise<void> {
this.process.kill();
setTimeout(() => this.process.kill("SIGKILL"), 5000); // Double tap.
}
// tslint:disable-next-line no-any
public async onEvent(cb: (event: string, ...args: any[]) => void): Promise<void> {
this.process.on("close", (code, signal) => cb("close", code, signal));
this.process.on("disconnect", () => cb("disconnect"));
this.process.on("error", (error) => cb("error", error));
this.process.on("exit", (exitCode, signal) => cb("exit", exitCode, signal));
this.process.on("message", (message) => cb("message", message));
}
}
export interface ChildProcessProxies {
childProcess: ChildProcessProxy;
stdin?: WritableProxy | null;
stdout?: ReadableProxy | null;
stderr?: ReadableProxy | null;
}
export class ChildProcessModuleProxy {
public constructor(private readonly forkProvider?: ForkProvider) {}
public async exec(
command: string,
options?: { encoding?: string | null } & cp.ExecOptions | null,
callback?: ((error: cp.ExecException | null, stdin: string | Buffer, stdout: string | Buffer) => void),
): Promise<ChildProcessProxies> {
preserveEnv(options);
return this.returnProxies(cp.exec(command, options, callback));
}
public async fork(modulePath: string, args?: string[], options?: cp.ForkOptions): Promise<ChildProcessProxies> {
preserveEnv(options);
return this.returnProxies((this.forkProvider || cp.fork)(modulePath, args, options));
}
public async spawn(command: string, args?: string[], options?: cp.SpawnOptions): Promise<ChildProcessProxies> {
preserveEnv(options);
return this.returnProxies(cp.spawn(command, args, options));
}
private returnProxies(process: cp.ChildProcess): ChildProcessProxies {
return {
childProcess: new ChildProcessProxy(process),
stdin: process.stdin && new WritableProxy(process.stdin),
stdout: process.stdout && new ReadableProxy(process.stdout),
stderr: process.stderr && new ReadableProxy(process.stderr),
};
}
}