1 import { RawData
} from
'ws';
3 import BaseError from
'../../../exception/BaseError';
4 import { JsonType
} from
'../../../types/JsonType';
8 ProtocolRequestHandler
,
14 } from
'../../../types/UIProtocol';
15 import logger from
'../../../utils/Logger';
16 import Utils from
'../../../utils/Utils';
17 import Bootstrap from
'../../Bootstrap';
18 import WorkerBroadcastChannel from
'../../WorkerBroadcastChannel';
19 import { AbstractUIServer
} from
'../AbstractUIServer';
21 const moduleName
= 'AbstractUIService';
23 export default abstract class AbstractUIService
{
24 protected readonly version
: ProtocolVersion
;
25 protected readonly uiServer
: AbstractUIServer
;
26 protected readonly requestHandlers
: Map
<ProcedureName
, ProtocolRequestHandler
>;
27 protected workerBroadcastChannel
: WorkerBroadcastChannel
;
29 constructor(uiServer
: AbstractUIServer
, version
: ProtocolVersion
) {
30 this.version
= version
;
31 this.uiServer
= uiServer
;
32 this.requestHandlers
= new Map
<ProcedureName
, ProtocolRequestHandler
>([
33 [ProcedureName
.LIST_CHARGING_STATIONS
, this.handleListChargingStations
.bind(this)],
34 [ProcedureName
.START_SIMULATOR
, this.handleStartSimulator
.bind(this)],
35 [ProcedureName
.STOP_SIMULATOR
, this.handleStopSimulator
.bind(this)],
37 this.workerBroadcastChannel
= new WorkerBroadcastChannel();
40 public async requestHandler(request
: RawData
): Promise
<void> {
41 let messageId
: string;
42 let command
: ProcedureName
;
43 let requestPayload
: RequestPayload
;
44 let responsePayload
: ResponsePayload
;
46 [messageId
, command
, requestPayload
] = this.requestValidation(request
);
48 if (this.requestHandlers
.has(command
) === false) {
50 `${command} is not implemented to handle message payload ${JSON.stringify(
58 // Call the message handler to build the response payload
59 responsePayload
= await this.requestHandlers
.get(command
)(messageId
, requestPayload
);
63 `${this.uiServer.logPrefix(moduleName, 'messageHandler')} Handle message error:`,
66 // Send the message response failure
67 this.uiServer
.sendResponse(
68 this.buildProtocolResponse(messageId
?? 'error', {
69 status: ResponseStatus
.FAILURE
,
72 errorMessage
: (error
as Error).message
,
73 errorStack
: (error
as Error).stack
,
79 // Send the message response success
80 this.uiServer
.sendResponse(this.buildProtocolResponse(messageId
, responsePayload
));
83 protected buildProtocolRequest(
85 procedureName
: ProcedureName
,
86 payload
: RequestPayload
88 return JSON
.stringify([messageId
, procedureName
, payload
] as ProtocolRequest
);
91 protected buildProtocolResponse(messageId
: string, payload
: ResponsePayload
): string {
92 return JSON
.stringify([messageId
, payload
] as ProtocolResponse
);
95 // Validate the raw data received from the WebSocket
96 // TODO: should probably be moved to the ws verify clients callback
97 private requestValidation(rawData
: RawData
): ProtocolRequest
{
99 // `${this.uiServer.logPrefix(
102 // )} Raw data received: ${rawData.toString()}`
105 const data
= JSON
.parse(rawData
.toString()) as JsonType
[];
107 if (Utils
.isIterable(data
) === false) {
108 throw new BaseError('UI protocol request is not iterable');
111 if (data
.length
!== 3) {
112 throw new BaseError('UI protocol request is malformed');
115 return data
as ProtocolRequest
;
118 private handleListChargingStations(): ResponsePayload
{
119 // TODO: remove cast to unknown
121 status: ResponseStatus
.SUCCESS
,
122 ...Array.from(this.uiServer
.chargingStations
.values()),
123 } as unknown
as ResponsePayload
;
126 private async handleStartSimulator(): Promise
<ResponsePayload
> {
127 await Bootstrap
.getInstance().start();
128 return { status: ResponseStatus
.SUCCESS
};
131 private async handleStopSimulator(): Promise
<ResponsePayload
> {
132 await Bootstrap
.getInstance().stop();
133 return { status: ResponseStatus
.SUCCESS
};