1 import { RawData
} from
'ws';
3 import BaseError from
'../../../exception/BaseError';
4 import { Bootstrap
} from
'../../../internal';
5 import { JsonType
} from
'../../../types/JsonType';
9 ProtocolRequestHandler
,
15 } from
'../../../types/UIProtocol';
16 import logger from
'../../../utils/Logger';
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
| JsonType
): 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
);
61 logger
.error(`${this.logPrefix(moduleName, 'messageHandler')} Handle request error:`, error
);
63 status: ResponseStatus
.FAILURE
,
67 errorMessage
: (error
as Error).message
,
68 errorStack
: (error
as Error).stack
,
72 if (responsePayload
!== undefined) {
74 this.sendResponse(messageId
?? 'error', responsePayload
);
80 procedureName
: ProcedureName
,
81 requestPayload
: RequestPayload
83 this.uiServer
.sendRequest(this.buildProtocolRequest(messageId
, procedureName
, requestPayload
));
86 public sendResponse(messageId
: string, responsePayload
: ResponsePayload
): void {
87 this.uiServer
.sendResponse(this.buildProtocolResponse(messageId
, responsePayload
));
90 public logPrefix(modName
: string, methodName
: string): string {
91 return this.uiServer
.logPrefix(modName
, methodName
);
94 private buildProtocolRequest(
96 procedureName
: ProcedureName
,
97 requestPayload
: RequestPayload
99 return JSON
.stringify([messageId
, procedureName
, requestPayload
] as ProtocolRequest
);
102 private buildProtocolResponse(messageId
: string, responsePayload
: ResponsePayload
): string {
103 return JSON
.stringify([messageId
, responsePayload
] as ProtocolResponse
);
106 // Validate the raw data received from the WebSocket
107 // TODO: should probably be moved to the ws verify clients callback
108 private requestValidation(rawData
: RawData
| JsonType
): ProtocolRequest
{
110 // `${this.logPrefix(
112 // 'requestValidation'
113 // )} Data received in string format: ${rawData.toString()}`
116 const data
= JSON
.parse(rawData
.toString()) as JsonType
[];
118 if (Array.isArray(data
) === false) {
119 throw new BaseError('UI protocol request is not an array');
122 if (data
.length
!== 3) {
123 throw new BaseError('UI protocol request is malformed');
126 return data
as ProtocolRequest
;
129 private handleListChargingStations(): ResponsePayload
{
130 // TODO: remove cast to unknown
132 status: ResponseStatus
.SUCCESS
,
133 ...Array.from(this.uiServer
.chargingStations
.values()),
134 } as unknown
as ResponsePayload
;
137 private async handleStartSimulator(): Promise
<ResponsePayload
> {
138 await Bootstrap
.getInstance().start();
139 return { status: ResponseStatus
.SUCCESS
};
142 private async handleStopSimulator(): Promise
<ResponsePayload
> {
143 await Bootstrap
.getInstance().stop();
144 return { status: ResponseStatus
.SUCCESS
};