Refactor evaluations (#285)
* 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
This commit is contained in:
126
packages/protocol/src/browser/modules/child_process.ts
Normal file
126
packages/protocol/src/browser/modules/child_process.ts
Normal file
@ -0,0 +1,126 @@
|
||||
import * as cp from "child_process";
|
||||
import * as net from "net";
|
||||
import * as stream from "stream";
|
||||
import { callbackify } from "util";
|
||||
import { ClientProxy } from "../../common/proxy";
|
||||
import { ChildProcessModuleProxy, ChildProcessProxy, ChildProcessProxies } from "../../node/modules/child_process";
|
||||
import { Readable, Writable } from "./stream";
|
||||
|
||||
export class ChildProcess extends ClientProxy<ChildProcessProxy> implements cp.ChildProcess {
|
||||
public readonly stdin: stream.Writable;
|
||||
public readonly stdout: stream.Readable;
|
||||
public readonly stderr: stream.Readable;
|
||||
public readonly stdio: [stream.Writable, stream.Readable, stream.Readable];
|
||||
|
||||
private _connected: boolean = false;
|
||||
private _killed: boolean = false;
|
||||
private _pid = -1;
|
||||
|
||||
public constructor(proxyPromises: Promise<ChildProcessProxies>) {
|
||||
super(proxyPromises.then((p) => p.childProcess));
|
||||
this.stdin = new Writable(proxyPromises.then((p) => p.stdin!));
|
||||
this.stdout = new Readable(proxyPromises.then((p) => p.stdout!));
|
||||
this.stderr = new Readable(proxyPromises.then((p) => p.stderr!));
|
||||
this.stdio = [this.stdin, this.stdout, this.stderr];
|
||||
|
||||
this.proxy.getPid().then((pid) => {
|
||||
this._pid = pid;
|
||||
this._connected = true;
|
||||
});
|
||||
this.on("disconnect", () => this._connected = false);
|
||||
this.on("exit", () => {
|
||||
this._connected = false;
|
||||
this._killed = true;
|
||||
});
|
||||
}
|
||||
|
||||
public get pid(): number {
|
||||
return this._pid;
|
||||
}
|
||||
|
||||
public get connected(): boolean {
|
||||
return this._connected;
|
||||
}
|
||||
|
||||
public get killed(): boolean {
|
||||
return this._killed;
|
||||
}
|
||||
|
||||
public kill(): void {
|
||||
this._killed = true;
|
||||
this.proxy.kill();
|
||||
}
|
||||
|
||||
public disconnect(): void {
|
||||
this.proxy.disconnect();
|
||||
}
|
||||
|
||||
public ref(): void {
|
||||
this.proxy.ref();
|
||||
}
|
||||
|
||||
public unref(): void {
|
||||
this.proxy.unref();
|
||||
}
|
||||
|
||||
public send(
|
||||
message: any, // tslint:disable-line no-any
|
||||
sendHandle?: net.Socket | net.Server | ((error: Error) => void),
|
||||
options?: cp.MessageOptions | ((error: Error) => void),
|
||||
callback?: (error: Error) => void): boolean {
|
||||
if (typeof sendHandle === "function") {
|
||||
callback = sendHandle;
|
||||
sendHandle = undefined;
|
||||
} else if (typeof options === "function") {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
if (sendHandle || options) {
|
||||
throw new Error("sendHandle and options are not supported");
|
||||
}
|
||||
|
||||
callbackify(this.proxy.send)(message, (error) => {
|
||||
if (callback) {
|
||||
callback(error);
|
||||
}
|
||||
});
|
||||
|
||||
return true; // Always true since we can't get this synchronously.
|
||||
}
|
||||
}
|
||||
|
||||
export class ChildProcessModule {
|
||||
public constructor(private readonly proxy: ChildProcessModuleProxy) {}
|
||||
|
||||
public exec = (
|
||||
command: string,
|
||||
options?: { encoding?: string | null } & cp.ExecOptions | null
|
||||
| ((error: cp.ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => void),
|
||||
callback?: ((error: cp.ExecException | null, stdout: string | Buffer, stderr: string | Buffer) => void),
|
||||
): cp.ChildProcess => {
|
||||
if (typeof options === "function") {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
|
||||
return new ChildProcess(this.proxy.exec(command, options, callback));
|
||||
}
|
||||
|
||||
public fork = (modulePath: string, args?: string[] | cp.ForkOptions, options?: cp.ForkOptions): cp.ChildProcess => {
|
||||
if (!Array.isArray(args)) {
|
||||
options = args;
|
||||
args = undefined;
|
||||
}
|
||||
|
||||
return new ChildProcess(this.proxy.fork(modulePath, args, options));
|
||||
}
|
||||
|
||||
public spawn = (command: string, args?: string[] | cp.SpawnOptions, options?: cp.SpawnOptions): cp.ChildProcess => {
|
||||
if (!Array.isArray(args)) {
|
||||
options = args;
|
||||
args = undefined;
|
||||
}
|
||||
|
||||
return new ChildProcess(this.proxy.spawn(command, args, options));
|
||||
}
|
||||
}
|
316
packages/protocol/src/browser/modules/fs.ts
Normal file
316
packages/protocol/src/browser/modules/fs.ts
Normal file
@ -0,0 +1,316 @@
|
||||
import * as fs from "fs";
|
||||
import { callbackify } from "util";
|
||||
import { ClientProxy } from "../../common/proxy";
|
||||
import { IEncodingOptions, IEncodingOptionsCallback } from "../../common/util";
|
||||
import { FsModuleProxy, Stats as IStats, WatcherProxy, WriteStreamProxy } from "../../node/modules/fs";
|
||||
import { Writable } from "./stream";
|
||||
|
||||
// tslint:disable no-any
|
||||
|
||||
class Watcher extends ClientProxy<WatcherProxy> implements fs.FSWatcher {
|
||||
public close(): void {
|
||||
this.proxy.close();
|
||||
}
|
||||
}
|
||||
|
||||
class WriteStream extends Writable<WriteStreamProxy> implements fs.WriteStream {
|
||||
public get bytesWritten(): number {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public get path(): string | Buffer {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
this.proxy.close();
|
||||
}
|
||||
}
|
||||
|
||||
export class FsModule {
|
||||
public constructor(private readonly proxy: FsModuleProxy) {}
|
||||
|
||||
public access = (path: fs.PathLike, mode: number | undefined | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => {
|
||||
if (typeof mode === "function") {
|
||||
callback = mode;
|
||||
mode = undefined;
|
||||
}
|
||||
callbackify(this.proxy.access)(path, mode, callback!);
|
||||
}
|
||||
|
||||
public appendFile = (path: fs.PathLike | number, data: any, options?: fs.WriteFileOptions | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => {
|
||||
if (typeof options === "function") {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
callbackify(this.proxy.appendFile)(path, data, options, callback!);
|
||||
}
|
||||
|
||||
public chmod = (path: fs.PathLike, mode: string | number, callback: (err: NodeJS.ErrnoException) => void): void => {
|
||||
callbackify(this.proxy.chmod)(path, mode, callback!);
|
||||
}
|
||||
|
||||
public chown = (path: fs.PathLike, uid: number, gid: number, callback: (err: NodeJS.ErrnoException) => void): void => {
|
||||
callbackify(this.proxy.chown)(path, uid, gid, callback!);
|
||||
}
|
||||
|
||||
public close = (fd: number, callback: (err: NodeJS.ErrnoException) => void): void => {
|
||||
callbackify(this.proxy.close)(fd, callback!);
|
||||
}
|
||||
|
||||
public copyFile = (src: fs.PathLike, dest: fs.PathLike, flags: number | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => {
|
||||
if (typeof flags === "function") {
|
||||
callback = flags;
|
||||
}
|
||||
callbackify(this.proxy.copyFile)(
|
||||
src, dest, typeof flags !== "function" ? flags : undefined, callback!,
|
||||
);
|
||||
}
|
||||
|
||||
public createWriteStream = (path: fs.PathLike, options?: any): fs.WriteStream => {
|
||||
return new WriteStream(this.proxy.createWriteStream(path, options));
|
||||
}
|
||||
|
||||
public exists = (path: fs.PathLike, callback: (exists: boolean) => void): void => {
|
||||
callbackify(this.proxy.exists)(path, (exists) => {
|
||||
callback!(exists as any);
|
||||
});
|
||||
}
|
||||
|
||||
public fchmod = (fd: number, mode: string | number, callback: (err: NodeJS.ErrnoException) => void): void => {
|
||||
callbackify(this.proxy.fchmod)(fd, mode, callback!);
|
||||
}
|
||||
|
||||
public fchown = (fd: number, uid: number, gid: number, callback: (err: NodeJS.ErrnoException) => void): void => {
|
||||
callbackify(this.proxy.fchown)(fd, uid, gid, callback!);
|
||||
}
|
||||
|
||||
public fdatasync = (fd: number, callback: (err: NodeJS.ErrnoException) => void): void => {
|
||||
callbackify(this.proxy.fdatasync)(fd, callback!);
|
||||
}
|
||||
|
||||
public fstat = (fd: number, callback: (err: NodeJS.ErrnoException, stats: fs.Stats) => void): void => {
|
||||
callbackify(this.proxy.fstat)(fd, (error, stats) => {
|
||||
callback(error, stats && new Stats(stats));
|
||||
});
|
||||
}
|
||||
|
||||
public fsync = (fd: number, callback: (err: NodeJS.ErrnoException) => void): void => {
|
||||
callbackify(this.proxy.fsync)(fd, callback!);
|
||||
}
|
||||
|
||||
public ftruncate = (fd: number, len: number | undefined | null | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => {
|
||||
if (typeof len === "function") {
|
||||
callback = len;
|
||||
len = undefined;
|
||||
}
|
||||
callbackify(this.proxy.ftruncate)(fd, len, callback!);
|
||||
}
|
||||
|
||||
public futimes = (fd: number, atime: string | number | Date, mtime: string | number | Date, callback: (err: NodeJS.ErrnoException) => void): void => {
|
||||
callbackify(this.proxy.futimes)(fd, atime, mtime, callback!);
|
||||
}
|
||||
|
||||
public lchmod = (path: fs.PathLike, mode: string | number, callback: (err: NodeJS.ErrnoException) => void): void => {
|
||||
callbackify(this.proxy.lchmod)(path, mode, callback!);
|
||||
}
|
||||
|
||||
public lchown = (path: fs.PathLike, uid: number, gid: number, callback: (err: NodeJS.ErrnoException) => void): void => {
|
||||
callbackify(this.proxy.lchown)(path, uid, gid, callback!);
|
||||
}
|
||||
|
||||
public link = (existingPath: fs.PathLike, newPath: fs.PathLike, callback: (err: NodeJS.ErrnoException) => void): void => {
|
||||
callbackify(this.proxy.link)(existingPath, newPath, callback!);
|
||||
}
|
||||
|
||||
public lstat = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException, stats: fs.Stats) => void): void => {
|
||||
callbackify(this.proxy.lstat)(path, (error, stats) => {
|
||||
callback(error, stats && new Stats(stats));
|
||||
});
|
||||
}
|
||||
|
||||
public mkdir = (path: fs.PathLike, mode: number | string | fs.MakeDirectoryOptions | undefined | null | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => {
|
||||
if (typeof mode === "function") {
|
||||
callback = mode;
|
||||
mode = undefined;
|
||||
}
|
||||
callbackify(this.proxy.mkdir)(path, mode, callback!);
|
||||
}
|
||||
|
||||
public mkdtemp = (prefix: string, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException, folder: string | Buffer) => void): void => {
|
||||
if (typeof options === "function") {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
callbackify(this.proxy.mkdtemp)(prefix, options, callback!);
|
||||
}
|
||||
|
||||
public open = (path: fs.PathLike, flags: string | number, mode: string | number | undefined | null | ((err: NodeJS.ErrnoException, fd: number) => void), callback?: (err: NodeJS.ErrnoException, fd: number) => void): void => {
|
||||
if (typeof mode === "function") {
|
||||
callback = mode;
|
||||
mode = undefined;
|
||||
}
|
||||
callbackify(this.proxy.open)(path, flags, mode, callback!);
|
||||
}
|
||||
|
||||
public read = (fd: number, buffer: Buffer, offset: number, length: number, position: number | null, callback: (err: NodeJS.ErrnoException, bytesRead: number, buffer: Buffer) => void): void => {
|
||||
this.proxy.read(fd, length, position).then((response) => {
|
||||
buffer.set(response.buffer, offset);
|
||||
callback(undefined!, response.bytesRead, response.buffer);
|
||||
}).catch((error) => {
|
||||
callback(error, undefined!, undefined!);
|
||||
});
|
||||
}
|
||||
|
||||
public readFile = (path: fs.PathLike | number, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException, data: string | Buffer) => void): void => {
|
||||
if (typeof options === "function") {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
callbackify(this.proxy.readFile)(path, options, callback!);
|
||||
}
|
||||
|
||||
public readdir = (path: fs.PathLike, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException, files: Buffer[] | fs.Dirent[] | string[]) => void): void => {
|
||||
if (typeof options === "function") {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
callbackify(this.proxy.readdir)(path, options, callback!);
|
||||
}
|
||||
|
||||
public readlink = (path: fs.PathLike, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException, linkString: string | Buffer) => void): void => {
|
||||
if (typeof options === "function") {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
callbackify(this.proxy.readlink)(path, options, callback!);
|
||||
}
|
||||
|
||||
public realpath = (path: fs.PathLike, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException, resolvedPath: string | Buffer) => void): void => {
|
||||
if (typeof options === "function") {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
callbackify(this.proxy.realpath)(path, options, callback!);
|
||||
}
|
||||
|
||||
public rename = (oldPath: fs.PathLike, newPath: fs.PathLike, callback: (err: NodeJS.ErrnoException) => void): void => {
|
||||
callbackify(this.proxy.rename)(oldPath, newPath, callback!);
|
||||
}
|
||||
|
||||
public rmdir = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException) => void): void => {
|
||||
callbackify(this.proxy.rmdir)(path, callback!);
|
||||
}
|
||||
|
||||
public stat = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException, stats: fs.Stats) => void): void => {
|
||||
callbackify(this.proxy.stat)(path, (error, stats) => {
|
||||
callback(error, stats && new Stats(stats));
|
||||
});
|
||||
}
|
||||
|
||||
public symlink = (target: fs.PathLike, path: fs.PathLike, type: fs.symlink.Type | undefined | null | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => {
|
||||
if (typeof type === "function") {
|
||||
callback = type;
|
||||
type = undefined;
|
||||
}
|
||||
callbackify(this.proxy.symlink)(target, path, type, callback!);
|
||||
}
|
||||
|
||||
public truncate = (path: fs.PathLike, len: number | undefined | null | ((err: NodeJS.ErrnoException) => void), callback?: (err: NodeJS.ErrnoException) => void): void => {
|
||||
if (typeof len === "function") {
|
||||
callback = len;
|
||||
len = undefined;
|
||||
}
|
||||
callbackify(this.proxy.truncate)(path, len, callback!);
|
||||
}
|
||||
|
||||
public unlink = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException) => void): void => {
|
||||
callbackify(this.proxy.unlink)(path, callback!);
|
||||
}
|
||||
|
||||
public utimes = (path: fs.PathLike, atime: string | number | Date, mtime: string | number | Date, callback: (err: NodeJS.ErrnoException) => void): void => {
|
||||
callbackify(this.proxy.utimes)(path, atime, mtime, callback!);
|
||||
}
|
||||
|
||||
public write = (fd: number, buffer: Buffer, offset: number | undefined | ((err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void), length: number | undefined | ((err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void), position: number | undefined | ((err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void), callback?: (err: NodeJS.ErrnoException, written: number, buffer: Buffer) => void): void => {
|
||||
if (typeof offset === "function") {
|
||||
callback = offset;
|
||||
offset = undefined;
|
||||
}
|
||||
if (typeof length === "function") {
|
||||
callback = length;
|
||||
length = undefined;
|
||||
}
|
||||
if (typeof position === "function") {
|
||||
callback = position;
|
||||
position = undefined;
|
||||
}
|
||||
this.proxy.write(fd, buffer, offset, length, position).then((r) => {
|
||||
callback!(undefined!, r.bytesWritten, r.buffer);
|
||||
}).catch((error) => {
|
||||
callback!(error, undefined!, undefined!);
|
||||
});
|
||||
}
|
||||
|
||||
public writeFile = (path: fs.PathLike | number, data: any, options: IEncodingOptionsCallback, callback?: (err: NodeJS.ErrnoException) => void): void => {
|
||||
if (typeof options === "function") {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
callbackify(this.proxy.writeFile)(path, data, options, callback!);
|
||||
}
|
||||
|
||||
public watch = (filename: fs.PathLike, options?: IEncodingOptions | ((event: string, filename: string | Buffer) => void), listener?: ((event: string, filename: string | Buffer) => void)): fs.FSWatcher => {
|
||||
if (typeof options === "function") {
|
||||
listener = options;
|
||||
options = undefined;
|
||||
}
|
||||
|
||||
const watcher = new Watcher(this.proxy.watch(filename, options));
|
||||
if (listener) {
|
||||
watcher.on("change", listener);
|
||||
}
|
||||
|
||||
return watcher;
|
||||
}
|
||||
}
|
||||
|
||||
class Stats implements fs.Stats {
|
||||
public readonly atime: Date;
|
||||
public readonly mtime: Date;
|
||||
public readonly ctime: Date;
|
||||
public readonly birthtime: Date;
|
||||
|
||||
public constructor(private readonly stats: IStats) {
|
||||
this.atime = new Date(stats.atime);
|
||||
this.mtime = new Date(stats.mtime);
|
||||
this.ctime = new Date(stats.ctime);
|
||||
this.birthtime = new Date(stats.birthtime);
|
||||
}
|
||||
|
||||
public get dev(): number { return this.stats.dev; }
|
||||
public get ino(): number { return this.stats.ino; }
|
||||
public get mode(): number { return this.stats.mode; }
|
||||
public get nlink(): number { return this.stats.nlink; }
|
||||
public get uid(): number { return this.stats.uid; }
|
||||
public get gid(): number { return this.stats.gid; }
|
||||
public get rdev(): number { return this.stats.rdev; }
|
||||
public get size(): number { return this.stats.size; }
|
||||
public get blksize(): number { return this.stats.blksize; }
|
||||
public get blocks(): number { return this.stats.blocks; }
|
||||
public get atimeMs(): number { return this.stats.atimeMs; }
|
||||
public get mtimeMs(): number { return this.stats.mtimeMs; }
|
||||
public get ctimeMs(): number { return this.stats.ctimeMs; }
|
||||
public get birthtimeMs(): number { return this.stats.birthtimeMs; }
|
||||
public isFile(): boolean { return this.stats._isFile; }
|
||||
public isDirectory(): boolean { return this.stats._isDirectory; }
|
||||
public isBlockDevice(): boolean { return this.stats._isBlockDevice; }
|
||||
public isCharacterDevice(): boolean { return this.stats._isCharacterDevice; }
|
||||
public isSymbolicLink(): boolean { return this.stats._isSymbolicLink; }
|
||||
public isFIFO(): boolean { return this.stats._isFIFO; }
|
||||
public isSocket(): boolean { return this.stats._isSocket; }
|
||||
|
||||
public toObject(): object {
|
||||
return JSON.parse(JSON.stringify(this));
|
||||
}
|
||||
}
|
6
packages/protocol/src/browser/modules/index.ts
Normal file
6
packages/protocol/src/browser/modules/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export * from "./child_process";
|
||||
export * from "./fs";
|
||||
export * from "./net";
|
||||
export * from "./node-pty";
|
||||
export * from "./spdlog";
|
||||
export * from "./trash";
|
280
packages/protocol/src/browser/modules/net.ts
Normal file
280
packages/protocol/src/browser/modules/net.ts
Normal file
@ -0,0 +1,280 @@
|
||||
import * as net from "net";
|
||||
import { callbackify } from "util";
|
||||
import { ClientProxy } from "../../common/proxy";
|
||||
import { NetModuleProxy, NetServerProxy, NetSocketProxy } from "../../node/modules/net";
|
||||
import { Duplex } from "./stream";
|
||||
|
||||
export class Socket extends Duplex<NetSocketProxy> implements net.Socket {
|
||||
private _connecting: boolean = false;
|
||||
private _destroyed: boolean = false;
|
||||
|
||||
public constructor(proxyPromise: Promise<NetSocketProxy> | NetSocketProxy, connecting?: boolean) {
|
||||
super(proxyPromise);
|
||||
if (connecting) {
|
||||
this._connecting = connecting;
|
||||
}
|
||||
this.on("close", () => {
|
||||
this._destroyed = true;
|
||||
this._connecting = false;
|
||||
});
|
||||
this.on("connect", () => this._connecting = false);
|
||||
}
|
||||
|
||||
public connect(options: number | string | net.SocketConnectOpts, host?: string | Function, callback?: Function): this {
|
||||
if (typeof host === "function") {
|
||||
callback = host;
|
||||
host = undefined;
|
||||
}
|
||||
this._connecting = true;
|
||||
if (callback) {
|
||||
this.on("connect", callback as () => void);
|
||||
}
|
||||
this.proxy.connect(options, host);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public end(data?: any, encoding?: string | Function, callback?: Function): void {
|
||||
if (typeof encoding === "function") {
|
||||
callback = encoding;
|
||||
encoding = undefined;
|
||||
}
|
||||
|
||||
callbackify(this.proxy.end)(data, encoding, () => {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public write(data: any, encoding?: string | Function, fd?: string | Function): boolean {
|
||||
let callback: undefined | Function;
|
||||
if (typeof encoding === "function") {
|
||||
callback = encoding;
|
||||
encoding = undefined;
|
||||
}
|
||||
if (typeof fd === "function") {
|
||||
callback = fd;
|
||||
fd = undefined;
|
||||
}
|
||||
if (typeof fd !== "undefined") {
|
||||
throw new Error("fd argument not supported");
|
||||
}
|
||||
|
||||
callbackify(this.proxy.write)(data, encoding, () => {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
return true; // Always true since we can't get this synchronously.
|
||||
}
|
||||
|
||||
public get connecting(): boolean {
|
||||
return this._connecting;
|
||||
}
|
||||
|
||||
public get destroyed(): boolean {
|
||||
return this._destroyed;
|
||||
}
|
||||
|
||||
public get bufferSize(): number {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public get bytesRead(): number {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public get bytesWritten(): number {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public get localAddress(): string {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public get localPort(): number {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public address(): net.AddressInfo | string {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public setTimeout(): this {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public setNoDelay(): this {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public setKeepAlive(): this {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public unref(): void {
|
||||
this.proxy.unref();
|
||||
}
|
||||
|
||||
public ref(): void {
|
||||
this.proxy.ref();
|
||||
}
|
||||
}
|
||||
|
||||
export class Server extends ClientProxy<NetServerProxy> implements net.Server {
|
||||
private readonly sockets = new Map<number, net.Socket>();
|
||||
private _listening: boolean = false;
|
||||
|
||||
public constructor(proxyPromise: Promise<NetServerProxy> | NetServerProxy) {
|
||||
super(proxyPromise);
|
||||
|
||||
this.proxy.onConnection((socketProxy) => {
|
||||
this.emit("connection", new Socket(socketProxy));
|
||||
});
|
||||
|
||||
this.on("listening", () => this._listening = true);
|
||||
this.on("error", () => this._listening = false);
|
||||
this.on("close", () => this._listening = false);
|
||||
}
|
||||
|
||||
public listen(handle?: net.ListenOptions | number | string, hostname?: string | number | Function, backlog?: number | Function, callback?: Function): this {
|
||||
if (typeof hostname === "function") {
|
||||
callback = hostname;
|
||||
hostname = undefined;
|
||||
}
|
||||
if (typeof backlog === "function") {
|
||||
callback = backlog;
|
||||
backlog = undefined;
|
||||
}
|
||||
if (callback) {
|
||||
this.on("listening", callback as () => void);
|
||||
}
|
||||
|
||||
this.proxy.listen(handle, hostname, backlog);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public get connections(): number {
|
||||
return this.sockets.size;
|
||||
}
|
||||
|
||||
public get listening(): boolean {
|
||||
return this._listening;
|
||||
}
|
||||
|
||||
public get maxConnections(): number {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public address(): net.AddressInfo | string {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public close(callback?: () => void): this {
|
||||
this._listening = false;
|
||||
if (callback) {
|
||||
this.on("close", callback);
|
||||
}
|
||||
this.proxy.close();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ref(): this {
|
||||
this.proxy.ref();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public unref(): this {
|
||||
this.proxy.unref();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public getConnections(cb: (error: Error | null, count: number) => void): void {
|
||||
cb(null, this.sockets.size);
|
||||
}
|
||||
}
|
||||
|
||||
type NodeNet = typeof net;
|
||||
|
||||
export class NetModule implements NodeNet {
|
||||
public readonly Socket: typeof net.Socket;
|
||||
public readonly Server: typeof net.Server;
|
||||
|
||||
public constructor(private readonly proxy: NetModuleProxy) {
|
||||
// @ts-ignore this is because Socket is missing things from the Stream
|
||||
// namespace but I'm unsure how best to provide them (finished,
|
||||
// finished.__promisify__, pipeline, and some others) or if it even matters.
|
||||
this.Socket = class extends Socket {
|
||||
public constructor(options?: net.SocketConstructorOpts) {
|
||||
super(proxy.createSocket(options));
|
||||
}
|
||||
};
|
||||
|
||||
this.Server = class extends Server {
|
||||
public constructor(options?: { allowHalfOpen?: boolean, pauseOnConnect?: boolean } | ((socket: Socket) => void), listener?: (socket: Socket) => void) {
|
||||
super(proxy.createServer(typeof options !== "function" ? options : undefined));
|
||||
if (typeof options === "function") {
|
||||
listener = options;
|
||||
}
|
||||
if (listener) {
|
||||
this.on("connection", listener);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public createConnection = (target: string | number | net.NetConnectOpts, host?: string | Function, callback?: Function): net.Socket => {
|
||||
if (typeof host === "function") {
|
||||
callback = host;
|
||||
host = undefined;
|
||||
}
|
||||
|
||||
const socket = new Socket(this.proxy.createConnection(target, host), true);
|
||||
if (callback) {
|
||||
socket.on("connect", callback as () => void);
|
||||
}
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
public createServer = (
|
||||
options?: { allowHalfOpen?: boolean, pauseOnConnect?: boolean } | ((socket: net.Socket) => void),
|
||||
callback?: (socket: net.Socket) => void,
|
||||
): net.Server => {
|
||||
if (typeof options === "function") {
|
||||
callback = options;
|
||||
options = undefined;
|
||||
}
|
||||
|
||||
const server = new Server(this.proxy.createServer(options));
|
||||
if (callback) {
|
||||
server.on("connection", callback);
|
||||
}
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
public connect = (): net.Socket => {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public isIP = (_input: string): number => {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public isIPv4 = (_input: string): boolean => {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public isIPv6 = (_input: string): boolean => {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
}
|
45
packages/protocol/src/browser/modules/node-pty.ts
Normal file
45
packages/protocol/src/browser/modules/node-pty.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import * as pty from "node-pty";
|
||||
import { ClientProxy } from "../../common/proxy";
|
||||
import { NodePtyModuleProxy, NodePtyProcessProxy } from "../../node/modules/node-pty";
|
||||
|
||||
export class NodePtyProcess extends ClientProxy<NodePtyProcessProxy> implements pty.IPty {
|
||||
private _pid = -1;
|
||||
private _process = "";
|
||||
|
||||
public constructor(proxyPromise: Promise<NodePtyProcessProxy>) {
|
||||
super(proxyPromise);
|
||||
this.proxy.getPid().then((pid) => this._pid = pid);
|
||||
this.proxy.getProcess().then((process) => this._process = process);
|
||||
this.on("process", (process) => this._process = process);
|
||||
}
|
||||
|
||||
public get pid(): number {
|
||||
return this._pid;
|
||||
}
|
||||
|
||||
public get process(): string {
|
||||
return this._process;
|
||||
}
|
||||
|
||||
public resize(columns: number, rows: number): void {
|
||||
this.proxy.resize(columns, rows);
|
||||
}
|
||||
|
||||
public write(data: string): void {
|
||||
this.proxy.write(data);
|
||||
}
|
||||
|
||||
public kill(signal?: string): void {
|
||||
this.proxy.kill(signal);
|
||||
}
|
||||
}
|
||||
|
||||
type NodePty = typeof pty;
|
||||
|
||||
export class NodePtyModule implements NodePty {
|
||||
public constructor(private readonly proxy: NodePtyModuleProxy) {}
|
||||
|
||||
public spawn = (file: string, args: string[] | string, options: pty.IPtyForkOptions): pty.IPty => {
|
||||
return new NodePtyProcess(this.proxy.spawn(file, args, options));
|
||||
}
|
||||
}
|
32
packages/protocol/src/browser/modules/spdlog.ts
Normal file
32
packages/protocol/src/browser/modules/spdlog.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import * as spdlog from "spdlog";
|
||||
import { ClientProxy } from "../../common/proxy";
|
||||
import { RotatingLoggerProxy, SpdlogModuleProxy } from "../../node/modules/spdlog";
|
||||
|
||||
class RotatingLogger extends ClientProxy<RotatingLoggerProxy> implements spdlog.RotatingLogger {
|
||||
public async trace (message: string): Promise<void> { this.proxy.trace(message); }
|
||||
public async debug (message: string): Promise<void> { this.proxy.debug(message); }
|
||||
public async info (message: string): Promise<void> { this.proxy.info(message); }
|
||||
public async warn (message: string): Promise<void> { this.proxy.warn(message); }
|
||||
public async error (message: string): Promise<void> { this.proxy.error(message); }
|
||||
public async critical (message: string): Promise<void> { this.proxy.critical(message); }
|
||||
public async setLevel (level: number): Promise<void> { this.proxy.setLevel(level); }
|
||||
public async clearFormatters (): Promise<void> { this.proxy.clearFormatters(); }
|
||||
public async flush (): Promise<void> { this.proxy.flush(); }
|
||||
public async drop (): Promise<void> { this.proxy.drop(); }
|
||||
}
|
||||
|
||||
export class SpdlogModule {
|
||||
public readonly RotatingLogger: typeof spdlog.RotatingLogger;
|
||||
|
||||
public constructor(private readonly proxy: SpdlogModuleProxy) {
|
||||
this.RotatingLogger = class extends RotatingLogger {
|
||||
public constructor(name: string, filename: string, filesize: number, filecount: number) {
|
||||
super(proxy.createLogger(name, filename, filesize, filecount));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public setAsyncMode = (bufferSize: number, flushInterval: number): void => {
|
||||
this.proxy.setAsyncMode(bufferSize, flushInterval);
|
||||
}
|
||||
}
|
233
packages/protocol/src/browser/modules/stream.ts
Normal file
233
packages/protocol/src/browser/modules/stream.ts
Normal file
@ -0,0 +1,233 @@
|
||||
import * as stream from "stream";
|
||||
import { callbackify } from "util";
|
||||
import { ClientProxy } from "../../common/proxy";
|
||||
import { DuplexProxy, IReadableProxy, WritableProxy } from "../../node/modules/stream";
|
||||
|
||||
export class Writable<T extends WritableProxy = WritableProxy> extends ClientProxy<T> implements stream.Writable {
|
||||
public get writable(): boolean {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public get writableHighWaterMark(): number {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public get writableLength(): number {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public _write(): void {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public _destroy(): void {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public _final(): void {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public pipe<T>(): T {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public cork(): void {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public uncork(): void {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
this.proxy.destroy();
|
||||
}
|
||||
|
||||
public setDefaultEncoding(encoding: string): this {
|
||||
this.proxy.setDefaultEncoding(encoding);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public write(chunk: any, encoding?: string | ((error?: Error | null) => void), callback?: (error?: Error | null) => void): boolean {
|
||||
if (typeof encoding === "function") {
|
||||
callback = encoding;
|
||||
encoding = undefined;
|
||||
}
|
||||
callbackify(this.proxy.write)(chunk, encoding, (error) => {
|
||||
if (callback) {
|
||||
callback(error);
|
||||
}
|
||||
});
|
||||
|
||||
return true; // Always true since we can't get this synchronously.
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public end(data?: any | (() => void), encoding?: string | (() => void), callback?: (() => void)): void {
|
||||
if (typeof data === "function") {
|
||||
callback = data;
|
||||
data = undefined;
|
||||
}
|
||||
if (typeof encoding === "function") {
|
||||
callback = encoding;
|
||||
encoding = undefined;
|
||||
}
|
||||
callbackify(this.proxy.end)(data, encoding, () => {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class Readable<T extends IReadableProxy = IReadableProxy> extends ClientProxy<T> implements stream.Readable {
|
||||
public get readable(): boolean {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public get readableHighWaterMark(): number {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public get readableLength(): number {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public _read(): void {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public read(): void {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public _destroy(): void {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public unpipe(): this {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public pause(): this {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public resume(): this {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public isPaused(): boolean {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public wrap(): this {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public push(): boolean {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public unshift(): void {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public pipe<T>(): T {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public [Symbol.asyncIterator](): AsyncIterableIterator<any> {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
this.proxy.destroy();
|
||||
}
|
||||
|
||||
public setEncoding(encoding: string): this {
|
||||
this.proxy.setEncoding(encoding);
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export class Duplex<T extends DuplexProxy = DuplexProxy> extends Writable<T> implements stream.Duplex, stream.Readable {
|
||||
private readonly _readable: Readable;
|
||||
|
||||
public constructor(proxyPromise: Promise<T> | T) {
|
||||
super(proxyPromise);
|
||||
this._readable = new Readable(proxyPromise, false);
|
||||
}
|
||||
|
||||
public get readable(): boolean {
|
||||
return this._readable.readable;
|
||||
}
|
||||
|
||||
public get readableHighWaterMark(): number {
|
||||
return this._readable.readableHighWaterMark;
|
||||
}
|
||||
|
||||
public get readableLength(): number {
|
||||
return this._readable.readableLength;
|
||||
}
|
||||
|
||||
public _read(): void {
|
||||
this._readable._read();
|
||||
}
|
||||
|
||||
public read(): void {
|
||||
this._readable.read();
|
||||
}
|
||||
|
||||
public unpipe(): this {
|
||||
this._readable.unpipe();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public pause(): this {
|
||||
this._readable.unpipe();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public resume(): this {
|
||||
this._readable.resume();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public isPaused(): boolean {
|
||||
return this._readable.isPaused();
|
||||
}
|
||||
|
||||
public wrap(): this {
|
||||
this._readable.wrap();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public push(): boolean {
|
||||
return this._readable.push();
|
||||
}
|
||||
|
||||
public unshift(): void {
|
||||
this._readable.unshift();
|
||||
}
|
||||
|
||||
// tslint:disable-next-line no-any
|
||||
public [Symbol.asyncIterator](): AsyncIterableIterator<any> {
|
||||
return this._readable[Symbol.asyncIterator]();
|
||||
}
|
||||
|
||||
public setEncoding(encoding: string): this {
|
||||
this.proxy.setEncoding(encoding);
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
10
packages/protocol/src/browser/modules/trash.ts
Normal file
10
packages/protocol/src/browser/modules/trash.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import * as trash from "trash";
|
||||
import { TrashModuleProxy } from "../../node/modules/trash";
|
||||
|
||||
export class TrashModule {
|
||||
public constructor(private readonly proxy: TrashModuleProxy) {}
|
||||
|
||||
public trash = (path: string, options?: trash.Options): Promise<void> => {
|
||||
return this.proxy.trash(path, options);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user