Archived
1
0

Create initial server layout (#11)

* Create initial server layout

* Adjust command name to entry

* Add @oclif/config as dependency

* Implement build process for outputting single binary

* Add init message

* Remove unused import, add tsconfig.json to .gitignore

* Accidently pushed wacky change to output host FS files

* Add options to createApp
This commit is contained in:
Kyle Carberry
2019-01-15 12:36:09 -06:00
parent 2ff34bc5e2
commit 05899b5edf
25 changed files with 4646 additions and 222 deletions

View File

@ -3,13 +3,13 @@
"main": "src/index.ts",
"dependencies": {
"express": "^4.16.4",
"google-protobuf": "^3.6.1",
"node-pty": "^0.8.0",
"ws": "^6.1.2"
},
"devDependencies": {
"@types/express": "^4.16.0",
"@types/google-protobuf": "^3.2.7",
"@types/text-encoding": "^0.0.35",
"@types/ws": "^6.0.1",
"text-encoding": "^0.7.0",
"ts-protoc-gen": "^0.8.0"
}

View File

@ -1,6 +1,6 @@
import { ReadWriteConnection } from "../common/connection";
import { NewEvalMessage, ServerMessage, EvalDoneMessage, EvalFailedMessage, TypedValue, ClientMessage, NewSessionMessage, TTYDimensions, SessionOutputMessage, CloseSessionInputMessage } from "../proto";
import { Emitter } from "@coder/events";
import { ReadWriteConnection, InitData, OperatingSystem } from "../common/connection";
import { NewEvalMessage, ServerMessage, EvalDoneMessage, EvalFailedMessage, TypedValue, ClientMessage, NewSessionMessage, TTYDimensions, SessionOutputMessage, CloseSessionInputMessage, InitMessage } from "../proto";
import { Emitter, Event } from "@coder/events";
import { logger, field } from "@coder/logger";
import { ChildProcess, SpawnOptions, ServerProcess } from "./command";
@ -15,12 +15,17 @@ export class Client {
private sessionId: number = 0;
private sessions: Map<number, ServerProcess> = new Map();
private _initData: InitData | undefined;
private initDataEmitter: Emitter<InitData> = new Emitter();
/**
* @param connection Established connection to the server
*/
public constructor(
private readonly connection: ReadWriteConnection,
) {
this.initDataEmitter = new Emitter();
connection.onMessage((data) => {
try {
this.handleMessage(ServerMessage.deserializeBinary(data));
@ -30,6 +35,14 @@ export class Client {
});
}
public get onInitData(): Event<InitData> {
return this.initDataEmitter.event;
}
public get initData(): InitData | undefined {
return this._initData;
}
public evaluate<R>(func: () => R | Promise<R>): Promise<R>;
public evaluate<R, T1>(func: (a1: T1) => R | Promise<R>, a1: T1): Promise<R>;
public evaluate<R, T1, T2>(func: (a1: T1, a2: T2) => R | Promise<R>, a1: T1, a2: T2): Promise<R>;
@ -47,7 +60,7 @@ export class Client {
* console.log(returned);
* // output: "hi"
* @param func Function to evaluate
* @returns {Promise} Promise rejected or resolved from the evaluated function
* @returns Promise rejected or resolved from the evaluated function
*/
public evaluate<R, T1, T2, T3, T4, T5, T6>(func: (a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6) => R | Promise<R>, a1?: T1, a2?: T2, a3?: T3, a4?: T4, a5?: T5, a6?: T6): Promise<R> {
const newEval = new NewEvalMessage();
@ -61,8 +74,8 @@ export class Client {
this.connection.send(clientMsg.serializeBinary());
let res: (value?: R) => void;
let rej: (err?: any) => void;
const prom = new Promise<R>((r, e) => {
let rej: (err?: Error) => void;
const prom = new Promise<R>((r, e): void => {
res = r;
rej = e;
});
@ -80,6 +93,7 @@ export class Client {
}
const rt = resp.getType();
// tslint:disable-next-line
let val: any;
switch (rt) {
case TypedValue.Type.BOOLEAN:
@ -107,7 +121,7 @@ export class Client {
d1.dispose();
d2.dispose();
rej(failedMsg.getMessage());
rej(new Error(failedMsg.getMessage()));
}
});
@ -120,7 +134,6 @@ export class Client {
* 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 command
* @param args Arguments
* @param options Options to execute for the command
*/
@ -167,7 +180,6 @@ export class Client {
const serverProc = new ServerProcess(this.connection, id, options ? options.tty !== undefined : false);
serverProc.stdin.on("close", () => {
console.log("stdin closed");
const c = new CloseSessionInputMessage();
c.setId(id);
const cm = new ClientMessage();
@ -175,6 +187,7 @@ export class Client {
this.connection.send(cm.serializeBinary());
});
this.sessions.set(id, serverProc);
return serverProc;
}
@ -183,7 +196,31 @@ export class Client {
* routed through here.
*/
private handleMessage(message: ServerMessage): void {
if (message.hasEvalDone()) {
if (message.hasInit()) {
const init = message.getInit()!;
let opSys: OperatingSystem;
switch (init.getOperatingSystem()) {
case InitMessage.OperatingSystem.WINDOWS:
opSys = OperatingSystem.Windows;
break;
case InitMessage.OperatingSystem.LINUX:
opSys = OperatingSystem.Linux;
break;
case InitMessage.OperatingSystem.MAC:
opSys = OperatingSystem.Mac;
break;
default:
throw new Error(`unsupported operating system ${init.getOperatingSystem()}`);
}
this._initData = {
dataDirectory: init.getDataDirectory(),
homeDirectory: init.getHomeDirectory(),
tmpDirectory: init.getTmpDirectory(),
workingDirectory: init.getWorkingDirectory(),
os: opSys,
};
this.initDataEmitter.emit(this._initData);
} else if (message.hasEvalDone()) {
this.evalDoneEmitter.emit(message.getEvalDone()!);
} else if (message.hasEvalFailed()) {
this.evalFailedEmitter.emit(message.getEvalFailed()!);

View File

@ -38,14 +38,18 @@ export class CP {
);
});
// @ts-ignore
return process;
}
public fork = (modulePath: string): cp.ChildProcess => {
public fork(modulePath: string): cp.ChildProcess {
//@ts-ignore
return this.client.fork(modulePath);
}
public spawn = (command: string, args?: ReadonlyArray<string> | cp.SpawnOptions, _options?: cp.SpawnOptions): cp.ChildProcess => {
public spawn(command: string, args?: ReadonlyArray<string> | cp.SpawnOptions, _options?: cp.SpawnOptions): cp.ChildProcess {
// TODO: fix this ignore. Should check for args or options here
//@ts-ignore
return this.client.spawn(command, args, options);
}

View File

@ -7,3 +7,17 @@ export interface ReadWriteConnection extends SendableConnection {
onClose(cb: () => void): void;
close(): void;
}
export enum OperatingSystem {
Windows,
Linux,
Mac,
}
export interface InitData {
readonly os: OperatingSystem;
readonly dataDirectory: string;
readonly workingDirectory: string;
readonly homeDirectory: string;
readonly tmpDirectory: string;
}

View File

@ -2,6 +2,7 @@ import * as vm from "vm";
import { NewEvalMessage, TypedValue, EvalFailedMessage, EvalDoneMessage, ServerMessage } from "../proto";
import { SendableConnection } from "../common/connection";
declare var __non_webpack_require__: typeof require;
export const evaluate = async (connection: SendableConnection, message: NewEvalMessage): Promise<void> => {
const argStr: string[] = [];
message.getArgsList().forEach((value) => {
@ -51,7 +52,7 @@ export const evaluate = async (connection: SendableConnection, message: NewEvalM
connection.send(serverMsg.serializeBinary());
};
try {
const value = vm.runInNewContext(`(${message.getFunction()})(${argStr.join(",")})`, { Buffer, require, setTimeout }, {
const value = vm.runInNewContext(`(${message.getFunction()})(${argStr.join(",")})`, { Buffer, require: typeof __non_webpack_require__ !== "undefined" ? __non_webpack_require__ : require, setTimeout }, {
timeout: message.getTimeout() || 30000,
});
sendResp(await value);

View File

@ -1,16 +1,23 @@
import { logger, field } from "@coder/logger";
import * as os from "os";
import { TextDecoder } from "text-encoding";
import { ClientMessage } from "../proto";
import { ClientMessage, InitMessage, ServerMessage } from "../proto";
import { evaluate } from "./evaluate";
import { ReadWriteConnection } from "../common/connection";
import { Process, handleNewSession } from "./command";
export interface ServerOptions {
readonly workingDirectory: string;
readonly dataDirectory: string;
}
export class Server {
private readonly sessions: Map<number, Process>;
public constructor(
private readonly connection: ReadWriteConnection,
options?: ServerOptions,
) {
this.sessions = new Map();
@ -21,6 +28,37 @@ export class Server {
logger.error("Failed to handle client message", field("length", data.byteLength), field("exception", ex));
}
});
if (!options) {
logger.warn("No server options provided. InitMessage will not be sent.");
return;
}
const initMsg = new InitMessage();
initMsg.setDataDirectory(options.dataDirectory);
initMsg.setWorkingDirectory(options.workingDirectory);
initMsg.setHomeDirectory(os.homedir());
initMsg.setTmpDirectory(os.tmpdir());
const platform = os.platform();
let operatingSystem: InitMessage.OperatingSystem;
switch (platform) {
case "win32":
operatingSystem = InitMessage.OperatingSystem.WINDOWS;
break;
case "linux":
operatingSystem = InitMessage.OperatingSystem.LINUX;
break;
case "darwin":
operatingSystem = InitMessage.OperatingSystem.MAC;
break;
default:
throw new Error(`unrecognized platform "${platform}"`);
}
initMsg.setOperatingSystem(operatingSystem);
const srvMsg = new ServerMessage();
srvMsg.setInit(initMsg);
connection.send(srvMsg.serializeBinary());
}
private handleMessage(message: ClientMessage): void {

View File

@ -27,5 +27,20 @@ message ServerMessage {
// node.proto
EvalFailedMessage eval_failed = 5;
EvalDoneMessage eval_done = 6;
InitMessage init = 7;
}
}
message InitMessage {
string home_directory = 1;
string tmp_directory = 2;
string data_directory = 3;
string working_directory = 4;
enum OperatingSystem {
Windows = 0;
Linux = 1;
Mac = 2;
}
OperatingSystem operating_system = 5;
}

View File

@ -99,6 +99,11 @@ export class ServerMessage extends jspb.Message {
getEvalDone(): node_pb.EvalDoneMessage | undefined;
setEvalDone(value?: node_pb.EvalDoneMessage): void;
hasInit(): boolean;
clearInit(): void;
getInit(): InitMessage | undefined;
setInit(value?: InitMessage): void;
getMsgCase(): ServerMessage.MsgCase;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ServerMessage.AsObject;
@ -118,6 +123,7 @@ export namespace ServerMessage {
identifySession?: command_pb.IdentifySessionMessage.AsObject,
evalFailed?: node_pb.EvalFailedMessage.AsObject,
evalDone?: node_pb.EvalDoneMessage.AsObject,
init?: InitMessage.AsObject,
}
export enum MsgCase {
@ -128,6 +134,49 @@ export namespace ServerMessage {
IDENTIFY_SESSION = 4,
EVAL_FAILED = 5,
EVAL_DONE = 6,
INIT = 7,
}
}
export class InitMessage extends jspb.Message {
getHomeDirectory(): string;
setHomeDirectory(value: string): void;
getTmpDirectory(): string;
setTmpDirectory(value: string): void;
getDataDirectory(): string;
setDataDirectory(value: string): void;
getWorkingDirectory(): string;
setWorkingDirectory(value: string): void;
getOperatingSystem(): InitMessage.OperatingSystem;
setOperatingSystem(value: InitMessage.OperatingSystem): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): InitMessage.AsObject;
static toObject(includeInstance: boolean, msg: InitMessage): InitMessage.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: InitMessage, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): InitMessage;
static deserializeBinaryFromReader(message: InitMessage, reader: jspb.BinaryReader): InitMessage;
}
export namespace InitMessage {
export type AsObject = {
homeDirectory: string,
tmpDirectory: string,
dataDirectory: string,
workingDirectory: string,
operatingSystem: InitMessage.OperatingSystem,
}
export enum OperatingSystem {
WINDOWS = 0,
LINUX = 1,
MAC = 2,
}
}

View File

@ -12,6 +12,8 @@ var global = Function('return this')();
var command_pb = require('./command_pb.js');
var node_pb = require('./node_pb.js');
goog.exportSymbol('proto.ClientMessage', null, global);
goog.exportSymbol('proto.InitMessage', null, global);
goog.exportSymbol('proto.InitMessage.OperatingSystem', null, global);
goog.exportSymbol('proto.ServerMessage', null, global);
/**
@ -465,7 +467,7 @@ if (goog.DEBUG && !COMPILED) {
* @private {!Array<!Array<number>>}
* @const
*/
proto.ServerMessage.oneofGroups_ = [[1,2,3,4,5,6]];
proto.ServerMessage.oneofGroups_ = [[1,2,3,4,5,6,7]];
/**
* @enum {number}
@ -477,7 +479,8 @@ proto.ServerMessage.MsgCase = {
SESSION_OUTPUT: 3,
IDENTIFY_SESSION: 4,
EVAL_FAILED: 5,
EVAL_DONE: 6
EVAL_DONE: 6,
INIT: 7
};
/**
@ -520,7 +523,8 @@ proto.ServerMessage.toObject = function(includeInstance, msg) {
sessionOutput: (f = msg.getSessionOutput()) && command_pb.SessionOutputMessage.toObject(includeInstance, f),
identifySession: (f = msg.getIdentifySession()) && command_pb.IdentifySessionMessage.toObject(includeInstance, f),
evalFailed: (f = msg.getEvalFailed()) && node_pb.EvalFailedMessage.toObject(includeInstance, f),
evalDone: (f = msg.getEvalDone()) && node_pb.EvalDoneMessage.toObject(includeInstance, f)
evalDone: (f = msg.getEvalDone()) && node_pb.EvalDoneMessage.toObject(includeInstance, f),
init: (f = msg.getInit()) && proto.InitMessage.toObject(includeInstance, f)
};
if (includeInstance) {
@ -587,6 +591,11 @@ proto.ServerMessage.deserializeBinaryFromReader = function(msg, reader) {
reader.readMessage(value,node_pb.EvalDoneMessage.deserializeBinaryFromReader);
msg.setEvalDone(value);
break;
case 7:
var value = new proto.InitMessage;
reader.readMessage(value,proto.InitMessage.deserializeBinaryFromReader);
msg.setInit(value);
break;
default:
reader.skipField();
break;
@ -673,6 +682,14 @@ proto.ServerMessage.prototype.serializeBinaryToWriter = function (writer) {
node_pb.EvalDoneMessage.serializeBinaryToWriter
);
}
f = this.getInit();
if (f != null) {
writer.writeMessage(
7,
f,
proto.InitMessage.serializeBinaryToWriter
);
}
};
@ -865,4 +882,310 @@ proto.ServerMessage.prototype.hasEvalDone = function() {
};
/**
* optional InitMessage init = 7;
* @return {proto.InitMessage}
*/
proto.ServerMessage.prototype.getInit = function() {
return /** @type{proto.InitMessage} */ (
jspb.Message.getWrapperField(this, proto.InitMessage, 7));
};
/** @param {proto.InitMessage|undefined} value */
proto.ServerMessage.prototype.setInit = function(value) {
jspb.Message.setOneofWrapperField(this, 7, proto.ServerMessage.oneofGroups_[0], value);
};
proto.ServerMessage.prototype.clearInit = function() {
this.setInit(undefined);
};
/**
* Returns whether this field is set.
* @return{!boolean}
*/
proto.ServerMessage.prototype.hasInit = function() {
return jspb.Message.getField(this, 7) != null;
};
/**
* 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.InitMessage = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.InitMessage, jspb.Message);
if (goog.DEBUG && !COMPILED) {
proto.InitMessage.displayName = 'proto.InitMessage';
}
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.InitMessage.prototype.toObject = function(opt_includeInstance) {
return proto.InitMessage.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.InitMessage} msg The msg instance to transform.
* @return {!Object}
*/
proto.InitMessage.toObject = function(includeInstance, msg) {
var f, obj = {
homeDirectory: msg.getHomeDirectory(),
tmpDirectory: msg.getTmpDirectory(),
dataDirectory: msg.getDataDirectory(),
workingDirectory: msg.getWorkingDirectory(),
operatingSystem: msg.getOperatingSystem()
};
if (includeInstance) {
obj.$jspbMessageInstance = msg;
}
return obj;
};
}
/**
* Deserializes binary data (in protobuf wire format).
* @param {jspb.ByteSource} bytes The bytes to deserialize.
* @return {!proto.InitMessage}
*/
proto.InitMessage.deserializeBinary = function(bytes) {
var reader = new jspb.BinaryReader(bytes);
var msg = new proto.InitMessage;
return proto.InitMessage.deserializeBinaryFromReader(msg, reader);
};
/**
* Deserializes binary data (in protobuf wire format) from the
* given reader into the given message object.
* @param {!proto.InitMessage} msg The message object to deserialize into.
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
* @return {!proto.InitMessage}
*/
proto.InitMessage.deserializeBinaryFromReader = function(msg, reader) {
while (reader.nextField()) {
if (reader.isEndGroup()) {
break;
}
var field = reader.getFieldNumber();
switch (field) {
case 1:
var value = /** @type {string} */ (reader.readString());
msg.setHomeDirectory(value);
break;
case 2:
var value = /** @type {string} */ (reader.readString());
msg.setTmpDirectory(value);
break;
case 3:
var value = /** @type {string} */ (reader.readString());
msg.setDataDirectory(value);
break;
case 4:
var value = /** @type {string} */ (reader.readString());
msg.setWorkingDirectory(value);
break;
case 5:
var value = /** @type {!proto.InitMessage.OperatingSystem} */ (reader.readEnum());
msg.setOperatingSystem(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.InitMessage} message
* @param {!jspb.BinaryWriter} writer
*/
proto.InitMessage.serializeBinaryToWriter = function(message, writer) {
message.serializeBinaryToWriter(writer);
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.InitMessage.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.InitMessage.prototype.serializeBinaryToWriter = function (writer) {
var f = undefined;
f = this.getHomeDirectory();
if (f.length > 0) {
writer.writeString(
1,
f
);
}
f = this.getTmpDirectory();
if (f.length > 0) {
writer.writeString(
2,
f
);
}
f = this.getDataDirectory();
if (f.length > 0) {
writer.writeString(
3,
f
);
}
f = this.getWorkingDirectory();
if (f.length > 0) {
writer.writeString(
4,
f
);
}
f = this.getOperatingSystem();
if (f !== 0.0) {
writer.writeEnum(
5,
f
);
}
};
/**
* Creates a deep clone of this proto. No data is shared with the original.
* @return {!proto.InitMessage} The clone.
*/
proto.InitMessage.prototype.cloneMessage = function() {
return /** @type {!proto.InitMessage} */ (jspb.Message.cloneMessage(this));
};
/**
* optional string home_directory = 1;
* @return {string}
*/
proto.InitMessage.prototype.getHomeDirectory = function() {
return /** @type {string} */ (jspb.Message.getFieldProto3(this, 1, ""));
};
/** @param {string} value */
proto.InitMessage.prototype.setHomeDirectory = function(value) {
jspb.Message.setField(this, 1, value);
};
/**
* optional string tmp_directory = 2;
* @return {string}
*/
proto.InitMessage.prototype.getTmpDirectory = function() {
return /** @type {string} */ (jspb.Message.getFieldProto3(this, 2, ""));
};
/** @param {string} value */
proto.InitMessage.prototype.setTmpDirectory = function(value) {
jspb.Message.setField(this, 2, value);
};
/**
* optional string data_directory = 3;
* @return {string}
*/
proto.InitMessage.prototype.getDataDirectory = function() {
return /** @type {string} */ (jspb.Message.getFieldProto3(this, 3, ""));
};
/** @param {string} value */
proto.InitMessage.prototype.setDataDirectory = function(value) {
jspb.Message.setField(this, 3, value);
};
/**
* optional string working_directory = 4;
* @return {string}
*/
proto.InitMessage.prototype.getWorkingDirectory = function() {
return /** @type {string} */ (jspb.Message.getFieldProto3(this, 4, ""));
};
/** @param {string} value */
proto.InitMessage.prototype.setWorkingDirectory = function(value) {
jspb.Message.setField(this, 4, value);
};
/**
* optional OperatingSystem operating_system = 5;
* @return {!proto.InitMessage.OperatingSystem}
*/
proto.InitMessage.prototype.getOperatingSystem = function() {
return /** @type {!proto.InitMessage.OperatingSystem} */ (jspb.Message.getFieldProto3(this, 5, 0));
};
/** @param {!proto.InitMessage.OperatingSystem} value */
proto.InitMessage.prototype.setOperatingSystem = function(value) {
jspb.Message.setField(this, 5, value);
};
/**
* @enum {number}
*/
proto.InitMessage.OperatingSystem = {
WINDOWS: 0,
LINUX: 1,
MAC: 2
};
goog.object.extend(exports, proto);

View File

@ -1,27 +1,28 @@
import { Emitter } from "@coder/events";
import { Client } from "../src/browser/client";
import { Server } from "../src/node/server";
import { Server, ServerOptions } from "../src/node/server";
export const createClient = (): Client => {
export const createClient = (serverOptions?: ServerOptions): Client => {
const s2c = new Emitter<Uint8Array | Buffer>();
const c2s = new Emitter<Uint8Array | Buffer>();
// tslint:disable-next-line
new Server({
close: () => undefined,
onClose: () => undefined,
onMessage: (cb) => {
close: (): void => undefined,
onClose: (): void => undefined,
onMessage: (cb): void => {
c2s.event((d) => cb(d));
},
send: (data) => setTimeout(() => s2c.emit(data), 0),
});
send: (data): NodeJS.Timer => setTimeout(() => s2c.emit(data), 0),
}, serverOptions);
const client = new Client({
close: () => undefined,
onClose: () => undefined,
onMessage: (cb) => {
close: (): void => undefined,
onClose: (): void => undefined,
onMessage: (cb): void => {
s2c.event((d) => cb(d));
},
send: (data) => setTimeout(() => c2s.emit(data), 0),
send: (data): NodeJS.Timer => setTimeout(() => c2s.emit(data), 0),
});
return client;

View File

@ -0,0 +1,18 @@
import { createClient } from "./helpers";
describe("Server", () => {
const dataDirectory = "/tmp/example";
const workingDirectory = "/working/dir";
const client = createClient({
dataDirectory,
workingDirectory,
});
it("should get init msg", (done) => {
client.onInitData((data) => {
expect(data.dataDirectory).toEqual(dataDirectory);
expect(data.workingDirectory).toEqual(workingDirectory);
done();
});
});
});

View File

@ -2,80 +2,16 @@
# yarn lockfile v1
"@types/body-parser@*":
version "1.17.0"
resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.0.tgz#9f5c9d9bd04bb54be32d5eb9fc0d8c974e6cf58c"
integrity sha512-a2+YeUjPkztKJu5aIF2yArYFQQp8d51wZ7DavSHjFuY1mqVgidGyzEQ41JIVNy82fXj8yPgy2vJmfIywgESW6w==
dependencies:
"@types/connect" "*"
"@types/node" "*"
"@types/connect@*":
version "3.4.32"
resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.32.tgz#aa0e9616b9435ccad02bc52b5b454ffc2c70ba28"
integrity sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==
dependencies:
"@types/node" "*"
"@types/events@*":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@types/events/-/events-1.2.0.tgz#81a6731ce4df43619e5c8c945383b3e62a89ea86"
integrity sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==
"@types/express-serve-static-core@*":
version "4.16.0"
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.0.tgz#fdfe777594ddc1fe8eb8eccce52e261b496e43e7"
integrity sha512-lTeoCu5NxJU4OD9moCgm0ESZzweAx0YqsAcab6OB0EB3+As1OaHtKnaGJvcngQxYsi9UNv0abn4/DRavrRxt4w==
dependencies:
"@types/events" "*"
"@types/node" "*"
"@types/range-parser" "*"
"@types/express@^4.16.0":
version "4.16.0"
resolved "https://registry.yarnpkg.com/@types/express/-/express-4.16.0.tgz#6d8bc42ccaa6f35cf29a2b7c3333cb47b5a32a19"
integrity sha512-TtPEYumsmSTtTetAPXlJVf3kEqb6wZK0bZojpJQrnD/djV4q1oB6QQ8aKvKqwNPACoe02GNiy5zDzcYivR5Z2w==
dependencies:
"@types/body-parser" "*"
"@types/express-serve-static-core" "*"
"@types/serve-static" "*"
"@types/mime@*":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.0.tgz#5a7306e367c539b9f6543499de8dd519fac37a8b"
integrity sha512-A2TAGbTFdBw9azHbpVd+/FkdW2T6msN1uct1O9bH3vTerEHKZhTXJUQXy+hNq1B0RagfU8U+KBdqiZpxjhOUQA==
"@types/node@*":
version "10.12.18"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67"
integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==
"@types/range-parser@*":
version "1.2.3"
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==
"@types/serve-static@*":
version "1.13.2"
resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.2.tgz#f5ac4d7a6420a99a6a45af4719f4dcd8cd907a48"
integrity sha512-/BZ4QRLpH/bNYgZgwhKEh+5AsboDBcUdlBYgzoLX0fpj3Y2gp6EApyOlM3bK53wQS/OE1SrdSYBAbux2D1528Q==
dependencies:
"@types/express-serve-static-core" "*"
"@types/mime" "*"
"@types/google-protobuf@^3.2.7":
version "3.2.7"
resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.2.7.tgz#9576ed5dd62cdb1c9f952522028a03b7cb2b69b5"
integrity sha512-Pb9wl5qDEwfnJeeu6Zpn5Y+waLrKETStqLZXHMGCTbkNuBBudPy4qOGN6veamyeoUBwTm2knOVeP/FlHHhhmzA==
"@types/text-encoding@^0.0.35":
version "0.0.35"
resolved "https://registry.yarnpkg.com/@types/text-encoding/-/text-encoding-0.0.35.tgz#6f14474e0b232bc70c59677aadc65dcc5a99c3a9"
integrity sha512-jfo/A88XIiAweUa8np+1mPbm3h2w0s425YrI8t3wk5QxhH6UI7w517MboNVnGDeMSuoFwA8Rwmklno+FicvV4g==
"@types/ws@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-6.0.1.tgz#ca7a3f3756aa12f62a0a62145ed14c6db25d5a28"
integrity sha512-EzH8k1gyZ4xih/MaZTXwT2xOkPiIMSrhQ9b8wrlX88L0T02eYsddatQlwVFlEPyEqV0ChpdpNnE51QPH6NVT4Q==
dependencies:
"@types/events" "*"
"@types/node" "*"
accepts@~1.3.5:
version "1.3.5"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2"