1 import { ProcedureName
, ResponseStatus
, type RequestPayload
} from
'@/types/UIProtocol';
2 import type { ProtocolResponse
, ResponsePayload
} from
'@/types/UIProtocol';
4 import Utils from
'./Utils';
5 import config from
'@/assets/config';
6 import { v4
as uuidv4
} from
'uuid';
8 type ResponseHandler
= {
9 procedureName
: ProcedureName
;
10 resolve
: (value
: ResponsePayload
| PromiseLike
<ResponsePayload
>) => void;
11 reject
: (reason
?: any) => void;
14 export default class UIClient
{
15 private static _instance
: UIClient
| null = null;
17 private _ws
!: WebSocket
;
18 private _responseHandlers
: Map
<string, ResponseHandler
>;
20 private constructor() {
22 this._responseHandlers
= new Map
<string, ResponseHandler
>();
25 public static getInstance() {
26 if (UIClient
._instance
=== null) {
27 UIClient
._instance
= new UIClient();
29 return UIClient
._instance
;
32 public registerWSonOpenListener(listener
: (event
: Event
) => void) {
33 this._ws
.addEventListener('open', listener
);
36 public async startSimulator(): Promise
<ResponsePayload
> {
37 return this.sendRequest(ProcedureName
.START_SIMULATOR
, {});
40 public async stopSimulator(): Promise
<ResponsePayload
> {
41 return this.sendRequest(ProcedureName
.STOP_SIMULATOR
, {});
44 public async listChargingStations(): Promise
<ResponsePayload
> {
45 return this.sendRequest(ProcedureName
.LIST_CHARGING_STATIONS
, {});
48 public async startChargingStation(hashId
: string): Promise
<ResponsePayload
> {
49 return this.sendRequest(ProcedureName
.START_CHARGING_STATION
, { hashIds
: [hashId
] });
52 public async stopChargingStation(hashId
: string): Promise
<ResponsePayload
> {
53 return this.sendRequest(ProcedureName
.STOP_CHARGING_STATION
, { hashIds
: [hashId
] });
56 public async openConnection(hashId
: string): Promise
<ResponsePayload
> {
57 return this.sendRequest(ProcedureName
.OPEN_CONNECTION
, {
62 public async closeConnection(hashId
: string): Promise
<ResponsePayload
> {
63 return this.sendRequest(ProcedureName
.CLOSE_CONNECTION
, {
68 public async startTransaction(
71 idTag
: string | undefined
72 ): Promise
<ResponsePayload
> {
73 return this.sendRequest(ProcedureName
.START_TRANSACTION
, {
80 public async stopTransaction(
82 transactionId
: number | undefined
83 ): Promise
<ResponsePayload
> {
84 return this.sendRequest(ProcedureName
.STOP_TRANSACTION
, {
90 public async startAutomaticTransactionGenerator(
93 ): Promise
<ResponsePayload
> {
94 return this.sendRequest(ProcedureName
.START_AUTOMATIC_TRANSACTION_GENERATOR
, {
96 connectorIds
: [connectorId
],
100 public async stopAutomaticTransactionGenerator(
103 ): Promise
<ResponsePayload
> {
104 return this.sendRequest(ProcedureName
.STOP_AUTOMATIC_TRANSACTION_GENERATOR
, {
106 connectorIds
: [connectorId
],
110 private openWS(): void {
111 this._ws
= new WebSocket(
112 `ws://${config.uiServer.host}:${config.uiServer.port}`,
113 config
.uiServer
.protocol
115 this._ws
.onmessage
= this.responseHandler
.bind(this);
116 this._ws
.onerror
= (errorEvent
) => {
117 console
.error('WebSocket error: ', errorEvent
);
119 this._ws
.onclose
= (closeEvent
) => {
120 console
.info('WebSocket close: ', closeEvent
);
124 private setResponseHandler(
126 procedureName
: ProcedureName
,
127 resolve
: (value
: ResponsePayload
| PromiseLike
<ResponsePayload
>) => void,
128 reject
: (reason
?: any) => void
130 this._responseHandlers
.set(id
, { procedureName
, resolve
, reject
});
133 private getResponseHandler(id
: string): ResponseHandler
| undefined {
134 return this._responseHandlers
.get(id
);
137 private deleteResponseHandler(id
: string): boolean {
138 return this._responseHandlers
.delete(id
);
141 private async sendRequest(
142 command
: ProcedureName
,
144 ): Promise
<ResponsePayload
> {
146 return Utils
.promiseWithTimeout(
147 new Promise((resolve
, reject
) => {
149 const msg
= JSON
.stringify([uuid
, command
, data
]);
151 if (this._ws
.readyState
!== WebSocket
.OPEN
) {
154 if (this._ws
.readyState
=== WebSocket
.OPEN
) {
157 throw new Error(`Send request ${command} message: connection not opened`);
160 this.setResponseHandler(uuid
, command
, resolve
, reject
);
163 Error(`Send request ${command} message timeout`),
165 this._responseHandlers
.delete(uuid
);
170 private responseHandler(messageEvent
: MessageEvent
<string>): void {
171 const data
= JSON
.parse(messageEvent
.data
) as ProtocolResponse
;
173 if (Array.isArray(data
) === false) {
174 throw new Error('Response not an array: ' + JSON
.stringify(data
, null, 2));
177 const [uuid
, response
] = data
;
179 if (this._responseHandlers
.has(uuid
) === true) {
180 switch (response
.status) {
181 case ResponseStatus
.SUCCESS
:
182 this.getResponseHandler(uuid
)?.resolve(response
);
184 case ResponseStatus
.FAILURE
:
185 this.getResponseHandler(uuid
)?.reject(response
);
188 console
.error(`Response status not supported: ${response.status}`);
190 this.deleteResponseHandler(uuid
);
192 throw new Error('Not a response to a request: ' + JSON
.stringify(data
, null, 2));