UNPKG

@egodigital/egoose

Version:

Helper classes and functions for Node.js 10 or later.

242 lines 7.61 kB
"use strict"; /** * This file is part of the @egodigital/egoose distribution. * Copyright (c) e.GO Digital GmbH, Aachen, Germany (https://www.e-go-digital.com/) * * @egodigital/egoose is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, version 3. * * @egodigital/egoose is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ Object.defineProperty(exports, "__esModule", { value: true }); const index_1 = require("../index"); const _ = require("lodash"); const events = require("events"); const http = require("http"); const ws = require("ws"); /** * A web socket host. */ class WebSocketHost extends events.EventEmitter { /** * Initializes a new instance of that class. * * @param {WebSocketHostOptions} [options] Custom options for the host. */ constructor(options) { super(); this.options = options; if (!this.options) { this.options = {}; } } /** * Gets if the server is currently running or not. */ get isRunning() { return !!this._server; } /** * Starts the host. * * @return {Promise<boolean>} The promise that indicates if operation was succesfull or not. */ start() { return new Promise(async (resolve, reject) => { try { if (this.isRunning) { resolve(false); return; } let serverFactory = this.options.serverFactory; if (!serverFactory) { serverFactory = () => { return http.createServer(); }; } let port = parseInt(index_1.toStringSafe(this.options.port) .trim()); if (isNaN(port)) { port = 5979; } const NEW_SERVER = await Promise.resolve(serverFactory()); if (!NEW_SERVER) { resolve(false); return; } NEW_SERVER.once('error', (err) => { reject(err); }); const VERIFY_CLIENT = async (info, callback) => { let isValid = true; try { if (this.options.verifyClient) { isValid = index_1.toBooleanSafe(await Promise.resolve(this.options.verifyClient({ isSecure: info.secure, request: info.req, }))); } } catch { isValid = false; } if (isValid) { callback(true); } else { callback(false, 401); } }; const WSS = new ws.Server({ server: NEW_SERVER, verifyClient: VERIFY_CLIENT, }); WSS.on('error', (err) => { /* ignore errors */ }); WSS.on('connection', (ws) => { try { const CONN = new WebSocketClient(this, ws); CONN.init(); this.emit('connection', CONN); } catch { try { ws.close(); } catch { } } }); NEW_SERVER.listen(port, () => { this._server = NEW_SERVER; resolve(true); }); } catch (e) { reject(e); } }); } /** * Stops the host. * * @return {Promise<boolean>} The promise that indicates if operation was succesfull or not. */ stop() { return new Promise((resolve, reject) => { try { const SERVER = this._server; if (!SERVER) { resolve(false); return; } SERVER.close((err) => { if (err) { reject(err); } else { this._server = null; resolve(true); } }); } catch (e) { reject(e); } }); } } exports.WebSocketHost = WebSocketHost; /** * A web socket client. */ class WebSocketClient extends events.EventEmitter { /** * Initializes a new instance of that class. * * @param {WebSocketHost} host The underlying host. * @param {ws} socket The underlying socket. */ constructor(host, socket) { super(); this.host = host; this.socket = socket; } /** * Initializes the instance. */ init() { this.socket.on('error', (err) => { /* ignore errors */ }); this.socket.on('message', (data) => { try { const MSG = JSON.parse(index_1.toStringSafe(data)); if (MSG) { this.emit('message', MSG); const TYPE = index_1.normalizeString(MSG.type); this.emit('message.' + TYPE, MSG, TYPE); } } catch { } }); this.socket.once('close', () => { this.emit('close'); }); } onType(checker, listener) { let predicate = checker; if (!_.isFunction(predicate)) { if (_.isRegExp(checker)) { predicate = (t) => checker.test(t); } else { predicate = (t) => t === index_1.normalizeString(checker); } } const MSG_LISTENER = (msg) => { const TYPE = index_1.normalizeString(msg.type); if (index_1.toBooleanSafe(predicate(TYPE))) { listener(msg.data, TYPE); } }; this.on('message', MSG_LISTENER); return MSG_LISTENER; } /** * Sends a message to the remote client. * * @param {string} type The type. * @param {any} [data] The data to send. */ send(type, data) { return new Promise((resolve, reject) => { try { const MSG = { data: data, type: index_1.normalizeString(type), }; this.socket.send(JSON.stringify(MSG), (err) => { if (err) { reject(err); } else { resolve(); } }); } catch (e) { reject(e); } }); } } exports.WebSocketClient = WebSocketClient; //# sourceMappingURL=websockets.js.map