Archived
1
0

Make everything use active evals (#30)

* Add trace log level

* Use active eval to implement spdlog

* Split server/client active eval interfaces

Since all properties are *not* valid on both sides

* +200% fire resistance

* Implement exec using active evaluations

* Fully implement child process streams

* Watch impl, move child_process back to explicitly adding events

Automatically forwarding all events might be the right move, but wanna
think/discuss it a bit more because it didn't come out very cleanly.

* Would you like some args with that callback?

* Implement the rest of child_process using active evals

* Rampant memory leaks

Emit "kill" to active evaluations when client disconnects in order to
kill processes. Most likely won't be the final solution.

* Resolve some minor issues with output panel

* Implement node-pty with active evals

* Provide clearTimeout to vm sandbox

* Implement socket with active evals

* Extract some callback logic

Also remove some eval interfaces, need to re-think those.

* Implement net.Server and remainder of net.Socket using active evals

* Implement dispose for active evaluations

* Use trace for express requests

* Handle sending buffers through evaluation events

* Make event logging a bit more clear

* Fix some errors due to us not actually instantiating until connect/listen

* is this a commit message?

* We can just create the evaluator in the ctor

Not sure what I was thinking.

* memory leak for you, memory leak for everyone

* it's a ternary now

* Don't dispose automatically on close or error

The code may or may not be disposable at that point.

* Handle parsing buffers on the client side as well

* Remove unused protobuf

* Remove TypedValue

* Remove unused forkProvider and test

* Improve dispose pattern for active evals

* Socket calls close after error; no need to bind both

* Improve comment

* Comment is no longer wishy washy due to explicit boolean

* Simplify check for sendHandle and options

* Replace _require with __non_webpack_require__

Webpack will then replace this with `require` which we then provide to
the vm sandbox.

* Provide path.parse

* Prevent original-fs from loading

* Start with a pid of -1

vscode immediately checks the PID to see if the debug process launch
correctly, but of course we don't get the pid synchronously.

* Pass arguments to bootstrap-fork

* Fully implement streams

Was causing errors because internally the stream would set this.writing
to true and it would never become false, so subsequent messages would
never send.

* Fix serializing errors and streams emitting errors multiple times

* Was emitting close to data

* Fix missing path for spawned processes

* Move evaluation onDispose call

Now it's accurate and runs when the active evaluation has actually
disposed.

* Fix promisifying fs.exists

* Fix some active eval callback issues

* Patch existsSync in debug adapter
This commit is contained in:
Asher
2019-02-19 10:17:03 -06:00
committed by GitHub
parent 73762017c8
commit 4a80bcb42c
39 changed files with 1694 additions and 8731 deletions

View File

@ -1,31 +1,20 @@
import { ReadWriteConnection, InitData, OperatingSystem, SharedProcessData } from "../common/connection";
import { NewEvalMessage, ServerMessage, EvalDoneMessage, EvalFailedMessage, TypedValue, ClientMessage, NewSessionMessage, TTYDimensions, SessionOutputMessage, CloseSessionInputMessage, WorkingInitMessage, EvalEventMessage } from "../proto";
import { EventEmitter } from "events";
import { Emitter } from "@coder/events";
import { logger, field } from "@coder/logger";
import { ChildProcess, SpawnOptions, ForkOptions, ServerProcess, ServerSocket, Socket, ServerListener, Server, ActiveEval } from "./command";
import { EventEmitter } from "events";
import { Socket as NetSocket } from "net";
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 { ActiveEval } from "./command";
/**
* Client accepts an arbitrary connection intended to communicate with the Server.
*/
export class Client {
public readonly Socket: typeof NetSocket;
private evalId = 0;
private readonly evalDoneEmitter = new Emitter<EvalDoneMessage>();
private readonly evalFailedEmitter = new Emitter<EvalFailedMessage>();
private readonly evalEventEmitter = new Emitter<EvalEventMessage>();
private sessionId = 0;
private readonly sessions = new Map<number, ServerProcess>();
private connectionId = 0;
private readonly connections = new Map<number, ServerSocket>();
private serverId = 0;
private readonly servers = new Map<number, ServerListener>();
private _initData: InitData | undefined;
private readonly initDataEmitter = new Emitter<InitData>();
private readonly initDataPromise: Promise<InitData>;
@ -40,21 +29,20 @@ export class Client {
private readonly connection: ReadWriteConnection,
) {
connection.onMessage((data) => {
let message: ServerMessage | undefined;
try {
this.handleMessage(ServerMessage.deserializeBinary(data));
} catch (ex) {
logger.error("Failed to handle server message", field("length", data.byteLength), field("exception", ex));
message = ServerMessage.deserializeBinary(data);
this.handleMessage(message);
} catch (error) {
logger.error(
"Failed to handle server message",
field("id", message && message.hasEvalEvent() ? message.getEvalEvent()!.getId() : undefined),
field("length", data.byteLength),
field("error", error.message),
);
}
});
const that = this;
// @ts-ignore NOTE: this doesn't fully implement net.Socket.
this.Socket = class extends ServerSocket {
public constructor() {
super(that.connection, that.connectionId++, that.registerConnection);
}
};
this.initDataPromise = new Promise((resolve): void => {
this.initDataEmitter.event(resolve);
});
@ -64,44 +52,55 @@ export class Client {
return this.initDataPromise;
}
public run(func: (ae: ActiveEval) => void | Promise<void>): ActiveEval;
public run<T1>(func: (ae: ActiveEval, a1: T1) => void | Promise<void>, a1: T1): ActiveEval;
public run<T1, T2>(func: (ae: ActiveEval, a1: T1, a2: T2) => void | Promise<void>, a1: T1, a2: T2): ActiveEval;
public run<T1, T2, T3>(func: (ae: ActiveEval, a1: T1, a2: T2, a3: T3) => void | Promise<void>, a1: T1, a2: T2, a3: T3): ActiveEval;
public run<T1, T2, T3, T4>(func: (ae: ActiveEval, a1: T1, a2: T2, a3: T3, a4: T4) => void | Promise<void>, a1: T1, a2: T2, a3: T3, a4: T4): ActiveEval;
public run<T1, T2, T3, T4, T5>(func: (ae: ActiveEval, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5) => void | Promise<void>, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5): ActiveEval;
public run<T1, T2, T3, T4, T5, T6>(func: (ae: ActiveEval, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6) => void | Promise<void>, a1: T1, a2: T2, a3: T3, a4: T4, a5: T5, a6: T6): ActiveEval;
public run<T1, T2, T3, T4, T5, T6>(func: (ae: ActiveEval, a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6) => void | Promise<void>, a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6): ActiveEval {
public run(func: (ae: ActiveEval) => Disposer): ActiveEval;
public run<T1>(func: (ae: ActiveEval, a1: T1) => Disposer, a1: T1): ActiveEval;
public run<T1, T2>(func: (ae: ActiveEval, a1: T1, a2: T2) => Disposer, a1: T1, a2: T2): ActiveEval;
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, 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, 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, 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;
/**
* Run a function on the server and provide an event emitter which allows
* listening and emitting to the emitter provided to that function. The
* function should return a disposer for cleaning up when the client
* disconnects and for notifying when disposal has happened outside manual
* 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 {
const doEval = this.doEvaluate(func, a1, a2, a3, a4, a5, a6, true);
// This takes server events and emits them to the client's emitter.
const eventEmitter = new EventEmitter();
const d1 = this.evalEventEmitter.event((msg) => {
if (msg.getId() !== doEval.id) {
return;
if (msg.getId() === doEval.id) {
eventEmitter.emit(msg.getEvent(), ...msg.getArgsList().map(parse));
}
eventEmitter.emit(msg.getEvent(), ...msg.getArgsList().filter(a => a).map(s => JSON.parse(s)));
});
doEval.completed.then(() => {
d1.dispose();
eventEmitter.emit("close");
}).catch((ex) => {
d1.dispose();
// This error event is only received by the client.
eventEmitter.emit("error", ex);
});
// 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).
return {
// tslint:disable no-any
on: (event: string, cb: (...args: any[]) => void): EventEmitter => eventEmitter.on(event, cb),
emit: (event: string, ...args: any[]): void => {
const eventsMsg = new EvalEventMessage();
eventsMsg.setId(doEval.id);
eventsMsg.setEvent(event);
eventsMsg.setArgsList(args.filter(a => a).map(a => JSON.stringify(a)));
eventsMsg.setArgsList(args.map(stringify));
const clientMsg = new ClientMessage();
clientMsg.setEvalEvent(eventsMsg);
this.connection.send(clientMsg.serializeBinary());
},
removeAllListeners: (event: string): EventEmitter => eventEmitter.removeAllListeners(event),
// tslint:enable no-any
};
}
@ -128,6 +127,7 @@ export class Client {
return this.doEvaluate(func, a1, a2, a3, a4, a5, a6, false).completed;
}
// tslint:disable-next-line no-any
private doEvaluate<R, T1, T2, T3, T4, T5, T6>(func: (...args: any[]) => void | Promise<void> | R | Promise<R>, a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6, active: boolean = false): {
readonly completed: Promise<R>;
readonly id: number;
@ -136,163 +136,36 @@ export class Client {
const id = this.evalId++;
newEval.setId(id);
newEval.setActive(active);
newEval.setArgsList([a1, a2, a3, a4, a5, a6].filter(a => typeof a !== "undefined").map(a => JSON.stringify(a)));
newEval.setArgsList([a1, a2, a3, a4, a5, a6].map(stringify));
newEval.setFunction(func.toString());
const clientMsg = new ClientMessage();
clientMsg.setNewEval(newEval);
this.connection.send(clientMsg.serializeBinary());
let res: (value?: R) => void;
let rej: (err?: Error) => void;
const prom = new Promise<R>((r, e): void => {
res = r;
rej = e;
});
const d1 = this.evalDoneEmitter.event((doneMsg) => {
if (doneMsg.getId() !== id) {
return;
}
d1.dispose();
d2.dispose();
const resp = doneMsg.getResponse();
if (!resp) {
return res();
}
const rt = resp.getType();
// tslint:disable-next-line no-any
let val: any;
switch (rt) {
case TypedValue.Type.BOOLEAN:
val = resp.getValue() === "true";
break;
case TypedValue.Type.NUMBER:
val = parseInt(resp.getValue(), 10);
break;
case TypedValue.Type.OBJECT:
val = JSON.parse(resp.getValue());
break;
case TypedValue.Type.STRING:
val = resp.getValue();
break;
default:
throw new Error(`unsupported typed value ${rt}`);
}
res(val);
});
const d2 = this.evalFailedEmitter.event((failedMsg) => {
if (failedMsg.getId() === id) {
const completed = new Promise<R>((resolve, reject): void => {
const dispose = (): void => {
d1.dispose();
d2.dispose();
};
rej(new Error(failedMsg.getMessage()));
}
const d1 = this.evalDoneEmitter.event((doneMsg) => {
if (doneMsg.getId() === id) {
const resp = doneMsg.getResponse();
dispose();
resolve(parse(resp));
}
});
const d2 = this.evalFailedEmitter.event((failedMsg) => {
if (failedMsg.getId() === id) {
dispose();
reject(new Error(failedMsg.getMessage()));
}
});
});
return {
completed: prom,
id,
};
}
/**
* Spawns a process from a command. _Somewhat_ reflects the "child_process" API.
* @example
* const cp = this.client.spawn("echo", ["test"]);
* cp.stdout.on("data", (data) => console.log(data.toString()));
* cp.on("exit", (code) => console.log("exited with", code));
* @param args Arguments
* @param options Options to execute for the command
*/
public spawn(command: string, args: string[] = [], options?: SpawnOptions): ChildProcess {
return this.doSpawn(command, args, options, false, false);
}
/**
* Fork a module.
* @param modulePath Path of the module
* @param args Args to add for the module
* @param options Options to execute
*/
public fork(modulePath: string, args: string[] = [], options?: ForkOptions): ChildProcess {
return this.doSpawn(modulePath, args, options, true);
}
/**
* VS Code specific.
* Forks a module from bootstrap-fork
* @param modulePath Path of the module
*/
public bootstrapFork(modulePath: string, args: string[] = [], options?: ForkOptions): ChildProcess {
return this.doSpawn(modulePath, args, options, true, true);
}
public createConnection(path: string, callback?: Function): Socket;
public createConnection(port: number, callback?: Function): Socket;
public createConnection(target: string | number, callback?: Function): Socket;
public createConnection(target: string | number, callback?: Function): Socket {
const id = this.connectionId++;
const socket = new ServerSocket(this.connection, id, this.registerConnection);
socket.connect(target, callback);
return socket;
}
public createServer(callback?: () => void): Server {
const id = this.serverId++;
const server = new ServerListener(this.connection, id, callback);
this.servers.set(id, server);
return server;
}
private doSpawn(command: string, args: string[] = [], options?: SpawnOptions, isFork: boolean = false, isBootstrapFork: boolean = true): ChildProcess {
const id = this.sessionId++;
const newSess = new NewSessionMessage();
newSess.setId(id);
newSess.setCommand(command);
newSess.setArgsList(args);
newSess.setIsFork(isFork);
newSess.setIsBootstrapFork(isBootstrapFork);
if (options) {
if (options.cwd) {
newSess.setCwd(options.cwd);
}
if (options.env) {
Object.keys(options.env).forEach((envKey) => {
if (options.env![envKey]) {
newSess.getEnvMap().set(envKey, options.env![envKey].toString());
}
});
}
if (options.tty) {
const tty = new TTYDimensions();
tty.setHeight(options.tty.rows);
tty.setWidth(options.tty.columns);
newSess.setTtyDimensions(tty);
}
}
const clientMsg = new ClientMessage();
clientMsg.setNewSession(newSess);
this.connection.send(clientMsg.serializeBinary());
const serverProc = new ServerProcess(this.connection, id, options ? options.tty !== undefined : false, isBootstrapFork);
serverProc.stdin.on("close", () => {
const c = new CloseSessionInputMessage();
c.setId(id);
const cm = new ClientMessage();
cm.setCloseSessionInput(c);
this.connection.send(cm.serializeBinary());
});
this.sessions.set(id, serverProc);
return serverProc;
return { completed, id };
}
/**
@ -332,121 +205,12 @@ export class Client {
this.evalFailedEmitter.emit(message.getEvalFailed()!);
} else if (message.hasEvalEvent()) {
this.evalEventEmitter.emit(message.getEvalEvent()!);
} else if (message.hasNewSessionFailure()) {
const s = this.sessions.get(message.getNewSessionFailure()!.getId());
if (!s) {
return;
}
s.emit("error", new Error(message.getNewSessionFailure()!.getMessage()));
this.sessions.delete(message.getNewSessionFailure()!.getId());
} else if (message.hasSessionDone()) {
const s = this.sessions.get(message.getSessionDone()!.getId());
if (!s) {
return;
}
s.emit("exit", message.getSessionDone()!.getExitStatus());
this.sessions.delete(message.getSessionDone()!.getId());
} else if (message.hasSessionOutput()) {
const output = message.getSessionOutput()!;
const s = this.sessions.get(output.getId());
if (!s) {
return;
}
const data = new TextDecoder().decode(output.getData_asU8());
const source = output.getSource();
switch (source) {
case SessionOutputMessage.Source.STDOUT:
case SessionOutputMessage.Source.STDERR:
(source === SessionOutputMessage.Source.STDOUT ? s.stdout : s.stderr).emit("data", data);
break;
case SessionOutputMessage.Source.IPC:
s.emit("message", JSON.parse(data));
break;
default:
throw new Error(`Unknown source ${source}`);
}
} else if (message.hasIdentifySession()) {
const s = this.sessions.get(message.getIdentifySession()!.getId());
if (!s) {
return;
}
const pid = message.getIdentifySession()!.getPid();
if (typeof pid !== "undefined") {
s.pid = pid;
}
const title = message.getIdentifySession()!.getTitle();
if (typeof title !== "undefined") {
s.title = title;
}
} else if (message.hasConnectionEstablished()) {
const c = this.connections.get(message.getConnectionEstablished()!.getId());
if (!c) {
return;
}
c.emit("connect");
} else if (message.hasConnectionOutput()) {
const c = this.connections.get(message.getConnectionOutput()!.getId());
if (!c) {
return;
}
c.emit("data", Buffer.from(message.getConnectionOutput()!.getData_asU8()));
} else if (message.hasConnectionClose()) {
const c = this.connections.get(message.getConnectionClose()!.getId());
if (!c) {
return;
}
c.emit("close");
c.emit("end");
this.connections.delete(message.getConnectionClose()!.getId());
} else if (message.hasConnectionFailure()) {
const c = this.connections.get(message.getConnectionFailure()!.getId());
if (!c) {
return;
}
c.emit("end");
this.connections.delete(message.getConnectionFailure()!.getId());
} else if (message.hasSharedProcessActive()) {
const sharedProcessActiveMessage = message.getSharedProcessActive()!;
this.sharedProcessActiveEmitter.emit({
socketPath: message.getSharedProcessActive()!.getSocketPath(),
logPath: message.getSharedProcessActive()!.getLogPath(),
socketPath: sharedProcessActiveMessage.getSocketPath(),
logPath: sharedProcessActiveMessage.getLogPath(),
});
} else if (message.hasServerEstablished()) {
const s = this.servers.get(message.getServerEstablished()!.getId());
if (!s) {
return;
}
s.emit("connect");
} else if (message.hasServerConnectionEstablished()) {
const s = this.servers.get(message.getServerConnectionEstablished()!.getServerId());
if (!s) {
return;
}
const conId = message.getServerConnectionEstablished()!.getConnectionId();
const serverSocket = new ServerSocket(this.connection, conId, this.registerConnection);
this.registerConnection(conId, serverSocket);
serverSocket.emit("connect");
s.emit("connection", serverSocket);
} else if (message.getServerFailure()) {
const s = this.servers.get(message.getServerFailure()!.getId());
if (!s) {
return;
}
s.emit("error", new Error(message.getNewSessionFailure()!.getReason().toString()));
this.servers.delete(message.getNewSessionFailure()!.getId());
} else if (message.hasServerClose()) {
const s = this.servers.get(message.getServerClose()!.getId());
if (!s) {
return;
}
s.emit("close");
this.servers.delete(message.getServerClose()!.getId());
}
}
private registerConnection = (id: number, socket: ServerSocket): void => {
if (this.connections.has(id)) {
throw new Error(`${id} is already registered`);
}
this.connections.set(id, socket);
}
}

View File

@ -1,366 +1,8 @@
import * as events from "events";
import * as stream from "stream";
import { ReadWriteConnection } from "../common/connection";
import { NewConnectionMessage, ShutdownSessionMessage, ClientMessage, WriteToSessionMessage, ResizeSessionTTYMessage, TTYDimensions as ProtoTTYDimensions, ConnectionOutputMessage, ConnectionCloseMessage, ServerCloseMessage, NewServerMessage } from "../proto";
export interface TTYDimensions {
readonly columns: number;
readonly rows: number;
}
export interface SpawnOptions {
cwd?: string;
env?: { [key: string]: string };
tty?: TTYDimensions;
}
export interface ForkOptions {
cwd?: string;
env?: { [key: string]: string };
}
export interface ChildProcess {
readonly stdin: stream.Writable;
readonly stdout: stream.Readable;
readonly stderr: stream.Readable;
readonly killed?: boolean;
readonly pid: number | undefined;
readonly title?: string;
kill(signal?: string): void;
send(message: string | Uint8Array, callback?: () => void, ipc?: false): void;
send(message: any, callback: undefined | (() => void), ipc: true): void;
on(event: "message", listener: (data: any) => void): void;
on(event: "error", listener: (err: Error) => void): void;
on(event: "exit", listener: (code: number, signal: string) => void): void;
resize?(dimensions: TTYDimensions): void;
}
export class ServerProcess extends events.EventEmitter implements ChildProcess {
public readonly stdin = new stream.Writable();
public readonly stdout = new stream.Readable({ read: (): boolean => true });
public readonly stderr = new stream.Readable({ read: (): boolean => true });
private _pid: number | undefined;
private _title: string | undefined;
private _killed: boolean = false;
private _connected: boolean = false;
public constructor(
private readonly connection: ReadWriteConnection,
private readonly id: number,
private readonly hasTty: boolean = false,
private readonly ipc: boolean = false,
) {
super();
if (!this.hasTty) {
delete this.resize;
}
}
public get pid(): number | undefined {
return this._pid;
}
public set pid(pid: number | undefined) {
this._pid = pid;
this._connected = true;
}
public get title(): string | undefined {
return this._title;
}
public set title(title: string | undefined) {
this._title = title;
}
public get connected(): boolean {
return this._connected;
}
public get killed(): boolean {
return this._killed;
}
public kill(signal?: string): void {
const kill = new ShutdownSessionMessage();
kill.setId(this.id);
if (signal) {
kill.setSignal(signal);
}
const client = new ClientMessage();
client.setShutdownSession(kill);
this.connection.send(client.serializeBinary());
this._killed = true;
this._connected = false;
}
public send(message: string | Uint8Array | any, callback?: (error: Error | null) => void, ipc: boolean = this.ipc): boolean {
const send = new WriteToSessionMessage();
send.setId(this.id);
send.setSource(ipc ? WriteToSessionMessage.Source.IPC : WriteToSessionMessage.Source.STDIN);
if (ipc) {
send.setData(new TextEncoder().encode(JSON.stringify(message)));
} else {
send.setData(typeof message === "string" ? new TextEncoder().encode(message) : message);
}
const client = new ClientMessage();
client.setWriteToSession(send);
this.connection.send(client.serializeBinary());
// TODO: properly implement?
if (callback) {
callback(null);
}
return true;
}
public resize(dimensions: TTYDimensions): void {
const resize = new ResizeSessionTTYMessage();
resize.setId(this.id);
const tty = new ProtoTTYDimensions();
tty.setHeight(dimensions.rows);
tty.setWidth(dimensions.columns);
resize.setTtyDimensions(tty);
const client = new ClientMessage();
client.setResizeSessionTty(resize);
this.connection.send(client.serializeBinary());
}
}
export interface Socket {
readonly destroyed: boolean;
readonly connecting: boolean;
write(buffer: Buffer): void;
end(): void;
connect(path: string, callback?: () => void): void;
connect(port: number, callback?: () => void): void;
addListener(event: "data", listener: (data: Buffer) => void): this;
addListener(event: "close", listener: (hasError: boolean) => void): this;
addListener(event: "connect", listener: () => void): this;
addListener(event: "end", listener: () => void): this;
on(event: "data", listener: (data: Buffer) => void): this;
on(event: "close", listener: (hasError: boolean) => void): this;
on(event: "connect", listener: () => void): this;
on(event: "end", listener: () => void): this;
once(event: "data", listener: (data: Buffer) => void): this;
once(event: "close", listener: (hasError: boolean) => void): this;
once(event: "connect", listener: () => void): this;
once(event: "end", listener: () => void): this;
removeListener(event: "data", listener: (data: Buffer) => void): this;
removeListener(event: "close", listener: (hasError: boolean) => void): this;
removeListener(event: "connect", listener: () => void): this;
removeListener(event: "end", listener: () => void): this;
emit(event: "data", data: Buffer): boolean;
emit(event: "close"): boolean;
emit(event: "connect"): boolean;
emit(event: "end"): boolean;
}
export class ServerSocket extends events.EventEmitter implements Socket {
public writable: boolean = true;
public readable: boolean = true;
private _destroyed: boolean = false;
private _connecting: boolean = false;
public constructor(
private readonly connection: ReadWriteConnection,
private readonly id: number,
private readonly beforeConnect: (id: number, socket: ServerSocket) => void,
) {
super();
}
public connect(target: string | number, callback?: Function): void {
this._connecting = true;
this.beforeConnect(this.id, this);
this.once("connect", () => {
this._connecting = false;
if (callback) {
callback();
}
});
const newCon = new NewConnectionMessage();
newCon.setId(this.id);
if (typeof target === "string") {
newCon.setPath(target);
} else {
newCon.setPort(target);
}
const clientMsg = new ClientMessage();
clientMsg.setNewConnection(newCon);
this.connection.send(clientMsg.serializeBinary());
}
public get destroyed(): boolean {
return this._destroyed;
}
public get connecting(): boolean {
return this._connecting;
}
public write(buffer: Buffer): void {
const sendData = new ConnectionOutputMessage();
sendData.setId(this.id);
sendData.setData(buffer);
const client = new ClientMessage();
client.setConnectionOutput(sendData);
this.connection.send(client.serializeBinary());
}
public end(): void {
const closeMsg = new ConnectionCloseMessage();
closeMsg.setId(this.id);
const client = new ClientMessage();
client.setConnectionClose(closeMsg);
this.connection.send(client.serializeBinary());
}
public addListener(event: "data", listener: (data: Buffer) => void): this;
public addListener(event: "close", listener: (hasError: boolean) => void): this;
public addListener(event: "connect", listener: () => void): this;
public addListener(event: "end", listener: () => void): this;
public addListener(event: string, listener: any): this {
return super.addListener(event, listener);
}
public removeListener(event: "data", listener: (data: Buffer) => void): this;
public removeListener(event: "close", listener: (hasError: boolean) => void): this;
public removeListener(event: "connect", listener: () => void): this;
public removeListener(event: "end", listener: () => void): this;
public removeListener(event: string, listener: any): this {
return super.removeListener(event, listener);
}
public on(event: "data", listener: (data: Buffer) => void): this;
public on(event: "close", listener: (hasError: boolean) => void): this;
public on(event: "connect", listener: () => void): this;
public on(event: "end", listener: () => void): this;
public on(event: string, listener: any): this {
return super.on(event, listener);
}
public once(event: "data", listener: (data: Buffer) => void): this;
public once(event: "close", listener: (hasError: boolean) => void): this;
public once(event: "connect", listener: () => void): this;
public once(event: "end", listener: () => void): this;
public once(event: string, listener: any): this {
return super.once(event, listener);
}
public emit(event: "data", data: Buffer): boolean;
public emit(event: "close"): boolean;
public emit(event: "connect"): boolean;
public emit(event: "end"): boolean;
public emit(event: string, ...args: any[]): boolean {
return super.emit(event, ...args);
}
public setDefaultEncoding(encoding: string): this {
throw new Error("Method not implemented.");
}
}
export interface Server {
addListener(event: "close", listener: () => void): this;
addListener(event: "connect", listener: (socket: Socket) => void): this;
addListener(event: "error", listener: (err: Error) => void): this;
on(event: "close", listener: () => void): this;
on(event: "connection", listener: (socket: Socket) => void): this;
on(event: "error", listener: (err: Error) => void): this;
once(event: "close", listener: () => void): this;
once(event: "connection", listener: (socket: Socket) => void): this;
once(event: "error", listener: (err: Error) => void): this;
removeListener(event: "close", listener: () => void): this;
removeListener(event: "connection", listener: (socket: Socket) => void): this;
removeListener(event: "error", listener: (err: Error) => void): this;
emit(event: "close"): boolean;
emit(event: "connection"): boolean;
emit(event: "error"): boolean;
listen(path: string, listeningListener?: () => void): this;
close(callback?: () => void): this;
readonly listening: boolean;
}
export class ServerListener extends events.EventEmitter implements Server {
private _listening: boolean = false;
public constructor(
private readonly connection: ReadWriteConnection,
private readonly id: number,
connectCallback?: () => void,
) {
super();
this.on("connect", () => {
this._listening = true;
if (connectCallback) {
connectCallback();
}
});
}
public get listening(): boolean {
return this._listening;
}
public listen(path: string, listener?: () => void): this {
const ns = new NewServerMessage();
ns.setId(this.id);
ns.setPath(path!);
const cm = new ClientMessage();
cm.setNewServer(ns);
this.connection.send(cm.serializeBinary());
if (typeof listener !== "undefined") {
this.once("connect", listener);
}
return this;
}
public close(callback?: Function | undefined): this {
const closeMsg = new ServerCloseMessage();
closeMsg.setId(this.id);
closeMsg.setReason("Manually closed");
const clientMsg = new ClientMessage();
clientMsg.setServerClose(closeMsg);
this.connection.send(clientMsg.serializeBinary());
if (callback) {
callback();
}
return this;
}
}
export interface ActiveEval {
emit(event: string, ...args: any[]): void;
removeAllListeners(event?: string): void;
on(event: "close", cb: () => void): void;
on(event: "error", cb: (err: Error) => void): void;
// tslint:disable no-any
emit(event: string, ...args: any[]): void;
on(event: string, cb: (...args: any[]) => void): void;
// tslint:disable no-any
}

View File

@ -1,3 +1,5 @@
import { IDisposable } from "@coder/disposable";
/**
* Return true if we're in a browser environment (including web workers).
*/
@ -25,10 +27,54 @@ export type IEncodingOptions = {
export type IEncodingOptionsCallback = IEncodingOptions | ((err: NodeJS.ErrnoException, ...args: any[]) => void);
/**
* Return true if the options specify to use a Buffer instead of string.
* Stringify an event argument.
*/
export const useBuffer = (options: IEncodingOptionsCallback): boolean => {
return options === "buffer"
|| (!!options && typeof options !== "string" && typeof options !== "function"
&& (options.encoding === "buffer" || options.encoding === null));
export const stringify = (arg: any): string => { // tslint:disable-line no-any
if (arg instanceof Error) {
return JSON.stringify({
type: "Error",
data: {
message: arg.message,
name: arg.name,
stack: arg.stack,
},
});
}
return JSON.stringify(arg);
};
/**
* Parse an event argument.
*/
export const parse = (arg: string): any => { // tslint:disable-line no-any
if (!arg) {
return arg;
}
const result = JSON.parse(arg);
if (result && result.data && result.type) {
switch (result.type) {
// JSON.stringify turns a Buffer into an object but JSON.parse doesn't
// turn it back, it just remains an object.
case "Buffer":
if (Array.isArray(result.data)) {
return Buffer.from(result);
}
break;
// Errors apparently can't be stringified, so we do something similar to
// what happens to buffers and stringify them as regular objects.
case "Error":
if (result.data.message) {
return new Error(result.data.message);
}
break;
}
}
return result;
};
export interface Disposer extends IDisposable {
onDidDispose: (cb: () => void) => void;
}

View File

@ -1,3 +1,4 @@
export * from "./browser/client";
export { ActiveEval } from "./browser/command";
export * from "./common/connection";
export * from "./common/util";

View File

@ -1,349 +0,0 @@
import * as cp from "child_process";
import * as net from "net";
import * as stream from "stream";
import { TextEncoder } from "text-encoding";
import { Logger, logger, field } from "@coder/logger";
import { NewSessionMessage, ServerMessage, SessionDoneMessage, SessionOutputMessage, IdentifySessionMessage, NewConnectionMessage, ConnectionEstablishedMessage, NewConnectionFailureMessage, ConnectionCloseMessage, ConnectionOutputMessage, NewServerMessage, ServerEstablishedMessage, NewServerFailureMessage, ServerCloseMessage, ServerConnectionEstablishedMessage } from "../proto";
import { SendableConnection } from "../common/connection";
import { ServerOptions } from "./server";
export interface Process {
stdio?: Array<stream.Readable | stream.Writable>;
stdin?: stream.Writable;
stdout?: stream.Readable;
stderr?: stream.Readable;
send?: (message: string) => void;
pid: number;
killed?: boolean;
on(event: "data" | "message", cb: (data: string) => void): void;
on(event: "exit", listener: (exitCode: number, signal?: number) => void): void;
write(data: string | Uint8Array): void;
resize?(cols: number, rows: number): void;
kill(signal?: string): void;
title?: number;
}
export const handleNewSession = (connection: SendableConnection, newSession: NewSessionMessage, serverOptions: ServerOptions | undefined, onExit: () => void): Process => {
const childLogger = getChildLogger(newSession.getCommand());
childLogger.debug(() => [
newSession.getIsFork() ? "Forking" : "Spawning",
field("command", newSession.getCommand()),
field("args", newSession.getArgsList()),
field("env", newSession.getEnvMap().toObject()),
]);
let process: Process;
let processTitle: string | undefined;
const env: { [key: string]: string } = {};
newSession.getEnvMap().forEach((value, key) => {
env[key] = value;
});
if (newSession.getTtyDimensions()) {
// Spawn with node-pty
const nodePty = require("node-pty") as typeof import("node-pty");
const ptyProc = nodePty.spawn(newSession.getCommand(), newSession.getArgsList(), {
cols: newSession.getTtyDimensions()!.getWidth(),
rows: newSession.getTtyDimensions()!.getHeight(),
cwd: newSession.getCwd(),
env,
});
const timer = setInterval(() => {
if (ptyProc.process !== processTitle) {
processTitle = ptyProc.process;
const id = new IdentifySessionMessage();
id.setId(newSession.getId());
id.setTitle(processTitle!);
const sm = new ServerMessage();
sm.setIdentifySession(id);
connection.send(sm.serializeBinary());
}
}, 200);
ptyProc.on("exit", () => {
clearTimeout(timer);
});
process = ptyProc;
processTitle = ptyProc.process;
} else {
const options = {
cwd: newSession.getCwd(),
env,
};
let proc: cp.ChildProcess;
if (newSession.getIsFork()) {
if (!serverOptions) {
throw new Error("No forkProvider set for bootstrap-fork request");
}
if (!serverOptions.forkProvider) {
throw new Error("No forkProvider set for server options");
}
proc = serverOptions.forkProvider(newSession);
} else {
proc = cp.spawn(newSession.getCommand(), newSession.getArgsList(), options);
}
process = {
stdin: proc.stdin,
stderr: proc.stderr,
stdout: proc.stdout,
stdio: proc.stdio,
send: (message): void => {
proc.send(message);
},
on: (...args: any[]): void => ((proc as any).on)(...args), // tslint:disable-line no-any
write: (d): boolean => proc.stdin.write(d),
kill: (s): void => proc.kill(s || "SIGTERM"),
pid: proc.pid,
};
}
const sendOutput = (_source: SessionOutputMessage.Source, msg: string | Uint8Array): void => {
childLogger.debug(() => {
let data = msg.toString();
if (_source === SessionOutputMessage.Source.IPC) {
// data = Buffer.from(msg.toString(), "base64").toString();
}
return [
_source === SessionOutputMessage.Source.STDOUT
? "stdout"
: (_source === SessionOutputMessage.Source.STDERR ? "stderr" : "ipc"),
field("id", newSession.getId()),
field("data", data),
];
});
const serverMsg = new ServerMessage();
const d = new SessionOutputMessage();
d.setId(newSession.getId());
d.setData(typeof msg === "string" ? new TextEncoder().encode(msg) : msg);
d.setSource(_source);
serverMsg.setSessionOutput(d);
connection.send(serverMsg.serializeBinary());
};
if (process.stdout && process.stderr) {
process.stdout.on("data", (data) => {
sendOutput(SessionOutputMessage.Source.STDOUT, data);
});
process.stderr.on("data", (data) => {
sendOutput(SessionOutputMessage.Source.STDERR, data);
});
} else {
process.on("data", (data) => {
sendOutput(SessionOutputMessage.Source.STDOUT, Buffer.from(data));
});
}
// IPC.
if (process.send) {
process.on("message", (data) => {
sendOutput(SessionOutputMessage.Source.IPC, JSON.stringify(data));
});
}
const id = new IdentifySessionMessage();
id.setId(newSession.getId());
id.setPid(process.pid);
if (processTitle) {
id.setTitle(processTitle);
}
const sm = new ServerMessage();
sm.setIdentifySession(id);
connection.send(sm.serializeBinary());
process.on("exit", (code) => {
childLogger.debug(() => [
"Exited",
field("id", newSession.getId()),
field("command", newSession.getCommand()),
field("args", newSession.getArgsList()),
]);
const serverMsg = new ServerMessage();
const exit = new SessionDoneMessage();
exit.setId(newSession.getId());
exit.setExitStatus(code);
serverMsg.setSessionDone(exit);
connection.send(serverMsg.serializeBinary());
onExit();
});
return process;
};
export const handleNewConnection = (connection: SendableConnection, newConnection: NewConnectionMessage, onExit: () => void): net.Socket => {
const target = newConnection.getPath() || `${newConnection.getPort()}`;
const childLogger = getChildLogger(target, ">");
const id = newConnection.getId();
let socket: net.Socket;
let didConnect = false;
const connectCallback = (): void => {
childLogger.debug("Connected", field("id", newConnection.getId()), field("target", target));
didConnect = true;
const estab = new ConnectionEstablishedMessage();
estab.setId(id);
const servMsg = new ServerMessage();
servMsg.setConnectionEstablished(estab);
connection.send(servMsg.serializeBinary());
};
if (newConnection.getPath()) {
socket = net.createConnection(newConnection.getPath(), connectCallback);
} else if (newConnection.getPort()) {
socket = net.createConnection(newConnection.getPort(), undefined, connectCallback);
} else {
throw new Error("No path or port provided for new connection");
}
socket.addListener("error", (err) => {
childLogger.debug("Error", field("id", newConnection.getId()), field("error", err));
if (!didConnect) {
const errMsg = new NewConnectionFailureMessage();
errMsg.setId(id);
errMsg.setMessage(err.message);
const servMsg = new ServerMessage();
servMsg.setConnectionFailure(errMsg);
connection.send(servMsg.serializeBinary());
onExit();
}
});
socket.addListener("close", () => {
childLogger.debug("Closed", field("id", newConnection.getId()));
if (didConnect) {
const closed = new ConnectionCloseMessage();
closed.setId(id);
const servMsg = new ServerMessage();
servMsg.setConnectionClose(closed);
connection.send(servMsg.serializeBinary());
onExit();
}
});
socket.addListener("data", (data) => {
childLogger.debug(() => [
"ipc",
field("id", newConnection.getId()),
field("data", data),
]);
const dataMsg = new ConnectionOutputMessage();
dataMsg.setId(id);
dataMsg.setData(data);
const servMsg = new ServerMessage();
servMsg.setConnectionOutput(dataMsg);
connection.send(servMsg.serializeBinary());
});
return socket;
};
export const handleNewServer = (connection: SendableConnection, newServer: NewServerMessage, addSocket: (socket: net.Socket) => number, onExit: () => void, onSocketExit: (id: number) => void): net.Server => {
const target = newServer.getPath() || `${newServer.getPort()}`;
const childLogger = getChildLogger(target, "|");
const s = net.createServer();
try {
s.listen(newServer.getPath() ? newServer.getPath() : newServer.getPort(), () => {
childLogger.debug("Listening", field("id", newServer.getId()), field("target", target));
const se = new ServerEstablishedMessage();
se.setId(newServer.getId());
const sm = new ServerMessage();
sm.setServerEstablished(se);
connection.send(sm.serializeBinary());
});
} catch (ex) {
childLogger.debug("Failed to listen", field("id", newServer.getId()), field("target", target));
const sf = new NewServerFailureMessage();
sf.setId(newServer.getId());
const sm = new ServerMessage();
sm.setServerFailure(sf);
connection.send(sm.serializeBinary());
onExit();
}
s.on("close", () => {
childLogger.debug("Stopped listening", field("id", newServer.getId()), field("target", target));
const sc = new ServerCloseMessage();
sc.setId(newServer.getId());
const sm = new ServerMessage();
sm.setServerClose(sc);
connection.send(sm.serializeBinary());
onExit();
});
s.on("connection", (socket) => {
const socketId = addSocket(socket);
childLogger.debug("Got connection", field("id", newServer.getId()), field("socketId", socketId));
const sock = new ServerConnectionEstablishedMessage();
sock.setServerId(newServer.getId());
sock.setConnectionId(socketId);
const sm = new ServerMessage();
sm.setServerConnectionEstablished(sock);
connection.send(sm.serializeBinary());
socket.addListener("data", (data) => {
childLogger.debug(() => [
"ipc",
field("id", newServer.getId()),
field("socketId", socketId),
field("data", data),
]);
const dataMsg = new ConnectionOutputMessage();
dataMsg.setId(socketId);
dataMsg.setData(data);
const servMsg = new ServerMessage();
servMsg.setConnectionOutput(dataMsg);
connection.send(servMsg.serializeBinary());
});
socket.on("error", (error) => {
childLogger.debug("Error", field("id", newServer.getId()), field("socketId", socketId), field("error", error));
onSocketExit(socketId);
});
socket.on("close", () => {
childLogger.debug("Closed", field("id", newServer.getId()), field("socketId", socketId));
onSocketExit(socketId);
});
});
return s;
};
const getChildLogger = (command: string, prefix: string = ""): Logger => {
// TODO: Temporary, for debugging. Should probably ask for a name?
let name: string;
if (command.includes("vscode-ipc") || command.includes("extensionHost")) {
name = "exthost";
} else if (command.includes("vscode-remote")) {
name = "shared";
} else {
const basename = command.split("/").pop()!;
let i = 0;
for (; i < basename.length; i++) {
const character = basename.charAt(i);
if (isNaN(+character) && character === character.toUpperCase()) {
break;
}
}
name = basename.substring(0, i);
}
return logger.named(prefix + name);
};

View File

@ -1,10 +1,13 @@
import * as vm from "vm";
import { NewEvalMessage, TypedValue, EvalFailedMessage, EvalDoneMessage, ServerMessage, EvalEventMessage } from "../proto";
import { SendableConnection } from "../common/connection";
import { EventEmitter } from "events";
import * as vm from "vm";
import { logger, field } from "@coder/logger";
import { NewEvalMessage, EvalFailedMessage, EvalDoneMessage, ServerMessage, EvalEventMessage } from "../proto";
import { SendableConnection } from "../common/connection";
import { stringify, parse } from "../common/util";
export interface ActiveEvaluation {
onEvent(msg: EvalEventMessage): void;
dispose(): void;
}
declare var __non_webpack_require__: typeof require;
@ -13,96 +16,117 @@ export const evaluate = (connection: SendableConnection, message: NewEvalMessage
message.getArgsList().forEach((value) => {
argStr.push(value);
});
/**
* Send the response and call onDispose.
*/
// tslint:disable-next-line no-any
const sendResp = (resp: any): void => {
const evalDone = new EvalDoneMessage();
evalDone.setId(message.getId());
const tof = typeof resp;
if (tof !== "undefined") {
const tv = new TypedValue();
let t: TypedValue.Type;
switch (tof) {
case "string":
t = TypedValue.Type.STRING;
break;
case "boolean":
t = TypedValue.Type.BOOLEAN;
break;
case "object":
t = TypedValue.Type.OBJECT;
break;
case "number":
t = TypedValue.Type.NUMBER;
break;
default:
return sendErr(EvalFailedMessage.Reason.EXCEPTION, `unsupported response type ${tof}`);
}
tv.setValue(tof === "string" ? resp : JSON.stringify(resp));
tv.setType(t);
evalDone.setResponse(tv);
}
evalDone.setResponse(stringify(resp));
const serverMsg = new ServerMessage();
serverMsg.setEvalDone(evalDone);
connection.send(serverMsg.serializeBinary());
onDispose();
};
const sendErr = (reason: EvalFailedMessage.Reason, msg: string): void => {
/**
* Send an exception and call onDispose.
*/
const sendException = (error: Error): void => {
const evalFailed = new EvalFailedMessage();
evalFailed.setId(message.getId());
evalFailed.setReason(reason);
evalFailed.setMessage(msg);
evalFailed.setReason(EvalFailedMessage.Reason.EXCEPTION);
evalFailed.setMessage(error.toString() + " " + error.stack);
const serverMsg = new ServerMessage();
serverMsg.setEvalFailed(evalFailed);
connection.send(serverMsg.serializeBinary());
};
let eventEmitter: EventEmitter | undefined;
try {
if (message.getActive()) {
eventEmitter = new EventEmitter();
}
const value = vm.runInNewContext(`(${message.getFunction()})(${eventEmitter ? `eventEmitter, ` : ""}${argStr.join(",")})`, {
eventEmitter: eventEmitter ? {
on: (event: string, cb: (...args: any[]) => void): void => {
eventEmitter!.on(event, cb);
},
emit: (event: string, ...args: any[]): void => {
const eventMsg = new EvalEventMessage();
eventMsg.setEvent(event);
eventMsg.setArgsList(args.filter(a => a).map(a => JSON.stringify(a)));
eventMsg.setId(message.getId());
const serverMsg = new ServerMessage();
serverMsg.setEvalEvent(eventMsg);
connection.send(serverMsg.serializeBinary());
},
} : undefined,
_Buffer: Buffer,
require: typeof __non_webpack_require__ !== "undefined" ? __non_webpack_require__ : require,
_require: typeof __non_webpack_require__ !== "undefined" ? __non_webpack_require__ : require,
setTimeout,
}, {
onDispose();
};
let eventEmitter = message.getActive() ? new EventEmitter(): undefined;
const sandbox = {
eventEmitter: eventEmitter ? {
// tslint:disable no-any
on: (event: string, cb: (...args: any[]) => void): void => {
eventEmitter!.on(event, (...args: any[]) => {
logger.trace(() => [
`${event}`,
field("id", message.getId()),
field("args", args.map(stringify)),
]);
cb(...args);
});
},
emit: (event: string, ...args: any[]): void => {
logger.trace(() => [
`emit ${event}`,
field("id", message.getId()),
field("args", args.map(stringify)),
]);
const eventMsg = new EvalEventMessage();
eventMsg.setEvent(event);
eventMsg.setArgsList(args.map(stringify));
eventMsg.setId(message.getId());
const serverMsg = new ServerMessage();
serverMsg.setEvalEvent(eventMsg);
connection.send(serverMsg.serializeBinary());
},
// tslint:enable no-any
} : undefined,
_Buffer: Buffer,
require: typeof __non_webpack_require__ !== "undefined" ? __non_webpack_require__ : require,
setTimeout,
setInterval,
clearTimeout,
process: {
env: process.env,
},
};
let value: any; // tslint:disable-line no-any
try {
const code = `(${message.getFunction()})(${eventEmitter ? "eventEmitter, " : ""}${argStr.join(",")});`;
value = vm.runInNewContext(code, sandbox, {
// If the code takes longer than this to return, it is killed and throws.
timeout: message.getTimeout() || 15000,
});
if (eventEmitter) {
// Is an active evaluation and should NOT be ended
eventEmitter.on("close", () => onDispose());
eventEmitter.on("error", () => onDispose());
} else {
if ((value as Promise<void>).then) {
// Is promise
(value as Promise<void>).then(r => sendResp(r)).catch(ex => sendErr(EvalFailedMessage.Reason.EXCEPTION, ex.toString()));
} else {
sendResp(value);
}
onDispose();
}
} catch (ex) {
sendErr(EvalFailedMessage.Reason.EXCEPTION, ex.toString() + " " + ex.stack);
sendException(ex);
}
// An evaluation completes when the value it returns resolves. An active
// evaluation completes when it is disposed. Active evaluations are required
// to return disposers so we can know both when it has ended (so we can clean
// up on our end) and how to force end it (for example when the client
// disconnects).
// tslint:disable-next-line no-any
const promise = !eventEmitter ? value as Promise<any> : new Promise((resolve): void => {
value.onDidDispose(resolve);
});
if (promise && promise.then) {
promise.then(sendResp).catch(sendException);
} else {
sendResp(value);
}
return eventEmitter ? {
onEvent: (eventMsg: EvalEventMessage): void => {
eventEmitter!.emit(eventMsg.getEvent(), ...eventMsg.getArgsList().map(a => JSON.parse(a)));
eventEmitter!.emit(eventMsg.getEvent(), ...eventMsg.getArgsList().map(parse));
},
dispose: (): void => {
if (eventEmitter) {
if (value && value.dispose) {
value.dispose();
}
eventEmitter.removeAllListeners();
eventEmitter = undefined;
}
},
} : undefined;
};

View File

@ -1,32 +1,21 @@
import * as os from "os";
import * as cp from "child_process";
import * as path from "path";
import { mkdir } from "fs";
import { promisify } from "util";
import { TextDecoder } from "text-encoding";
import { logger, field } from "@coder/logger";
import { ClientMessage, WorkingInitMessage, ServerMessage, NewSessionMessage, WriteToSessionMessage } from "../proto";
import { ClientMessage, WorkingInitMessage, ServerMessage } from "../proto";
import { evaluate, ActiveEvaluation } from "./evaluate";
import { ReadWriteConnection } from "../common/connection";
import { Process, handleNewSession, handleNewConnection, handleNewServer } from "./command";
import * as net from "net";
export interface ServerOptions {
readonly workingDirectory: string;
readonly dataDirectory: string;
readonly builtInExtensionsDirectory: string;
forkProvider?(message: NewSessionMessage): cp.ChildProcess;
}
export class Server {
private readonly sessions = new Map<number, Process>();
private readonly connections = new Map<number, net.Socket>();
private readonly servers = new Map<number, net.Server>();
private readonly evals = new Map<number, ActiveEvaluation>();
private connectionId = Number.MAX_SAFE_INTEGER;
public constructor(
private readonly connection: ReadWriteConnection,
private readonly options?: ServerOptions,
@ -42,18 +31,10 @@ export class Server {
}
});
connection.onClose(() => {
this.sessions.forEach((s) => {
s.kill();
});
this.connections.forEach((c) => {
c.destroy();
});
this.servers.forEach((s) => {
s.close();
});
this.evals.forEach((e) => e.dispose());
});
if (!options) {
if (!this.options) {
logger.warn("No server options provided. InitMessage will not be sent.");
return;
@ -74,16 +55,16 @@ export class Server {
}
}
};
Promise.all([ mkdirP(path.join(options.dataDirectory, "User", "workspaceStorage")) ]).then(() => {
Promise.all([ mkdirP(path.join(this.options.dataDirectory, "User", "workspaceStorage")) ]).then(() => {
logger.info("Created data directory");
}).catch((error) => {
logger.error(error.message, field("error", error));
});
const initMsg = new WorkingInitMessage();
initMsg.setDataDirectory(options.dataDirectory);
initMsg.setWorkingDirectory(options.workingDirectory);
initMsg.setBuiltinExtensionsDir(options.builtInExtensionsDirectory);
initMsg.setDataDirectory(this.options.dataDirectory);
initMsg.setWorkingDirectory(this.options.workingDirectory);
initMsg.setBuiltinExtensionsDir(this.options.builtInExtensionsDirectory);
initMsg.setHomeDirectory(os.homedir());
initMsg.setTmpDirectory(os.tmpdir());
const platform = os.platform();
@ -113,7 +94,7 @@ export class Server {
private handleMessage(message: ClientMessage): void {
if (message.hasNewEval()) {
const evalMessage = message.getNewEval()!;
logger.debug(() => [
logger.trace(() => [
"EvalMessage",
field("id", evalMessage.getId()),
field("args", evalMessage.getArgsList()),
@ -121,132 +102,22 @@ export class Server {
]);
const resp = evaluate(this.connection, evalMessage, () => {
this.evals.delete(evalMessage.getId());
logger.trace(() => [
`dispose ${evalMessage.getId()}, ${this.evals.size} left`,
]);
});
if (resp) {
this.evals.set(evalMessage.getId(), resp);
}
} else if (message.hasEvalEvent()) {
const evalEventMessage = message.getEvalEvent()!;
logger.debug("EvalEventMessage", field("id", evalEventMessage.getId()));
const e = this.evals.get(evalEventMessage.getId());
if (!e) {
return;
}
e.onEvent(evalEventMessage);
} else if (message.hasNewSession()) {
const sessionMessage = message.getNewSession()!;
logger.debug("NewSession", field("id", sessionMessage.getId()));
const session = handleNewSession(this.connection, sessionMessage, this.options, () => {
this.sessions.delete(sessionMessage.getId());
});
this.sessions.set(sessionMessage.getId(), session);
} else if (message.hasCloseSessionInput()) {
const closeSessionMessage = message.getCloseSessionInput()!;
logger.debug("CloseSessionInput", field("id", closeSessionMessage.getId()));
const s = this.getSession(closeSessionMessage.getId());
if (!s || !s.stdin) {
return;
}
s.stdin.end();
} else if (message.hasResizeSessionTty()) {
const resizeSessionTtyMessage = message.getResizeSessionTty()!;
logger.debug("ResizeSessionTty", field("id", resizeSessionTtyMessage.getId()));
const s = this.getSession(resizeSessionTtyMessage.getId());
if (!s || !s.resize) {
return;
}
const tty = resizeSessionTtyMessage.getTtyDimensions()!;
s.resize(tty.getWidth(), tty.getHeight());
} else if (message.hasShutdownSession()) {
const shutdownSessionMessage = message.getShutdownSession()!;
logger.debug("ShutdownSession", field("id", shutdownSessionMessage.getId()));
const s = this.getSession(shutdownSessionMessage.getId());
if (!s) {
return;
}
s.kill(shutdownSessionMessage.getSignal());
} else if (message.hasWriteToSession()) {
const writeToSessionMessage = message.getWriteToSession()!;
logger.debug("WriteToSession", field("id", writeToSessionMessage.getId()));
const s = this.getSession(writeToSessionMessage.getId());
if (!s) {
return;
}
const data = new TextDecoder().decode(writeToSessionMessage.getData_asU8());
const source = writeToSessionMessage.getSource();
if (source === WriteToSessionMessage.Source.IPC) {
if (!s.send) {
throw new Error("Cannot send message via IPC to process without IPC");
}
s.send(JSON.parse(data));
} else {
s.write(data);
}
} else if (message.hasNewConnection()) {
const connectionMessage = message.getNewConnection()!;
logger.debug("NewConnection", field("id", connectionMessage.getId()));
if (this.connections.has(connectionMessage.getId())) {
throw new Error(`connect EISCONN ${connectionMessage.getPath() || connectionMessage.getPort()}`);
}
const socket = handleNewConnection(this.connection, connectionMessage, () => {
this.connections.delete(connectionMessage.getId());
});
this.connections.set(connectionMessage.getId(), socket);
} else if (message.hasConnectionOutput()) {
const connectionOutputMessage = message.getConnectionOutput()!;
logger.debug("ConnectionOuput", field("id", connectionOutputMessage.getId()));
const c = this.getConnection(connectionOutputMessage.getId());
if (!c) {
return;
}
c.write(Buffer.from(connectionOutputMessage.getData_asU8()));
} else if (message.hasConnectionClose()) {
const connectionCloseMessage = message.getConnectionClose()!;
logger.debug("ConnectionClose", field("id", connectionCloseMessage.getId()));
const c = this.getConnection(connectionCloseMessage.getId());
if (!c) {
return;
}
c.end();
} else if (message.hasNewServer()) {
const serverMessage = message.getNewServer()!;
logger.debug("NewServer", field("id", serverMessage.getId()));
if (this.servers.has(serverMessage.getId())) {
throw new Error("multiple listeners not supported");
}
const s = handleNewServer(this.connection, serverMessage, (socket) => {
const id = this.connectionId--;
this.connections.set(id, socket);
return id;
}, () => {
this.connections.delete(serverMessage.getId());
}, (id) => {
this.connections.delete(id);
});
this.servers.set(serverMessage.getId(), s);
} else if (message.hasServerClose()) {
const serverCloseMessage = message.getServerClose()!;
logger.debug("ServerClose", field("id", serverCloseMessage.getId()));
const s = this.getServer(serverCloseMessage.getId());
if (!s) {
return;
}
s.close();
} else {
logger.debug("Received unknown message type");
throw new Error("unknown message type");
}
}
private getServer(id: number): net.Server | undefined {
return this.servers.get(id);
}
private getConnection(id: number): net.Socket | undefined {
return this.connections.get(id);
}
private getSession(id: number): Process | undefined {
return this.sessions.get(id);
}
}

View File

@ -1,22 +1,9 @@
syntax = "proto3";
import "command.proto";
import "node.proto";
import "vscode.proto";
message ClientMessage {
oneof msg {
// command.proto
NewSessionMessage new_session = 1;
ShutdownSessionMessage shutdown_session = 2;
WriteToSessionMessage write_to_session = 3;
CloseSessionInputMessage close_session_input = 4;
ResizeSessionTTYMessage resize_session_tty = 5;
NewConnectionMessage new_connection = 6;
ConnectionOutputMessage connection_output = 7;
ConnectionCloseMessage connection_close = 8;
NewServerMessage new_server = 9;
ServerCloseMessage server_close = 10;
// node.proto
NewEvalMessage new_eval = 11;
EvalEventMessage eval_event = 12;
@ -25,20 +12,6 @@ message ClientMessage {
message ServerMessage {
oneof msg {
// command.proto
NewSessionFailureMessage new_session_failure = 1;
SessionDoneMessage session_done = 2;
SessionOutputMessage session_output = 3;
IdentifySessionMessage identify_session = 4;
NewConnectionFailureMessage connection_failure = 5;
ConnectionOutputMessage connection_output = 6;
ConnectionCloseMessage connection_close = 7;
ConnectionEstablishedMessage connection_established = 8;
NewServerFailureMessage server_failure = 9;
ServerEstablishedMessage server_established = 10;
ServerCloseMessage server_close = 11;
ServerConnectionEstablishedMessage server_connection_established = 12;
// node.proto
EvalFailedMessage eval_failed = 13;
EvalDoneMessage eval_done = 14;

View File

@ -2,61 +2,10 @@
// file: client.proto
import * as jspb from "google-protobuf";
import * as command_pb from "./command_pb";
import * as node_pb from "./node_pb";
import * as vscode_pb from "./vscode_pb";
export class ClientMessage extends jspb.Message {
hasNewSession(): boolean;
clearNewSession(): void;
getNewSession(): command_pb.NewSessionMessage | undefined;
setNewSession(value?: command_pb.NewSessionMessage): void;
hasShutdownSession(): boolean;
clearShutdownSession(): void;
getShutdownSession(): command_pb.ShutdownSessionMessage | undefined;
setShutdownSession(value?: command_pb.ShutdownSessionMessage): void;
hasWriteToSession(): boolean;
clearWriteToSession(): void;
getWriteToSession(): command_pb.WriteToSessionMessage | undefined;
setWriteToSession(value?: command_pb.WriteToSessionMessage): void;
hasCloseSessionInput(): boolean;
clearCloseSessionInput(): void;
getCloseSessionInput(): command_pb.CloseSessionInputMessage | undefined;
setCloseSessionInput(value?: command_pb.CloseSessionInputMessage): void;
hasResizeSessionTty(): boolean;
clearResizeSessionTty(): void;
getResizeSessionTty(): command_pb.ResizeSessionTTYMessage | undefined;
setResizeSessionTty(value?: command_pb.ResizeSessionTTYMessage): void;
hasNewConnection(): boolean;
clearNewConnection(): void;
getNewConnection(): command_pb.NewConnectionMessage | undefined;
setNewConnection(value?: command_pb.NewConnectionMessage): void;
hasConnectionOutput(): boolean;
clearConnectionOutput(): void;
getConnectionOutput(): command_pb.ConnectionOutputMessage | undefined;
setConnectionOutput(value?: command_pb.ConnectionOutputMessage): void;
hasConnectionClose(): boolean;
clearConnectionClose(): void;
getConnectionClose(): command_pb.ConnectionCloseMessage | undefined;
setConnectionClose(value?: command_pb.ConnectionCloseMessage): void;
hasNewServer(): boolean;
clearNewServer(): void;
getNewServer(): command_pb.NewServerMessage | undefined;
setNewServer(value?: command_pb.NewServerMessage): void;
hasServerClose(): boolean;
clearServerClose(): void;
getServerClose(): command_pb.ServerCloseMessage | undefined;
setServerClose(value?: command_pb.ServerCloseMessage): void;
hasNewEval(): boolean;
clearNewEval(): void;
getNewEval(): node_pb.NewEvalMessage | undefined;
@ -80,98 +29,18 @@ export class ClientMessage extends jspb.Message {
export namespace ClientMessage {
export type AsObject = {
newSession?: command_pb.NewSessionMessage.AsObject,
shutdownSession?: command_pb.ShutdownSessionMessage.AsObject,
writeToSession?: command_pb.WriteToSessionMessage.AsObject,
closeSessionInput?: command_pb.CloseSessionInputMessage.AsObject,
resizeSessionTty?: command_pb.ResizeSessionTTYMessage.AsObject,
newConnection?: command_pb.NewConnectionMessage.AsObject,
connectionOutput?: command_pb.ConnectionOutputMessage.AsObject,
connectionClose?: command_pb.ConnectionCloseMessage.AsObject,
newServer?: command_pb.NewServerMessage.AsObject,
serverClose?: command_pb.ServerCloseMessage.AsObject,
newEval?: node_pb.NewEvalMessage.AsObject,
evalEvent?: node_pb.EvalEventMessage.AsObject,
}
export enum MsgCase {
MSG_NOT_SET = 0,
NEW_SESSION = 1,
SHUTDOWN_SESSION = 2,
WRITE_TO_SESSION = 3,
CLOSE_SESSION_INPUT = 4,
RESIZE_SESSION_TTY = 5,
NEW_CONNECTION = 6,
CONNECTION_OUTPUT = 7,
CONNECTION_CLOSE = 8,
NEW_SERVER = 9,
SERVER_CLOSE = 10,
NEW_EVAL = 11,
EVAL_EVENT = 12,
}
}
export class ServerMessage extends jspb.Message {
hasNewSessionFailure(): boolean;
clearNewSessionFailure(): void;
getNewSessionFailure(): command_pb.NewSessionFailureMessage | undefined;
setNewSessionFailure(value?: command_pb.NewSessionFailureMessage): void;
hasSessionDone(): boolean;
clearSessionDone(): void;
getSessionDone(): command_pb.SessionDoneMessage | undefined;
setSessionDone(value?: command_pb.SessionDoneMessage): void;
hasSessionOutput(): boolean;
clearSessionOutput(): void;
getSessionOutput(): command_pb.SessionOutputMessage | undefined;
setSessionOutput(value?: command_pb.SessionOutputMessage): void;
hasIdentifySession(): boolean;
clearIdentifySession(): void;
getIdentifySession(): command_pb.IdentifySessionMessage | undefined;
setIdentifySession(value?: command_pb.IdentifySessionMessage): void;
hasConnectionFailure(): boolean;
clearConnectionFailure(): void;
getConnectionFailure(): command_pb.NewConnectionFailureMessage | undefined;
setConnectionFailure(value?: command_pb.NewConnectionFailureMessage): void;
hasConnectionOutput(): boolean;
clearConnectionOutput(): void;
getConnectionOutput(): command_pb.ConnectionOutputMessage | undefined;
setConnectionOutput(value?: command_pb.ConnectionOutputMessage): void;
hasConnectionClose(): boolean;
clearConnectionClose(): void;
getConnectionClose(): command_pb.ConnectionCloseMessage | undefined;
setConnectionClose(value?: command_pb.ConnectionCloseMessage): void;
hasConnectionEstablished(): boolean;
clearConnectionEstablished(): void;
getConnectionEstablished(): command_pb.ConnectionEstablishedMessage | undefined;
setConnectionEstablished(value?: command_pb.ConnectionEstablishedMessage): void;
hasServerFailure(): boolean;
clearServerFailure(): void;
getServerFailure(): command_pb.NewServerFailureMessage | undefined;
setServerFailure(value?: command_pb.NewServerFailureMessage): void;
hasServerEstablished(): boolean;
clearServerEstablished(): void;
getServerEstablished(): command_pb.ServerEstablishedMessage | undefined;
setServerEstablished(value?: command_pb.ServerEstablishedMessage): void;
hasServerClose(): boolean;
clearServerClose(): void;
getServerClose(): command_pb.ServerCloseMessage | undefined;
setServerClose(value?: command_pb.ServerCloseMessage): void;
hasServerConnectionEstablished(): boolean;
clearServerConnectionEstablished(): void;
getServerConnectionEstablished(): command_pb.ServerConnectionEstablishedMessage | undefined;
setServerConnectionEstablished(value?: command_pb.ServerConnectionEstablishedMessage): void;
hasEvalFailed(): boolean;
clearEvalFailed(): void;
getEvalFailed(): node_pb.EvalFailedMessage | undefined;
@ -210,18 +79,6 @@ export class ServerMessage extends jspb.Message {
export namespace ServerMessage {
export type AsObject = {
newSessionFailure?: command_pb.NewSessionFailureMessage.AsObject,
sessionDone?: command_pb.SessionDoneMessage.AsObject,
sessionOutput?: command_pb.SessionOutputMessage.AsObject,
identifySession?: command_pb.IdentifySessionMessage.AsObject,
connectionFailure?: command_pb.NewConnectionFailureMessage.AsObject,
connectionOutput?: command_pb.ConnectionOutputMessage.AsObject,
connectionClose?: command_pb.ConnectionCloseMessage.AsObject,
connectionEstablished?: command_pb.ConnectionEstablishedMessage.AsObject,
serverFailure?: command_pb.NewServerFailureMessage.AsObject,
serverEstablished?: command_pb.ServerEstablishedMessage.AsObject,
serverClose?: command_pb.ServerCloseMessage.AsObject,
serverConnectionEstablished?: command_pb.ServerConnectionEstablishedMessage.AsObject,
evalFailed?: node_pb.EvalFailedMessage.AsObject,
evalDone?: node_pb.EvalDoneMessage.AsObject,
evalEvent?: node_pb.EvalEventMessage.AsObject,
@ -231,18 +88,6 @@ export namespace ServerMessage {
export enum MsgCase {
MSG_NOT_SET = 0,
NEW_SESSION_FAILURE = 1,
SESSION_DONE = 2,
SESSION_OUTPUT = 3,
IDENTIFY_SESSION = 4,
CONNECTION_FAILURE = 5,
CONNECTION_OUTPUT = 6,
CONNECTION_CLOSE = 7,
CONNECTION_ESTABLISHED = 8,
SERVER_FAILURE = 9,
SERVER_ESTABLISHED = 10,
SERVER_CLOSE = 11,
SERVER_CONNECTION_ESTABLISHED = 12,
EVAL_FAILED = 13,
EVAL_DONE = 14,
EVAL_EVENT = 15,

File diff suppressed because it is too large Load Diff

View File

@ -1,143 +0,0 @@
syntax = "proto3";
// Executes a command.
// Ensure the id field is unique for each new session. If a client reuses the id of an existing
// session, the connection will be closed.
// If env is provided, the environment variables will be set.
// If tty_dimensions is included, we will spawn a tty for the command using the given dimensions.
message NewSessionMessage {
uint64 id = 1;
string command = 2;
repeated string args = 3;
map<string, string> env = 4;
string cwd = 5;
TTYDimensions tty_dimensions = 6;
bool is_fork = 7;
// Janky, but required for having custom handling of the bootstrap fork
bool is_bootstrap_fork = 8;
}
// Sent when starting a session failed.
message NewSessionFailureMessage {
uint64 id = 1;
enum Reason {
Prohibited = 0;
ResourceShortage = 1;
}
Reason reason = 2;
string message = 3;
}
// Sent when a session has completed
message SessionDoneMessage {
uint64 id = 1;
int64 exit_status = 2;
}
// Identifies a session with a PID and a title.
// Can be sent multiple times when title changes.
message IdentifySessionMessage {
uint64 id = 1;
uint64 pid = 2;
string title = 3;
}
// Writes data to a session.
message WriteToSessionMessage {
uint64 id = 1;
bytes data = 2;
enum Source {
Stdin = 0;
Ipc = 1;
}
Source source = 3;
}
// Resizes the TTY of the session identified by the id.
// The connection will be closed if a TTY was not requested when the session was created.
message ResizeSessionTTYMessage {
uint64 id = 1;
TTYDimensions tty_dimensions = 2;
}
// CloseSessionInputMessage closes the stdin of the session by the ID.
message CloseSessionInputMessage {
uint64 id = 1;
}
message ShutdownSessionMessage {
uint64 id = 1;
string signal = 2;
}
// SessionOutputMessage carries data read from the stdout or stderr of the session identified by the id.
message SessionOutputMessage {
uint64 id = 1;
enum Source {
Stdout = 0;
Stderr = 1;
Ipc = 2;
}
Source source = 2;
bytes data = 3;
}
message TTYDimensions {
uint32 height = 1;
uint32 width = 2;
}
// Initializes a new connection to a port or path
message NewConnectionMessage {
uint64 id = 1;
uint64 port = 2;
string path = 3;
}
// Sent when a connection has successfully established
message ConnectionEstablishedMessage {
uint64 id = 1;
}
// Sent when a connection fails
message NewConnectionFailureMessage {
uint64 id = 1;
string message = 2;
}
// Sent for connection output
message ConnectionOutputMessage {
uint64 id = 1;
bytes data = 2;
}
// Sent to close a connection
message ConnectionCloseMessage {
uint64 id = 1;
}
message NewServerMessage {
uint64 id = 1;
uint64 port = 2;
string path = 3;
}
message NewServerFailureMessage {
uint64 id = 1;
string message = 2;
}
message ServerEstablishedMessage {
uint64 id = 1;
}
message ServerCloseMessage {
uint64 id = 1;
string reason = 2;
}
message ServerConnectionEstablishedMessage {
uint64 server_id = 1;
uint64 connection_id = 2;
}

View File

@ -1,544 +0,0 @@
// package:
// file: command.proto
import * as jspb from "google-protobuf";
export class NewSessionMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
getCommand(): string;
setCommand(value: string): void;
clearArgsList(): void;
getArgsList(): Array<string>;
setArgsList(value: Array<string>): void;
addArgs(value: string, index?: number): string;
getEnvMap(): jspb.Map<string, string>;
clearEnvMap(): void;
getCwd(): string;
setCwd(value: string): void;
hasTtyDimensions(): boolean;
clearTtyDimensions(): void;
getTtyDimensions(): TTYDimensions | undefined;
setTtyDimensions(value?: TTYDimensions): void;
getIsFork(): boolean;
setIsFork(value: boolean): void;
getIsBootstrapFork(): boolean;
setIsBootstrapFork(value: boolean): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): NewSessionMessage.AsObject;
static toObject(includeInstance: boolean, msg: NewSessionMessage): NewSessionMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: NewSessionMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): NewSessionMessage;
static deserializeBinaryFromReader(message: NewSessionMessage, reader: jspb.BinaryReader): NewSessionMessage;
}
export namespace NewSessionMessage {
export type AsObject = {
id: number,
command: string,
argsList: Array<string>,
envMap: Array<[string, string]>,
cwd: string,
ttyDimensions?: TTYDimensions.AsObject,
isFork: boolean,
isBootstrapFork: boolean,
}
}
export class NewSessionFailureMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
getReason(): NewSessionFailureMessage.Reason;
setReason(value: NewSessionFailureMessage.Reason): void;
getMessage(): string;
setMessage(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): NewSessionFailureMessage.AsObject;
static toObject(includeInstance: boolean, msg: NewSessionFailureMessage): NewSessionFailureMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: NewSessionFailureMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): NewSessionFailureMessage;
static deserializeBinaryFromReader(message: NewSessionFailureMessage, reader: jspb.BinaryReader): NewSessionFailureMessage;
}
export namespace NewSessionFailureMessage {
export type AsObject = {
id: number,
reason: NewSessionFailureMessage.Reason,
message: string,
}
export enum Reason {
PROHIBITED = 0,
RESOURCESHORTAGE = 1,
}
}
export class SessionDoneMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
getExitStatus(): number;
setExitStatus(value: number): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): SessionDoneMessage.AsObject;
static toObject(includeInstance: boolean, msg: SessionDoneMessage): SessionDoneMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: SessionDoneMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): SessionDoneMessage;
static deserializeBinaryFromReader(message: SessionDoneMessage, reader: jspb.BinaryReader): SessionDoneMessage;
}
export namespace SessionDoneMessage {
export type AsObject = {
id: number,
exitStatus: number,
}
}
export class IdentifySessionMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
getPid(): number;
setPid(value: number): void;
getTitle(): string;
setTitle(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): IdentifySessionMessage.AsObject;
static toObject(includeInstance: boolean, msg: IdentifySessionMessage): IdentifySessionMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: IdentifySessionMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): IdentifySessionMessage;
static deserializeBinaryFromReader(message: IdentifySessionMessage, reader: jspb.BinaryReader): IdentifySessionMessage;
}
export namespace IdentifySessionMessage {
export type AsObject = {
id: number,
pid: number,
title: string,
}
}
export class WriteToSessionMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
getData(): Uint8Array | string;
getData_asU8(): Uint8Array;
getData_asB64(): string;
setData(value: Uint8Array | string): void;
getSource(): WriteToSessionMessage.Source;
setSource(value: WriteToSessionMessage.Source): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): WriteToSessionMessage.AsObject;
static toObject(includeInstance: boolean, msg: WriteToSessionMessage): WriteToSessionMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: WriteToSessionMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): WriteToSessionMessage;
static deserializeBinaryFromReader(message: WriteToSessionMessage, reader: jspb.BinaryReader): WriteToSessionMessage;
}
export namespace WriteToSessionMessage {
export type AsObject = {
id: number,
data: Uint8Array | string,
source: WriteToSessionMessage.Source,
}
export enum Source {
STDIN = 0,
IPC = 1,
}
}
export class ResizeSessionTTYMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
hasTtyDimensions(): boolean;
clearTtyDimensions(): void;
getTtyDimensions(): TTYDimensions | undefined;
setTtyDimensions(value?: TTYDimensions): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ResizeSessionTTYMessage.AsObject;
static toObject(includeInstance: boolean, msg: ResizeSessionTTYMessage): ResizeSessionTTYMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: ResizeSessionTTYMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): ResizeSessionTTYMessage;
static deserializeBinaryFromReader(message: ResizeSessionTTYMessage, reader: jspb.BinaryReader): ResizeSessionTTYMessage;
}
export namespace ResizeSessionTTYMessage {
export type AsObject = {
id: number,
ttyDimensions?: TTYDimensions.AsObject,
}
}
export class CloseSessionInputMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): CloseSessionInputMessage.AsObject;
static toObject(includeInstance: boolean, msg: CloseSessionInputMessage): CloseSessionInputMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: CloseSessionInputMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): CloseSessionInputMessage;
static deserializeBinaryFromReader(message: CloseSessionInputMessage, reader: jspb.BinaryReader): CloseSessionInputMessage;
}
export namespace CloseSessionInputMessage {
export type AsObject = {
id: number,
}
}
export class ShutdownSessionMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
getSignal(): string;
setSignal(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ShutdownSessionMessage.AsObject;
static toObject(includeInstance: boolean, msg: ShutdownSessionMessage): ShutdownSessionMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: ShutdownSessionMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): ShutdownSessionMessage;
static deserializeBinaryFromReader(message: ShutdownSessionMessage, reader: jspb.BinaryReader): ShutdownSessionMessage;
}
export namespace ShutdownSessionMessage {
export type AsObject = {
id: number,
signal: string,
}
}
export class SessionOutputMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
getSource(): SessionOutputMessage.Source;
setSource(value: SessionOutputMessage.Source): void;
getData(): Uint8Array | string;
getData_asU8(): Uint8Array;
getData_asB64(): string;
setData(value: Uint8Array | string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): SessionOutputMessage.AsObject;
static toObject(includeInstance: boolean, msg: SessionOutputMessage): SessionOutputMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: SessionOutputMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): SessionOutputMessage;
static deserializeBinaryFromReader(message: SessionOutputMessage, reader: jspb.BinaryReader): SessionOutputMessage;
}
export namespace SessionOutputMessage {
export type AsObject = {
id: number,
source: SessionOutputMessage.Source,
data: Uint8Array | string,
}
export enum Source {
STDOUT = 0,
STDERR = 1,
IPC = 2,
}
}
export class TTYDimensions extends jspb.Message {
getHeight(): number;
setHeight(value: number): void;
getWidth(): number;
setWidth(value: number): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): TTYDimensions.AsObject;
static toObject(includeInstance: boolean, msg: TTYDimensions): TTYDimensions.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: TTYDimensions, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): TTYDimensions;
static deserializeBinaryFromReader(message: TTYDimensions, reader: jspb.BinaryReader): TTYDimensions;
}
export namespace TTYDimensions {
export type AsObject = {
height: number,
width: number,
}
}
export class NewConnectionMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
getPort(): number;
setPort(value: number): void;
getPath(): string;
setPath(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): NewConnectionMessage.AsObject;
static toObject(includeInstance: boolean, msg: NewConnectionMessage): NewConnectionMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: NewConnectionMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): NewConnectionMessage;
static deserializeBinaryFromReader(message: NewConnectionMessage, reader: jspb.BinaryReader): NewConnectionMessage;
}
export namespace NewConnectionMessage {
export type AsObject = {
id: number,
port: number,
path: string,
}
}
export class ConnectionEstablishedMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ConnectionEstablishedMessage.AsObject;
static toObject(includeInstance: boolean, msg: ConnectionEstablishedMessage): ConnectionEstablishedMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: ConnectionEstablishedMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): ConnectionEstablishedMessage;
static deserializeBinaryFromReader(message: ConnectionEstablishedMessage, reader: jspb.BinaryReader): ConnectionEstablishedMessage;
}
export namespace ConnectionEstablishedMessage {
export type AsObject = {
id: number,
}
}
export class NewConnectionFailureMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
getMessage(): string;
setMessage(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): NewConnectionFailureMessage.AsObject;
static toObject(includeInstance: boolean, msg: NewConnectionFailureMessage): NewConnectionFailureMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: NewConnectionFailureMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): NewConnectionFailureMessage;
static deserializeBinaryFromReader(message: NewConnectionFailureMessage, reader: jspb.BinaryReader): NewConnectionFailureMessage;
}
export namespace NewConnectionFailureMessage {
export type AsObject = {
id: number,
message: string,
}
}
export class ConnectionOutputMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
getData(): Uint8Array | string;
getData_asU8(): Uint8Array;
getData_asB64(): string;
setData(value: Uint8Array | string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ConnectionOutputMessage.AsObject;
static toObject(includeInstance: boolean, msg: ConnectionOutputMessage): ConnectionOutputMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: ConnectionOutputMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): ConnectionOutputMessage;
static deserializeBinaryFromReader(message: ConnectionOutputMessage, reader: jspb.BinaryReader): ConnectionOutputMessage;
}
export namespace ConnectionOutputMessage {
export type AsObject = {
id: number,
data: Uint8Array | string,
}
}
export class ConnectionCloseMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ConnectionCloseMessage.AsObject;
static toObject(includeInstance: boolean, msg: ConnectionCloseMessage): ConnectionCloseMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: ConnectionCloseMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): ConnectionCloseMessage;
static deserializeBinaryFromReader(message: ConnectionCloseMessage, reader: jspb.BinaryReader): ConnectionCloseMessage;
}
export namespace ConnectionCloseMessage {
export type AsObject = {
id: number,
}
}
export class NewServerMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
getPort(): number;
setPort(value: number): void;
getPath(): string;
setPath(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): NewServerMessage.AsObject;
static toObject(includeInstance: boolean, msg: NewServerMessage): NewServerMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: NewServerMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): NewServerMessage;
static deserializeBinaryFromReader(message: NewServerMessage, reader: jspb.BinaryReader): NewServerMessage;
}
export namespace NewServerMessage {
export type AsObject = {
id: number,
port: number,
path: string,
}
}
export class NewServerFailureMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
getMessage(): string;
setMessage(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): NewServerFailureMessage.AsObject;
static toObject(includeInstance: boolean, msg: NewServerFailureMessage): NewServerFailureMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: NewServerFailureMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): NewServerFailureMessage;
static deserializeBinaryFromReader(message: NewServerFailureMessage, reader: jspb.BinaryReader): NewServerFailureMessage;
}
export namespace NewServerFailureMessage {
export type AsObject = {
id: number,
message: string,
}
}
export class ServerEstablishedMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ServerEstablishedMessage.AsObject;
static toObject(includeInstance: boolean, msg: ServerEstablishedMessage): ServerEstablishedMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: ServerEstablishedMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): ServerEstablishedMessage;
static deserializeBinaryFromReader(message: ServerEstablishedMessage, reader: jspb.BinaryReader): ServerEstablishedMessage;
}
export namespace ServerEstablishedMessage {
export type AsObject = {
id: number,
}
}
export class ServerCloseMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
getReason(): string;
setReason(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ServerCloseMessage.AsObject;
static toObject(includeInstance: boolean, msg: ServerCloseMessage): ServerCloseMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: ServerCloseMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): ServerCloseMessage;
static deserializeBinaryFromReader(message: ServerCloseMessage, reader: jspb.BinaryReader): ServerCloseMessage;
}
export namespace ServerCloseMessage {
export type AsObject = {
id: number,
reason: string,
}
}
export class ServerConnectionEstablishedMessage extends jspb.Message {
getServerId(): number;
setServerId(value: number): void;
getConnectionId(): number;
setConnectionId(value: number): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ServerConnectionEstablishedMessage.AsObject;
static toObject(includeInstance: boolean, msg: ServerConnectionEstablishedMessage): ServerConnectionEstablishedMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: ServerConnectionEstablishedMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): ServerConnectionEstablishedMessage;
static deserializeBinaryFromReader(message: ServerConnectionEstablishedMessage, reader: jspb.BinaryReader): ServerConnectionEstablishedMessage;
}
export namespace ServerConnectionEstablishedMessage {
export type AsObject = {
serverId: number,
connectionId: number,
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,3 @@
export * from "./client_pb";
export * from "./command_pb";
export * from "./node_pb";
export * from "./vscode_pb";

View File

@ -1,16 +1,5 @@
syntax = "proto3";
message TypedValue {
enum Type {
String = 0;
Number = 1;
Object = 2;
Boolean = 3;
}
Type type = 1;
string value = 2;
}
message NewEvalMessage {
uint64 id = 1;
string function = 2;
@ -41,5 +30,5 @@ message EvalFailedMessage {
message EvalDoneMessage {
uint64 id = 1;
TypedValue response = 2;
string response = 2;
}

View File

@ -3,37 +3,6 @@
import * as jspb from "google-protobuf";
export class TypedValue extends jspb.Message {
getType(): TypedValue.Type;
setType(value: TypedValue.Type): void;
getValue(): string;
setValue(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): TypedValue.AsObject;
static toObject(includeInstance: boolean, msg: TypedValue): TypedValue.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: TypedValue, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): TypedValue;
static deserializeBinaryFromReader(message: TypedValue, reader: jspb.BinaryReader): TypedValue;
}
export namespace TypedValue {
export type AsObject = {
type: TypedValue.Type,
value: string,
}
export enum Type {
STRING = 0,
NUMBER = 1,
OBJECT = 2,
BOOLEAN = 3,
}
}
export class NewEvalMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
@ -140,10 +109,8 @@ export class EvalDoneMessage extends jspb.Message {
getId(): number;
setId(value: number): void;
hasResponse(): boolean;
clearResponse(): void;
getResponse(): TypedValue | undefined;
setResponse(value?: TypedValue): void;
getResponse(): string;
setResponse(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): EvalDoneMessage.AsObject;
@ -158,7 +125,7 @@ export class EvalDoneMessage extends jspb.Message {
export namespace EvalDoneMessage {
export type AsObject = {
id: number,
response?: TypedValue.AsObject,
response: string,
}
}

View File

@ -1,6 +1,8 @@
/**
* @fileoverview
* @enhanceable
* @suppress {messageConventions} JS Compiler reports an error if a variable or
* field starts with 'MSG_' and isn't a translatable message.
* @public
*/
// GENERATED CODE -- DO NOT EDIT!
@ -14,204 +16,6 @@ goog.exportSymbol('proto.EvalEventMessage', null, global);
goog.exportSymbol('proto.EvalFailedMessage', null, global);
goog.exportSymbol('proto.EvalFailedMessage.Reason', null, global);
goog.exportSymbol('proto.NewEvalMessage', null, global);
goog.exportSymbol('proto.TypedValue', null, global);
goog.exportSymbol('proto.TypedValue.Type', null, global);
/**
* Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a
* server response, or constructed directly in Javascript. The array is used
* in place and becomes part of the constructed object. It is not cloned.
* If no data is provided, the constructed object will be empty, but still
* valid.
* @extends {jspb.Message}
* @constructor
*/
proto.TypedValue = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.TypedValue, jspb.Message);
if (goog.DEBUG && !COMPILED) {
proto.TypedValue.displayName = 'proto.TypedValue';
}
if (jspb.Message.GENERATE_TO_OBJECT) {
/**
* Creates an object representation of this proto suitable for use in Soy templates.
* Field names that are reserved in JavaScript and will be renamed to pb_name.
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
* For the list of reserved names please see:
* com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS.
* @param {boolean=} opt_includeInstance Whether to include the JSPB instance
* for transitional soy proto support: http://goto/soy-param-migration
* @return {!Object}
*/
proto.TypedValue.prototype.toObject = function(opt_includeInstance) {
return proto.TypedValue.toObject(opt_includeInstance, this);
};
/**
* Static version of the {@see toObject} method.
* @param {boolean|undefined} includeInstance Whether to include the JSPB
* instance for transitional soy proto support:
* http://goto/soy-param-migration
* @param {!proto.TypedValue} msg The msg instance to transform.
* @return {!Object}
*/
proto.TypedValue.toObject = function(includeInstance, msg) {
var f, obj = {
type: msg.getType(),
value: msg.getValue()
};
if (includeInstance) {
obj.$jspbMessageInstance = msg;
}
return obj;
};
}
/**
* Deserializes binary data (in protobuf wire format).
* @param {jspb.ByteSource} bytes The bytes to deserialize.
* @return {!proto.TypedValue}
*/
proto.TypedValue.deserializeBinary = function(bytes) {
var reader = new jspb.BinaryReader(bytes);
var msg = new proto.TypedValue;
return proto.TypedValue.deserializeBinaryFromReader(msg, reader);
};
/**
* Deserializes binary data (in protobuf wire format) from the
* given reader into the given message object.
* @param {!proto.TypedValue} msg The message object to deserialize into.
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
* @return {!proto.TypedValue}
*/
proto.TypedValue.deserializeBinaryFromReader = function(msg, reader) {
while (reader.nextField()) {
if (reader.isEndGroup()) {
break;
}
var field = reader.getFieldNumber();
switch (field) {
case 1:
var value = /** @type {!proto.TypedValue.Type} */ (reader.readEnum());
msg.setType(value);
break;
case 2:
var value = /** @type {string} */ (reader.readString());
msg.setValue(value);
break;
default:
reader.skipField();
break;
}
}
return msg;
};
/**
* Class method variant: serializes the given message to binary data
* (in protobuf wire format), writing to the given BinaryWriter.
* @param {!proto.TypedValue} message
* @param {!jspb.BinaryWriter} writer
*/
proto.TypedValue.serializeBinaryToWriter = function(message, writer) {
message.serializeBinaryToWriter(writer);
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.TypedValue.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
this.serializeBinaryToWriter(writer);
return writer.getResultBuffer();
};
/**
* Serializes the message to binary data (in protobuf wire format),
* writing to the given BinaryWriter.
* @param {!jspb.BinaryWriter} writer
*/
proto.TypedValue.prototype.serializeBinaryToWriter = function (writer) {
var f = undefined;
f = this.getType();
if (f !== 0.0) {
writer.writeEnum(
1,
f
);
}
f = this.getValue();
if (f.length > 0) {
writer.writeString(
2,
f
);
}
};
/**
* Creates a deep clone of this proto. No data is shared with the original.
* @return {!proto.TypedValue} The clone.
*/
proto.TypedValue.prototype.cloneMessage = function() {
return /** @type {!proto.TypedValue} */ (jspb.Message.cloneMessage(this));
};
/**
* optional Type type = 1;
* @return {!proto.TypedValue.Type}
*/
proto.TypedValue.prototype.getType = function() {
return /** @type {!proto.TypedValue.Type} */ (jspb.Message.getFieldProto3(this, 1, 0));
};
/** @param {!proto.TypedValue.Type} value */
proto.TypedValue.prototype.setType = function(value) {
jspb.Message.setField(this, 1, value);
};
/**
* optional string value = 2;
* @return {string}
*/
proto.TypedValue.prototype.getValue = function() {
return /** @type {string} */ (jspb.Message.getFieldProto3(this, 2, ""));
};
/** @param {string} value */
proto.TypedValue.prototype.setValue = function(value) {
jspb.Message.setField(this, 2, value);
};
/**
* @enum {number}
*/
proto.TypedValue.Type = {
STRING: 0,
NUMBER: 1,
OBJECT: 2,
BOOLEAN: 3
};
/**
* Generated by JsPbCodeGenerator.
@ -262,14 +66,15 @@ proto.NewEvalMessage.prototype.toObject = function(opt_includeInstance) {
* http://goto/soy-param-migration
* @param {!proto.NewEvalMessage} msg The msg instance to transform.
* @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.NewEvalMessage.toObject = function(includeInstance, msg) {
var f, obj = {
id: msg.getId(),
pb_function: msg.getFunction(),
argsList: jspb.Message.getField(msg, 3),
timeout: msg.getTimeout(),
active: msg.getActive()
id: jspb.Message.getFieldWithDefault(msg, 1, 0),
pb_function: jspb.Message.getFieldWithDefault(msg, 2, ""),
argsList: jspb.Message.getRepeatedField(msg, 3),
timeout: jspb.Message.getFieldWithDefault(msg, 4, 0),
active: jspb.Message.getFieldWithDefault(msg, 5, false)
};
if (includeInstance) {
@ -316,8 +121,7 @@ proto.NewEvalMessage.deserializeBinaryFromReader = function(msg, reader) {
break;
case 3:
var value = /** @type {string} */ (reader.readString());
msg.getArgsList().push(value);
msg.setArgsList(msg.getArgsList());
msg.addArgs(value);
break;
case 4:
var value = /** @type {number} */ (reader.readUint32());
@ -336,64 +140,55 @@ proto.NewEvalMessage.deserializeBinaryFromReader = function(msg, reader) {
};
/**
* Class method variant: serializes the given message to binary data
* (in protobuf wire format), writing to the given BinaryWriter.
* @param {!proto.NewEvalMessage} message
* @param {!jspb.BinaryWriter} writer
*/
proto.NewEvalMessage.serializeBinaryToWriter = function(message, writer) {
message.serializeBinaryToWriter(writer);
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.NewEvalMessage.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
this.serializeBinaryToWriter(writer);
proto.NewEvalMessage.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
};
/**
* Serializes the message to binary data (in protobuf wire format),
* writing to the given BinaryWriter.
* Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter.
* @param {!proto.NewEvalMessage} message
* @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.NewEvalMessage.prototype.serializeBinaryToWriter = function (writer) {
proto.NewEvalMessage.serializeBinaryToWriter = function(message, writer) {
var f = undefined;
f = this.getId();
f = message.getId();
if (f !== 0) {
writer.writeUint64(
1,
f
);
}
f = this.getFunction();
f = message.getFunction();
if (f.length > 0) {
writer.writeString(
2,
f
);
}
f = this.getArgsList();
f = message.getArgsList();
if (f.length > 0) {
writer.writeRepeatedString(
3,
f
);
}
f = this.getTimeout();
f = message.getTimeout();
if (f !== 0) {
writer.writeUint32(
4,
f
);
}
f = this.getActive();
f = message.getActive();
if (f) {
writer.writeBool(
5,
@ -403,27 +198,18 @@ proto.NewEvalMessage.prototype.serializeBinaryToWriter = function (writer) {
};
/**
* Creates a deep clone of this proto. No data is shared with the original.
* @return {!proto.NewEvalMessage} The clone.
*/
proto.NewEvalMessage.prototype.cloneMessage = function() {
return /** @type {!proto.NewEvalMessage} */ (jspb.Message.cloneMessage(this));
};
/**
* optional uint64 id = 1;
* @return {number}
*/
proto.NewEvalMessage.prototype.getId = function() {
return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0));
return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0));
};
/** @param {number} value */
/** @param {number} value */
proto.NewEvalMessage.prototype.setId = function(value) {
jspb.Message.setField(this, 1, value);
jspb.Message.setProto3IntField(this, 1, value);
};
@ -432,35 +218,42 @@ proto.NewEvalMessage.prototype.setId = function(value) {
* @return {string}
*/
proto.NewEvalMessage.prototype.getFunction = function() {
return /** @type {string} */ (jspb.Message.getFieldProto3(this, 2, ""));
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
};
/** @param {string} value */
/** @param {string} value */
proto.NewEvalMessage.prototype.setFunction = function(value) {
jspb.Message.setField(this, 2, value);
jspb.Message.setProto3StringField(this, 2, value);
};
/**
* repeated string args = 3;
* If you change this array by adding, removing or replacing elements, or if you
* replace the array itself, then you must call the setter to update it.
* @return {!Array.<string>}
* @return {!Array<string>}
*/
proto.NewEvalMessage.prototype.getArgsList = function() {
return /** @type {!Array.<string>} */ (jspb.Message.getField(this, 3));
return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 3));
};
/** @param {Array.<string>} value */
/** @param {!Array<string>} value */
proto.NewEvalMessage.prototype.setArgsList = function(value) {
jspb.Message.setField(this, 3, value || []);
};
/**
* @param {!string} value
* @param {number=} opt_index
*/
proto.NewEvalMessage.prototype.addArgs = function(value, opt_index) {
jspb.Message.addToRepeatedField(this, 3, value, opt_index);
};
proto.NewEvalMessage.prototype.clearArgsList = function() {
jspb.Message.setField(this, 3, []);
this.setArgsList([]);
};
@ -469,13 +262,13 @@ proto.NewEvalMessage.prototype.clearArgsList = function() {
* @return {number}
*/
proto.NewEvalMessage.prototype.getTimeout = function() {
return /** @type {number} */ (jspb.Message.getFieldProto3(this, 4, 0));
return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 4, 0));
};
/** @param {number} value */
/** @param {number} value */
proto.NewEvalMessage.prototype.setTimeout = function(value) {
jspb.Message.setField(this, 4, value);
jspb.Message.setProto3IntField(this, 4, value);
};
@ -486,13 +279,13 @@ proto.NewEvalMessage.prototype.setTimeout = function(value) {
* @return {boolean}
*/
proto.NewEvalMessage.prototype.getActive = function() {
return /** @type {boolean} */ (jspb.Message.getFieldProto3(this, 5, false));
return /** @type {boolean} */ (jspb.Message.getFieldWithDefault(this, 5, false));
};
/** @param {boolean} value */
/** @param {boolean} value */
proto.NewEvalMessage.prototype.setActive = function(value) {
jspb.Message.setField(this, 5, value);
jspb.Message.setProto3BooleanField(this, 5, value);
};
@ -546,12 +339,13 @@ proto.EvalEventMessage.prototype.toObject = function(opt_includeInstance) {
* http://goto/soy-param-migration
* @param {!proto.EvalEventMessage} msg The msg instance to transform.
* @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.EvalEventMessage.toObject = function(includeInstance, msg) {
var f, obj = {
id: msg.getId(),
event: msg.getEvent(),
argsList: jspb.Message.getField(msg, 3)
id: jspb.Message.getFieldWithDefault(msg, 1, 0),
event: jspb.Message.getFieldWithDefault(msg, 2, ""),
argsList: jspb.Message.getRepeatedField(msg, 3)
};
if (includeInstance) {
@ -598,8 +392,7 @@ proto.EvalEventMessage.deserializeBinaryFromReader = function(msg, reader) {
break;
case 3:
var value = /** @type {string} */ (reader.readString());
msg.getArgsList().push(value);
msg.setArgsList(msg.getArgsList());
msg.addArgs(value);
break;
default:
reader.skipField();
@ -610,50 +403,41 @@ proto.EvalEventMessage.deserializeBinaryFromReader = function(msg, reader) {
};
/**
* Class method variant: serializes the given message to binary data
* (in protobuf wire format), writing to the given BinaryWriter.
* @param {!proto.EvalEventMessage} message
* @param {!jspb.BinaryWriter} writer
*/
proto.EvalEventMessage.serializeBinaryToWriter = function(message, writer) {
message.serializeBinaryToWriter(writer);
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.EvalEventMessage.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
this.serializeBinaryToWriter(writer);
proto.EvalEventMessage.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
};
/**
* Serializes the message to binary data (in protobuf wire format),
* writing to the given BinaryWriter.
* Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter.
* @param {!proto.EvalEventMessage} message
* @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.EvalEventMessage.prototype.serializeBinaryToWriter = function (writer) {
proto.EvalEventMessage.serializeBinaryToWriter = function(message, writer) {
var f = undefined;
f = this.getId();
f = message.getId();
if (f !== 0) {
writer.writeUint64(
1,
f
);
}
f = this.getEvent();
f = message.getEvent();
if (f.length > 0) {
writer.writeString(
2,
f
);
}
f = this.getArgsList();
f = message.getArgsList();
if (f.length > 0) {
writer.writeRepeatedString(
3,
@ -663,27 +447,18 @@ proto.EvalEventMessage.prototype.serializeBinaryToWriter = function (writer) {
};
/**
* Creates a deep clone of this proto. No data is shared with the original.
* @return {!proto.EvalEventMessage} The clone.
*/
proto.EvalEventMessage.prototype.cloneMessage = function() {
return /** @type {!proto.EvalEventMessage} */ (jspb.Message.cloneMessage(this));
};
/**
* optional uint64 id = 1;
* @return {number}
*/
proto.EvalEventMessage.prototype.getId = function() {
return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0));
return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0));
};
/** @param {number} value */
/** @param {number} value */
proto.EvalEventMessage.prototype.setId = function(value) {
jspb.Message.setField(this, 1, value);
jspb.Message.setProto3IntField(this, 1, value);
};
@ -692,35 +467,42 @@ proto.EvalEventMessage.prototype.setId = function(value) {
* @return {string}
*/
proto.EvalEventMessage.prototype.getEvent = function() {
return /** @type {string} */ (jspb.Message.getFieldProto3(this, 2, ""));
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
};
/** @param {string} value */
/** @param {string} value */
proto.EvalEventMessage.prototype.setEvent = function(value) {
jspb.Message.setField(this, 2, value);
jspb.Message.setProto3StringField(this, 2, value);
};
/**
* repeated string args = 3;
* If you change this array by adding, removing or replacing elements, or if you
* replace the array itself, then you must call the setter to update it.
* @return {!Array.<string>}
* @return {!Array<string>}
*/
proto.EvalEventMessage.prototype.getArgsList = function() {
return /** @type {!Array.<string>} */ (jspb.Message.getField(this, 3));
return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 3));
};
/** @param {Array.<string>} value */
/** @param {!Array<string>} value */
proto.EvalEventMessage.prototype.setArgsList = function(value) {
jspb.Message.setField(this, 3, value || []);
};
/**
* @param {!string} value
* @param {number=} opt_index
*/
proto.EvalEventMessage.prototype.addArgs = function(value, opt_index) {
jspb.Message.addToRepeatedField(this, 3, value, opt_index);
};
proto.EvalEventMessage.prototype.clearArgsList = function() {
jspb.Message.setField(this, 3, []);
this.setArgsList([]);
};
@ -767,12 +549,13 @@ proto.EvalFailedMessage.prototype.toObject = function(opt_includeInstance) {
* http://goto/soy-param-migration
* @param {!proto.EvalFailedMessage} msg The msg instance to transform.
* @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.EvalFailedMessage.toObject = function(includeInstance, msg) {
var f, obj = {
id: msg.getId(),
reason: msg.getReason(),
message: msg.getMessage()
id: jspb.Message.getFieldWithDefault(msg, 1, 0),
reason: jspb.Message.getFieldWithDefault(msg, 2, 0),
message: jspb.Message.getFieldWithDefault(msg, 3, "")
};
if (includeInstance) {
@ -830,50 +613,41 @@ proto.EvalFailedMessage.deserializeBinaryFromReader = function(msg, reader) {
};
/**
* Class method variant: serializes the given message to binary data
* (in protobuf wire format), writing to the given BinaryWriter.
* @param {!proto.EvalFailedMessage} message
* @param {!jspb.BinaryWriter} writer
*/
proto.EvalFailedMessage.serializeBinaryToWriter = function(message, writer) {
message.serializeBinaryToWriter(writer);
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.EvalFailedMessage.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
this.serializeBinaryToWriter(writer);
proto.EvalFailedMessage.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
};
/**
* Serializes the message to binary data (in protobuf wire format),
* writing to the given BinaryWriter.
* Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter.
* @param {!proto.EvalFailedMessage} message
* @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.EvalFailedMessage.prototype.serializeBinaryToWriter = function (writer) {
proto.EvalFailedMessage.serializeBinaryToWriter = function(message, writer) {
var f = undefined;
f = this.getId();
f = message.getId();
if (f !== 0) {
writer.writeUint64(
1,
f
);
}
f = this.getReason();
f = message.getReason();
if (f !== 0.0) {
writer.writeEnum(
2,
f
);
}
f = this.getMessage();
f = message.getMessage();
if (f.length > 0) {
writer.writeString(
3,
@ -883,60 +657,6 @@ proto.EvalFailedMessage.prototype.serializeBinaryToWriter = function (writer) {
};
/**
* Creates a deep clone of this proto. No data is shared with the original.
* @return {!proto.EvalFailedMessage} The clone.
*/
proto.EvalFailedMessage.prototype.cloneMessage = function() {
return /** @type {!proto.EvalFailedMessage} */ (jspb.Message.cloneMessage(this));
};
/**
* optional uint64 id = 1;
* @return {number}
*/
proto.EvalFailedMessage.prototype.getId = function() {
return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0));
};
/** @param {number} value */
proto.EvalFailedMessage.prototype.setId = function(value) {
jspb.Message.setField(this, 1, value);
};
/**
* optional Reason reason = 2;
* @return {!proto.EvalFailedMessage.Reason}
*/
proto.EvalFailedMessage.prototype.getReason = function() {
return /** @type {!proto.EvalFailedMessage.Reason} */ (jspb.Message.getFieldProto3(this, 2, 0));
};
/** @param {!proto.EvalFailedMessage.Reason} value */
proto.EvalFailedMessage.prototype.setReason = function(value) {
jspb.Message.setField(this, 2, value);
};
/**
* optional string message = 3;
* @return {string}
*/
proto.EvalFailedMessage.prototype.getMessage = function() {
return /** @type {string} */ (jspb.Message.getFieldProto3(this, 3, ""));
};
/** @param {string} value */
proto.EvalFailedMessage.prototype.setMessage = function(value) {
jspb.Message.setField(this, 3, value);
};
/**
* @enum {number}
*/
@ -946,6 +666,51 @@ proto.EvalFailedMessage.Reason = {
CONFLICT: 2
};
/**
* optional uint64 id = 1;
* @return {number}
*/
proto.EvalFailedMessage.prototype.getId = function() {
return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0));
};
/** @param {number} value */
proto.EvalFailedMessage.prototype.setId = function(value) {
jspb.Message.setProto3IntField(this, 1, value);
};
/**
* optional Reason reason = 2;
* @return {!proto.EvalFailedMessage.Reason}
*/
proto.EvalFailedMessage.prototype.getReason = function() {
return /** @type {!proto.EvalFailedMessage.Reason} */ (jspb.Message.getFieldWithDefault(this, 2, 0));
};
/** @param {!proto.EvalFailedMessage.Reason} value */
proto.EvalFailedMessage.prototype.setReason = function(value) {
jspb.Message.setProto3EnumField(this, 2, value);
};
/**
* optional string message = 3;
* @return {string}
*/
proto.EvalFailedMessage.prototype.getMessage = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, ""));
};
/** @param {string} value */
proto.EvalFailedMessage.prototype.setMessage = function(value) {
jspb.Message.setProto3StringField(this, 3, value);
};
/**
* Generated by JsPbCodeGenerator.
@ -989,11 +754,12 @@ proto.EvalDoneMessage.prototype.toObject = function(opt_includeInstance) {
* http://goto/soy-param-migration
* @param {!proto.EvalDoneMessage} msg The msg instance to transform.
* @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.EvalDoneMessage.toObject = function(includeInstance, msg) {
var f, obj = {
id: msg.getId(),
response: (f = msg.getResponse()) && proto.TypedValue.toObject(includeInstance, f)
id: jspb.Message.getFieldWithDefault(msg, 1, 0),
response: jspb.Message.getFieldWithDefault(msg, 2, "")
};
if (includeInstance) {
@ -1035,8 +801,7 @@ proto.EvalDoneMessage.deserializeBinaryFromReader = function(msg, reader) {
msg.setId(value);
break;
case 2:
var value = new proto.TypedValue;
reader.readMessage(value,proto.TypedValue.deserializeBinaryFromReader);
var value = /** @type {string} */ (reader.readString());
msg.setResponse(value);
break;
default:
@ -1048,104 +813,70 @@ proto.EvalDoneMessage.deserializeBinaryFromReader = function(msg, reader) {
};
/**
* Class method variant: serializes the given message to binary data
* (in protobuf wire format), writing to the given BinaryWriter.
* @param {!proto.EvalDoneMessage} message
* @param {!jspb.BinaryWriter} writer
*/
proto.EvalDoneMessage.serializeBinaryToWriter = function(message, writer) {
message.serializeBinaryToWriter(writer);
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.EvalDoneMessage.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
this.serializeBinaryToWriter(writer);
proto.EvalDoneMessage.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
};
/**
* Serializes the message to binary data (in protobuf wire format),
* writing to the given BinaryWriter.
* Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter.
* @param {!proto.EvalDoneMessage} message
* @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.EvalDoneMessage.prototype.serializeBinaryToWriter = function (writer) {
proto.EvalDoneMessage.serializeBinaryToWriter = function(message, writer) {
var f = undefined;
f = this.getId();
f = message.getId();
if (f !== 0) {
writer.writeUint64(
1,
f
);
}
f = this.getResponse();
if (f != null) {
writer.writeMessage(
f = message.getResponse();
if (f.length > 0) {
writer.writeString(
2,
f,
proto.TypedValue.serializeBinaryToWriter
f
);
}
};
/**
* Creates a deep clone of this proto. No data is shared with the original.
* @return {!proto.EvalDoneMessage} The clone.
*/
proto.EvalDoneMessage.prototype.cloneMessage = function() {
return /** @type {!proto.EvalDoneMessage} */ (jspb.Message.cloneMessage(this));
};
/**
* optional uint64 id = 1;
* @return {number}
*/
proto.EvalDoneMessage.prototype.getId = function() {
return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0));
return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0));
};
/** @param {number} value */
/** @param {number} value */
proto.EvalDoneMessage.prototype.setId = function(value) {
jspb.Message.setField(this, 1, value);
jspb.Message.setProto3IntField(this, 1, value);
};
/**
* optional TypedValue response = 2;
* @return {proto.TypedValue}
* optional string response = 2;
* @return {string}
*/
proto.EvalDoneMessage.prototype.getResponse = function() {
return /** @type{proto.TypedValue} */ (
jspb.Message.getWrapperField(this, proto.TypedValue, 2));
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
};
/** @param {proto.TypedValue|undefined} value */
/** @param {string} value */
proto.EvalDoneMessage.prototype.setResponse = function(value) {
jspb.Message.setWrapperField(this, 2, value);
};
proto.EvalDoneMessage.prototype.clearResponse = function() {
this.setResponse(undefined);
};
/**
* Returns whether this field is set.
* @return{!boolean}
*/
proto.EvalDoneMessage.prototype.hasResponse = function() {
return jspb.Message.getField(this, 2) != null;
jspb.Message.setProto3StringField(this, 2, value);
};

View File

@ -1,6 +1,8 @@
/**
* @fileoverview
* @enhanceable
* @suppress {messageConventions} JS Compiler reports an error if a variable or
* field starts with 'MSG_' and isn't a translatable message.
* @public
*/
// GENERATED CODE -- DO NOT EDIT!
@ -53,11 +55,12 @@ proto.SharedProcessActiveMessage.prototype.toObject = function(opt_includeInstan
* http://goto/soy-param-migration
* @param {!proto.SharedProcessActiveMessage} msg The msg instance to transform.
* @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.SharedProcessActiveMessage.toObject = function(includeInstance, msg) {
var f, obj = {
socketPath: msg.getSocketPath(),
logPath: msg.getLogPath()
socketPath: jspb.Message.getFieldWithDefault(msg, 1, ""),
logPath: jspb.Message.getFieldWithDefault(msg, 2, "")
};
if (includeInstance) {
@ -111,43 +114,34 @@ proto.SharedProcessActiveMessage.deserializeBinaryFromReader = function(msg, rea
};
/**
* Class method variant: serializes the given message to binary data
* (in protobuf wire format), writing to the given BinaryWriter.
* @param {!proto.SharedProcessActiveMessage} message
* @param {!jspb.BinaryWriter} writer
*/
proto.SharedProcessActiveMessage.serializeBinaryToWriter = function(message, writer) {
message.serializeBinaryToWriter(writer);
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.SharedProcessActiveMessage.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
this.serializeBinaryToWriter(writer);
proto.SharedProcessActiveMessage.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
};
/**
* Serializes the message to binary data (in protobuf wire format),
* writing to the given BinaryWriter.
* Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter.
* @param {!proto.SharedProcessActiveMessage} message
* @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.SharedProcessActiveMessage.prototype.serializeBinaryToWriter = function (writer) {
proto.SharedProcessActiveMessage.serializeBinaryToWriter = function(message, writer) {
var f = undefined;
f = this.getSocketPath();
f = message.getSocketPath();
if (f.length > 0) {
writer.writeString(
1,
f
);
}
f = this.getLogPath();
f = message.getLogPath();
if (f.length > 0) {
writer.writeString(
2,
@ -157,27 +151,18 @@ proto.SharedProcessActiveMessage.prototype.serializeBinaryToWriter = function (w
};
/**
* Creates a deep clone of this proto. No data is shared with the original.
* @return {!proto.SharedProcessActiveMessage} The clone.
*/
proto.SharedProcessActiveMessage.prototype.cloneMessage = function() {
return /** @type {!proto.SharedProcessActiveMessage} */ (jspb.Message.cloneMessage(this));
};
/**
* optional string socket_path = 1;
* @return {string}
*/
proto.SharedProcessActiveMessage.prototype.getSocketPath = function() {
return /** @type {string} */ (jspb.Message.getFieldProto3(this, 1, ""));
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
};
/** @param {string} value */
/** @param {string} value */
proto.SharedProcessActiveMessage.prototype.setSocketPath = function(value) {
jspb.Message.setField(this, 1, value);
jspb.Message.setProto3StringField(this, 1, value);
};
@ -186,13 +171,13 @@ proto.SharedProcessActiveMessage.prototype.setSocketPath = function(value) {
* @return {string}
*/
proto.SharedProcessActiveMessage.prototype.getLogPath = function() {
return /** @type {string} */ (jspb.Message.getFieldProto3(this, 2, ""));
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
};
/** @param {string} value */
/** @param {string} value */
proto.SharedProcessActiveMessage.prototype.setLogPath = function(value) {
jspb.Message.setField(this, 2, value);
jspb.Message.setProto3StringField(this, 2, value);
};

View File

@ -1,268 +0,0 @@
import * as cp from "child_process";
import * as net from "net";
import * as os from "os";
import * as path from "path";
import { TextEncoder, TextDecoder } from "text-encoding";
import { createClient } from "./helpers";
import { ChildProcess } from "../src/browser/command";
(global as any).TextDecoder = TextDecoder; // tslint:disable-line no-any
(global as any).TextEncoder = TextEncoder; // tslint:disable-line no-any
describe("spawn", () => {
const client = createClient({
dataDirectory: "",
workingDirectory: "",
builtInExtensionsDirectory: "",
forkProvider: (msg): cp.ChildProcess => {
return cp.spawn(msg.getCommand(), msg.getArgsList(), {
stdio: [null, null, null, "ipc"],
});
},
});
/**
* Returns a function that when called returns a promise that resolves with
* the next chunk of data from the process.
*/
const promisifyData = (proc: ChildProcess): (() => Promise<string>) => {
// Use a persistent callback instead of creating it in the promise since
// otherwise we could lose data that comes in while no promise is listening.
let onData: (() => void) | undefined;
let buffer: string | undefined;
proc.stdout.on("data", (data) => {
// Remove everything that isn't a letter, number, or $ to avoid issues
// with ANSI escape codes printing inside the test output.
buffer = (buffer || "") + data.toString().replace(/[^a-zA-Z0-9$]/g, "");
if (onData) {
onData();
}
});
return (): Promise<string> => new Promise((resolve): void => {
onData = (): void => {
if (typeof buffer !== "undefined") {
const data = buffer;
buffer = undefined;
onData = undefined;
resolve(data);
}
};
onData();
});
};
it("should execute command and return output", (done) => {
const proc = client.spawn("echo", ["test"]);
proc.stdout.on("data", (data) => {
expect(data).toEqual("test\n");
});
proc.on("exit", (): void => {
done();
});
});
it("should create shell", async () => {
// Setting the config file to something that shouldn't exist so the test
// isn't affected by custom configuration.
const proc = client.spawn("/bin/bash", ["--rcfile", "/tmp/test/nope/should/not/exist"], {
tty: {
columns: 100,
rows: 10,
},
});
const getData = promisifyData(proc);
// First it outputs @hostname:cwd
expect((await getData()).length).toBeGreaterThan(1);
// Then it seems to overwrite that with a shorter prompt in the format of
// [hostname@user]$
expect((await getData())).toContain("$");
proc.kill();
await new Promise((resolve): void => {
proc.on("exit", resolve);
});
});
it("should cat", (done) => {
const proc = client.spawn("cat", []);
expect(proc.pid).toBeUndefined();
proc.stdout.on("data", (data) => {
expect(data).toEqual("banana");
expect(proc.pid).toBeDefined();
proc.kill();
});
proc.on("exit", () => done());
proc.send("banana");
proc.stdin.end();
});
it("should print env variable", (done) => {
const proc = client.spawn("env", [], {
env: { hi: "donkey" },
});
proc.stdout.on("data", (data) => {
expect(data).toEqual("hi=donkey\n");
done();
});
});
it("should resize", async () => {
// Requires the `tput lines` cmd to be available.
// Setting the config file to something that shouldn't exist so the test
// isn't affected by custom configuration.
const proc = client.spawn("/bin/bash", ["--rcfile", "/tmp/test/nope/should/not/exist"], {
tty: {
columns: 10,
rows: 10,
},
});
const getData = promisifyData(proc);
// We've already tested these first two bits of output; see shell test.
await getData();
await getData();
proc.send("tput lines\n");
expect(await getData()).toContain("tput");
expect((await getData()).trim()).toContain("10");
proc.resize!({
columns: 10,
rows: 50,
});
// The prompt again.
await getData();
await getData();
proc.send("tput lines\n");
expect(await getData()).toContain("tput");
expect((await getData())).toContain("50");
proc.kill();
expect(proc.killed).toBeTruthy();
await new Promise((resolve): void => {
proc.on("exit", resolve);
});
});
it("should fork and echo messages", (done) => {
const proc = client.fork(path.join(__dirname, "forker.js"));
proc.on("message", (msg) => {
expect(msg.bananas).toBeTruthy();
proc.kill();
});
proc.send({ bananas: true }, undefined, true);
proc.on("exit", () => done());
});
});
describe("createConnection", () => {
const client = createClient();
const tmpPath = path.join(os.tmpdir(), Math.random().toString());
let server: net.Server;
beforeAll(async () => {
await new Promise((r): void => {
server = net.createServer().listen(tmpPath, () => {
r();
});
});
});
afterAll(() => {
server.close();
});
it("should connect to socket", async () => {
await new Promise((resolve): void => {
const socket = client.createConnection(tmpPath, () => {
socket.end();
socket.addListener("close", () => {
resolve();
});
});
});
await new Promise((resolve): void => {
const socket = new client.Socket();
socket.connect(tmpPath, () => {
socket.end();
socket.addListener("close", () => {
resolve();
});
});
});
});
it("should get data from server", (done) => {
server.once("connection", (socket: net.Socket) => {
socket.write("hi how r u");
});
const socket = client.createConnection(tmpPath);
socket.addListener("data", (data) => {
expect(data.toString()).toEqual("hi how r u");
socket.end();
socket.addListener("close", () => {
done();
});
});
});
it("should send data to server", (done) => {
const clientSocket = client.createConnection(tmpPath);
clientSocket.write(Buffer.from("bananas"));
server.once("connection", (socket: net.Socket) => {
socket.addListener("data", (data) => {
expect(data.toString()).toEqual("bananas");
socket.end();
clientSocket.addListener("end", () => {
done();
});
});
});
});
});
describe("createServer", () => {
const client = createClient();
const tmpPath = path.join(os.tmpdir(), Math.random().toString());
it("should connect to server", (done) => {
const s = client.createServer(() => {
s.close();
});
s.on("close", () => {
done();
});
s.listen(tmpPath);
});
it("should connect to server and get socket connection", (done) => {
const s = client.createServer();
s.listen(tmpPath, () => {
net.createConnection(tmpPath, () => {
checks++;
s.close();
});
});
let checks = 0;
s.on("connection", (con) => {
expect(checks).toEqual(1);
con.end();
checks++;
});
s.on("close", () => {
expect(checks).toEqual(2);
done();
});
});
});

View File

@ -48,7 +48,7 @@ describe("Evaluate", () => {
it("should resolve with promise", async () => {
const value = await client.evaluate(async () => {
await new Promise((r) => setTimeout(r, 100));
await new Promise((r): number => setTimeout(r, 100));
return "donkey";
});
@ -64,6 +64,11 @@ describe("Evaluate", () => {
ae.emit("close");
});
});
return {
onDidDispose: (): void => undefined,
dispose: (): void => undefined,
};
});
runner.emit("1");
runner.on("2", () => runner.emit("3"));