Commit | Line | Data |
---|---|---|
a10297ba | 1 | import { Protocol, ProtocolCommand, ProtocolRequest, ProtocolVersion } from '../types/UIProtocol'; |
6a49ad23 | 2 | import WebSocket, { OPEN, Server, ServerOptions } from 'ws'; |
4198ad5c | 3 | |
383cb2ae | 4 | import AbstractUIService from './ui-websocket-services/AbstractUIService'; |
4198ad5c | 5 | import BaseError from '../exception/BaseError'; |
6a49ad23 | 6 | import Configuration from '../utils/Configuration'; |
4198ad5c | 7 | import { IncomingMessage } from 'http'; |
383cb2ae | 8 | import UIServiceFactory from './ui-websocket-services/UIServiceFactory'; |
4198ad5c | 9 | import Utils from '../utils/Utils'; |
bc464bb1 | 10 | import getLogger from '../utils/Logger'; |
4198ad5c | 11 | |
6a49ad23 | 12 | export default class UIWebSocketServer extends Server { |
de9136ae JB |
13 | public readonly chargingStations: Set<string>; |
14 | public readonly uiServices: Map<ProtocolVersion, AbstractUIService>; | |
4198ad5c | 15 | |
6a49ad23 | 16 | public constructor(options?: ServerOptions, callback?: () => void) { |
4198ad5c | 17 | // Create the WebSocket Server |
6a49ad23 | 18 | super(options ?? Configuration.getUIWebSocketServer().options, callback); |
de9136ae JB |
19 | this.chargingStations = new Set<string>(); |
20 | this.uiServices = new Map<ProtocolVersion, AbstractUIService>(); | |
21 | for (const version of Object.values(ProtocolVersion)) { | |
22 | this.uiServices.set(version, UIServiceFactory.getUIServiceImplementation(version, this)); | |
23 | } | |
4198ad5c JB |
24 | } |
25 | ||
d1888640 | 26 | public broadcastToClients(message: string): void { |
4198ad5c | 27 | for (const client of this.clients) { |
6a49ad23 | 28 | if (client?.readyState === OPEN) { |
4198ad5c JB |
29 | client.send(message); |
30 | } | |
31 | } | |
32 | } | |
33 | ||
34 | public start(): void { | |
35 | this.on('connection', (socket: WebSocket, request: IncomingMessage): void => { | |
36 | const protocolIndex = socket.protocol.indexOf(Protocol.UI); | |
37 | const version = socket.protocol.substring(protocolIndex + Protocol.UI.length) as ProtocolVersion; | |
de9136ae | 38 | if (!this.uiServices.has(version)) { |
410a760d | 39 | throw new BaseError(`Could not find a UI service implementation for UI protocol version ${version}`); |
4198ad5c JB |
40 | } |
41 | // FIXME: check connection validity | |
42 | socket.on('message', (messageData) => { | |
43 | let [command, payload]: ProtocolRequest = [ProtocolCommand.UNKNOWN, {}]; | |
44 | const protocolRequest = JSON.parse(messageData.toString()) as ProtocolRequest; | |
45 | if (Utils.isIterable(protocolRequest)) { | |
46 | [command, payload] = protocolRequest; | |
47 | } else { | |
410a760d | 48 | throw new BaseError('UI protocol request is not iterable'); |
4198ad5c | 49 | } |
de9136ae | 50 | this.uiServices.get(version).handleMessage(command, payload).catch(() => { |
bc464bb1 | 51 | getLogger().error(`${this.logPrefix()} Error while handling command %s message: %j`, command, payload); |
4198ad5c JB |
52 | }); |
53 | }); | |
54 | socket.on('error', (error) => { | |
bc464bb1 | 55 | getLogger().error(`${this.logPrefix()} Error on WebSocket: %j`, error); |
4198ad5c JB |
56 | }); |
57 | }); | |
58 | } | |
59 | ||
60 | public stop(): void { | |
61 | this.close(); | |
62 | } | |
63 | ||
64 | public logPrefix(): string { | |
410a760d | 65 | return Utils.logPrefix(' UI WebSocket Server:'); |
4198ad5c JB |
66 | } |
67 | } |