7 } from
'@/types/UIProtocol';
9 import Utils from
'./Utils';
10 import config from
'@/assets/config';
12 type ResponseHandler
= {
13 procedureName
: ProcedureName
;
14 resolve
: (value
: ResponsePayload
| PromiseLike
<ResponsePayload
>) => void;
15 reject
: (reason
?: any) => void;
18 export default class UIClient
{
19 private static _instance
: UIClient
| null = null;
21 private _ws
!: WebSocket
;
22 private _responseHandlers
: Map
<string, ResponseHandler
>;
24 private constructor() {
26 this._responseHandlers
= new Map
<string, ResponseHandler
>();
29 public static getInstance() {
30 if (UIClient
._instance
=== null) {
31 UIClient
._instance
= new UIClient();
33 return UIClient
._instance
;
36 public registerWSonOpenListener(listener
: (event
: Event
) => void) {
37 this._ws
.addEventListener('open', listener
);
40 public async startSimulator(): Promise
<ResponsePayload
> {
41 return this.sendRequest(ProcedureName
.START_SIMULATOR
, {});
44 public async stopSimulator(): Promise
<ResponsePayload
> {
45 return this.sendRequest(ProcedureName
.STOP_SIMULATOR
, {});
48 public async listChargingStations(): Promise
<ResponsePayload
> {
49 return this.sendRequest(ProcedureName
.LIST_CHARGING_STATIONS
, {});
52 public async startChargingStation(hashId
: string): Promise
<ResponsePayload
> {
53 return this.sendRequest(ProcedureName
.START_CHARGING_STATION
, { hashIds
: [hashId
] });
56 public async stopChargingStation(hashId
: string): Promise
<ResponsePayload
> {
57 return this.sendRequest(ProcedureName
.STOP_CHARGING_STATION
, { hashIds
: [hashId
] });
60 public async openConnection(hashId
: string): Promise
<ResponsePayload
> {
61 return this.sendRequest(ProcedureName
.OPEN_CONNECTION
, {
66 public async closeConnection(hashId
: string): Promise
<ResponsePayload
> {
67 return this.sendRequest(ProcedureName
.CLOSE_CONNECTION
, {
72 public async startTransaction(
75 idTag
: string | undefined
76 ): Promise
<ResponsePayload
> {
77 return this.sendRequest(ProcedureName
.START_TRANSACTION
, {
84 public async stopTransaction(
86 transactionId
: number | undefined
87 ): Promise
<ResponsePayload
> {
88 return this.sendRequest(ProcedureName
.STOP_TRANSACTION
, {
94 public async startAutomaticTransactionGenerator(
97 ): Promise
<ResponsePayload
> {
98 return this.sendRequest(ProcedureName
.START_AUTOMATIC_TRANSACTION_GENERATOR
, {
100 connectorIds
: [connectorId
],
104 public async stopAutomaticTransactionGenerator(
107 ): Promise
<ResponsePayload
> {
108 return this.sendRequest(ProcedureName
.STOP_AUTOMATIC_TRANSACTION_GENERATOR
, {
110 connectorIds
: [connectorId
],
114 private openWS(): void {
115 this._ws
= new WebSocket(
116 `ws://${config.uiServer.host}:${config.uiServer.port}`,
117 config
.uiServer
.protocol
119 this._ws
.onmessage
= this.responseHandler
.bind(this);
120 this._ws
.onerror
= (errorEvent
) => {
121 console
.error('WebSocket error: ', errorEvent
);
123 this._ws
.onclose
= (closeEvent
) => {
124 console
.info('WebSocket closed: ', closeEvent
);
128 private setResponseHandler(
130 procedureName
: ProcedureName
,
131 resolve
: (value
: ResponsePayload
| PromiseLike
<ResponsePayload
>) => void,
132 reject
: (reason
?: any) => void
134 this._responseHandlers
.set(id
, { procedureName
, resolve
, reject
});
137 private getResponseHandler(id
: string): ResponseHandler
| undefined {
138 return this._responseHandlers
.get(id
);
141 private deleteResponseHandler(id
: string): boolean {
142 return this._responseHandlers
.delete(id
);
145 private async sendRequest(
146 command
: ProcedureName
,
148 ): Promise
<ResponsePayload
> {
150 return Utils
.promiseWithTimeout(
151 new Promise((resolve
, reject
) => {
152 uuid
= crypto
.randomUUID();
153 const msg
= JSON
.stringify([uuid
, command
, data
]);
155 if (this._ws
.readyState
!== WebSocket
.OPEN
) {
158 if (this._ws
.readyState
=== WebSocket
.OPEN
) {
161 throw new Error(`Send request '${command}' message: connection not opened`);
164 this.setResponseHandler(uuid
, command
, resolve
, reject
);
167 Error(`Send request '${command}' message timeout`),
169 this._responseHandlers
.delete(uuid
);
174 private responseHandler(messageEvent
: MessageEvent
<string>): void {
175 const response
= JSON
.parse(messageEvent
.data
) as ProtocolResponse
;
177 if (Array.isArray(response
) === false) {
178 throw new Error(`Response not an array: ${JSON.stringify(response, null, 2)}`);
181 const [uuid
, responsePayload
] = response
;
183 if (this._responseHandlers
.has(uuid
) === true) {
184 switch (responsePayload
.status) {
185 case ResponseStatus
.SUCCESS
:
186 this.getResponseHandler(uuid
)?.resolve(responsePayload
);
188 case ResponseStatus
.FAILURE
:
189 this.getResponseHandler(uuid
)?.reject(responsePayload
);
192 console
.error(`Response status not supported: ${responsePayload.status}`);
194 this.deleteResponseHandler(uuid
);
196 throw new Error(`Not a response to a request: ${JSON.stringify(response, null, 2)}`);