1 import { RawData
} from
'ws';
3 import BaseError from
'../../../exception/BaseError';
4 import { JsonType
} from
'../../../types/JsonType';
8 ProtocolRequestHandler
,
13 } from
'../../../types/UIProtocol';
14 import logger from
'../../../utils/Logger';
15 import Utils from
'../../../utils/Utils';
16 import Bootstrap from
'../../Bootstrap';
17 import WorkerBroadcastChannel from
'../../WorkerBroadcastChannel';
18 import { AbstractUIServer
} from
'../AbstractUIServer';
20 const moduleName
= 'AbstractUIService';
22 export default abstract class AbstractUIService
{
23 protected readonly version
: ProtocolVersion
;
24 protected readonly uiServer
: AbstractUIServer
;
25 protected readonly messageHandlers
: Map
<ProcedureName
, ProtocolRequestHandler
>;
26 protected workerBroadcastChannel
: WorkerBroadcastChannel
;
28 constructor(uiServer
: AbstractUIServer
, version
: ProtocolVersion
) {
29 this.version
= version
;
30 this.uiServer
= uiServer
;
31 this.messageHandlers
= new Map
<ProcedureName
, ProtocolRequestHandler
>([
32 [ProcedureName
.LIST_CHARGING_STATIONS
, this.handleListChargingStations
.bind(this)],
33 [ProcedureName
.START_SIMULATOR
, this.handleStartSimulator
.bind(this)],
34 [ProcedureName
.STOP_SIMULATOR
, this.handleStopSimulator
.bind(this)],
36 this.workerBroadcastChannel
= new WorkerBroadcastChannel();
39 public async messageHandler(request
: RawData
): Promise
<void> {
40 let messageId
: string;
41 let command
: ProcedureName
;
42 let requestPayload
: JsonType
;
43 let responsePayload
: ResponsePayload
;
45 [messageId
, command
, requestPayload
] = this.dataValidation(request
);
47 if (this.messageHandlers
.has(command
) === false) {
50 `${command} is not implemented to handle message payload ${JSON.stringify(
57 // Call the message handler to build the response payload
58 responsePayload
= (await this.messageHandlers
.get(command
)(
60 )) as ResponsePayload
;
64 `${this.uiServer.logPrefix(moduleName, 'messageHandler')} Handle message error:`,
67 // Send the message response failure
68 this.uiServer
.sendResponse(
69 this.buildProtocolResponse(messageId
?? 'error', {
70 status: ResponseStatus
.FAILURE
,
73 errorMessage
: (error
as Error).message
,
74 errorStack
: (error
as Error).stack
,
80 // Send the message response success
81 this.uiServer
.sendResponse(this.buildProtocolResponse(messageId
, responsePayload
));
84 protected buildProtocolResponse(messageId
: string, payload
: ResponsePayload
): string {
85 return JSON
.stringify([messageId
, payload
] as ProtocolResponse
);
88 // Validate the raw data received from the WebSocket
89 // TODO: should probably be moved to the ws verify clients callback
90 private dataValidation(rawData
: RawData
): ProtocolRequest
{
92 `${this.uiServer.logPrefix(
95 )} Raw data received: ${rawData.toString()}`
97 const data
= JSON
.parse(rawData
.toString()) as JsonType
[];
99 if (Utils
.isIterable(data
) === false) {
100 throw new BaseError('UI protocol request is not iterable');
103 if (data
.length
!== 3) {
104 throw new BaseError('UI protocol request is malformed');
107 return data
as ProtocolRequest
;
110 private handleListChargingStations(): JsonType
{
112 status: ResponseStatus
.SUCCESS
,
113 ...Array.from(this.uiServer
.chargingStations
.values()),
117 private async handleStartSimulator(): Promise
<ResponsePayload
> {
118 await Bootstrap
.getInstance().start();
119 return { status: ResponseStatus
.SUCCESS
};
122 private async handleStopSimulator(): Promise
<ResponsePayload
> {
123 await Bootstrap
.getInstance().stop();
124 return { status: ResponseStatus
.SUCCESS
};