|
@@ -7,13 +7,17 @@ import { ServerProperties } from './ServerProperties';
|
|
|
import { i18nLoader, $$ } from '../base/i18n';
|
|
|
import path from 'path';
|
|
|
import fs from 'fs';
|
|
|
+import http from 'http';
|
|
|
+import { Server as WebSocketServer, WebSocket as WS } from 'ws';
|
|
|
import { InvalidMiddlewareException } from '../base/exceptions';
|
|
|
import { InvalidRouteException } from '../base/exceptions';
|
|
|
import { ServerNotInitializedException } from '../base/exceptions';
|
|
|
+import { WebSocketHandler } from '../base/websocket';
|
|
|
|
|
|
/** @sealed */
|
|
|
class Server {
|
|
|
private instance: Express;
|
|
|
+ private httpServer: http.Server;
|
|
|
private readonly port: number;
|
|
|
private readonly logger: Logger;
|
|
|
private i18n: i18nLoader;
|
|
@@ -21,6 +25,8 @@ class Server {
|
|
|
public static readonly defaultMiddlewaresPath = '../middlewares';
|
|
|
public static readonly defaultRoutesPath = '../routes';
|
|
|
private readonly httpHandlers: {[key: string]: HttpHandler};
|
|
|
+ private readonly wsHandlers: {[url: string]: WebSocketHandler};
|
|
|
+ private readonly wsServers: {[url: string]: WebSocketServer};
|
|
|
private initialized: boolean;
|
|
|
|
|
|
private readonly i18nPath?: string;
|
|
@@ -32,12 +38,15 @@ class Server {
|
|
|
|
|
|
public constructor(properties: ServerProperties) {
|
|
|
this.instance = express();
|
|
|
+ this.httpServer = http.createServer(this.instance);
|
|
|
this.port = properties.port;
|
|
|
this.i18n = i18nLoader.getInstance();
|
|
|
if(properties.locale)
|
|
|
this.i18n.setLocale(properties.locale);
|
|
|
this.logger = new Logger();
|
|
|
this.httpHandlers = {};
|
|
|
+ this.wsHandlers = properties.wsHandlers || {};
|
|
|
+ this.wsServers = {};
|
|
|
this.i18nPath = properties.i18nPath;
|
|
|
this.middlewaresPath = properties.middlewaresPath;
|
|
|
this.routesPath = properties.routesPath;
|
|
@@ -67,6 +76,10 @@ class Server {
|
|
|
await this.registerMiddlewares(this.middlewaresPath);
|
|
|
if(this.routesPath)
|
|
|
await this.registerRoutes(this.routesPath);
|
|
|
+ if(Object.keys(this.wsHandlers).length > 0) {
|
|
|
+ this.registerWsServers();
|
|
|
+ this.applyWsHandlers();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private processHttpHandlers(): void {
|
|
@@ -104,6 +117,40 @@ class Server {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ public registerWsServers(): Server {
|
|
|
+ for(const url of Object.keys(this.wsHandlers)) {
|
|
|
+ const wsServer = this.wsServers[url] = new WebSocketServer({ noServer: true });
|
|
|
+ const wsHandler = this.wsHandlers[url];
|
|
|
+ wsServer.on(WebSocketHandler.Event.CONNECTION, (ws: WS) => {
|
|
|
+ wsHandler.onConnect(ws);
|
|
|
+ ws.on(WebSocketHandler.Event.MESSAGE, wsHandler.onMessage);
|
|
|
+ ws.on(WebSocketHandler.Event.ERROR, wsHandler.onError);
|
|
|
+ ws.on(WebSocketHandler.Event.CLOSE, wsHandler.onClose);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public applyWsHandlers(): Server {
|
|
|
+ this.httpServer.on('upgrade', (request, socket, head) => {
|
|
|
+ const url = request.url?.split('?')[0];
|
|
|
+ if(url && this.wsHandlers[url] && this.wsServers[url]) {
|
|
|
+ const wsServer = this.wsServers[url];
|
|
|
+ wsServer.handleUpgrade(request, socket, head, (ws) => {
|
|
|
+ wsServer.emit(WebSocketHandler.Event.CONNECTION, ws, request);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ socket.destroy();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public getWsConnections(url: string): Set<WS> | null {
|
|
|
+ const wsServer = this.wsServers[url];
|
|
|
+ return wsServer ? wsServer.clients : null;
|
|
|
+ }
|
|
|
+
|
|
|
public logInfo(message: string): void {
|
|
|
this.logger.getLogger().info(message);
|
|
|
}
|
|
@@ -186,7 +233,7 @@ class Server {
|
|
|
this.logInfo($$('org.crazydoctor.expressts.start', { 'port': this.port }));
|
|
|
if(callback) callback();
|
|
|
};
|
|
|
- this.instance.listen(this.port, cb);
|
|
|
+ this.httpServer.listen(this.port, cb);
|
|
|
}
|
|
|
}
|
|
|
|