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 Bootstrap from
'../../Bootstrap';
17 import UIServiceWorkerBroadcastChannel from
'../../UIServiceWorkerBroadcastChannel';
18 import type { 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 requestHandlers
: Map
<ProcedureName
, ProtocolRequestHandler
>;
26 protected uiServiceWorkerBroadcastChannel
: UIServiceWorkerBroadcastChannel
;
28 constructor(uiServer
: AbstractUIServer
, version
: ProtocolVersion
) {
29 this.version
= version
;
30 this.uiServer
= uiServer
;
31 this.requestHandlers
= 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.uiServiceWorkerBroadcastChannel
= new UIServiceWorkerBroadcastChannel(this);
39 public async requestHandler(request
: RawData
): Promise
<void> {
40 let messageId
: string;
41 let command
: ProcedureName
;
42 let requestPayload
: RequestPayload
| undefined;
43 let responsePayload
: ResponsePayload
;
45 [messageId
, command
, requestPayload
] = this.requestValidation(request
);
47 if (this.requestHandlers
.has(command
) === false) {
49 `${command} is not implemented to handle message payload ${JSON.stringify(
57 // Call the request handler to build the response payload
58 responsePayload
= await this.requestHandlers
.get(command
)(messageId
, requestPayload
);
62 `${this.uiServer.logPrefix(moduleName, 'messageHandler')} Handle request error:`,
66 status: ResponseStatus
.FAILURE
,
70 errorMessage
: (error
as Error).message
,
71 errorStack
: (error
as Error).stack
,
75 if (responsePayload
!== undefined) {
77 this.uiServer
.sendResponse(this.buildProtocolResponse(messageId
?? 'error', responsePayload
));
83 procedureName
: ProcedureName
,
84 requestPayload
: RequestPayload
86 this.uiServer
.sendRequest(this.buildProtocolRequest(messageId
, procedureName
, requestPayload
));
89 public sendResponse(messageId
: string, responsePayload
: ResponsePayload
): void {
90 this.uiServer
.sendResponse(this.buildProtocolResponse(messageId
, responsePayload
));
93 public logPrefix(modName
: string, methodName
: string): string {
94 return this.uiServer
.logPrefix(modName
, methodName
);
97 private buildProtocolRequest(
99 procedureName
: ProcedureName
,
100 requestPayload
: RequestPayload
102 return JSON
.stringify([messageId
, procedureName
, requestPayload
] as ProtocolRequest
);
105 private buildProtocolResponse(messageId
: string, responsePayload
: ResponsePayload
): string {
106 return JSON
.stringify([messageId
, responsePayload
] as ProtocolResponse
);
109 // Validate the raw data received from the WebSocket
110 // TODO: should probably be moved to the ws verify clients callback
111 private requestValidation(rawData
: RawData
): ProtocolRequest
{
113 // `${this.uiServer.logPrefix(
116 // )} Raw data received: ${rawData.toString()}`
119 const data
= JSON
.parse(rawData
.toString()) as JsonType
[];
121 if (Array.isArray(data
) === false) {
122 throw new BaseError('UI protocol request is not an array');
125 if (data
.length
!== 3) {
126 throw new BaseError('UI protocol request is malformed');
129 return data
as ProtocolRequest
;
132 private handleListChargingStations(): ResponsePayload
{
133 // TODO: remove cast to unknown
135 status: ResponseStatus
.SUCCESS
,
136 ...Array.from(this.uiServer
.chargingStations
.values()),
137 } as unknown
as ResponsePayload
;
140 private async handleStartSimulator(): Promise
<ResponsePayload
> {
141 await Bootstrap
.getInstance().start();
142 return { status: ResponseStatus
.SUCCESS
};
145 private async handleStopSimulator(): Promise
<ResponsePayload
> {
146 await Bootstrap
.getInstance().stop();
147 return { status: ResponseStatus
.SUCCESS
};