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