Skip to content

Add ping/pong to the protocol #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion packages/protocol/src/browser/client.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { EventEmitter } from "events";
import { Emitter } from "@coder/events";
import { logger, field } from "@coder/logger";
import { NewEvalMessage, ServerMessage, EvalDoneMessage, EvalFailedMessage, ClientMessage, WorkingInitMessage, EvalEventMessage } from "../proto";
import { Ping, NewEvalMessage, ServerMessage, EvalDoneMessage, EvalFailedMessage, ClientMessage, WorkingInitMessage, EvalEventMessage } from "../proto";
import { ReadWriteConnection, InitData, OperatingSystem, SharedProcessData } from "../common/connection";
import { ActiveEvalHelper, EvalHelper, Disposer, ServerActiveEvalHelper } from "../common/helpers";
import { stringify, parse } from "../common/util";
Expand All @@ -22,6 +22,11 @@ export class Client {
private readonly sharedProcessActiveEmitter = new Emitter<SharedProcessData>();
public readonly onSharedProcessActive = this.sharedProcessActiveEmitter.event;

// The socket timeout is 60s, so we need to send a ping periodically to
// prevent it from closing.
private pingTimeout: NodeJS.Timer | number | undefined;
private readonly pingTimeoutDelay = 30000;

/**
* @param connection Established connection to the server
*/
Expand All @@ -43,9 +48,16 @@ export class Client {
}
});

connection.onClose(() => {
clearTimeout(this.pingTimeout as any); // tslint:disable-line no-any
this.pingTimeout = undefined;
});

this.initDataPromise = new Promise((resolve): void => {
this.initDataEmitter.event(resolve);
});

this.startPinging();
}

public dispose(): void {
Expand Down Expand Up @@ -214,6 +226,28 @@ export class Client {
socketPath: sharedProcessActiveMessage.getSocketPath(),
logPath: sharedProcessActiveMessage.getLogPath(),
});
} else if (message.hasPong()) {
// Nothing to do since we run the pings on a timer, in case either message
// is dropped which would break the ping cycle.
} else {
throw new Error("unknown message type");
}
}

private startPinging = (): void => {
if (typeof this.pingTimeout !== "undefined") {
return;
}

const schedulePing = (): void => {
this.pingTimeout = setTimeout(() => {
const clientMsg = new ClientMessage();
clientMsg.setPing(new Ping());
this.connection.send(clientMsg.serializeBinary());
schedulePing();
}, this.pingTimeoutDelay);
};

schedulePing();
}
}
7 changes: 6 additions & 1 deletion packages/protocol/src/node/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as path from "path";
import { mkdir } from "fs";
import { promisify } from "util";
import { logger, field } from "@coder/logger";
import { ClientMessage, WorkingInitMessage, ServerMessage } from "../proto";
import { Pong, ClientMessage, WorkingInitMessage, ServerMessage } from "../proto";
import { evaluate, ActiveEvaluation } from "./evaluate";
import { ForkProvider } from "../common/helpers";
import { ReadWriteConnection } from "../common/connection";
Expand Down Expand Up @@ -116,6 +116,11 @@ export class Server {
return;
}
e.onEvent(evalEventMessage);
} else if (message.hasPing()) {
logger.trace("ping");
const srvMsg = new ServerMessage();
srvMsg.setPong(new Pong());
this.connection.send(srvMsg.serializeBinary());
} else {
throw new Error("unknown message type");
}
Expand Down
4 changes: 4 additions & 0 deletions packages/protocol/src/proto/client.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ message ClientMessage {
// node.proto
NewEvalMessage new_eval = 11;
EvalEventMessage eval_event = 12;

Ping ping = 13;
}
}

Expand All @@ -21,6 +23,8 @@ message ServerMessage {

// vscode.proto
SharedProcessActiveMessage shared_process_active = 17;

Pong pong = 18;
}
}

Expand Down
14 changes: 14 additions & 0 deletions packages/protocol/src/proto/client_pb.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export class ClientMessage extends jspb.Message {
getEvalEvent(): node_pb.EvalEventMessage | undefined;
setEvalEvent(value?: node_pb.EvalEventMessage): void;

hasPing(): boolean;
clearPing(): void;
getPing(): node_pb.Ping | undefined;
setPing(value?: node_pb.Ping): void;

getMsgCase(): ClientMessage.MsgCase;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ClientMessage.AsObject;
Expand All @@ -31,12 +36,14 @@ export namespace ClientMessage {
export type AsObject = {
newEval?: node_pb.NewEvalMessage.AsObject,
evalEvent?: node_pb.EvalEventMessage.AsObject,
ping?: node_pb.Ping.AsObject,
}

export enum MsgCase {
MSG_NOT_SET = 0,
NEW_EVAL = 11,
EVAL_EVENT = 12,
PING = 13,
}
}

Expand Down Expand Up @@ -66,6 +73,11 @@ export class ServerMessage extends jspb.Message {
getSharedProcessActive(): vscode_pb.SharedProcessActiveMessage | undefined;
setSharedProcessActive(value?: vscode_pb.SharedProcessActiveMessage): void;

hasPong(): boolean;
clearPong(): void;
getPong(): node_pb.Pong | undefined;
setPong(value?: node_pb.Pong): void;

getMsgCase(): ServerMessage.MsgCase;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ServerMessage.AsObject;
Expand All @@ -84,6 +96,7 @@ export namespace ServerMessage {
evalEvent?: node_pb.EvalEventMessage.AsObject,
init?: WorkingInitMessage.AsObject,
sharedProcessActive?: vscode_pb.SharedProcessActiveMessage.AsObject,
pong?: node_pb.Pong.AsObject,
}

export enum MsgCase {
Expand All @@ -93,6 +106,7 @@ export namespace ServerMessage {
EVAL_EVENT = 15,
INIT = 16,
SHARED_PROCESS_ACTIVE = 17,
PONG = 18,
}
}

Expand Down
102 changes: 96 additions & 6 deletions packages/protocol/src/proto/client_pb.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,16 @@ if (goog.DEBUG && !COMPILED) {
* @private {!Array<!Array<number>>}
* @const
*/
proto.ClientMessage.oneofGroups_ = [[11,12]];
proto.ClientMessage.oneofGroups_ = [[11,12,13]];

/**
* @enum {number}
*/
proto.ClientMessage.MsgCase = {
MSG_NOT_SET: 0,
NEW_EVAL: 11,
EVAL_EVENT: 12
EVAL_EVENT: 12,
PING: 13
};

/**
Expand Down Expand Up @@ -91,7 +92,8 @@ proto.ClientMessage.prototype.toObject = function(opt_includeInstance) {
proto.ClientMessage.toObject = function(includeInstance, msg) {
var f, obj = {
newEval: (f = msg.getNewEval()) && node_pb.NewEvalMessage.toObject(includeInstance, f),
evalEvent: (f = msg.getEvalEvent()) && node_pb.EvalEventMessage.toObject(includeInstance, f)
evalEvent: (f = msg.getEvalEvent()) && node_pb.EvalEventMessage.toObject(includeInstance, f),
ping: (f = msg.getPing()) && node_pb.Ping.toObject(includeInstance, f)
};

if (includeInstance) {
Expand Down Expand Up @@ -138,6 +140,11 @@ proto.ClientMessage.deserializeBinaryFromReader = function(msg, reader) {
reader.readMessage(value,node_pb.EvalEventMessage.deserializeBinaryFromReader);
msg.setEvalEvent(value);
break;
case 13:
var value = new node_pb.Ping;
reader.readMessage(value,node_pb.Ping.deserializeBinaryFromReader);
msg.setPing(value);
break;
default:
reader.skipField();
break;
Expand Down Expand Up @@ -183,6 +190,14 @@ proto.ClientMessage.serializeBinaryToWriter = function(message, writer) {
node_pb.EvalEventMessage.serializeBinaryToWriter
);
}
f = message.getPing();
if (f != null) {
writer.writeMessage(
13,
f,
node_pb.Ping.serializeBinaryToWriter
);
}
};


Expand Down Expand Up @@ -246,6 +261,36 @@ proto.ClientMessage.prototype.hasEvalEvent = function() {
};


/**
* optional Ping ping = 13;
* @return {?proto.Ping}
*/
proto.ClientMessage.prototype.getPing = function() {
return /** @type{?proto.Ping} */ (
jspb.Message.getWrapperField(this, node_pb.Ping, 13));
};


/** @param {?proto.Ping|undefined} value */
proto.ClientMessage.prototype.setPing = function(value) {
jspb.Message.setOneofWrapperField(this, 13, proto.ClientMessage.oneofGroups_[0], value);
};


proto.ClientMessage.prototype.clearPing = function() {
this.setPing(undefined);
};


/**
* Returns whether this field is set.
* @return {!boolean}
*/
proto.ClientMessage.prototype.hasPing = function() {
return jspb.Message.getField(this, 13) != null;
};



/**
* Generated by JsPbCodeGenerator.
Expand All @@ -272,7 +317,7 @@ if (goog.DEBUG && !COMPILED) {
* @private {!Array<!Array<number>>}
* @const
*/
proto.ServerMessage.oneofGroups_ = [[13,14,15,16,17]];
proto.ServerMessage.oneofGroups_ = [[13,14,15,16,17,18]];

/**
* @enum {number}
Expand All @@ -283,7 +328,8 @@ proto.ServerMessage.MsgCase = {
EVAL_DONE: 14,
EVAL_EVENT: 15,
INIT: 16,
SHARED_PROCESS_ACTIVE: 17
SHARED_PROCESS_ACTIVE: 17,
PONG: 18
};

/**
Expand Down Expand Up @@ -326,7 +372,8 @@ proto.ServerMessage.toObject = function(includeInstance, msg) {
evalDone: (f = msg.getEvalDone()) && node_pb.EvalDoneMessage.toObject(includeInstance, f),
evalEvent: (f = msg.getEvalEvent()) && node_pb.EvalEventMessage.toObject(includeInstance, f),
init: (f = msg.getInit()) && proto.WorkingInitMessage.toObject(includeInstance, f),
sharedProcessActive: (f = msg.getSharedProcessActive()) && vscode_pb.SharedProcessActiveMessage.toObject(includeInstance, f)
sharedProcessActive: (f = msg.getSharedProcessActive()) && vscode_pb.SharedProcessActiveMessage.toObject(includeInstance, f),
pong: (f = msg.getPong()) && node_pb.Pong.toObject(includeInstance, f)
};

if (includeInstance) {
Expand Down Expand Up @@ -388,6 +435,11 @@ proto.ServerMessage.deserializeBinaryFromReader = function(msg, reader) {
reader.readMessage(value,vscode_pb.SharedProcessActiveMessage.deserializeBinaryFromReader);
msg.setSharedProcessActive(value);
break;
case 18:
var value = new node_pb.Pong;
reader.readMessage(value,node_pb.Pong.deserializeBinaryFromReader);
msg.setPong(value);
break;
default:
reader.skipField();
break;
Expand Down Expand Up @@ -457,6 +509,14 @@ proto.ServerMessage.serializeBinaryToWriter = function(message, writer) {
vscode_pb.SharedProcessActiveMessage.serializeBinaryToWriter
);
}
f = message.getPong();
if (f != null) {
writer.writeMessage(
18,
f,
node_pb.Pong.serializeBinaryToWriter
);
}
};


Expand Down Expand Up @@ -610,6 +670,36 @@ proto.ServerMessage.prototype.hasSharedProcessActive = function() {
};


/**
* optional Pong pong = 18;
* @return {?proto.Pong}
*/
proto.ServerMessage.prototype.getPong = function() {
return /** @type{?proto.Pong} */ (
jspb.Message.getWrapperField(this, node_pb.Pong, 18));
};


/** @param {?proto.Pong|undefined} value */
proto.ServerMessage.prototype.setPong = function(value) {
jspb.Message.setOneofWrapperField(this, 18, proto.ServerMessage.oneofGroups_[0], value);
};


proto.ServerMessage.prototype.clearPong = function() {
this.setPong(undefined);
};


/**
* Returns whether this field is set.
* @return {!boolean}
*/
proto.ServerMessage.prototype.hasPong = function() {
return jspb.Message.getField(this, 18) != null;
};



/**
* Generated by JsPbCodeGenerator.
Expand Down
4 changes: 4 additions & 0 deletions packages/protocol/src/proto/node.proto
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ message EvalDoneMessage {
uint64 id = 1;
string response = 2;
}

message Ping {}

message Pong {}
32 changes: 32 additions & 0 deletions packages/protocol/src/proto/node_pb.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,35 @@ export namespace EvalDoneMessage {
}
}

export class Ping extends jspb.Message {
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): Ping.AsObject;
static toObject(includeInstance: boolean, msg: Ping): Ping.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: Ping, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): Ping;
static deserializeBinaryFromReader(message: Ping, reader: jspb.BinaryReader): Ping;
}

export namespace Ping {
export type AsObject = {
}
}

export class Pong extends jspb.Message {
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): Pong.AsObject;
static toObject(includeInstance: boolean, msg: Pong): Pong.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: Pong, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): Pong;
static deserializeBinaryFromReader(message: Pong, reader: jspb.BinaryReader): Pong;
}

export namespace Pong {
export type AsObject = {
}
}

Loading