From 0c0dafbecfc7e6600c30ac4d9b2ae57ad6e3fdc9 Mon Sep 17 00:00:00 2001 From: Lorenz Stechauner Date: Mon, 29 Aug 2022 22:45:10 +0200 Subject: [PATCH] Add websocket ping --- src/usimp.ts | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/usimp.ts b/src/usimp.ts index 576bcd6..e14d833 100644 --- a/src/usimp.ts +++ b/src/usimp.ts @@ -3,6 +3,8 @@ const DNS_RE = /^([a-z0-9_-]+\.)+[a-z]{2,}$/i; const UUID_RE = /^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$/i; +const WEBSOCKET_KEEP_ALIVE = 5 * 60; // [sec] + type DomainJson = { name: string, id: string, @@ -295,6 +297,7 @@ export class Session { httpBaseUrl: string | null; websocket: WebSocket | null; + websocketPingInterval: number | null; numRequests: number; requestNumDiscriminator: number; subscriptions: { @@ -314,6 +317,7 @@ export class Session { this.token = null; this.httpBaseUrl = null; this.websocket = null; + this.websocketPingInterval = null; this.subscriptions = []; this.subscriptionEndpoints = []; } @@ -329,13 +333,29 @@ export class Session { async close(keepEndpoints: boolean = false) { await this.unsubscribeAll(keepEndpoints); if (this.websocket && (this.websocket.readyState !== WebSocket.CLOSING && this.websocket.readyState !== WebSocket.CLOSED)) { - this.websocket.close(); + this.closeWebsocket() this.subscriptions = []; - this.websocket = null; this.server = null; } } + private setWebsocketNull() { + if (this.websocketPingInterval) clearInterval(this.websocketPingInterval); + this.websocket = null; + this.websocketPingInterval = null; + } + + closeWebsocket() { + if (this.websocket) { + this.websocket.close(); + this.setWebsocketNull(); + } + } + + hasWebsocket(): boolean { + return this.websocket !== null; + } + async sleep() { await this.close(true); } @@ -359,8 +379,11 @@ export class Session { this.websocket = new WebSocket(`wss://${host}:${protocols.wss}/_usimp/websocket`, ["usimp"]); this.websocket.addEventListener("error", (error) => { console.error(error); - this.websocket = null; + this.setWebsocketNull(); }); + this.websocketPingInterval = setInterval(() => { + if (this.hasWebsocket()) this.send("ping", {}) + }, WEBSOCKET_KEEP_ALIVE * 1000); } if ("https" in protocols) { @@ -520,10 +543,8 @@ export class Session { } } catch (error) { console.error(error); - if (this.websocket !== null) { - this.websocket.close(); - this.websocket = null; - } + if (this.hasWebsocket()) this.closeWebsocket(); + this.httpBaseUrl = null; if (this.server !== null) { this.domain.invalidServers.push(this.server); @@ -539,7 +560,7 @@ export class Session { const resHttp = await this.send("ping", {}, undefined, true); result.http = resHttp.duration; - if (this.websocket) { + if (this.hasWebsocket()) { const resWs = await this.send("ping", {}); result.ws = resWs.duration; } @@ -575,7 +596,7 @@ export class Session { } private async _subscribe(cb: EventHandler) { - if (this.websocket !== null) { + if (this.hasWebsocket()) { const subscription = await this.send('subscribe', {}, 60_000, false, undefined, (res) => { if (res.action === 'push') { if (isEventPushEnvelopeJson(res.data)) { @@ -621,7 +642,7 @@ export class Session { } private async unsubscribe(requestNr: number | undefined = undefined, abortController: AbortController | undefined = undefined) { - if (this.websocket !== null) { + if (this.hasWebsocket()) { await this.send('unsubscribe', {'request_nr': requestNr}) } else { if (abortController) abortController.abort('unsubscribe');