UNPKG

homebridge-gsh

Version:
121 lines 4.48 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WebSocket = void 0; const url = require("url"); const events_1 = require("events"); const WebSocketClient = require("ws"); class WebSocket extends events_1.EventEmitter { constructor(address, options = {}) { super(); this.connectionAttempt = 0; this.closed = false; this.address = address; this.protocols = options.protocols || []; this.options = options.options || {}; this.reconnectInterval = options.reconnectInterval || 5000; this.pingInterval = options.pingInterval || 10000; this.pingFailureLimit = options.pingFailureLimit || 2; this.pingTimeout = (this.pingInterval * this.pingFailureLimit) + 100; this.beforeConnect = options.beforeConnect; this.init(); } init() { // run a user defined function, if defined, before trying a reconnect if (this.beforeConnect) { return this.beforeConnect(this.connectionAttempt) .then(() => this.connect()); } else { return this.connect(); } } connect() { this.connectionAttempt++; const attempt = this.connectionAttempt; this.url = url.parse(this.address); const ws = new WebSocketClient(this.address, this.protocols, this.options); this.ws = ws; // Ping the server every x seconds to make sure the server is alive this.ping = setInterval(() => { if (ws.readyState === 1) { ws.ping('ping', true); } }, this.pingInterval); // If the server does not respond with pong for x consecutive pings start a reconnect const pongTimeout = () => { this.emit('websocket-status', `Lost Connection (${attempt}) - No ping back for ${this.pingTimeout}ms.`); this.reconnect(); }; // Received pong back from server ws.on('pong', () => { clearTimeout(this.pong); this.emit('pong'); this.pong = setTimeout(pongTimeout.bind(this), this.pingTimeout); }); // Connection open ws.on('open', () => { this.reconnecting = false; this.emit('open'); this.emit('websocket-status', `Connected (${attempt}) - ${this.url.protocol}//${this.url.host}`); this.pong = setTimeout(pongTimeout.bind(this), this.pingTimeout); }); // Connection closed - try reconnect ws.on('close', (code, reason) => { this.emit('close', code, reason); this.reconnect(); }); // Connection error - try reconnect ws.on('error', (e) => { this.emit('websocket-status', `Error (${attempt}) - ${e.message}`); this.reconnect(); }); // Received data - pass through ws.on('message', (msg) => { this.emit('message', msg); try { this.emit('json', JSON.parse(msg)); } catch (e) { /* not json */ } }); } reconnect() { clearInterval(this.ping); clearTimeout(this.pong); if (!this.reconnecting && !this.closed) { this.reconnecting = true; this.emit('websocket-status', `Disconnected (${this.connectionAttempt}) - Retry in ${this.reconnectInterval}ms`); // cleanup this.ws.removeAllListeners(); this.ws.terminate(); setTimeout(() => { this.reconnecting = false; this.emit('websocket-status', `Reconnecting (${this.connectionAttempt})`); this.init(); }, this.reconnectInterval); } } send(msg, callback) { if (this.ws.readyState === 1) { this.ws.send(msg, callback); } } sendJson(msg, callback) { this.send(JSON.stringify(msg), callback); } close(code, reason) { clearInterval(this.ping); clearTimeout(this.pong); this.closed = true; this.ws.close(code, reason); this.emit('websocket-status', `Closed (${this.connectionAttempt})`); } isConnected() { return this.ws.readyState === this.ws.OPEN; } setAddresss(address) { this.address = address; this.url = url.parse(this.address); } } exports.WebSocket = WebSocket; //# sourceMappingURL=index.js.map