Skip to content

Commit 49290eb

Browse files
committed
Convert fully to protobuf (was partially JSON)
1 parent 7481395 commit 49290eb

File tree

14 files changed

+4308
-1830
lines changed

14 files changed

+4308
-1830
lines changed

packages/protocol/src/browser/client.ts

+77-56
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { Emitter } from "@coder/events";
55
import { logger, field } from "@coder/logger";
66
import { ReadWriteConnection, InitData, SharedProcessData } from "../common/connection";
77
import { Module, ServerProxy } from "../common/proxy";
8-
import { stringify, parse, moduleToProto, protoToModule, protoToOperatingSystem } from "../common/util";
9-
import { Ping, ServerMessage, ClientMessage, MethodMessage, NamedProxyMessage, NumberedProxyMessage, SuccessMessage, FailMessage, EventMessage, CallbackMessage } from "../proto";
8+
import { argumentToProto, protoToArgument, moduleToProto, protoToModule, protoToOperatingSystem } from "../common/util";
9+
import { Argument, Ping, ServerMessage, ClientMessage, Method, Event, Callback } from "../proto";
1010
import { FsModule, ChildProcessModule, NetModule, NodePtyModule, SpdlogModule, TrashModule } from "./modules";
1111

1212
// tslint:disable no-any
@@ -24,8 +24,8 @@ export class Client {
2424
private messageId = 0;
2525
private callbackId = 0;
2626
private readonly proxies = new Map<number | Module, ProxyData>();
27-
private readonly successEmitter = new Emitter<SuccessMessage>();
28-
private readonly failEmitter = new Emitter<FailMessage>();
27+
private readonly successEmitter = new Emitter<Method.Success>();
28+
private readonly failEmitter = new Emitter<Method.Fail>();
2929
private readonly eventEmitter = new Emitter<{ event: string; args: any[]; }>();
3030

3131
private _initData: InitData | undefined;
@@ -129,9 +129,9 @@ export class Client {
129129
field("event listeners", this.eventEmitter.counts),
130130
]);
131131

132-
const message = new FailMessage();
132+
const message = new Method.Fail();
133133
const error = new Error("disconnected");
134-
message.setResponse(stringify(error));
134+
message.setResponse(argumentToProto(error));
135135
this.failEmitter.emit(message);
136136

137137
this.eventEmitter.emit({ event: "disconnected", args: [error] });
@@ -182,20 +182,21 @@ export class Client {
182182
case "kill":
183183
return Promise.resolve();
184184
}
185+
185186
return Promise.reject(
186187
new Error(`Unable to call "${method}" on proxy ${proxyId}: disconnected`),
187188
);
188189
}
189190

190-
const message = new MethodMessage();
191+
const message = new Method();
191192
const id = this.messageId++;
192-
let proxyMessage: NamedProxyMessage | NumberedProxyMessage;
193+
let proxyMessage: Method.Named | Method.Numbered;
193194
if (typeof proxyId === "string") {
194-
proxyMessage = new NamedProxyMessage();
195+
proxyMessage = new Method.Named();
195196
proxyMessage.setModule(moduleToProto(proxyId));
196197
message.setNamedProxy(proxyMessage);
197198
} else {
198-
proxyMessage = new NumberedProxyMessage();
199+
proxyMessage = new Method.Numbered();
199200
proxyMessage.setProxyId(proxyId);
200201
message.setNumberedProxy(proxyMessage);
201202
}
@@ -215,16 +216,16 @@ export class Client {
215216
return callbackId;
216217
};
217218

218-
const stringifiedArgs = args.map((a) => stringify(a, storeCallback));
219+
const protoArgs = args.map((a) => argumentToProto(a, storeCallback));
219220
logger.trace(() => [
220221
"sending",
221222
field("id", id),
222223
field("proxyId", proxyId),
223224
field("method", method),
224-
field("args", stringifiedArgs),
225+
field("args", protoArgs),
225226
]);
226227

227-
proxyMessage.setArgsList(stringifiedArgs);
228+
proxyMessage.setArgsList(protoArgs);
228229

229230
const clientMessage = new ClientMessage();
230231
clientMessage.setMethod(message);
@@ -246,12 +247,12 @@ export class Client {
246247

247248
const d1 = this.successEmitter.event(id, (message) => {
248249
dispose();
249-
resolve(this.parse(message.getResponse(), promise));
250+
resolve(this.protoToArgument(message.getResponse(), promise));
250251
});
251252

252253
const d2 = this.failEmitter.event(id, (message) => {
253254
dispose();
254-
reject(parse(message.getResponse()));
255+
reject(protoToArgument(message.getResponse()));
255256
});
256257
});
257258

@@ -262,42 +263,53 @@ export class Client {
262263
* Handle all messages from the server.
263264
*/
264265
private async handleMessage(message: ServerMessage): Promise<void> {
265-
if (message.hasInit()) {
266-
const init = message.getInit()!;
267-
this._initData = {
268-
dataDirectory: init.getDataDirectory(),
269-
homeDirectory: init.getHomeDirectory(),
270-
tmpDirectory: init.getTmpDirectory(),
271-
workingDirectory: init.getWorkingDirectory(),
272-
os: protoToOperatingSystem(init.getOperatingSystem()),
273-
shell: init.getShell(),
274-
builtInExtensionsDirectory: init.getBuiltinExtensionsDir(),
275-
};
276-
this.initDataEmitter.emit(this._initData);
277-
} else if (message.hasSuccess()) {
278-
this.emitSuccess(message.getSuccess()!);
279-
} else if (message.hasFail()) {
280-
this.emitFail(message.getFail()!);
281-
} else if (message.hasEvent()) {
282-
await this.emitEvent(message.getEvent()!);
283-
} else if (message.hasCallback()) {
284-
await this.runCallback(message.getCallback()!);
285-
} else if (message.hasSharedProcessActive()) {
286-
const sharedProcessActiveMessage = message.getSharedProcessActive()!;
287-
this.sharedProcessActiveEmitter.emit({
288-
socketPath: sharedProcessActiveMessage.getSocketPath(),
289-
logPath: sharedProcessActiveMessage.getLogPath(),
290-
});
291-
} else if (message.hasPong()) {
292-
// Nothing to do since pings are on a timer rather than waiting for the
293-
// next pong in case a message from either the client or server is dropped
294-
// which would break the ping cycle.
295-
} else {
296-
throw new Error("unknown message type");
266+
switch (message.getMsgCase()) {
267+
case ServerMessage.MsgCase.INIT:
268+
const init = message.getInit()!;
269+
this._initData = {
270+
dataDirectory: init.getDataDirectory(),
271+
homeDirectory: init.getHomeDirectory(),
272+
tmpDirectory: init.getTmpDirectory(),
273+
workingDirectory: init.getWorkingDirectory(),
274+
os: protoToOperatingSystem(init.getOperatingSystem()),
275+
shell: init.getShell(),
276+
builtInExtensionsDirectory: init.getBuiltinExtensionsDir(),
277+
};
278+
this.initDataEmitter.emit(this._initData);
279+
break;
280+
case ServerMessage.MsgCase.SUCCESS:
281+
this.emitSuccess(message.getSuccess()!);
282+
break;
283+
case ServerMessage.MsgCase.FAIL:
284+
this.emitFail(message.getFail()!);
285+
break;
286+
case ServerMessage.MsgCase.EVENT:
287+
await this.emitEvent(message.getEvent()!);
288+
break;
289+
case ServerMessage.MsgCase.CALLBACK:
290+
await this.runCallback(message.getCallback()!);
291+
break;
292+
case ServerMessage.MsgCase.SHARED_PROCESS_ACTIVE:
293+
const sharedProcessActiveMessage = message.getSharedProcessActive()!;
294+
this.sharedProcessActiveEmitter.emit({
295+
socketPath: sharedProcessActiveMessage.getSocketPath(),
296+
logPath: sharedProcessActiveMessage.getLogPath(),
297+
});
298+
break;
299+
case ServerMessage.MsgCase.PONG:
300+
// Nothing to do since pings are on a timer rather than waiting for the
301+
// next pong in case a message from either the client or server is dropped
302+
// which would break the ping cycle.
303+
break;
304+
default:
305+
throw new Error("unknown message type");
297306
}
298307
}
299308

300-
private emitSuccess(message: SuccessMessage): void {
309+
/**
310+
* Convert message to a success event.
311+
*/
312+
private emitSuccess(message: Method.Success): void {
301313
logger.trace(() => [
302314
"received resolve",
303315
field("id", message.getId()),
@@ -306,7 +318,10 @@ export class Client {
306318
this.successEmitter.emit(message.getId(), message);
307319
}
308320

309-
private emitFail(message: FailMessage): void {
321+
/**
322+
* Convert message to a fail event.
323+
*/
324+
private emitFail(message: Method.Fail): void {
310325
logger.trace(() => [
311326
"received reject",
312327
field("id", message.getId()),
@@ -322,7 +337,7 @@ export class Client {
322337
* request before it emits. Instead, emit all events from the server so all
323338
* events are always caught on the client.
324339
*/
325-
private async emitEvent(message: EventMessage): Promise<void> {
340+
private async emitEvent(message: Event): Promise<void> {
326341
const eventMessage = message.getNamedEvent()! || message.getNumberedEvent()!;
327342
const proxyId = message.getNamedEvent()
328343
? protoToModule(message.getNamedEvent()!.getModule())
@@ -336,7 +351,7 @@ export class Client {
336351
field("args", eventMessage.getArgsList()),
337352
]);
338353

339-
const args = eventMessage.getArgsList().map((a) => this.parse(a));
354+
const args = eventMessage.getArgsList().map((a) => this.protoToArgument(a));
340355
this.eventEmitter.emit(proxyId, { event, args });
341356
}
342357

@@ -348,7 +363,7 @@ export class Client {
348363
* also only be used when passed together with the method. If they are sent
349364
* afterward, they may never be called due to timing issues.
350365
*/
351-
private async runCallback(message: CallbackMessage): Promise<void> {
366+
private async runCallback(message: Callback): Promise<void> {
352367
const callbackMessage = message.getNamedCallback()! || message.getNumberedCallback()!;
353368
const proxyId = message.getNamedCallback()
354369
? protoToModule(message.getNamedCallback()!.getModule())
@@ -361,14 +376,14 @@ export class Client {
361376
field("callbackId", callbackId),
362377
field("args", callbackMessage.getArgsList()),
363378
]);
364-
const args = callbackMessage.getArgsList().map((a) => this.parse(a));
379+
const args = callbackMessage.getArgsList().map((a) => this.protoToArgument(a));
365380
this.getProxy(proxyId).callbacks.get(callbackId)!(...args);
366381
}
367382

368383
/**
369384
* Start the ping loop. Does nothing if already pinging.
370385
*/
371-
private startPinging = (): void => {
386+
private readonly startPinging = (): void => {
372387
if (typeof this.pingTimeout !== "undefined") {
373388
return;
374389
}
@@ -505,10 +520,16 @@ export class Client {
505520
await this.getProxy(proxyId).promise;
506521
}
507522

508-
private parse(value?: string, promise?: Promise<any>): any {
509-
return parse(value, undefined, (id) => this.createProxy(id, promise));
523+
/**
524+
* Same as protoToArgument except provides createProxy.
525+
*/
526+
private protoToArgument(value?: Argument, promise?: Promise<any>): any {
527+
return protoToArgument(value, undefined, (id) => this.createProxy(id, promise));
510528
}
511529

530+
/**
531+
* Get a proxy. Error if it doesn't exist.
532+
*/
512533
private getProxy(proxyId: number | Module): ProxyData {
513534
if (!this.proxies.has(proxyId)) {
514535
throw new Error(`proxy ${proxyId} disposed too early`);

0 commit comments

Comments
 (0)