From 4cfd7c50adbe2c8e053972976ae2436574bc46a6 Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 28 Apr 2020 13:13:35 -0500 Subject: [PATCH] Remove unused class I managed to lose this deletion in a merge. --- src/browser/socket.ts | 204 ------------------------------------------ 1 file changed, 204 deletions(-) delete mode 100644 src/browser/socket.ts diff --git a/src/browser/socket.ts b/src/browser/socket.ts deleted file mode 100644 index 67c834e2..00000000 --- a/src/browser/socket.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { field, logger, Logger } from "@coder/logger" -import { Emitter } from "../common/emitter" -import { generateUuid } from "../common/util" - -const decoder = new TextDecoder("utf8") -export const decode = (buffer: string | ArrayBuffer): string => { - return typeof buffer !== "string" ? decoder.decode(buffer) : buffer -} - -/** - * A web socket that reconnects itself when it closes. Sending messages while - * disconnected will throw an error. - */ -export class ReconnectingSocket { - protected readonly _onMessage = new Emitter() - public readonly onMessage = this._onMessage.event - protected readonly _onDisconnect = new Emitter() - public readonly onDisconnect = this._onDisconnect.event - protected readonly _onClose = new Emitter() - public readonly onClose = this._onClose.event - protected readonly _onConnect = new Emitter() - public readonly onConnect = this._onConnect.event - - // This helps distinguish messages between sockets. - private readonly logger: Logger - - private socket?: WebSocket - private connecting?: Promise - private closed = false - private readonly openTimeout = 10000 - - // Every time the socket fails to connect, the retry will be increasingly - // delayed up to a maximum. - private readonly retryBaseDelay = 1000 - private readonly retryMaxDelay = 10000 - private retryDelay?: number - private readonly retryDelayFactor = 1.5 - - // The socket must be connected for this amount of time before resetting the - // retry delay. This prevents rapid retries when the socket does connect but - // is closed shortly after. - private resetRetryTimeout?: NodeJS.Timeout - private readonly resetRetryDelay = 10000 - - private _binaryType: typeof WebSocket.prototype.binaryType = "arraybuffer" - - public constructor(private path: string, public readonly id: string = generateUuid(4)) { - // On Firefox the socket seems to somehow persist a page reload so the close - // event runs and we see "attempting to reconnect". - if (typeof window !== "undefined") { - window.addEventListener("beforeunload", () => this.close()) - } - this.logger = logger.named(this.id) - } - - public set binaryType(b: typeof WebSocket.prototype.binaryType) { - this._binaryType = b - if (this.socket) { - this.socket.binaryType = b - } - } - - /** - * Permanently close the connection. Will not attempt to reconnect. Will - * remove event listeners. - */ - public close(code?: number): void { - if (this.closed) { - return - } - - if (code) { - this.logger.info(`closing with code ${code}`) - } - - if (this.resetRetryTimeout) { - clearTimeout(this.resetRetryTimeout) - } - - this.closed = true - - if (this.socket) { - this.socket.close() - } else { - this._onClose.emit(code) - } - } - - public dispose(): void { - this._onMessage.dispose() - this._onDisconnect.dispose() - this._onClose.dispose() - this._onConnect.dispose() - this.logger.debug("disposed handlers") - } - - /** - * Send a message on the socket. Logs an error if currently disconnected. - */ - public send(message: string | ArrayBuffer): void { - this.logger.trace(() => ["sending message", field("message", decode(message))]) - if (!this.socket) { - return logger.error("tried to send message on closed socket") - } - this.socket.send(message) - } - - /** - * Connect to the socket. Can also be called to wait until the connection is - * established in the case of disconnections. Multiple calls will be handled - * correctly. - */ - public async connect(): Promise { - if (!this.connecting) { - this.connecting = new Promise((resolve, reject) => { - const tryConnect = (): void => { - if (this.closed) { - return reject(new Error("disconnected")) // Don't keep trying if we've closed permanently. - } - if (typeof this.retryDelay === "undefined") { - this.retryDelay = 0 - } else { - this.retryDelay = this.retryDelay * this.retryDelayFactor || this.retryBaseDelay - if (this.retryDelay > this.retryMaxDelay) { - this.retryDelay = this.retryMaxDelay - } - } - this._connect() - .then((socket) => { - this.logger.info("connected") - this.socket = socket - this.socket.binaryType = this._binaryType - if (this.resetRetryTimeout) { - clearTimeout(this.resetRetryTimeout) - } - this.resetRetryTimeout = setTimeout(() => (this.retryDelay = undefined), this.resetRetryDelay) - this.connecting = undefined - this._onConnect.emit() - resolve() - }) - .catch((error) => { - this.logger.error(`failed to connect: ${error.message}`) - tryConnect() - }) - } - tryConnect() - }) - } - return this.connecting - } - - private async _connect(): Promise { - const socket = await new Promise((resolve, _reject) => { - if (this.retryDelay) { - this.logger.info(`retrying in ${this.retryDelay}ms...`) - } - setTimeout(() => { - this.logger.info("connecting...", field("path", this.path)) - const socket = new WebSocket(this.path) - - const reject = (): void => { - _reject(new Error("socket closed")) - } - - const timeout = setTimeout(() => { - // eslint-disable-next-line @typescript-eslint/no-use-before-define - socket.removeEventListener("open", open) - socket.removeEventListener("close", reject) - _reject(new Error("timeout")) - }, this.openTimeout) - - const open = (): void => { - clearTimeout(timeout) - socket.removeEventListener("close", reject) - resolve(socket) - } - - socket.addEventListener("open", open) - socket.addEventListener("close", reject) - }, this.retryDelay) - }) - - socket.addEventListener("message", (event) => { - this.logger.trace(() => ["got message", field("message", decode(event.data))]) - this._onMessage.emit(event.data) - }) - socket.addEventListener("close", (event) => { - this.socket = undefined - if (!this.closed) { - this._onDisconnect.emit(event.code) - // It might be closed in the event handler. - if (!this.closed) { - this.logger.info("connection closed; attempting to reconnect") - this.connect() - } - } else { - this._onClose.emit(event.code) - this.logger.info("connection closed permanently") - } - }) - - return socket - } -}