UNPKG

7.63 kBJavaScriptView Raw
1"use strict";
2/**
3 * This file is part of the @egodigital/egoose distribution.
4 * Copyright (c) e.GO Digital GmbH, Aachen, Germany (https://www.e-go-digital.com/)
5 *
6 * @egodigital/egoose is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation, version 3.
9 *
10 * @egodigital/egoose is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18Object.defineProperty(exports, "__esModule", { value: true });
19const index_1 = require("../index");
20const _ = require("lodash");
21const events = require("events");
22const http = require("http");
23const ws = require("ws");
24/**
25 * A web socket host.
26 */
27class WebSocketHost extends events.EventEmitter {
28 /**
29 * Initializes a new instance of that class.
30 *
31 * @param {WebSocketHostOptions} [options] Custom options for the host.
32 */
33 constructor(options) {
34 super();
35 this.options = options;
36 if (!this.options) {
37 this.options = {};
38 }
39 }
40 /**
41 * Gets if the server is currently running or not.
42 */
43 get isRunning() {
44 return !!this._server;
45 }
46 /**
47 * Starts the host.
48 *
49 * @return {Promise<boolean>} The promise that indicates if operation was succesfull or not.
50 */
51 start() {
52 return new Promise(async (resolve, reject) => {
53 try {
54 if (this.isRunning) {
55 resolve(false);
56 return;
57 }
58 let serverFactory = this.options.serverFactory;
59 if (!serverFactory) {
60 serverFactory = () => {
61 return http.createServer();
62 };
63 }
64 let port = parseInt(index_1.toStringSafe(this.options.port)
65 .trim());
66 if (isNaN(port)) {
67 port = 5979;
68 }
69 const NEW_SERVER = await Promise.resolve(serverFactory());
70 if (!NEW_SERVER) {
71 resolve(false);
72 return;
73 }
74 NEW_SERVER.once('error', (err) => {
75 reject(err);
76 });
77 const VERIFY_CLIENT = async (info, callback) => {
78 let isValid = true;
79 try {
80 if (this.options.verifyClient) {
81 isValid = index_1.toBooleanSafe(await Promise.resolve(this.options.verifyClient({
82 isSecure: info.secure,
83 request: info.req,
84 })));
85 }
86 }
87 catch (_a) {
88 isValid = false;
89 }
90 if (isValid) {
91 callback(true);
92 }
93 else {
94 callback(false, 401);
95 }
96 };
97 const WSS = new ws.Server({
98 server: NEW_SERVER,
99 verifyClient: VERIFY_CLIENT,
100 });
101 WSS.on('error', (err) => {
102 /* ignore errors */
103 });
104 WSS.on('connection', (ws) => {
105 try {
106 const CONN = new WebSocketClient(this, ws);
107 CONN.init();
108 this.emit('connection', CONN);
109 }
110 catch (_a) {
111 try {
112 ws.close();
113 }
114 catch (_b) { }
115 }
116 });
117 NEW_SERVER.listen(port, () => {
118 this._server = NEW_SERVER;
119 resolve(true);
120 });
121 }
122 catch (e) {
123 reject(e);
124 }
125 });
126 }
127 /**
128 * Stops the host.
129 *
130 * @return {Promise<boolean>} The promise that indicates if operation was succesfull or not.
131 */
132 stop() {
133 return new Promise((resolve, reject) => {
134 try {
135 const SERVER = this._server;
136 if (!SERVER) {
137 resolve(false);
138 return;
139 }
140 SERVER.close((err) => {
141 if (err) {
142 reject(err);
143 }
144 else {
145 this._server = null;
146 resolve(true);
147 }
148 });
149 }
150 catch (e) {
151 reject(e);
152 }
153 });
154 }
155}
156exports.WebSocketHost = WebSocketHost;
157/**
158 * A web socket client.
159 */
160class WebSocketClient extends events.EventEmitter {
161 /**
162 * Initializes a new instance of that class.
163 *
164 * @param {WebSocketHost} host The underlying host.
165 * @param {ws} socket The underlying socket.
166 */
167 constructor(host, socket) {
168 super();
169 this.host = host;
170 this.socket = socket;
171 }
172 /**
173 * Initializes the instance.
174 */
175 init() {
176 this.socket.on('error', (err) => {
177 /* ignore errors */
178 });
179 this.socket.on('message', (data) => {
180 try {
181 const MSG = JSON.parse(index_1.toStringSafe(data));
182 if (MSG) {
183 this.emit('message', MSG);
184 const TYPE = index_1.normalizeString(MSG.type);
185 this.emit('message.' + TYPE, MSG, TYPE);
186 }
187 }
188 catch (_a) { }
189 });
190 this.socket.once('close', () => {
191 this.emit('close');
192 });
193 }
194 onType(checker, listener) {
195 let predicate = checker;
196 if (!_.isFunction(predicate)) {
197 if (_.isRegExp(checker)) {
198 predicate = (t) => checker.test(t);
199 }
200 else {
201 predicate = (t) => t === index_1.normalizeString(checker);
202 }
203 }
204 const MSG_LISTENER = (msg) => {
205 const TYPE = index_1.normalizeString(msg.type);
206 if (index_1.toBooleanSafe(predicate(TYPE))) {
207 listener(msg.data, TYPE);
208 }
209 };
210 this.on('message', MSG_LISTENER);
211 return MSG_LISTENER;
212 }
213 /**
214 * Sends a message to the remote client.
215 *
216 * @param {string} type The type.
217 * @param {any} [data] The data to send.
218 */
219 send(type, data) {
220 return new Promise((resolve, reject) => {
221 try {
222 const MSG = {
223 data: data,
224 type: index_1.normalizeString(type),
225 };
226 this.socket.send(JSON.stringify(MSG), (err) => {
227 if (err) {
228 reject(err);
229 }
230 else {
231 resolve();
232 }
233 });
234 }
235 catch (e) {
236 reject(e);
237 }
238 });
239 }
240}
241exports.WebSocketClient = WebSocketClient;
242//# sourceMappingURL=websockets.js.map
\No newline at end of file