2021-05-03 19:29:22 +02:00
|
|
|
import config from "config";
|
2020-04-22 15:52:17 +02:00
|
|
|
import cookie from "cookie";
|
|
|
|
import cookieParser from "cookie-parser";
|
2021-05-03 19:29:22 +02:00
|
|
|
import {Express, Request} from "express";
|
2021-01-25 16:36:15 +01:00
|
|
|
import {Session} from "express-session";
|
2021-11-08 00:52:33 +01:00
|
|
|
import {WebSocketServer} from "ws";
|
2021-05-03 19:29:22 +02:00
|
|
|
|
|
|
|
import Application from "../Application.js";
|
|
|
|
import ApplicationComponent from "../ApplicationComponent.js";
|
|
|
|
import {logger} from "../Logger.js";
|
|
|
|
import WebSocketListener from "../WebSocketListener.js";
|
|
|
|
import ExpressAppComponent from "./ExpressAppComponent.js";
|
2021-05-13 16:03:59 +02:00
|
|
|
import FrontendToolsComponent from "./FrontendToolsComponent.js";
|
2021-05-03 19:29:22 +02:00
|
|
|
import RedisComponent from "./RedisComponent.js";
|
2020-04-22 15:52:17 +02:00
|
|
|
|
2020-09-25 22:03:22 +02:00
|
|
|
export default class WebSocketServerComponent extends ApplicationComponent {
|
2021-11-08 00:52:33 +01:00
|
|
|
private wss?: WebSocketServer;
|
2020-04-22 15:52:17 +02:00
|
|
|
|
2021-05-13 16:03:59 +02:00
|
|
|
public async init(): Promise<void> {
|
|
|
|
const app = this.getApp();
|
2021-04-30 13:59:22 +02:00
|
|
|
|
2021-05-13 16:03:59 +02:00
|
|
|
app.require(ExpressAppComponent);
|
|
|
|
app.require(RedisComponent);
|
|
|
|
|
|
|
|
const globals = app.asOptional(FrontendToolsComponent)?.getGlobals();
|
|
|
|
if (globals) {
|
2021-06-01 14:38:53 +02:00
|
|
|
globals.set('websocketUrl', config.get('app.public_websocket_url'));
|
2021-05-13 16:03:59 +02:00
|
|
|
}
|
2020-04-22 15:52:17 +02:00
|
|
|
}
|
|
|
|
|
2020-09-25 23:42:15 +02:00
|
|
|
public async start(_app: Express): Promise<void> {
|
2021-05-13 16:03:59 +02:00
|
|
|
const app = this.getApp();
|
|
|
|
|
|
|
|
const listeners: { [p: string]: WebSocketListener<Application> } = app.getWebSocketListeners();
|
2021-11-08 00:52:33 +01:00
|
|
|
this.wss = new WebSocketServer({
|
2021-05-13 16:03:59 +02:00
|
|
|
server: app.as(ExpressAppComponent).getServer(),
|
2020-04-22 15:52:17 +02:00
|
|
|
}, () => {
|
2021-01-22 15:54:26 +01:00
|
|
|
logger.info(`Websocket server started over webserver.`);
|
2020-04-22 15:52:17 +02:00
|
|
|
}).on('error', (err) => {
|
2021-01-22 15:54:26 +01:00
|
|
|
logger.error(err, 'An error occurred in the websocket server.');
|
2020-04-22 15:52:17 +02:00
|
|
|
}).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) {
|
2020-07-19 17:37:10 +02:00
|
|
|
listener.handle(socket, request, null).catch(err => {
|
2021-01-22 15:54:26 +01:00
|
|
|
logger.error(err, 'Error in websocket listener.');
|
2020-07-19 17:37:10 +02:00
|
|
|
});
|
2020-04-22 15:52:17 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-01-22 15:54:26 +01:00
|
|
|
logger.debug(`Websocket on ${request.url}`);
|
2020-04-22 15:52:17 +02:00
|
|
|
|
|
|
|
const cookies = cookie.parse(request.headers.cookie);
|
|
|
|
const sid = cookieParser.signedCookie(cookies['connect.sid'], config.get('session.secret'));
|
|
|
|
|
|
|
|
if (!sid) {
|
|
|
|
socket.close(1002);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-05-13 16:03:59 +02:00
|
|
|
const store = app.as(RedisComponent).getStore();
|
2020-04-22 15:52:17 +02:00
|
|
|
store.get(sid, (err, session) => {
|
|
|
|
if (err || !session) {
|
2021-01-22 15:54:26 +01:00
|
|
|
logger.error(err, 'Error while initializing session in websocket.');
|
2020-04-22 15:52:17 +02:00
|
|
|
socket.close(1011);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
session.id = sid;
|
|
|
|
|
|
|
|
store.createSession(<Request>request, session);
|
2021-01-25 16:36:15 +01:00
|
|
|
listener.handle(socket, request, session as Session).catch(err => {
|
2021-01-22 15:54:26 +01:00
|
|
|
logger.error(err, 'Error in websocket listener.');
|
2020-04-22 15:52:17 +02:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public async stop(): Promise<void> {
|
2020-09-25 23:42:15 +02:00
|
|
|
const wss = this.wss;
|
|
|
|
if (wss) {
|
|
|
|
await this.close('WebSocket server', callback => wss.close(callback));
|
2020-04-22 15:52:17 +02:00
|
|
|
}
|
|
|
|
}
|
2020-09-25 23:42:15 +02:00
|
|
|
}
|