const WebSocket = require("ws"); const JsonRpcClientProtocol = require("./base"); const logging = require("../../util/logger"); /** * Creates and instance of WsClientProtocol * * @extends JsonRpcClientProtocol * @requires ws */ class WsClientProtocol extends JsonRpcClientProtocol { /** @inheritdoc */ /** @property {string} url The websocket URL to connect to, i.e. `ws://127.0.0.1:8100` */ constructor(factory, version, delimiter) { super(factory, version, delimiter); this.url = this.factory.url; } /** * Set the `connector` attribute for the protocol instance. The connector is essentially the * socket instance for the client. * * For the [WsClientProtocol]{@link WsClientProtocol} this is `WebSocket()` */ setConnector() { const { perMessageDeflate } = this.factory.options; this.connector = new WebSocket(this.url, perMessageDeflate); this.connector.write = this.connector.send; // tcp uses .write(), ws uses .send() } /** * @inheritdoc */ _retryConnection(resolve, reject) { this.setConnector(); this.connector.onopen = (event) => { this.listener = this.connector; this.listen(); resolve(event); }; this.connector.onerror = (error) => { // let the onclose event get it otherwise if (error.error && error.error.code !== "ECONNREFUSED") { reject(error); } }; this.connector.onclose = (event) => { if (this.connector.__clientClosed) { // we dont want to retry if the client purposefully closed the connection logging .getLogger() .info( `Client closed connection. Code [${event.code}]. Reason [${event.reason}].` ); } else { return this._onConnectionFailed(event, resolve, reject); } }; } /** * @inheritdoc */ _onConnectionFailed(event, resolve, reject) { if (this.factory.remainingRetries > 0) { this.factory.remainingRetries -= 1; logging .getLogger() .error( `Failed to connect. Address [${this.url}]. Retrying. ${this.factory.remainingRetries} attempts left.` ); } else if (this.factory.remainingRetries === 0) { this.factory.pcolInstance = undefined; return reject(event); } else { logging .getLogger() .error(`Failed to connect. Address [${this.url}]. Retrying.`); } this._connectionTimeout = setTimeout(() => { this._retryConnection(resolve, reject); }, this.factory.connectionTimeout); } /** * Ends connection to the server. * * Sets `JsonRpcClientFactory.pcolInstance` to `undefined` * * Clears the connection timeout * * @param {number} code Status code for the close event. https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code * @param {string} reason Reason the connection was closed. */ end(code, reason) { clearTimeout(this._connectionTimeout); this.factory.pcolInstance = undefined; this.connector.__clientClosed = true; // used to determine if client initiated close event this.connector.close(code, reason); } /** @inheritdoc */ listen() { this.listener.onmessage = (message) => { this.messageBuffer.push(message.data); this._waitForData(message.data); }; } } module.exports = WsClientProtocol;