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 UIServiceWorkerBroadcastChannel from
'../../UIServiceWorkerBroadcastChannel';
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 uiServiceWorkerBroadcastChannel
: UIServiceWorkerBroadcastChannel
;
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.uiServiceWorkerBroadcastChannel
= new UIServiceWorkerBroadcastChannel(this);
40 public async requestHandler(request
: RawData
): Promise
<void> {
41 let messageId
: string;
42 let command
: ProcedureName
;
43 let requestPayload
: RequestPayload
| undefined;
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 request handler to build the response payload
59 responsePayload
= await this.requestHandlers
.get(command
)(messageId
, requestPayload
);
63 `${this.uiServer.logPrefix(moduleName, 'messageHandler')} Handle request error:`,
67 status: ResponseStatus
.FAILURE
,
71 errorMessage
: (error
as Error).message
,
72 errorStack
: (error
as Error).stack
,
76 if (responsePayload
!== undefined) {
78 this.uiServer
.sendResponse(this.buildProtocolResponse(messageId
?? 'error', responsePayload
));
84 procedureName
: ProcedureName
,
85 requestPayload
: RequestPayload
87 this.uiServer
.sendRequest(this.buildProtocolRequest(messageId
, procedureName
, requestPayload
));
90 public sendResponse(messageId
: string, responsePayload
: ResponsePayload
): void {
91 this.uiServer
.sendResponse(this.buildProtocolResponse(messageId
, responsePayload
));
94 public logPrefix(modName
: string, methodName
: string): string {
95 return this.uiServer
.logPrefix(modName
, methodName
);
98 private buildProtocolRequest(
100 procedureName
: ProcedureName
,
101 requestPayload
: RequestPayload
103 return JSON
.stringify([messageId
, procedureName
, requestPayload
] as ProtocolRequest
);
106 private buildProtocolResponse(messageId
: string, responsePayload
: ResponsePayload
): string {
107 return JSON
.stringify([messageId
, responsePayload
] as ProtocolResponse
);
110 // Validate the raw data received from the WebSocket
111 // TODO: should probably be moved to the ws verify clients callback
112 private requestValidation(rawData
: RawData
): ProtocolRequest
{
114 // `${this.uiServer.logPrefix(
117 // )} Raw data received: ${rawData.toString()}`
120 const data
= JSON
.parse(rawData
.toString()) as JsonType
[];
122 if (Utils
.isIterable(data
) === false) {
123 throw new BaseError('UI protocol request is not iterable');
126 if (data
.length
!== 3) {
127 throw new BaseError('UI protocol request is malformed');
130 return data
as ProtocolRequest
;
133 private handleListChargingStations(): ResponsePayload
{
134 // TODO: remove cast to unknown
136 status: ResponseStatus
.SUCCESS
,
137 ...Array.from(this.uiServer
.chargingStations
.values()),
138 } as unknown
as ResponsePayload
;
141 private async handleStartSimulator(): Promise
<ResponsePayload
> {
142 await Bootstrap
.getInstance().start();
143 return { status: ResponseStatus
.SUCCESS
};
146 private async handleStopSimulator(): Promise
<ResponsePayload
> {
147 await Bootstrap
.getInstance().stop();
148 return { status: ResponseStatus
.SUCCESS
};