mirror of https://git.tuxpa.in/a/code-server.git
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:
parent
de3fbd689f
commit
8b8bef015e
|
@ -1,7 +1,7 @@
|
||||||
import * as cp from "child_process";
|
import * as cp from "child_process";
|
||||||
import * as net from "net";
|
import * as net from "net";
|
||||||
import * as stream from "stream";
|
import * as stream from "stream";
|
||||||
import { CallbackEmitter, ActiveEvalReadable, ActiveEvalWritable, createUniqueEval } from "./evaluation";
|
import { CallbackEmitter, ActiveEvalReadable, ActiveEvalWritable } from "@coder/protocol";
|
||||||
import { client } from "./client";
|
import { client } from "./client";
|
||||||
import { promisify } from "util";
|
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) => {
|
this.ae = client.run((ae, command, method, args, options, callbackId) => {
|
||||||
const cp = __non_webpack_require__("child_process") as typeof import("child_process");
|
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;
|
let childProcess: cp.ChildProcess;
|
||||||
switch (method) {
|
switch (method) {
|
||||||
case "exec":
|
case "exec":
|
||||||
childProcess = cp.exec(command, options, maybeCallback(ae, callbackId));
|
childProcess = cp.exec(command, options, ae.maybeCallback(callbackId));
|
||||||
break;
|
break;
|
||||||
case "spawn":
|
case "spawn":
|
||||||
childProcess = cp.spawn(command, args, options);
|
childProcess = cp.spawn(command, args, options);
|
||||||
break;
|
break;
|
||||||
case "fork":
|
case "fork":
|
||||||
const forkOptions = options as cp.ForkOptions;
|
childProcess = ae.fork(command, args, options);
|
||||||
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);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`invalid method ${method}`);
|
throw new Error(`invalid method ${method}`);
|
||||||
|
@ -62,7 +54,7 @@ class ChildProcess extends CallbackEmitter implements cp.ChildProcess {
|
||||||
ae.on("disconnect", () => childProcess.disconnect());
|
ae.on("disconnect", () => childProcess.disconnect());
|
||||||
ae.on("kill", (signal: string) => childProcess.kill(signal));
|
ae.on("kill", (signal: string) => childProcess.kill(signal));
|
||||||
ae.on("ref", () => childProcess.ref());
|
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.on("unref", () => childProcess.unref());
|
||||||
|
|
||||||
ae.emit("pid", childProcess.pid);
|
ae.emit("pid", childProcess.pid);
|
||||||
|
@ -73,13 +65,16 @@ class ChildProcess extends CallbackEmitter implements cp.ChildProcess {
|
||||||
childProcess.on("message", (message) => ae.emit("message", message));
|
childProcess.on("message", (message) => ae.emit("message", message));
|
||||||
|
|
||||||
if (childProcess.stdin) {
|
if (childProcess.stdin) {
|
||||||
bindWritable(createUniqueEval(ae, "stdin"), childProcess.stdin);
|
const stdinAe = ae.createUnique("stdin");
|
||||||
|
stdinAe.bindWritable(childProcess.stdin);
|
||||||
}
|
}
|
||||||
if (childProcess.stdout) {
|
if (childProcess.stdout) {
|
||||||
bindReadable(createUniqueEval(ae, "stdout"), childProcess.stdout);
|
const stdoutAe = ae.createUnique("stdout");
|
||||||
|
stdoutAe.bindReadable(childProcess.stdout);
|
||||||
}
|
}
|
||||||
if (childProcess.stderr) {
|
if (childProcess.stderr) {
|
||||||
bindReadable(createUniqueEval(ae, "stderr"), childProcess.stderr);
|
const stderrAe = ae.createUnique("stderr");
|
||||||
|
stderrAe.bindReadable(childProcess.stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -96,9 +91,9 @@ class ChildProcess extends CallbackEmitter implements cp.ChildProcess {
|
||||||
this._connected = true;
|
this._connected = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.stdin = new ActiveEvalWritable(createUniqueEval(this.ae, "stdin"));
|
this.stdin = new ActiveEvalWritable(this.ae.createUnique("stdin"));
|
||||||
this.stdout = new ActiveEvalReadable(createUniqueEval(this.ae, "stdout"));
|
this.stdout = new ActiveEvalReadable(this.ae.createUnique("stdout"));
|
||||||
this.stderr = new ActiveEvalReadable(createUniqueEval(this.ae, "stderr"));
|
this.stderr = new ActiveEvalReadable(this.ae.createUnique("stderr"));
|
||||||
|
|
||||||
this.ae.on("close", (code, signal) => this.emit("close", code, signal));
|
this.ae.on("close", (code, signal) => this.emit("close", code, signal));
|
||||||
this.ae.on("disconnect", () => this.emit("disconnect"));
|
this.ae.on("disconnect", () => this.emit("disconnect"));
|
||||||
|
|
|
@ -152,7 +152,7 @@ class Clipboard {
|
||||||
|
|
||||||
class Shell {
|
class Shell {
|
||||||
public async moveItemToTrash(path: string): Promise<void> {
|
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");
|
const trash = __non_webpack_require__("trash") as typeof import("trash");
|
||||||
|
|
||||||
return trash(path);
|
return trash(path);
|
||||||
|
|
|
@ -26,7 +26,7 @@ class FS {
|
||||||
callback = mode;
|
callback = mode;
|
||||||
mode = undefined;
|
mode = undefined;
|
||||||
}
|
}
|
||||||
this.client.evaluate((path, mode) => {
|
this.client.evaluate((_helper, path, mode) => {
|
||||||
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
const util = __non_webpack_require__("util") as typeof import("util");
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ class FS {
|
||||||
callback = options;
|
callback = options;
|
||||||
options = undefined;
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
const util = __non_webpack_require__("util") as typeof import("util");
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ class FS {
|
||||||
if (typeof flags === "function") {
|
if (typeof flags === "function") {
|
||||||
callback = flags;
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
const util = __non_webpack_require__("util") as typeof import("util");
|
||||||
const tslib = __non_webpack_require__("tslib") as typeof import("tslib");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
const util = __non_webpack_require__("util") as typeof import("util");
|
||||||
|
|
||||||
|
@ -259,7 +259,7 @@ class FS {
|
||||||
callback = len;
|
callback = len;
|
||||||
len = undefined;
|
len = undefined;
|
||||||
}
|
}
|
||||||
this.client.evaluate((fd, len) => {
|
this.client.evaluate((_helper, fd, len) => {
|
||||||
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
const util = __non_webpack_require__("util") as typeof import("util");
|
||||||
const tslib = __non_webpack_require__("tslib") as typeof import("tslib");
|
const tslib = __non_webpack_require__("tslib") as typeof import("tslib");
|
||||||
|
@ -352,7 +352,7 @@ class FS {
|
||||||
callback = mode;
|
callback = mode;
|
||||||
mode = undefined;
|
mode = undefined;
|
||||||
}
|
}
|
||||||
this.client.evaluate((path, mode) => {
|
this.client.evaluate((_helper, path, mode) => {
|
||||||
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
const util = __non_webpack_require__("util") as typeof import("util");
|
||||||
|
|
||||||
|
@ -369,7 +369,7 @@ class FS {
|
||||||
callback = options;
|
callback = options;
|
||||||
options = undefined;
|
options = undefined;
|
||||||
}
|
}
|
||||||
this.client.evaluate((prefix, options) => {
|
this.client.evaluate((_helper, prefix, options) => {
|
||||||
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
const util = __non_webpack_require__("util") as typeof import("util");
|
||||||
|
|
||||||
|
@ -386,7 +386,7 @@ class FS {
|
||||||
callback = mode;
|
callback = mode;
|
||||||
mode = undefined;
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
const util = __non_webpack_require__("util") as typeof import("util");
|
||||||
const buffer = new _Buffer(length);
|
const buffer = new _Buffer(length);
|
||||||
|
@ -424,7 +424,7 @@ class FS {
|
||||||
callback = options;
|
callback = options;
|
||||||
options = undefined;
|
options = undefined;
|
||||||
}
|
}
|
||||||
this.client.evaluate((path, options) => {
|
this.client.evaluate((_helper, path, options) => {
|
||||||
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
const util = __non_webpack_require__("util") as typeof import("util");
|
||||||
|
|
||||||
|
@ -442,7 +442,7 @@ class FS {
|
||||||
options = undefined;
|
options = undefined;
|
||||||
}
|
}
|
||||||
// TODO: options can also take `withFileTypes` but the types aren't working.
|
// 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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
const util = __non_webpack_require__("util") as typeof import("util");
|
||||||
|
|
||||||
|
@ -459,7 +459,7 @@ class FS {
|
||||||
callback = options;
|
callback = options;
|
||||||
options = undefined;
|
options = undefined;
|
||||||
}
|
}
|
||||||
this.client.evaluate((path, options) => {
|
this.client.evaluate((_helper, path, options) => {
|
||||||
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
const util = __non_webpack_require__("util") as typeof import("util");
|
||||||
|
|
||||||
|
@ -476,7 +476,7 @@ class FS {
|
||||||
callback = options;
|
callback = options;
|
||||||
options = undefined;
|
options = undefined;
|
||||||
}
|
}
|
||||||
this.client.evaluate((path, options) => {
|
this.client.evaluate((_helper, path, options) => {
|
||||||
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
const util = __non_webpack_require__("util") as typeof import("util");
|
||||||
const tslib = __non_webpack_require__("tslib") as typeof import("tslib");
|
const tslib = __non_webpack_require__("tslib") as typeof import("tslib");
|
||||||
|
@ -547,7 +547,7 @@ class FS {
|
||||||
callback = type;
|
callback = type;
|
||||||
type = undefined;
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
const util = __non_webpack_require__("util") as typeof import("util");
|
||||||
|
|
||||||
|
@ -564,7 +564,7 @@ class FS {
|
||||||
callback = len;
|
callback = len;
|
||||||
len = undefined;
|
len = undefined;
|
||||||
}
|
}
|
||||||
this.client.evaluate((path, len) => {
|
this.client.evaluate((_helper, path, len) => {
|
||||||
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
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 => {
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
const util = __non_webpack_require__("util") as typeof import("util");
|
||||||
|
|
||||||
|
@ -615,7 +615,7 @@ class FS {
|
||||||
callback = position;
|
callback = position;
|
||||||
position = undefined;
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
const util = __non_webpack_require__("util") as typeof import("util");
|
||||||
|
|
||||||
|
@ -638,7 +638,7 @@ class FS {
|
||||||
callback = options;
|
callback = options;
|
||||||
options = undefined;
|
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 fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
const util = __non_webpack_require__("util") as typeof import("util");
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import * as net from "net";
|
import * as net from "net";
|
||||||
import { ActiveEval } from "@coder/protocol";
|
import { CallbackEmitter, ActiveEvalDuplex, ActiveEvalHelper } from "@coder/protocol";
|
||||||
import { CallbackEmitter, ActiveEvalDuplex, createUniqueEval } from "./evaluation";
|
|
||||||
import { client } from "./client";
|
import { client } from "./client";
|
||||||
|
|
||||||
declare var __non_webpack_require__: typeof require;
|
declare var __non_webpack_require__: typeof require;
|
||||||
|
@ -9,12 +8,11 @@ class Socket extends ActiveEvalDuplex implements net.Socket {
|
||||||
private _connecting: boolean = false;
|
private _connecting: boolean = false;
|
||||||
private _destroyed: 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) => {
|
super(ae || client.run((ae, options) => {
|
||||||
const net = __non_webpack_require__("net") as typeof import("net");
|
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));
|
}, options));
|
||||||
|
|
||||||
this.ae.on("connect", () => {
|
this.ae.on("connect", () => {
|
||||||
|
@ -94,14 +92,14 @@ class Server extends CallbackEmitter implements net.Server {
|
||||||
|
|
||||||
this.ae = client.run((ae, options, callbackId) => {
|
this.ae = client.run((ae, options, callbackId) => {
|
||||||
const net = __non_webpack_require__("net") as typeof import("net");
|
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;
|
let connectionId = 0;
|
||||||
const sockets = new Map<number, net.Socket>();
|
const sockets = new Map<number, net.Socket>();
|
||||||
const storeSocket = (socket: net.Socket): number => {
|
const storeSocket = (socket: net.Socket): number => {
|
||||||
const socketId = connectionId++;
|
const socketId = connectionId++;
|
||||||
sockets.set(socketId, socket);
|
sockets.set(socketId, socket);
|
||||||
const disposer = bindSocket(createUniqueEval(ae, socketId), socket);
|
const socketAe = ae.createUnique(socketId);
|
||||||
|
const disposer = socketAe.bindSocket(socket);
|
||||||
socket.on("close", () => {
|
socket.on("close", () => {
|
||||||
disposer.dispose();
|
disposer.dispose();
|
||||||
sockets.delete(socketId);
|
sockets.delete(socketId);
|
||||||
|
@ -110,7 +108,7 @@ class Server extends CallbackEmitter implements net.Server {
|
||||||
return socketId;
|
return socketId;
|
||||||
};
|
};
|
||||||
|
|
||||||
const callback = maybeCallback(ae, callbackId);
|
const callback = ae.maybeCallback(callbackId);
|
||||||
let server = new net.Server(options, typeof callback !== "undefined" ? (socket): void => {
|
let server = new net.Server(options, typeof callback !== "undefined" ? (socket): void => {
|
||||||
callback(storeSocket(socket));
|
callback(storeSocket(socket));
|
||||||
} : undefined);
|
} : undefined);
|
||||||
|
@ -120,7 +118,7 @@ class Server extends CallbackEmitter implements net.Server {
|
||||||
server.on("error", (error) => ae.emit("error", error));
|
server.on("error", (error) => ae.emit("error", error));
|
||||||
server.on("listening", () => ae.emit("listening"));
|
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("listen", (handle?: net.ListenOptions | number | string) => server.listen(handle));
|
||||||
ae.on("ref", () => server.ref());
|
ae.on("ref", () => server.ref());
|
||||||
ae.on("unref", () => server.unref());
|
ae.on("unref", () => server.unref());
|
||||||
|
@ -147,7 +145,8 @@ class Server extends CallbackEmitter implements net.Server {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.ae.on("connection", (socketId) => {
|
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);
|
this.sockets.set(socketId, socket);
|
||||||
socket.on("close", () => this.sockets.delete(socketId));
|
socket.on("close", () => this.sockets.delete(socketId));
|
||||||
if (connectionListener) {
|
if (connectionListener) {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
import { Emitter } from "@coder/events";
|
import { Emitter } from "@coder/events";
|
||||||
import { logger, field } from "@coder/logger";
|
import { logger, field } from "@coder/logger";
|
||||||
import { ReadWriteConnection, InitData, OperatingSystem, SharedProcessData } from "../common/connection";
|
|
||||||
import { Disposer, stringify, parse } from "../common/util";
|
|
||||||
import { NewEvalMessage, ServerMessage, EvalDoneMessage, EvalFailedMessage, ClientMessage, WorkingInitMessage, EvalEventMessage } from "../proto";
|
import { NewEvalMessage, ServerMessage, EvalDoneMessage, EvalFailedMessage, ClientMessage, WorkingInitMessage, EvalEventMessage } from "../proto";
|
||||||
import { ActiveEval } from "./evaluate";
|
import { ReadWriteConnection, InitData, OperatingSystem, SharedProcessData } from "../common/connection";
|
||||||
|
import { ActiveEvalHelper, EvalHelper, Disposer, ServerActiveEvalHelper } from "../common/helpers";
|
||||||
|
import { stringify, parse } from "../common/util";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client accepts an arbitrary connection intended to communicate with the Server.
|
* Client accepts an arbitrary connection intended to communicate with the Server.
|
||||||
|
@ -56,13 +56,13 @@ export class Client {
|
||||||
return this.initDataPromise;
|
return this.initDataPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
public run(func: (ae: ActiveEval) => Disposer): ActiveEval;
|
public run(func: (helper: ServerActiveEvalHelper) => Disposer): ActiveEvalHelper;
|
||||||
public run<T1>(func: (ae: ActiveEval, a1: T1) => Disposer, a1: T1): ActiveEval;
|
public run<T1>(func: (helper: ServerActiveEvalHelper, a1: T1) => Disposer, a1: T1): ActiveEvalHelper;
|
||||||
public run<T1, T2>(func: (ae: ActiveEval, a1: T1, a2: T2) => Disposer, a1: T1, a2: T2): ActiveEval;
|
public run<T1, T2>(func: (helper: ServerActiveEvalHelper, a1: T1, a2: T2) => Disposer, a1: T1, a2: T2): ActiveEvalHelper;
|
||||||
public run<T1, T2, T3>(func: (ae: ActiveEval, a1: T1, a2: T2, a3: T3) => Disposer, a1: T1, a2: T2, a3: T3): ActiveEval;
|
public run<T1, T2, T3>(func: (helper: ServerActiveEvalHelper, a1: T1, a2: T2, a3: T3) => Disposer, a1: T1, a2: T2, a3: T3): ActiveEvalHelper;
|
||||||
public run<T1, T2, T3, T4>(func: (ae: ActiveEval, a1: T1, a2: T2, a3: T3, a4: T4) => Disposer, a1: T1, a2: T2, a3: T3, a4: T4): ActiveEval;
|
public run<T1, T2, T3, T4>(func: (helper: ServerActiveEvalHelper, a1: T1, a2: T2, a3: T3, a4: T4) => Disposer, a1: T1, a2: T2, a3: T3, a4: T4): ActiveEvalHelper;
|
||||||
public run<T1, T2, T3, T4, T5>(func: (ae: ActiveEval, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5) => Disposer, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5): ActiveEval;
|
public run<T1, T2, T3, T4, T5>(func: (helper: ServerActiveEvalHelper, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5) => Disposer, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5): ActiveEvalHelper;
|
||||||
public run<T1, T2, T3, T4, T5, T6>(func: (ae: ActiveEval, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6) => Disposer, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6): ActiveEval;
|
public run<T1, T2, T3, T4, T5, T6>(func: (helper: ServerActiveEvalHelper, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6) => Disposer, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6): ActiveEvalHelper;
|
||||||
/**
|
/**
|
||||||
* Run a function on the server and provide an event emitter which allows
|
* Run a function on the server and provide an event emitter which allows
|
||||||
* listening and emitting to the emitter provided to that function. The
|
* listening and emitting to the emitter provided to that function. The
|
||||||
|
@ -70,7 +70,7 @@ export class Client {
|
||||||
* disconnects and for notifying when disposal has happened outside manual
|
* disconnects and for notifying when disposal has happened outside manual
|
||||||
* activation.
|
* activation.
|
||||||
*/
|
*/
|
||||||
public run<T1, T2, T3, T4, T5, T6>(func: (ae: ActiveEval, a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6) => Disposer, a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6): ActiveEval {
|
public run<T1, T2, T3, T4, T5, T6>(func: (helper: ServerActiveEvalHelper, a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6) => Disposer, a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6): ActiveEvalHelper {
|
||||||
const doEval = this.doEvaluate(func, a1, a2, a3, a4, a5, a6, true);
|
const doEval = this.doEvaluate(func, a1, a2, a3, a4, a5, a6, true);
|
||||||
|
|
||||||
// This takes server events and emits them to the client's emitter.
|
// This takes server events and emits them to the client's emitter.
|
||||||
|
@ -89,9 +89,9 @@ export class Client {
|
||||||
eventEmitter.emit("error", ex);
|
eventEmitter.emit("error", ex);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return new ActiveEvalHelper({
|
||||||
// This takes client events and emits them to the server's emitter and
|
// This takes client events and emits them to the server's emitter and
|
||||||
// listens to events received from the server (via the event hook above).
|
// listens to events received from the server (via the event hook above).
|
||||||
return {
|
|
||||||
// tslint:disable no-any
|
// tslint:disable no-any
|
||||||
on: (event: string, cb: (...args: any[]) => void): EventEmitter => eventEmitter.on(event, cb),
|
on: (event: string, cb: (...args: any[]) => void): EventEmitter => eventEmitter.on(event, cb),
|
||||||
emit: (event: string, ...args: any[]): void => {
|
emit: (event: string, ...args: any[]): void => {
|
||||||
|
@ -105,21 +105,21 @@ export class Client {
|
||||||
},
|
},
|
||||||
removeAllListeners: (event: string): EventEmitter => eventEmitter.removeAllListeners(event),
|
removeAllListeners: (event: string): EventEmitter => eventEmitter.removeAllListeners(event),
|
||||||
// tslint:enable no-any
|
// tslint:enable no-any
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public evaluate<R>(func: () => R | Promise<R>): Promise<R>;
|
public evaluate<R>(func: (helper: EvalHelper) => R | Promise<R>): Promise<R>;
|
||||||
public evaluate<R, T1>(func: (a1: T1) => R | Promise<R>, a1: T1): Promise<R>;
|
public evaluate<R, T1>(func: (helper: EvalHelper, a1: T1) => R | Promise<R>, a1: T1): Promise<R>;
|
||||||
public evaluate<R, T1, T2>(func: (a1: T1, a2: T2) => R | Promise<R>, a1: T1, a2: T2): Promise<R>;
|
public evaluate<R, T1, T2>(func: (helper: EvalHelper, a1: T1, a2: T2) => R | Promise<R>, a1: T1, a2: T2): Promise<R>;
|
||||||
public evaluate<R, T1, T2, T3>(func: (a1: T1, a2: T2, a3: T3) => R | Promise<R>, a1: T1, a2: T2, a3: T3): Promise<R>;
|
public evaluate<R, T1, T2, T3>(func: (helper: EvalHelper, a1: T1, a2: T2, a3: T3) => R | Promise<R>, a1: T1, a2: T2, a3: T3): Promise<R>;
|
||||||
public evaluate<R, T1, T2, T3, T4>(func: (a1: T1, a2: T2, a3: T3, a4: T4) => R | Promise<R>, a1: T1, a2: T2, a3: T3, a4: T4): Promise<R>;
|
public evaluate<R, T1, T2, T3, T4>(func: (helper: EvalHelper, a1: T1, a2: T2, a3: T3, a4: T4) => R | Promise<R>, a1: T1, a2: T2, a3: T3, a4: T4): Promise<R>;
|
||||||
public evaluate<R, T1, T2, T3, T4, T5>(func: (a1: T1, a2: T2, a3: T3, a4: T4, a5: T5) => R | Promise<R>, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5): Promise<R>;
|
public evaluate<R, T1, T2, T3, T4, T5>(func: (helper: EvalHelper, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5) => R | Promise<R>, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5): Promise<R>;
|
||||||
public evaluate<R, T1, T2, T3, T4, T5, T6>(func: (a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6) => R | Promise<R>, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6): Promise<R>;
|
public evaluate<R, T1, T2, T3, T4, T5, T6>(func: (helper: EvalHelper, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6) => R | Promise<R>, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6): Promise<R>;
|
||||||
/**
|
/**
|
||||||
* Evaluates a function on the server.
|
* Evaluates a function on the server.
|
||||||
* To pass variables, ensure they are serializable and passed through the included function.
|
* To pass variables, ensure they are serializable and passed through the included function.
|
||||||
* @example
|
* @example
|
||||||
* const returned = await this.client.evaluate((value) => {
|
* const returned = await this.client.evaluate((helper, value) => {
|
||||||
* return value;
|
* return value;
|
||||||
* }, "hi");
|
* }, "hi");
|
||||||
* console.log(returned);
|
* console.log(returned);
|
||||||
|
@ -127,7 +127,7 @@ export class Client {
|
||||||
* @param func Function to evaluate
|
* @param func Function to evaluate
|
||||||
* @returns Promise rejected or resolved from the evaluated function
|
* @returns Promise rejected or resolved from the evaluated function
|
||||||
*/
|
*/
|
||||||
public evaluate<R, T1, T2, T3, T4, T5, T6>(func: (a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6) => R | Promise<R>, a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6): Promise<R> {
|
public evaluate<R, T1, T2, T3, T4, T5, T6>(func: (helper: EvalHelper, a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6) => R | Promise<R>, a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6): Promise<R> {
|
||||||
return this.doEvaluate(func, a1, a2, a3, a4, a5, a6, false).completed;
|
return this.doEvaluate(func, a1, a2, a3, a4, a5, a6, false).completed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
export interface ActiveEval {
|
|
||||||
removeAllListeners(event?: string): void;
|
|
||||||
|
|
||||||
// tslint:disable no-any
|
|
||||||
emit(event: string, ...args: any[]): void;
|
|
||||||
on(event: string, cb: (...args: any[]) => void): void;
|
|
||||||
// tslint:disable no-any
|
|
||||||
}
|
|
|
@ -1,50 +1,138 @@
|
||||||
import { SpawnOptions, ForkOptions } from "child_process";
|
import { ChildProcess, SpawnOptions, ForkOptions } from "child_process";
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
import { Socket } from "net";
|
import { Socket } from "net";
|
||||||
import { Duplex, Readable, Writable } from "stream";
|
import { Duplex, Readable, Writable } from "stream";
|
||||||
|
import { IDisposable } from "@coder/disposable";
|
||||||
import { logger } from "@coder/logger";
|
import { logger } from "@coder/logger";
|
||||||
import { ActiveEval, Disposer } from "@coder/protocol";
|
|
||||||
|
|
||||||
// tslint:disable no-any
|
// 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
|
export type ForkProvider = (modulePath: string, args: string[], options: ForkOptions, dataDir?: string) => ChildProcess;
|
||||||
// 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
|
export interface Disposer extends IDisposable {
|
||||||
// won't have access to PATH, etc.
|
onDidDispose: (cb: () => void) => void;
|
||||||
// TODO: An alternative solution would be to send the env to the browser?
|
}
|
||||||
export const preserveEnv = (options: SpawnOptions | ForkOptions): void => {
|
|
||||||
|
interface ActiveEvalEmitter {
|
||||||
|
removeAllListeners(event?: string): void;
|
||||||
|
emit(event: string, ...args: any[]): void;
|
||||||
|
on(event: string, cb: (...args: any[]) => void): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for evaluations.
|
||||||
|
*/
|
||||||
|
export class EvalHelper {
|
||||||
|
/**
|
||||||
|
* 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?
|
||||||
|
*/
|
||||||
|
public preserveEnv(options: SpawnOptions | ForkOptions): void {
|
||||||
if (options && options.env) {
|
if (options && options.env) {
|
||||||
options.env = { ...process.env, ...options.env };
|
options.env = { ...process.env, ...options.env };
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind a socket to an active evaluation.
|
* Helper class for active evaluations.
|
||||||
*/
|
*/
|
||||||
export const bindSocket = (ae: ActiveEval, socket: Socket): Disposer => {
|
export class ActiveEvalHelper extends EvalHelper implements ActiveEvalEmitter {
|
||||||
socket.on("connect", () => ae.emit("connect"));
|
public constructor(private readonly emitter: ActiveEvalEmitter) {
|
||||||
socket.on("lookup", (error, address, family, host) => ae.emit("lookup", error, address, family, host));
|
super();
|
||||||
socket.on("timeout", () => ae.emit("timeout"));
|
}
|
||||||
|
|
||||||
ae.on("connect", (options, callbackId) => socket.connect(options, maybeCallback(ae, callbackId)));
|
public removeAllListeners(event?: string): void {
|
||||||
ae.on("ref", () => socket.ref());
|
this.emitter.removeAllListeners(event);
|
||||||
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);
|
public emit(event: string, ...args: any[]): void {
|
||||||
bindWritable(ae, socket);
|
this.emitter.emit(event, ...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public on(event: string, cb: (...args: any[]) => void): void {
|
||||||
|
this.emitter.on(event, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new helper to make unique events for an item.
|
||||||
|
*/
|
||||||
|
public createUnique(id: number | "stdout" | "stderr" | "stdin"): ActiveEvalHelper {
|
||||||
|
return new ActiveEvalHelper(this.createUniqueEmitter(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap the evaluation emitter to make unique events for an item to prevent
|
||||||
|
* conflicts when it shares that emitter with other items.
|
||||||
|
*/
|
||||||
|
protected createUniqueEmitter(id: number | "stdout" | "stderr" | "stdin"): ActiveEvalEmitter {
|
||||||
|
let events = <string[]>[];
|
||||||
|
|
||||||
|
return {
|
||||||
|
removeAllListeners: (event?: string): void => {
|
||||||
|
if (!event) {
|
||||||
|
events.forEach((e) => this.removeAllListeners(e));
|
||||||
|
events = [];
|
||||||
|
} else {
|
||||||
|
const index = events.indexOf(event);
|
||||||
|
if (index !== -1) {
|
||||||
|
events.splice(index, 1);
|
||||||
|
this.removeAllListeners(`${event}:${id}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emit: (event: string, ...args: any[]): void => {
|
||||||
|
this.emit(`${event}:${id}`, ...args);
|
||||||
|
},
|
||||||
|
on: (event: string, cb: (...args: any[]) => void): void => {
|
||||||
|
if (!events.includes(event)) {
|
||||||
|
events.push(event);
|
||||||
|
}
|
||||||
|
this.on(`${event}:${id}`, cb);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class for server-side active evaluations.
|
||||||
|
*/
|
||||||
|
export class ServerActiveEvalHelper extends ActiveEvalHelper {
|
||||||
|
public constructor(emitter: ActiveEvalEmitter, public readonly fork: ForkProvider) {
|
||||||
|
super(emitter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
public maybeCallback(callbackId?: number): ((...args: any[]) => void) | undefined {
|
||||||
|
return typeof callbackId !== "undefined" ? (...args: any[]): void => {
|
||||||
|
this.emit("callback", callbackId, ...args);
|
||||||
|
} : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a socket to an active evaluation and returns a disposer.
|
||||||
|
*/
|
||||||
|
public bindSocket(socket: Socket): Disposer {
|
||||||
|
socket.on("connect", () => this.emit("connect"));
|
||||||
|
socket.on("lookup", (error, address, family, host) => this.emit("lookup", error, address, family, host));
|
||||||
|
socket.on("timeout", () => this.emit("timeout"));
|
||||||
|
|
||||||
|
this.on("connect", (options, callbackId) => socket.connect(options, this.maybeCallback(callbackId)));
|
||||||
|
this.on("ref", () => socket.ref());
|
||||||
|
this.on("setKeepAlive", (enable, initialDelay) => socket.setKeepAlive(enable, initialDelay));
|
||||||
|
this.on("setNoDelay", (noDelay) => socket.setNoDelay(noDelay));
|
||||||
|
this.on("setTimeout", (timeout, callbackId) => socket.setTimeout(timeout, this.maybeCallback(callbackId)));
|
||||||
|
this.on("unref", () => socket.unref());
|
||||||
|
|
||||||
|
this.bindReadable(socket);
|
||||||
|
this.bindWritable(socket);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
onDidDispose: (cb): Socket => socket.on("close", cb),
|
onDidDispose: (cb): Socket => socket.on("close", cb),
|
||||||
|
@ -55,100 +143,73 @@ export const bindSocket = (ae: ActiveEval, socket: Socket): Disposer => {
|
||||||
socket.unref();
|
socket.unref();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind a writable stream to an active evaluation.
|
* Bind a writable stream to the active evaluation.
|
||||||
*/
|
*/
|
||||||
export const bindWritable = (ae: ActiveEval, writable: Writable | Duplex): void => {
|
public bindWritable(writable: Writable | Duplex): void {
|
||||||
if (!((writable as Readable).read)) { // To avoid binding twice.
|
if (!((writable as Readable).read)) { // To avoid binding twice.
|
||||||
writable.on("close", () => ae.emit("close"));
|
writable.on("close", () => this.emit("close"));
|
||||||
writable.on("error", (error) => ae.emit("error", error));
|
writable.on("error", (error) => this.emit("error", error));
|
||||||
|
|
||||||
ae.on("destroy", () => writable.destroy());
|
this.on("destroy", () => writable.destroy());
|
||||||
}
|
}
|
||||||
|
|
||||||
writable.on("drain", () => ae.emit("drain"));
|
writable.on("drain", () => this.emit("drain"));
|
||||||
writable.on("finish", () => ae.emit("finish"));
|
writable.on("finish", () => this.emit("finish"));
|
||||||
writable.on("pipe", () => ae.emit("pipe"));
|
writable.on("pipe", () => this.emit("pipe"));
|
||||||
writable.on("unpipe", () => ae.emit("unpipe"));
|
writable.on("unpipe", () => this.emit("unpipe"));
|
||||||
|
|
||||||
ae.on("cork", () => writable.cork());
|
this.on("cork", () => writable.cork());
|
||||||
ae.on("end", (chunk, encoding, callbackId) => writable.end(chunk, encoding, maybeCallback(ae, callbackId)));
|
this.on("end", (chunk, encoding, callbackId) => writable.end(chunk, encoding, this.maybeCallback(callbackId)));
|
||||||
ae.on("setDefaultEncoding", (encoding) => writable.setDefaultEncoding(encoding));
|
this.on("setDefaultEncoding", (encoding) => writable.setDefaultEncoding(encoding));
|
||||||
ae.on("uncork", () => writable.uncork());
|
this.on("uncork", () => writable.uncork());
|
||||||
// Sockets can pass an fd instead of a callback but streams cannot.
|
// 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));
|
this.on("write", (chunk, encoding, fd, callbackId) => writable.write(chunk, encoding, this.maybeCallback(callbackId) || fd));
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind a readable stream to an active evaluation.
|
* Bind a readable stream to the active evaluation.
|
||||||
*/
|
*/
|
||||||
export const bindReadable = (ae: ActiveEval, readable: Readable): void => {
|
public bindReadable(readable: Readable): void {
|
||||||
// Streams don't have an argument on close but sockets do.
|
// Streams don't have an argument on close but sockets do.
|
||||||
readable.on("close", (...args: any[]) => ae.emit("close", ...args));
|
readable.on("close", (...args: any[]) => this.emit("close", ...args));
|
||||||
readable.on("data", (data) => ae.emit("data", data));
|
readable.on("data", (data) => this.emit("data", data));
|
||||||
readable.on("end", () => ae.emit("end"));
|
readable.on("end", () => this.emit("end"));
|
||||||
readable.on("error", (error) => ae.emit("error", error));
|
readable.on("error", (error) => this.emit("error", error));
|
||||||
readable.on("readable", () => ae.emit("readable"));
|
readable.on("readable", () => this.emit("readable"));
|
||||||
|
|
||||||
ae.on("destroy", () => readable.destroy());
|
this.on("destroy", () => readable.destroy());
|
||||||
ae.on("pause", () => readable.pause());
|
this.on("pause", () => readable.pause());
|
||||||
ae.on("push", (chunk, encoding) => readable.push(chunk, encoding));
|
this.on("push", (chunk, encoding) => readable.push(chunk, encoding));
|
||||||
ae.on("resume", () => readable.resume());
|
this.on("resume", () => readable.resume());
|
||||||
ae.on("setEncoding", (encoding) => readable.setEncoding(encoding));
|
this.on("setEncoding", (encoding) => readable.setEncoding(encoding));
|
||||||
ae.on("unshift", (chunk) => readable.unshift(chunk));
|
this.on("unshift", (chunk) => readable.unshift(chunk));
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
public createUnique(id: number | "stdout" | "stderr" | "stdin"): ServerActiveEvalHelper {
|
||||||
* Wrap an evaluation emitter to make unique events for an item to prevent
|
return new ServerActiveEvalHelper(this.createUniqueEmitter(id), this.fork);
|
||||||
* 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
|
* 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.
|
* them back and forth through an active evaluation using those IDs.
|
||||||
*/
|
*/
|
||||||
export class CallbackEmitter extends EventEmitter {
|
export class CallbackEmitter extends EventEmitter {
|
||||||
private _ae: ActiveEval | undefined;
|
private _ae: ActiveEvalHelper | undefined;
|
||||||
private callbackId = 0;
|
private callbackId = 0;
|
||||||
private readonly callbacks = new Map<number, Function>();
|
private readonly callbacks = new Map<number, Function>();
|
||||||
|
|
||||||
public constructor(ae?: ActiveEval) {
|
public constructor(ae?: ActiveEvalHelper) {
|
||||||
super();
|
super();
|
||||||
if (ae) {
|
if (ae) {
|
||||||
this.ae = ae;
|
this.ae = ae;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get ae(): ActiveEval {
|
protected get ae(): ActiveEvalHelper {
|
||||||
if (!this._ae) {
|
if (!this._ae) {
|
||||||
throw new Error("trying to access active evaluation before it has been set");
|
throw new Error("trying to access active evaluation before it has been set");
|
||||||
}
|
}
|
||||||
|
@ -156,7 +217,7 @@ export class CallbackEmitter extends EventEmitter {
|
||||||
return this._ae;
|
return this._ae;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected set ae(ae: ActiveEval) {
|
protected set ae(ae: ActiveEvalHelper) {
|
||||||
if (this._ae) {
|
if (this._ae) {
|
||||||
throw new Error("cannot override active evaluation");
|
throw new Error("cannot override active evaluation");
|
||||||
}
|
}
|
||||||
|
@ -195,7 +256,7 @@ export class CallbackEmitter extends EventEmitter {
|
||||||
* A writable stream over an active evaluation.
|
* A writable stream over an active evaluation.
|
||||||
*/
|
*/
|
||||||
export class ActiveEvalWritable extends CallbackEmitter implements Writable {
|
export class ActiveEvalWritable extends CallbackEmitter implements Writable {
|
||||||
public constructor(ae: ActiveEval) {
|
public constructor(ae: ActiveEvalHelper) {
|
||||||
super(ae);
|
super(ae);
|
||||||
// Streams don't have an argument on close but sockets do.
|
// Streams don't have an argument on close but sockets do.
|
||||||
this.ae.on("close", (...args: any[]) => this.emit("close", ...args));
|
this.ae.on("close", (...args: any[]) => this.emit("close", ...args));
|
||||||
|
@ -249,7 +310,7 @@ export class ActiveEvalWritable extends CallbackEmitter implements Writable {
|
||||||
* A readable stream over an active evaluation.
|
* A readable stream over an active evaluation.
|
||||||
*/
|
*/
|
||||||
export class ActiveEvalReadable extends CallbackEmitter implements Readable {
|
export class ActiveEvalReadable extends CallbackEmitter implements Readable {
|
||||||
public constructor(ae: ActiveEval) {
|
public constructor(ae: ActiveEvalHelper) {
|
||||||
super(ae);
|
super(ae);
|
||||||
this.ae.on("close", () => this.emit("close"));
|
this.ae.on("close", () => this.emit("close"));
|
||||||
this.ae.on("data", (data) => this.emit("data", data));
|
this.ae.on("data", (data) => this.emit("data", data));
|
||||||
|
@ -290,7 +351,7 @@ export class ActiveEvalReadable extends CallbackEmitter implements Readable {
|
||||||
*/
|
*/
|
||||||
export class ActiveEvalDuplex extends ActiveEvalReadable implements Duplex {
|
export class ActiveEvalDuplex extends ActiveEvalReadable implements Duplex {
|
||||||
// Some unfortunate duplication here since we can't have multiple extends.
|
// Some unfortunate duplication here since we can't have multiple extends.
|
||||||
public constructor(ae: ActiveEval) {
|
public constructor(ae: ActiveEvalHelper) {
|
||||||
super(ae);
|
super(ae);
|
||||||
this.ae.on("drain", () => this.emit("drain"));
|
this.ae.on("drain", () => this.emit("drain"));
|
||||||
this.ae.on("finish", () => this.emit("finish"));
|
this.ae.on("finish", () => this.emit("finish"));
|
|
@ -1,5 +1,3 @@
|
||||||
import { IDisposable } from "@coder/disposable";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if we're in a browser environment (including web workers).
|
* Return true if we're in a browser environment (including web workers).
|
||||||
*/
|
*/
|
||||||
|
@ -84,7 +82,3 @@ export const parse = (arg: string): any => { // tslint:disable-line no-any
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface Disposer extends IDisposable {
|
|
||||||
onDidDispose: (cb: () => void) => void;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
export * from "./browser/client";
|
export * from "./browser/client";
|
||||||
export * from "./browser/evaluate";
|
|
||||||
export * from "./common/connection";
|
export * from "./common/connection";
|
||||||
|
export * from "./common/helpers";
|
||||||
export * from "./common/util";
|
export * from "./common/util";
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
import { fork as cpFork } from "child_process";
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
import * as vm from "vm";
|
import * as vm from "vm";
|
||||||
import { logger, field } from "@coder/logger";
|
import { logger, field } from "@coder/logger";
|
||||||
import { NewEvalMessage, EvalFailedMessage, EvalDoneMessage, ServerMessage, EvalEventMessage } from "../proto";
|
import { NewEvalMessage, EvalFailedMessage, EvalDoneMessage, ServerMessage, EvalEventMessage } from "../proto";
|
||||||
import { SendableConnection } from "../common/connection";
|
import { SendableConnection } from "../common/connection";
|
||||||
|
import { ServerActiveEvalHelper, EvalHelper, ForkProvider } from "../common/helpers";
|
||||||
import { stringify, parse } from "../common/util";
|
import { stringify, parse } from "../common/util";
|
||||||
|
|
||||||
export interface ActiveEvaluation {
|
export interface ActiveEvaluation {
|
||||||
|
@ -11,7 +13,7 @@ export interface ActiveEvaluation {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare var __non_webpack_require__: typeof require;
|
declare var __non_webpack_require__: typeof require;
|
||||||
export const evaluate = (connection: SendableConnection, message: NewEvalMessage, onDispose: () => void): ActiveEvaluation | void => {
|
export const evaluate = (connection: SendableConnection, message: NewEvalMessage, onDispose: () => void, fork?: ForkProvider): ActiveEvaluation | void => {
|
||||||
/**
|
/**
|
||||||
* Send the response and call onDispose.
|
* Send the response and call onDispose.
|
||||||
*/
|
*/
|
||||||
|
@ -46,7 +48,10 @@ export const evaluate = (connection: SendableConnection, message: NewEvalMessage
|
||||||
|
|
||||||
let eventEmitter = message.getActive() ? new EventEmitter(): undefined;
|
let eventEmitter = message.getActive() ? new EventEmitter(): undefined;
|
||||||
const sandbox = {
|
const sandbox = {
|
||||||
eventEmitter: eventEmitter ? {
|
helper: eventEmitter ? new ServerActiveEvalHelper({
|
||||||
|
removeAllListeners: (event?: string): void => {
|
||||||
|
eventEmitter!.removeAllListeners(event);
|
||||||
|
},
|
||||||
// tslint:disable no-any
|
// tslint:disable no-any
|
||||||
on: (event: string, cb: (...args: any[]) => void): void => {
|
on: (event: string, cb: (...args: any[]) => void): void => {
|
||||||
eventEmitter!.on(event, (...args: any[]) => {
|
eventEmitter!.on(event, (...args: any[]) => {
|
||||||
|
@ -73,7 +78,7 @@ export const evaluate = (connection: SendableConnection, message: NewEvalMessage
|
||||||
connection.send(serverMsg.serializeBinary());
|
connection.send(serverMsg.serializeBinary());
|
||||||
},
|
},
|
||||||
// tslint:enable no-any
|
// tslint:enable no-any
|
||||||
} : undefined,
|
}, fork || cpFork) : new EvalHelper(),
|
||||||
_Buffer: Buffer,
|
_Buffer: Buffer,
|
||||||
// When the client is ran from Webpack, it will replace
|
// When the client is ran from Webpack, it will replace
|
||||||
// __non_webpack_require__ with require, which we then need to provide to
|
// __non_webpack_require__ with require, which we then need to provide to
|
||||||
|
@ -94,7 +99,7 @@ export const evaluate = (connection: SendableConnection, message: NewEvalMessage
|
||||||
|
|
||||||
let value: any; // tslint:disable-line no-any
|
let value: any; // tslint:disable-line no-any
|
||||||
try {
|
try {
|
||||||
const code = `(${message.getFunction()})(${eventEmitter ? "eventEmitter, " : ""}...args);`;
|
const code = `(${message.getFunction()})(helper, ...args);`;
|
||||||
value = vm.runInNewContext(code, sandbox, {
|
value = vm.runInNewContext(code, sandbox, {
|
||||||
// If the code takes longer than this to return, it is killed and throws.
|
// If the code takes longer than this to return, it is killed and throws.
|
||||||
timeout: message.getTimeout() || 15000,
|
timeout: message.getTimeout() || 15000,
|
||||||
|
|
|
@ -5,12 +5,14 @@ import { promisify } from "util";
|
||||||
import { logger, field } from "@coder/logger";
|
import { logger, field } from "@coder/logger";
|
||||||
import { ClientMessage, WorkingInitMessage, ServerMessage } from "../proto";
|
import { ClientMessage, WorkingInitMessage, ServerMessage } from "../proto";
|
||||||
import { evaluate, ActiveEvaluation } from "./evaluate";
|
import { evaluate, ActiveEvaluation } from "./evaluate";
|
||||||
|
import { ForkProvider } from "../common/helpers";
|
||||||
import { ReadWriteConnection } from "../common/connection";
|
import { ReadWriteConnection } from "../common/connection";
|
||||||
|
|
||||||
export interface ServerOptions {
|
export interface ServerOptions {
|
||||||
readonly workingDirectory: string;
|
readonly workingDirectory: string;
|
||||||
readonly dataDirectory: string;
|
readonly dataDirectory: string;
|
||||||
readonly builtInExtensionsDirectory: string;
|
readonly builtInExtensionsDirectory: string;
|
||||||
|
readonly fork?: ForkProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Server {
|
export class Server {
|
||||||
|
@ -105,7 +107,7 @@ export class Server {
|
||||||
logger.trace(() => [
|
logger.trace(() => [
|
||||||
`dispose ${evalMessage.getId()}, ${this.evals.size} left`,
|
`dispose ${evalMessage.getId()}, ${this.evals.size} left`,
|
||||||
]);
|
]);
|
||||||
});
|
}, this.options ? this.options.fork : undefined);
|
||||||
if (resp) {
|
if (resp) {
|
||||||
this.evals.set(evalMessage.getId(), resp);
|
this.evals.set(evalMessage.getId(), resp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ describe("Evaluate", () => {
|
||||||
|
|
||||||
it("should compute from string", async () => {
|
it("should compute from string", async () => {
|
||||||
const start = "ban\%\$\"``a,,,,asdasd";
|
const start = "ban\%\$\"``a,,,,asdasd";
|
||||||
const value = await client.evaluate((a) => {
|
const value = await client.evaluate((_helper, a) => {
|
||||||
return a;
|
return a;
|
||||||
}, start);
|
}, start);
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ describe("Evaluate", () => {
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
it("should compute from object", async () => {
|
it("should compute from object", async () => {
|
||||||
const value = await client.evaluate((arg) => {
|
const value = await client.evaluate((_helper, arg) => {
|
||||||
return arg.bananas * 2;
|
return arg.bananas * 2;
|
||||||
}, { bananas: 1 });
|
}, { bananas: 1 });
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import { field, logger } from "@coder/logger";
|
import { field, logger } from "@coder/logger";
|
||||||
import { ServerMessage, SharedProcessActiveMessage } from "@coder/protocol/src/proto";
|
import { ServerMessage, SharedProcessActiveMessage } from "@coder/protocol/src/proto";
|
||||||
import { Command, flags } from "@oclif/command";
|
import { Command, flags } from "@oclif/command";
|
||||||
|
import { fork, ForkOptions, ChildProcess } from "child_process";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import * as os from "os";
|
import * as os from "os";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import * as WebSocket from "ws";
|
import * as WebSocket from "ws";
|
||||||
import { createApp } from "./server";
|
import { createApp } from "./server";
|
||||||
import { requireModule, requireFork } from "./vscode/bootstrapFork";
|
import { requireModule, requireFork, forkModule } from "./vscode/bootstrapFork";
|
||||||
import { SharedProcess, SharedProcessState } from "./vscode/sharedProcess";
|
import { SharedProcess, SharedProcessState } from "./vscode/sharedProcess";
|
||||||
import { setup as setupNativeModules } from "./modules";
|
import { setup as setupNativeModules } from "./modules";
|
||||||
import { fillFs } from "./fill";
|
import { fillFs } from "./fill";
|
||||||
|
@ -161,6 +162,13 @@ export class Entry extends Command {
|
||||||
builtInExtensionsDirectory: builtInExtensionsDir,
|
builtInExtensionsDirectory: builtInExtensionsDir,
|
||||||
dataDirectory: dataDir,
|
dataDirectory: dataDir,
|
||||||
workingDirectory: workingDir,
|
workingDirectory: workingDir,
|
||||||
|
fork: (modulePath: string, args: string[], options: ForkOptions, dataDir?: string): ChildProcess => {
|
||||||
|
if (options && options.env && options.env.AMD_ENTRYPOINT) {
|
||||||
|
return forkModule(options.env.AMD_ENTRYPOINT, args, options, dataDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fork(modulePath, args, options);
|
||||||
|
},
|
||||||
}, password, hasCustomHttps ? {
|
}, password, hasCustomHttps ? {
|
||||||
key: certKeyData,
|
key: certKeyData,
|
||||||
cert: certData,
|
cert: certData,
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
|
@ -380,7 +380,7 @@ class Dialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
private async list(directory: string): Promise<ReadonlyArray<DialogEntry>> {
|
private async list(directory: string): Promise<ReadonlyArray<DialogEntry>> {
|
||||||
return ideClient.evaluate((directory) => {
|
return ideClient.evaluate((_helper, directory) => {
|
||||||
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
const fs = __non_webpack_require__("fs") as typeof import("fs");
|
||||||
const util = __non_webpack_require__("util") as typeof import("util");
|
const util = __non_webpack_require__("util") as typeof import("util");
|
||||||
const path = __non_webpack_require__("path") as typeof import("path");
|
const path = __non_webpack_require__("path") as typeof import("path");
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { client } from "@coder/ide/src/fill/client";
|
import { client } from "@coder/ide/src/fill/client";
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
import * as nodePty from "node-pty";
|
import * as nodePty from "node-pty";
|
||||||
import { ActiveEval } from "@coder/protocol";
|
import { ActiveEvalHelper } from "@coder/protocol";
|
||||||
|
|
||||||
// Use this to prevent Webpack from hijacking require.
|
// Use this to prevent Webpack from hijacking require.
|
||||||
declare var __non_webpack_require__: typeof require;
|
declare var __non_webpack_require__: typeof require;
|
||||||
|
@ -11,16 +11,15 @@ declare var __non_webpack_require__: typeof require;
|
||||||
*/
|
*/
|
||||||
class Pty implements nodePty.IPty {
|
class Pty implements nodePty.IPty {
|
||||||
private readonly emitter = new EventEmitter();
|
private readonly emitter = new EventEmitter();
|
||||||
private readonly ae: ActiveEval;
|
private readonly ae: ActiveEvalHelper;
|
||||||
private _pid = -1;
|
private _pid = -1;
|
||||||
private _process = "";
|
private _process = "";
|
||||||
|
|
||||||
public constructor(file: string, args: string[] | string, options: nodePty.IPtyForkOptions) {
|
public constructor(file: string, args: string[] | string, options: nodePty.IPtyForkOptions) {
|
||||||
this.ae = client.run((ae, file, args, options) => {
|
this.ae = client.run((ae, file, args, options) => {
|
||||||
const nodePty = __non_webpack_require__("node-pty") as typeof import("node-pty");
|
const nodePty = __non_webpack_require__("node-pty") as typeof import("node-pty");
|
||||||
const { preserveEnv } = __non_webpack_require__("@coder/ide/src/fill/evaluation") as typeof import("@coder/ide/src/fill/evaluation");
|
|
||||||
|
|
||||||
preserveEnv(options);
|
ae.preserveEnv(options);
|
||||||
|
|
||||||
const ptyProc = nodePty.spawn(file, args, options);
|
const ptyProc = nodePty.spawn(file, args, options);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue