import ApplicationComponent from "../ApplicationComponent"; import {Express, Request} from "express"; import WebSocket, {Server as WebSocketServer} from "ws"; import Logger from "../Logger"; import cookie from "cookie"; import cookieParser from "cookie-parser"; import config from "config"; import ExpressAppComponent from "./ExpressAppComponent"; import Application from "../Application"; import RedisComponent from "./RedisComponent"; import WebSocketListener from "../WebSocketListener"; export default class WebSocketServerComponent extends ApplicationComponent { private readonly application: Application; private readonly expressAppComponent: ExpressAppComponent; private readonly storeComponent: RedisComponent; private wss?: WebSocket.Server; constructor(application: Application, expressAppComponent: ExpressAppComponent, storeComponent: RedisComponent) { super(); this.expressAppComponent = expressAppComponent; this.application = application; this.storeComponent = storeComponent; } public async start(app: Express): Promise { const listeners: { [p: string]: WebSocketListener } = this.application.getWebSocketListeners(); this.wss = new WebSocketServer({ server: this.expressAppComponent.getServer(), }, () => { Logger.info(`Websocket server started over webserver.`); }).on('error', (err) => { Logger.error(err, 'An error occurred in the websocket server.'); }).on('connection', (socket, request) => { const listener = request.url ? listeners[request.url] : null; if (!listener) { socket.close(1002, `Path not found ${request.url}`); return; } else if (!request.headers.cookie) { socket.close(1002, `Can't process request without cookies.`); return; } Logger.debug(`Websocket on ${request.url}`); const cookies = cookie.parse(request.headers.cookie); const sid = cookieParser.signedCookie(cookies['connect.sid'], config.get('session.secret')); if (!sid) { socket.close(1002); return; } const store = this.storeComponent.getStore(); store.get(sid, (err, session) => { if (err || !session) { Logger.error(err, 'Error while initializing session in websocket.'); socket.close(1011); return; } session.id = sid; store.createSession(request, session); listener.handle(socket, request, session).catch(err => { Logger.error(err, 'Error in websocket listener.'); }); }); }); } public async stop(): Promise { if (this.wss) { await this.close('WebSocket server', this.wss, this.wss.close); } } }