Archived
1
0

Add evaluation helpers (#33)

* Add evaluation helpers

* Make some helpers only available server-side

They don't make any sense on the client side.

* Fork the right thing
This commit is contained in:
Asher
2019-02-22 15:56:29 -06:00
committed by GitHub
parent de3fbd689f
commit 8b8bef015e
17 changed files with 306 additions and 247 deletions

View File

@ -1,7 +1,7 @@
import * as cp from "child_process";
import * as net from "net";
import * as stream from "stream";
import { CallbackEmitter, ActiveEvalReadable, ActiveEvalWritable, createUniqueEval } from "./evaluation";
import { CallbackEmitter, ActiveEvalReadable, ActiveEvalWritable } from "@coder/protocol";
import { client } from "./client";
import { promisify } from "util";
@ -33,27 +33,19 @@ class ChildProcess extends CallbackEmitter implements cp.ChildProcess {
this.ae = client.run((ae, command, method, args, options, callbackId) => {
const cp = __non_webpack_require__("child_process") as typeof import("child_process");
const { maybeCallback, createUniqueEval, bindWritable, bindReadable, preserveEnv } = __non_webpack_require__("@coder/ide/src/fill/evaluation") as typeof import("@coder/ide/src/fill/evaluation");
preserveEnv(options);
ae.preserveEnv(options);
let childProcess: cp.ChildProcess;
switch (method) {
case "exec":
childProcess = cp.exec(command, options, maybeCallback(ae, callbackId));
childProcess = cp.exec(command, options, ae.maybeCallback(callbackId));
break;
case "spawn":
childProcess = cp.spawn(command, args, options);
break;
case "fork":
const forkOptions = options as cp.ForkOptions;
if (forkOptions && forkOptions.env && forkOptions.env.AMD_ENTRYPOINT) {
// TODO: This is vscode-specific and should be abstracted.
const { forkModule } = __non_webpack_require__("@coder/server/src/vscode/bootstrapFork") as typeof import ("@coder/server/src/vscode/bootstrapFork");
childProcess = forkModule(forkOptions.env.AMD_ENTRYPOINT, args, forkOptions);
} else {
childProcess = cp.fork(command, args, options);
}
childProcess = ae.fork(command, args, options);
break;
default:
throw new Error(`invalid method ${method}`);
@ -62,7 +54,7 @@ class ChildProcess extends CallbackEmitter implements cp.ChildProcess {
ae.on("disconnect", () => childProcess.disconnect());
ae.on("kill", (signal: string) => childProcess.kill(signal));
ae.on("ref", () => childProcess.ref());
ae.on("send", (message: string, callbackId: number) => childProcess.send(message, maybeCallback(ae, callbackId)));
ae.on("send", (message: string, callbackId: number) => childProcess.send(message, ae.maybeCallback(callbackId)));
ae.on("unref", () => childProcess.unref());
ae.emit("pid", childProcess.pid);
@ -73,13 +65,16 @@ class ChildProcess extends CallbackEmitter implements cp.ChildProcess {
childProcess.on("message", (message) => ae.emit("message", message));
if (childProcess.stdin) {
bindWritable(createUniqueEval(ae, "stdin"), childProcess.stdin);
const stdinAe = ae.createUnique("stdin");
stdinAe.bindWritable(childProcess.stdin);
}
if (childProcess.stdout) {
bindReadable(createUniqueEval(ae, "stdout"), childProcess.stdout);
const stdoutAe = ae.createUnique("stdout");
stdoutAe.bindReadable(childProcess.stdout);
}
if (childProcess.stderr) {
bindReadable(createUniqueEval(ae, "stderr"), childProcess.stderr);
const stderrAe = ae.createUnique("stderr");
stderrAe.bindReadable(childProcess.stderr);
}
return {
@ -96,9 +91,9 @@ class ChildProcess extends CallbackEmitter implements cp.ChildProcess {
this._connected = true;
});
this.stdin = new ActiveEvalWritable(createUniqueEval(this.ae, "stdin"));
this.stdout = new ActiveEvalReadable(createUniqueEval(this.ae, "stdout"));
this.stderr = new ActiveEvalReadable(createUniqueEval(this.ae, "stderr"));
this.stdin = new ActiveEvalWritable(this.ae.createUnique("stdin"));
this.stdout = new ActiveEvalReadable(this.ae.createUnique("stdout"));
this.stderr = new ActiveEvalReadable(this.ae.createUnique("stderr"));
this.ae.on("close", (code, signal) => this.emit("close", code, signal));
this.ae.on("disconnect", () => this.emit("disconnect"));

View File

@ -152,7 +152,7 @@ class Clipboard {
class Shell {
public async moveItemToTrash(path: string): Promise<void> {
await client.evaluate((path) => {
await client.evaluate((_helper, path) => {
const trash = __non_webpack_require__("trash") as typeof import("trash");
return trash(path);

View File

@ -1,338 +0,0 @@
import { SpawnOptions, ForkOptions } from "child_process";
import { EventEmitter } from "events";
import { Socket } from "net";
import { Duplex, Readable, Writable } from "stream";
import { logger } from "@coder/logger";
import { ActiveEval, Disposer } from "@coder/protocol";
// tslint:disable no-any
/**
* If there is a callback ID, return a function that emits the callback event on
* the active evaluation with that ID and all arguments passed to it. Otherwise,
* return undefined.
*/
export const maybeCallback = (ae: ActiveEval, callbackId?: number): ((...args: any[]) => void) | undefined => {
return typeof callbackId !== "undefined" ? (...args: any[]): void => {
ae.emit("callback", callbackId, ...args);
} : undefined;
};
// Some spawn code tries to preserve the env (the debug adapter for
// instance) but the env is mostly blank (since we're in the browser), so
// we'll just always preserve the main process.env here, otherwise it
// won't have access to PATH, etc.
// TODO: An alternative solution would be to send the env to the browser?
export const preserveEnv = (options: SpawnOptions | ForkOptions): void => {
if (options && options.env) {
options.env = { ...process.env, ...options.env };
}
};
/**
* Bind a socket to an active evaluation.
*/
export const bindSocket = (ae: ActiveEval, socket: Socket): Disposer => {
socket.on("connect", () => ae.emit("connect"));
socket.on("lookup", (error, address, family, host) => ae.emit("lookup", error, address, family, host));
socket.on("timeout", () => ae.emit("timeout"));
ae.on("connect", (options, callbackId) => socket.connect(options, maybeCallback(ae, callbackId)));
ae.on("ref", () => socket.ref());
ae.on("setKeepAlive", (enable, initialDelay) => socket.setKeepAlive(enable, initialDelay));
ae.on("setNoDelay", (noDelay) => socket.setNoDelay(noDelay));
ae.on("setTimeout", (timeout, callbackId) => socket.setTimeout(timeout, maybeCallback(ae, callbackId)));
ae.on("unref", () => socket.unref());
bindReadable(ae, socket);
bindWritable(ae, socket);
return {
onDidDispose: (cb): Socket => socket.on("close", cb),
dispose: (): void => {
socket.removeAllListeners();
socket.end();
socket.destroy();
socket.unref();
},
};
};
/**
* Bind a writable stream to an active evaluation.
*/
export const bindWritable = (ae: ActiveEval, writable: Writable | Duplex): void => {
if (!((writable as Readable).read)) { // To avoid binding twice.
writable.on("close", () => ae.emit("close"));
writable.on("error", (error) => ae.emit("error", error));
ae.on("destroy", () => writable.destroy());
}
writable.on("drain", () => ae.emit("drain"));
writable.on("finish", () => ae.emit("finish"));
writable.on("pipe", () => ae.emit("pipe"));
writable.on("unpipe", () => ae.emit("unpipe"));
ae.on("cork", () => writable.cork());
ae.on("end", (chunk, encoding, callbackId) => writable.end(chunk, encoding, maybeCallback(ae, callbackId)));
ae.on("setDefaultEncoding", (encoding) => writable.setDefaultEncoding(encoding));
ae.on("uncork", () => writable.uncork());
// Sockets can pass an fd instead of a callback but streams cannot.
ae.on("write", (chunk, encoding, fd, callbackId) => writable.write(chunk, encoding, maybeCallback(ae, callbackId) || fd));
};
/**
* Bind a readable stream to an active evaluation.
*/
export const bindReadable = (ae: ActiveEval, readable: Readable): void => {
// Streams don't have an argument on close but sockets do.
readable.on("close", (...args: any[]) => ae.emit("close", ...args));
readable.on("data", (data) => ae.emit("data", data));
readable.on("end", () => ae.emit("end"));
readable.on("error", (error) => ae.emit("error", error));
readable.on("readable", () => ae.emit("readable"));
ae.on("destroy", () => readable.destroy());
ae.on("pause", () => readable.pause());
ae.on("push", (chunk, encoding) => readable.push(chunk, encoding));
ae.on("resume", () => readable.resume());
ae.on("setEncoding", (encoding) => readable.setEncoding(encoding));
ae.on("unshift", (chunk) => readable.unshift(chunk));
};
/**
* Wrap an evaluation emitter to make unique events for an item to prevent
* conflicts when it shares that emitter with other items.
*/
export const createUniqueEval = (ae: ActiveEval, id: number | "stdout" | "stderr" | "stdin"): ActiveEval => {
let events = <string[]>[];
return {
removeAllListeners: (event?: string): void => {
if (!event) {
events.forEach((e) => ae.removeAllListeners(e));
events = [];
} else {
const index = events.indexOf(event);
if (index !== -1) {
events.splice(index, 1);
ae.removeAllListeners(`${event}:${id}`);
}
}
},
emit: (event: string, ...args: any[]): void => {
ae.emit(`${event}:${id}`, ...args);
},
on: (event: string, cb: (...args: any[]) => void): void => {
if (!events.includes(event)) {
events.push(event);
}
ae.on(`${event}:${id}`, cb);
},
};
};
/**
* An event emitter that can store callbacks with IDs in a map so we can pass
* them back and forth through an active evaluation using those IDs.
*/
export class CallbackEmitter extends EventEmitter {
private _ae: ActiveEval | undefined;
private callbackId = 0;
private readonly callbacks = new Map<number, Function>();
public constructor(ae?: ActiveEval) {
super();
if (ae) {
this.ae = ae;
}
}
protected get ae(): ActiveEval {
if (!this._ae) {
throw new Error("trying to access active evaluation before it has been set");
}
return this._ae;
}
protected set ae(ae: ActiveEval) {
if (this._ae) {
throw new Error("cannot override active evaluation");
}
this._ae = ae;
this.ae.on("callback", (callbackId, ...args: any[]) => this.runCallback(callbackId, ...args));
}
/**
* Store the callback and return and ID referencing its location in the map.
*/
protected storeCallback(callback?: Function): number | undefined {
if (!callback) {
return undefined;
}
const callbackId = this.callbackId++;
this.callbacks.set(callbackId, callback);
return callbackId;
}
/**
* Call the function with the specified ID and delete it from the map.
* If the ID is undefined or doesn't exist, nothing happens.
*/
private runCallback(callbackId?: number, ...args: any[]): void {
const callback = typeof callbackId !== "undefined" && this.callbacks.get(callbackId);
if (callback && typeof callbackId !== "undefined") {
this.callbacks.delete(callbackId);
callback(...args);
}
}
}
/**
* A writable stream over an active evaluation.
*/
export class ActiveEvalWritable extends CallbackEmitter implements Writable {
public constructor(ae: ActiveEval) {
super(ae);
// Streams don't have an argument on close but sockets do.
this.ae.on("close", (...args: any[]) => this.emit("close", ...args));
this.ae.on("drain", () => this.emit("drain"));
this.ae.on("error", (error) => this.emit("error", error));
this.ae.on("finish", () => this.emit("finish"));
this.ae.on("pipe", () => logger.warn("pipe is not supported"));
this.ae.on("unpipe", () => logger.warn("unpipe is not supported"));
}
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 { this.ae.emit("cork"); }
public destroy(): void { this.ae.emit("destroy"); }
public setDefaultEncoding(encoding: string): this {
this.ae.emit("setDefaultEncoding", encoding);
return this;
}
public uncork(): void { this.ae.emit("uncork"); }
public write(chunk: any, encoding?: string | ((error?: Error | null) => void), callback?: (error?: Error | null) => void): boolean {
if (typeof encoding === "function") {
callback = encoding;
encoding = undefined;
}
// Sockets can pass an fd instead of a callback but streams cannot..
this.ae.emit("write", chunk, encoding, undefined, this.storeCallback(callback));
// Always true since we can't get this synchronously.
return true;
}
public end(data?: any, encoding?: string | Function, callback?: Function): void {
if (typeof encoding === "function") {
callback = encoding;
encoding = undefined;
}
this.ae.emit("end", data, encoding, this.storeCallback(callback));
}
}
/**
* A readable stream over an active evaluation.
*/
export class ActiveEvalReadable extends CallbackEmitter implements Readable {
public constructor(ae: ActiveEval) {
super(ae);
this.ae.on("close", () => this.emit("close"));
this.ae.on("data", (data) => this.emit("data", data));
this.ae.on("end", () => this.emit("end"));
this.ae.on("error", (error) => this.emit("error", error));
this.ae.on("readable", () => this.emit("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(): any { throw new Error("not implemented"); }
public isPaused(): boolean { throw new Error("not implemented"); }
public pipe<T>(): T { throw new Error("not implemented"); }
public unpipe(): this { throw new Error("not implemented"); }
public unshift(): this { throw new Error("not implemented"); }
public wrap(): this { throw new Error("not implemented"); }
public push(): boolean { throw new Error("not implemented"); }
public _destroy(): void { throw new Error("not implemented"); }
public [Symbol.asyncIterator](): AsyncIterableIterator<any> { throw new Error("not implemented"); }
public destroy(): void { this.ae.emit("destroy"); }
public pause(): this { return this.emitReturnThis("pause"); }
public resume(): this { return this.emitReturnThis("resume"); }
public setEncoding(encoding?: string): this { return this.emitReturnThis("setEncoding", encoding); }
// tslint:disable-next-line no-any
protected emitReturnThis(event: string, ...args: any[]): this {
this.ae.emit(event, ...args);
return this;
}
}
/**
* An duplex stream over an active evaluation.
*/
export class ActiveEvalDuplex extends ActiveEvalReadable implements Duplex {
// Some unfortunate duplication here since we can't have multiple extends.
public constructor(ae: ActiveEval) {
super(ae);
this.ae.on("drain", () => this.emit("drain"));
this.ae.on("finish", () => this.emit("finish"));
this.ae.on("pipe", () => logger.warn("pipe is not supported"));
this.ae.on("unpipe", () => logger.warn("unpipe is not supported"));
}
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 { this.ae.emit("cork"); }
public destroy(): void { this.ae.emit("destroy"); }
public setDefaultEncoding(encoding: string): this {
this.ae.emit("setDefaultEncoding", encoding);
return this;
}
public uncork(): void { this.ae.emit("uncork"); }
public write(chunk: any, encoding?: string | ((error?: Error | null) => void), callback?: (error?: Error | null) => void): boolean {
if (typeof encoding === "function") {
callback = encoding;
encoding = undefined;
}
// Sockets can pass an fd instead of a callback but streams cannot..
this.ae.emit("write", chunk, encoding, undefined, this.storeCallback(callback));
// Always true since we can't get this synchronously.
return true;
}
public end(data?: any, encoding?: string | Function, callback?: Function): void {
if (typeof encoding === "function") {
callback = encoding;
encoding = undefined;
}
this.ae.emit("end", data, encoding, this.storeCallback(callback));
}
}

View File

@ -26,7 +26,7 @@ class FS {
callback = mode;
mode = undefined;
}
this.client.evaluate((path, mode) => {
this.client.evaluate((_helper, path, mode) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -44,7 +44,7 @@ class FS {
callback = options;
options = undefined;
}
this.client.evaluate((path, data, options) => {
this.client.evaluate((_helper, path, data, options) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -57,7 +57,7 @@ class FS {
}
public chmod = (path: fs.PathLike, mode: string | number, callback: (err: NodeJS.ErrnoException) => void): void => {
this.client.evaluate((path, mode) => {
this.client.evaluate((_helper, path, mode) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -70,7 +70,7 @@ class FS {
}
public chown = (path: fs.PathLike, uid: number, gid: number, callback: (err: NodeJS.ErrnoException) => void): void => {
this.client.evaluate((path, uid, gid) => {
this.client.evaluate((_helper, path, uid, gid) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -83,7 +83,7 @@ class FS {
}
public close = (fd: number, callback: (err: NodeJS.ErrnoException) => void): void => {
this.client.evaluate((fd) => {
this.client.evaluate((_helper, fd) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -99,7 +99,7 @@ class FS {
if (typeof flags === "function") {
callback = flags;
}
this.client.evaluate((src, dest, flags) => {
this.client.evaluate((_helper, src, dest, flags) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -166,7 +166,7 @@ class FS {
}
public exists = (path: fs.PathLike, callback: (exists: boolean) => void): void => {
this.client.evaluate((path) => {
this.client.evaluate((_helper, path) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -179,7 +179,7 @@ class FS {
}
public fchmod = (fd: number, mode: string | number, callback: (err: NodeJS.ErrnoException) => void): void => {
this.client.evaluate((fd, mode) => {
this.client.evaluate((_helper, fd, mode) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -192,7 +192,7 @@ class FS {
}
public fchown = (fd: number, uid: number, gid: number, callback: (err: NodeJS.ErrnoException) => void): void => {
this.client.evaluate((fd, uid, gid) => {
this.client.evaluate((_helper, fd, uid, gid) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -205,7 +205,7 @@ class FS {
}
public fdatasync = (fd: number, callback: (err: NodeJS.ErrnoException) => void): void => {
this.client.evaluate((fd) => {
this.client.evaluate((_helper, fd) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -218,7 +218,7 @@ class FS {
}
public fstat = (fd: number, callback: (err: NodeJS.ErrnoException, stats: fs.Stats) => void): void => {
this.client.evaluate((fd) => {
this.client.evaluate((_helper, fd) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
const tslib = __non_webpack_require__("tslib") as typeof import("tslib");
@ -242,7 +242,7 @@ class FS {
}
public fsync = (fd: number, callback: (err: NodeJS.ErrnoException) => void): void => {
this.client.evaluate((fd) => {
this.client.evaluate((_helper, fd) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -259,7 +259,7 @@ class FS {
callback = len;
len = undefined;
}
this.client.evaluate((fd, len) => {
this.client.evaluate((_helper, fd, len) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -272,7 +272,7 @@ class FS {
}
public futimes = (fd: number, atime: string | number | Date, mtime: string | number | Date, callback: (err: NodeJS.ErrnoException) => void): void => {
this.client.evaluate((fd, atime, mtime) => {
this.client.evaluate((_helper, fd, atime, mtime) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -285,7 +285,7 @@ class FS {
}
public lchmod = (path: fs.PathLike, mode: string | number, callback: (err: NodeJS.ErrnoException) => void): void => {
this.client.evaluate((path, mode) => {
this.client.evaluate((_helper, path, mode) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -298,7 +298,7 @@ class FS {
}
public lchown = (path: fs.PathLike, uid: number, gid: number, callback: (err: NodeJS.ErrnoException) => void): void => {
this.client.evaluate((path, uid, gid) => {
this.client.evaluate((_helper, path, uid, gid) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -311,7 +311,7 @@ class FS {
}
public link = (existingPath: fs.PathLike, newPath: fs.PathLike, callback: (err: NodeJS.ErrnoException) => void): void => {
this.client.evaluate((existingPath, newPath) => {
this.client.evaluate((_helper, existingPath, newPath) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -324,7 +324,7 @@ class FS {
}
public lstat = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException, stats: fs.Stats) => void): void => {
this.client.evaluate((path) => {
this.client.evaluate((_helper, path) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
const tslib = __non_webpack_require__("tslib") as typeof import("tslib");
@ -352,7 +352,7 @@ class FS {
callback = mode;
mode = undefined;
}
this.client.evaluate((path, mode) => {
this.client.evaluate((_helper, path, mode) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -369,7 +369,7 @@ class FS {
callback = options;
options = undefined;
}
this.client.evaluate((prefix, options) => {
this.client.evaluate((_helper, prefix, options) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -386,7 +386,7 @@ class FS {
callback = mode;
mode = undefined;
}
this.client.evaluate((path, flags, mode) => {
this.client.evaluate((_helper, path, flags, mode) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -399,7 +399,7 @@ class FS {
}
public read = <TBuffer extends Buffer | Uint8Array>(fd: number, buffer: TBuffer, offset: number, length: number, position: number | null, callback: (err: NodeJS.ErrnoException, bytesRead: number, buffer: TBuffer) => void): void => {
this.client.evaluate((fd, length, position) => {
this.client.evaluate((_helper, fd, length, position) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
const buffer = new _Buffer(length);
@ -424,7 +424,7 @@ class FS {
callback = options;
options = undefined;
}
this.client.evaluate((path, options) => {
this.client.evaluate((_helper, path, options) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -442,7 +442,7 @@ class FS {
options = undefined;
}
// TODO: options can also take `withFileTypes` but the types aren't working.
this.client.evaluate((path, options) => {
this.client.evaluate((_helper, path, options) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -459,7 +459,7 @@ class FS {
callback = options;
options = undefined;
}
this.client.evaluate((path, options) => {
this.client.evaluate((_helper, path, options) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -476,7 +476,7 @@ class FS {
callback = options;
options = undefined;
}
this.client.evaluate((path, options) => {
this.client.evaluate((_helper, path, options) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -489,7 +489,7 @@ class FS {
}
public rename = (oldPath: fs.PathLike, newPath: fs.PathLike, callback: (err: NodeJS.ErrnoException) => void): void => {
this.client.evaluate((oldPath, newPath) => {
this.client.evaluate((_helper, oldPath, newPath) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -502,7 +502,7 @@ class FS {
}
public rmdir = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException) => void): void => {
this.client.evaluate((path) => {
this.client.evaluate((_helper, path) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -515,7 +515,7 @@ class FS {
}
public stat = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException, stats: fs.Stats) => void): void => {
this.client.evaluate((path) => {
this.client.evaluate((_helper, path) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
const tslib = __non_webpack_require__("tslib") as typeof import("tslib");
@ -547,7 +547,7 @@ class FS {
callback = type;
type = undefined;
}
this.client.evaluate((target, path, type) => {
this.client.evaluate((_helper, target, path, type) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -564,7 +564,7 @@ class FS {
callback = len;
len = undefined;
}
this.client.evaluate((path, len) => {
this.client.evaluate((_helper, path, len) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -577,7 +577,7 @@ class FS {
}
public unlink = (path: fs.PathLike, callback: (err: NodeJS.ErrnoException) => void): void => {
this.client.evaluate((path) => {
this.client.evaluate((_helper, path) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -590,7 +590,7 @@ class FS {
}
public utimes = (path: fs.PathLike, atime: string | number | Date, mtime: string | number | Date, callback: (err: NodeJS.ErrnoException) => void): void => {
this.client.evaluate((path, atime, mtime) => {
this.client.evaluate((_helper, path, atime, mtime) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -615,7 +615,7 @@ class FS {
callback = position;
position = undefined;
}
this.client.evaluate((fd, buffer, offset, length, position) => {
this.client.evaluate((_helper, fd, buffer, offset, length, position) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");
@ -638,7 +638,7 @@ class FS {
callback = options;
options = undefined;
}
this.client.evaluate((path, data, options) => {
this.client.evaluate((_helper, path, data, options) => {
const fs = __non_webpack_require__("fs") as typeof import("fs");
const util = __non_webpack_require__("util") as typeof import("util");

View File

@ -1,6 +1,5 @@
import * as net from "net";
import { ActiveEval } from "@coder/protocol";
import { CallbackEmitter, ActiveEvalDuplex, createUniqueEval } from "./evaluation";
import { CallbackEmitter, ActiveEvalDuplex, ActiveEvalHelper } from "@coder/protocol";
import { client } from "./client";
declare var __non_webpack_require__: typeof require;
@ -9,12 +8,11 @@ class Socket extends ActiveEvalDuplex implements net.Socket {
private _connecting: boolean = false;
private _destroyed: boolean = false;
public constructor(options?: net.SocketConstructorOpts, ae?: ActiveEval) {
public constructor(options?: net.SocketConstructorOpts, ae?: ActiveEvalHelper) {
super(ae || client.run((ae, options) => {
const net = __non_webpack_require__("net") as typeof import("net");
const { bindSocket } = __non_webpack_require__("@coder/ide/src/fill/evaluation") as typeof import("@coder/ide/src/fill/evaluation");
return bindSocket(ae, new net.Socket(options));
return ae.bindSocket(new net.Socket(options));
}, options));
this.ae.on("connect", () => {
@ -94,14 +92,14 @@ class Server extends CallbackEmitter implements net.Server {
this.ae = client.run((ae, options, callbackId) => {
const net = __non_webpack_require__("net") as typeof import("net");
const { maybeCallback, bindSocket, createUniqueEval } = __non_webpack_require__("@coder/ide/src/fill/evaluation") as typeof import("@coder/ide/src/fill/evaluation");
let connectionId = 0;
const sockets = new Map<number, net.Socket>();
const storeSocket = (socket: net.Socket): number => {
const socketId = connectionId++;
sockets.set(socketId, socket);
const disposer = bindSocket(createUniqueEval(ae, socketId), socket);
const socketAe = ae.createUnique(socketId);
const disposer = socketAe.bindSocket(socket);
socket.on("close", () => {
disposer.dispose();
sockets.delete(socketId);
@ -110,7 +108,7 @@ class Server extends CallbackEmitter implements net.Server {
return socketId;
};
const callback = maybeCallback(ae, callbackId);
const callback = ae.maybeCallback(callbackId);
let server = new net.Server(options, typeof callback !== "undefined" ? (socket): void => {
callback(storeSocket(socket));
} : undefined);
@ -120,7 +118,7 @@ class Server extends CallbackEmitter implements net.Server {
server.on("error", (error) => ae.emit("error", error));
server.on("listening", () => ae.emit("listening"));
ae.on("close", (callbackId: number) => server.close(maybeCallback(ae, callbackId)));
ae.on("close", (callbackId: number) => server.close(ae.maybeCallback(callbackId)));
ae.on("listen", (handle?: net.ListenOptions | number | string) => server.listen(handle));
ae.on("ref", () => server.ref());
ae.on("unref", () => server.unref());
@ -147,7 +145,8 @@ class Server extends CallbackEmitter implements net.Server {
});
this.ae.on("connection", (socketId) => {
const socket = new Socket(undefined, createUniqueEval(this.ae, socketId));
const socketAe = this.ae.createUnique(socketId);
const socket = new Socket(undefined, socketAe);
this.sockets.set(socketId, socket);
socket.on("close", () => this.sockets.delete(socketId));
if (connectionListener) {