mirror of
https://github.com/cdr/code-server.git
synced 2025-12-09 09:55:30 +01:00
* Replace evaluations with proxies and messages * Return proxies synchronously Otherwise events can be lost. * Ensure events cannot be missed * Refactor remaining fills * Use more up-to-date version of util For callbackify. * Wait for dispose to come back before removing This prevents issues with the "done" event not always being the last event fired. For example a socket might close and then end, but only if the caller called end. * Remove old node-pty tests * Fix emitting events twice on duplex streams * Preserve environment when spawning processes * Throw a better error if the proxy doesn't exist * Remove rimraf dependency from ide * Update net.Server.listening * Use exit event instead of killed Doesn't look like killed is even a thing. * Add response timeout to server * Fix trash * Require node-pty & spdlog after they get unpackaged This fixes an error when running in the binary. * Fix errors in down emitter preventing reconnecting * Fix disposing proxies when nothing listens to "error" event * Refactor event tests to use jest.fn() * Reject proxy call when disconnected Otherwise it'll wait for the timeout which is a waste of time since we already know the connection is dead. * Use nbin for binary packaging * Remove additional module requires * Attempt to remove require for local bootstrap-fork * Externalize fsevents
103 lines
3 KiB
TypeScript
103 lines
3 KiB
TypeScript
import * as cp from "child_process";
|
|
import { ServerProxy } from "../../common/proxy";
|
|
import { preserveEnv } from "../../common/util";
|
|
import { WritableProxy, ReadableProxy } from "./stream";
|
|
|
|
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) => {
|
|
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.kill();
|
|
setTimeout(() => this.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;
|
|
stdout?: ReadableProxy;
|
|
stderr?: ReadableProxy;
|
|
}
|
|
|
|
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),
|
|
};
|
|
}
|
|
}
|