Add heartbeat file (#1115)

Fixes #1050.
This commit is contained in:
Asher 2019-10-28 09:59:34 -05:00 committed by GitHub
parent f73e9225b4
commit 3a9b032c72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 49 additions and 0 deletions

View File

@ -474,6 +474,9 @@ export class MainServer extends Server {
private readonly proxyTimeout = 5000; private readonly proxyTimeout = 5000;
private settings: Settings = {}; private settings: Settings = {};
private heartbeatTimer?: NodeJS.Timeout;
private heartbeatInterval = 60000;
private lastHeartbeat = 0;
public constructor(options: ServerOptions, args: ParsedArgs) { public constructor(options: ServerOptions, args: ParsedArgs) {
super(options); super(options);
@ -491,6 +494,7 @@ export class MainServer extends Server {
} }
protected async handleWebSocket(socket: net.Socket, parsedUrl: url.UrlWithParsedQuery): Promise<void> { protected async handleWebSocket(socket: net.Socket, parsedUrl: url.UrlWithParsedQuery): Promise<void> {
this.heartbeat();
if (!parsedUrl.query.reconnectionToken) { if (!parsedUrl.query.reconnectionToken) {
throw new Error("Reconnection token is missing from query parameters"); throw new Error("Reconnection token is missing from query parameters");
} }
@ -514,6 +518,7 @@ export class MainServer extends Server {
parsedUrl: url.UrlWithParsedQuery, parsedUrl: url.UrlWithParsedQuery,
request: http.IncomingMessage, request: http.IncomingMessage,
): Promise<Response> { ): Promise<Response> {
this.heartbeat();
switch (base) { switch (base) {
case "/": return this.getRoot(request, parsedUrl); case "/": return this.getRoot(request, parsedUrl);
case "/resource": case "/resource":
@ -876,4 +881,48 @@ export class MainServer extends Server {
(this.services.get(ILogService) as ILogService).warn(error.message); (this.services.get(ILogService) as ILogService).warn(error.message);
} }
} }
/**
* Return the file path for the heartbeat file.
*/
private get heartbeatPath(): string {
const environment = this.services.get(IEnvironmentService) as IEnvironmentService;
return path.join(environment.userDataPath, "heartbeat");
}
/**
* Return all online connections regardless of type.
*/
private get onlineConnections(): Connection[] {
const online = <Connection[]>[];
this.connections.forEach((connections) => {
connections.forEach((connection) => {
if (typeof connection.offline === "undefined") {
online.push(connection);
}
});
});
return online;
}
/**
* Write to the heartbeat file if we haven't already done so within the
* timeout and start or reset a timer that keeps running as long as there are
* active connections. Failures are logged as warnings.
*/
private heartbeat(): void {
const now = Date.now();
if (now - this.lastHeartbeat >= this.heartbeatInterval) {
util.promisify(fs.writeFile)(this.heartbeatPath, "").catch((error) => {
(this.services.get(ILogService) as ILogService).warn(error.message);
});
this.lastHeartbeat = now;
clearTimeout(this.heartbeatTimer!); // We can clear undefined so ! is fine.
this.heartbeatTimer = setTimeout(() => {
if (this.onlineConnections.length > 0) {
this.heartbeat();
}
}, this.heartbeatInterval);
}
}
} }