swaf/src/components/WebSocketServerComponent.ts

79 lines
3.0 KiB
TypeScript

import ApplicationComponent from "../ApplicationComponent";
import {Express, Request, Router} 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<void> {
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, router: Router): Promise<void> {
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>request, session);
listener.handle(socket, request, session).catch(err => {
Logger.error(err, 'Error in websocket listener.');
});
});
});
}
public async stop(): Promise<void> {
if (this.wss) {
await this.close('WebSocket server', this.wss, this.wss.close);
}
}
}