Fix UI WebSocket server protocol parsing at connection
[e-mobility-charging-stations-simulator.git] / src / charging-station / ui-server / UIWebSocketServer.ts
1 import type { IncomingMessage } from 'http';
2
3 import WebSocket from 'ws';
4
5 import type { ServerOptions } from '../../types/ConfigurationData';
6 import Configuration from '../../utils/Configuration';
7 import logger from '../../utils/Logger';
8 import Utils from '../../utils/Utils';
9 import { AbstractUIServer } from './AbstractUIServer';
10 import UIServiceFactory from './ui-services/UIServiceFactory';
11 import { UIServiceUtils } from './ui-services/UIServiceUtils';
12
13 const moduleName = 'UIWebSocketServer';
14
15 export default class UIWebSocketServer extends AbstractUIServer {
16 public constructor(options?: ServerOptions) {
17 super();
18 this.server = new WebSocket.Server(options ?? Configuration.getUIServer().options);
19 }
20
21 public start(): void {
22 this.server.on('connection', (socket: WebSocket, request: IncomingMessage): void => {
23 const [protocol, version] = UIServiceUtils.getProtocolAndVersion(socket.protocol);
24 if (UIServiceUtils.isProtocolAndVersionSupported(protocol, version) === false) {
25 logger.error(
26 `${this.logPrefix(
27 moduleName,
28 'start.server.onconnection'
29 )} Unsupported UI protocol version: '${protocol}${version}'`
30 );
31 socket.close();
32 }
33 if (!this.uiServices.has(version)) {
34 this.uiServices.set(version, UIServiceFactory.getUIServiceImplementation(version, this));
35 }
36 // FIXME: check connection validity
37 socket.on('message', (rawData) => {
38 this.uiServices
39 .get(version)
40 .requestHandler(rawData)
41 .catch(() => {
42 /* Error caught by AbstractUIService */
43 });
44 });
45 socket.on('error', (error) => {
46 logger.error(
47 `${this.logPrefix(moduleName, 'start.socket.onerror')} Error on WebSocket:`,
48 error
49 );
50 });
51 });
52 }
53
54 public stop(): void {
55 this.chargingStations.clear();
56 }
57
58 public sendRequest(request: string): void {
59 this.broadcastToClients(request);
60 }
61
62 public sendResponse(response: string): void {
63 // TODO: send response only to the client that sent the request
64 this.broadcastToClients(response);
65 }
66
67 public logPrefix(modName?: string, methodName?: string): string {
68 const logMsg =
69 modName && methodName
70 ? ` UI WebSocket Server | ${modName}.${methodName}:`
71 : ' UI WebSocket Server |';
72 return Utils.logPrefix(logMsg);
73 }
74
75 private broadcastToClients(message: string): void {
76 for (const client of (this.server as WebSocket.Server).clients) {
77 if (client?.readyState === WebSocket.OPEN) {
78 client.send(message);
79 }
80 }
81 }
82 }