{
"_type": "export",
"__export_format": 4,
- "__export_date": "2022-09-08T22:23:58.294Z",
+ "__export_date": "2022-09-09T05:06:59.623Z",
"__export_source": "insomnia.desktop.app:v2022.5.1",
"resources": [
{
"_id": "req_606dcee139984772877def40fcbb5c76",
"parentId": "wrk_d64b10b1e0c14563a80484ee684b5205",
- "modified": 1662675789048,
+ "modified": 1662699976610,
"created": 1661789624987,
"url": "{{baseUrl}}/{{protocol}}/{{version}}/listChargingStations",
"name": "listChargingStations",
{
"_id": "req_7d5f9506e7ac49208a4f960a7740663e",
"parentId": "wrk_d64b10b1e0c14563a80484ee684b5205",
- "modified": 1662675781452,
+ "modified": 1662700001883,
"created": 1661789624990,
"url": "{{baseUrl}}/{{protocol}}/{{version}}/startSimulator",
"name": "startSimulator",
{
"_id": "req_59056be11534481c80a0b0da32e2a06a",
"parentId": "wrk_d64b10b1e0c14563a80484ee684b5205",
- "modified": 1662675782590,
+ "modified": 1662700001136,
"created": 1661789624994,
"url": "{{baseUrl}}/{{protocol}}/{{version}}/stopSimulator",
"name": "stopSimulator",
{
"_id": "req_aad7fd6db4c64869b60048b915010efc",
"parentId": "wrk_d64b10b1e0c14563a80484ee684b5205",
- "modified": 1662675784826,
+ "modified": 1662699999845,
"created": 1661789624998,
"url": "{{baseUrl}}/{{protocol}}/{{version}}/startChargingStation",
"name": "startChargingStation",
{
"_id": "req_d72d91cf3fb044179b8ae9d92a74f99c",
"parentId": "wrk_d64b10b1e0c14563a80484ee684b5205",
- "modified": 1662674004751,
+ "modified": 1662699974387,
"created": 1661789625002,
"url": "{{baseUrl}}/{{protocol}}/{{version}}/stopChargingStation",
"name": "stopChargingStation",
{
"_id": "req_747f458d196f4681b5fe15204b0067aa",
"parentId": "wrk_d64b10b1e0c14563a80484ee684b5205",
- "modified": 1662675794900,
+ "modified": 1662699923383,
"created": 1661789625005,
"url": "{{baseUrl}}/{{protocol}}/{{version}}/openConnection",
"name": "openConnection",
{
"_id": "req_401e6a62a33c4b6c90aaa2e019daab6d",
"parentId": "wrk_d64b10b1e0c14563a80484ee684b5205",
- "modified": 1662675791687,
+ "modified": 1662699980072,
"created": 1661789625014,
"url": "{{baseUrl}}/{{protocol}}/{{version}}/closeConnection",
"name": "closeConnection",
{
"_id": "req_2f757efe92fb4936ad4fa4b6763f9293",
"parentId": "wrk_d64b10b1e0c14563a80484ee684b5205",
- "modified": 1662675797662,
+ "modified": 1662699966562,
"created": 1661789625017,
"url": "{{baseUrl}}/{{protocol}}/{{version}}/startTransaction",
"name": "startTransaction",
"username": "{{username}}",
"password": "{{password}}"
},
- "metaSortKey": -999999750,
+ "metaSortKey": -999999587.5,
"isPrivate": false,
"settingStoreCookies": true,
"settingSendCookies": true,
{
"_id": "req_7c285fb6cb6948a08235a6c73cbeb1f9",
"parentId": "wrk_d64b10b1e0c14563a80484ee684b5205",
- "modified": 1662675801164,
+ "modified": 1662699963660,
"created": 1661789625020,
"url": "{{baseUrl}}/{{protocol}}/{{version}}/stopTransaction",
"name": "stopTransaction",
"username": "{{username}}",
"password": "{{password}}"
},
- "metaSortKey": -999999700,
+ "metaSortKey": -999999575,
"isPrivate": false,
"settingStoreCookies": true,
"settingSendCookies": true,
{
"_id": "req_b33c704fe3464dc5a5d3694abd9320d0",
"parentId": "wrk_d64b10b1e0c14563a80484ee684b5205",
- "modified": 1662675804146,
+ "modified": 1662699972371,
"created": 1661803778569,
"url": "{{baseUrl}}/{{protocol}}/{{version}}/startAutomaticTransactionGenerator",
"name": "startAutomaticTransactionGenerator",
{
"_id": "req_24c1c55fe3ba4ddb94702408f21a64df",
"parentId": "wrk_d64b10b1e0c14563a80484ee684b5205",
- "modified": 1662675807062,
+ "modified": 1662699969481,
"created": 1661803846882,
"url": "{{baseUrl}}/{{protocol}}/{{version}}/stopAutomaticTransactionGenerator",
"name": "stopAutomaticTransactionGenerator",
{
"_id": "req_6a78267706094fb59d85ed1531e07a55",
"parentId": "wrk_d64b10b1e0c14563a80484ee684b5205",
- "modified": 1662675809951,
+ "modified": 1662699960920,
"created": 1662330215407,
"url": "{{baseUrl}}/{{protocol}}/{{version}}/statusNotification",
"name": "statusNotification",
{
"_id": "req_61efafe9f4a14c268b948b9f9c5c4195",
"parentId": "wrk_d64b10b1e0c14563a80484ee684b5205",
- "modified": 1662675812274,
+ "modified": 1662699996869,
"created": 1662409405256,
"url": "{{baseUrl}}/{{protocol}}/{{version}}/heartbeat",
"name": "heartbeat",
{
"_id": "req_9633f79d949d491e8b6892eed08bd198",
"parentId": "wrk_d64b10b1e0c14563a80484ee684b5205",
- "modified": 1662675815887,
+ "modified": 1662700003452,
"created": 1662648910935,
"url": "{{baseUrl}}/{{protocol}}/{{version}}/authorize",
"name": "authorize",
{
"_id": "req_5874d988a93a4d28b860b7ab65e534e0",
"parentId": "wrk_d64b10b1e0c14563a80484ee684b5205",
- "modified": 1662675817875,
+ "modified": 1662700004341,
"created": 1662673259612,
"url": "{{baseUrl}}/{{protocol}}/{{version}}/meterValues",
"name": "meterValues",
import { RequestCommand } from '../types/ocpp/Requests';
import {
AuthorizationStatus,
- AuthorizeRequest,
- AuthorizeResponse,
- StartTransactionRequest,
- StartTransactionResponse,
+ type AuthorizeRequest,
+ type AuthorizeResponse,
+ type StartTransactionRequest,
+ type StartTransactionResponse,
StopTransactionReason,
- StopTransactionResponse,
+ type StopTransactionResponse,
} from '../types/ocpp/Transaction';
import Constants from '../utils/Constants';
import logger from '../utils/Logger';
);
this.initialize();
Configuration.getUIServer().enabled === true &&
- (this.uiServer = UIServerFactory.getUIServerImplementation(
- Configuration.getUIServer().type,
- Configuration.getUIServer()
- ));
+ (this.uiServer = UIServerFactory.getUIServerImplementation(Configuration.getUIServer()));
Configuration.getPerformanceStorage().enabled === true &&
(this.storage = StorageFactory.getStorage(
Configuration.getPerformanceStorage().type,
export abstract class AbstractUIServer {
public readonly chargingStations: Map<string, ChargingStationData>;
- protected httpServer: Server;
- protected responseHandlers: Map<string, ServerResponse | WebSocket>;
+ protected readonly httpServer: Server;
+ protected readonly responseHandlers: Map<string, ServerResponse | WebSocket>;
protected readonly uiServices: Map<ProtocolVersion, AbstractUIService>;
public constructor(protected readonly uiServerConfiguration: UIServerConfiguration) {
}
}
- protected isBasicAuthEnabled(): boolean {
+ protected authenticate(req: IncomingMessage, next: (err?: Error) => void): void {
+ if (this.isBasicAuthEnabled() === true) {
+ if (this.isValidBasicAuth(req) === false) {
+ next(new Error('Unauthorized'));
+ }
+ next();
+ }
+ next();
+ }
+
+ private isBasicAuthEnabled(): boolean {
return (
this.uiServerConfiguration.authentication?.enabled === true &&
this.uiServerConfiguration.authentication?.type === AuthenticationType.BASIC_AUTH
);
}
- protected isValidBasicAuth(req: IncomingMessage): boolean {
+ private isValidBasicAuth(req: IncomingMessage): boolean {
const authorizationHeader = req.headers.authorization ?? '';
const authorizationToken = authorizationHeader.split(/\s+/).pop() ?? '';
const authentication = Buffer.from(authorizationToken, 'base64').toString();
);
}
- protected authenticate(req: IncomingMessage, next: (err?: Error) => void): void {
- if (this.isBasicAuthEnabled() === true) {
- if (this.isValidBasicAuth(req) === false) {
- next(new Error('Unauthorized'));
- }
- next();
- }
- next();
- }
-
public abstract start(): void;
public abstract sendRequest(request: ProtocolRequest): void;
public abstract sendResponse(response: ProtocolResponse): void;
public sendResponse(response: ProtocolResponse): void {
const [uuid, payload] = response;
- if (this.responseHandlers.has(uuid) === true) {
- const res = this.responseHandlers.get(uuid) as ServerResponse;
- res.writeHead(this.responseStatusToStatusCode(payload.status), {
- 'Content-Type': 'application/json',
- });
- res.end(JSON.stringify(payload));
- this.responseHandlers.delete(uuid);
- } else {
+ try {
+ if (this.responseHandlers.has(uuid) === true) {
+ const res = this.responseHandlers.get(uuid) as ServerResponse;
+ res.writeHead(this.responseStatusToStatusCode(payload.status), {
+ 'Content-Type': 'application/json',
+ });
+ res.end(JSON.stringify(payload));
+ this.responseHandlers.delete(uuid);
+ } else {
+ logger.error(
+ `${this.logPrefix(moduleName, 'sendResponse')} Response for unknown request id: ${uuid}`
+ );
+ }
+ } catch (error) {
logger.error(
- `${this.logPrefix(moduleName, 'sendResponse')} Response for unknown request id: ${uuid}`
+ `${this.logPrefix(moduleName, 'sendResponse')} Error at sending response id '${uuid}':`,
+ error
);
}
}
.get(version)
.requestHandler(this.buildProtocolRequest(uuid, procedureName, body ?? {}))
.catch(() => {
- this.sendResponse(
- this.buildProtocolResponse(uuid, { status: ResponseStatus.FAILURE })
- );
+ /* Error caught by AbstractUIService */
});
});
} else {
}
public static getUIServerImplementation(
- applicationProtocol: ApplicationProtocol,
uiServerConfiguration?: UIServerConfiguration
): AbstractUIServer | null {
if (UIServiceUtils.isLoopback(uiServerConfiguration.options?.host) === false) {
)
);
}
- switch (applicationProtocol) {
+ switch (uiServerConfiguration?.type ?? Configuration.getUIServer().type) {
case ApplicationProtocol.WS:
return new UIWebSocketServer(uiServerConfiguration ?? Configuration.getUIServer());
case ApplicationProtocol.HTTP:
import { StatusCodes } from 'http-status-codes';
import * as uuid from 'uuid';
-import WebSocket, { RawData, WebSocketServer } from 'ws';
+import WebSocket, { type RawData, WebSocketServer } from 'ws';
import type { UIServerConfiguration } from '../../types/ConfigurationData';
import type { ProtocolRequest, ProtocolResponse } from '../../types/UIProtocol';
public sendResponse(response: ProtocolResponse): void {
const responseId = response[0];
- if (this.responseHandlers.has(responseId)) {
- const ws = this.responseHandlers.get(responseId) as WebSocket;
- if (ws?.readyState === WebSocket.OPEN) {
- ws.send(JSON.stringify(response));
+ try {
+ if (this.responseHandlers.has(responseId)) {
+ const ws = this.responseHandlers.get(responseId) as WebSocket;
+ if (ws?.readyState === WebSocket.OPEN) {
+ ws.send(JSON.stringify(response));
+ }
+ this.responseHandlers.delete(responseId);
+ } else {
+ logger.error(
+ `${this.logPrefix(
+ moduleName,
+ 'sendResponse'
+ )} Response for unknown request id: ${responseId}`
+ );
}
- this.responseHandlers.delete(responseId);
- } else {
+ } catch (error) {
logger.error(
`${this.logPrefix(
moduleName,
'sendResponse'
- )} Response for unknown request id: ${responseId}`
+ )} Error at sending response id '${responseId}':`,
+ error
);
}
}
import { Bootstrap } from '../../../internal';
import {
ProcedureName,
- ProtocolRequest,
- ProtocolRequestHandler,
- ProtocolVersion,
- RequestPayload,
- ResponsePayload,
+ type ProtocolRequest,
+ type ProtocolRequestHandler,
+ type ProtocolVersion,
+ type RequestPayload,
+ type ResponsePayload,
ResponseStatus,
} from '../../../types/UIProtocol';
-import type {
+import {
BroadcastChannelProcedureName,
- BroadcastChannelRequestPayload,
+ type BroadcastChannelRequestPayload,
} from '../../../types/WorkerBroadcastChannel';
import logger from '../../../utils/Logger';
import Utils from '../../../utils/Utils';
const moduleName = 'AbstractUIService';
export default abstract class AbstractUIService {
+ protected static readonly ProcedureNameToBroadCastChannelProcedureNameMap: Omit<
+ Record<ProcedureName, BroadcastChannelProcedureName>,
+ 'startSimulator' | 'stopSimulator' | 'listChargingStations'
+ > = {
+ [ProcedureName.START_CHARGING_STATION]: BroadcastChannelProcedureName.START_CHARGING_STATION,
+ [ProcedureName.STOP_CHARGING_STATION]: BroadcastChannelProcedureName.STOP_CHARGING_STATION,
+ [ProcedureName.CLOSE_CONNECTION]: BroadcastChannelProcedureName.CLOSE_CONNECTION,
+ [ProcedureName.OPEN_CONNECTION]: BroadcastChannelProcedureName.OPEN_CONNECTION,
+ [ProcedureName.START_AUTOMATIC_TRANSACTION_GENERATOR]:
+ BroadcastChannelProcedureName.START_AUTOMATIC_TRANSACTION_GENERATOR,
+ [ProcedureName.STOP_AUTOMATIC_TRANSACTION_GENERATOR]:
+ BroadcastChannelProcedureName.STOP_AUTOMATIC_TRANSACTION_GENERATOR,
+ [ProcedureName.START_TRANSACTION]: BroadcastChannelProcedureName.START_TRANSACTION,
+ [ProcedureName.STOP_TRANSACTION]: BroadcastChannelProcedureName.STOP_TRANSACTION,
+ [ProcedureName.AUTHORIZE]: BroadcastChannelProcedureName.AUTHORIZE,
+ [ProcedureName.STATUS_NOTIFICATION]: BroadcastChannelProcedureName.STATUS_NOTIFICATION,
+ [ProcedureName.HEARTBEAT]: BroadcastChannelProcedureName.HEARTBEAT,
+ [ProcedureName.METER_VALUES]: BroadcastChannelProcedureName.METER_VALUES,
+ };
+
protected readonly requestHandlers: Map<ProcedureName, ProtocolRequestHandler>;
private readonly version: ProtocolVersion;
private readonly uiServer: AbstractUIServer;
private readonly broadcastChannelRequests: Map<string, number>;
constructor(uiServer: AbstractUIServer, version: ProtocolVersion) {
- this.version = version;
this.uiServer = uiServer;
+ this.version = version;
this.requestHandlers = new Map<ProcedureName, ProtocolRequestHandler>([
[ProcedureName.LIST_CHARGING_STATIONS, this.handleListChargingStations.bind(this)],
[ProcedureName.START_SIMULATOR, this.handleStartSimulator.bind(this)],
this.broadcastChannelRequests.set(uuid, expectedNumberOfResponses);
}
+ protected handleProtocolRequest(
+ uuid: string,
+ procedureName: ProcedureName,
+ payload: RequestPayload
+ ): void {
+ this.sendBroadcastChannelRequest(
+ uuid,
+ AbstractUIService.ProcedureNameToBroadCastChannelProcedureNameMap[
+ procedureName
+ ] as BroadcastChannelProcedureName,
+ payload
+ );
+ }
+
private handleListChargingStations(): ResponsePayload {
return {
status: ResponseStatus.SUCCESS,
import {
ProcedureName,
- ProtocolRequestHandler,
+ type ProtocolRequestHandler,
ProtocolVersion,
- RequestPayload,
} from '../../../types/UIProtocol';
-import { BroadcastChannelProcedureName } from '../../../types/WorkerBroadcastChannel';
import type { AbstractUIServer } from '../AbstractUIServer';
import AbstractUIService from './AbstractUIService';
export default class UIService001 extends AbstractUIService {
- private static readonly ProcedureNameToBroadCastChannelProcedureNameMap: Omit<
- Record<ProcedureName, BroadcastChannelProcedureName>,
- 'startSimulator' | 'stopSimulator' | 'listChargingStations'
- > = {
- [ProcedureName.START_CHARGING_STATION]: BroadcastChannelProcedureName.START_CHARGING_STATION,
- [ProcedureName.STOP_CHARGING_STATION]: BroadcastChannelProcedureName.STOP_CHARGING_STATION,
- [ProcedureName.CLOSE_CONNECTION]: BroadcastChannelProcedureName.CLOSE_CONNECTION,
- [ProcedureName.OPEN_CONNECTION]: BroadcastChannelProcedureName.OPEN_CONNECTION,
- [ProcedureName.START_AUTOMATIC_TRANSACTION_GENERATOR]:
- BroadcastChannelProcedureName.START_AUTOMATIC_TRANSACTION_GENERATOR,
- [ProcedureName.STOP_AUTOMATIC_TRANSACTION_GENERATOR]:
- BroadcastChannelProcedureName.STOP_AUTOMATIC_TRANSACTION_GENERATOR,
- [ProcedureName.START_TRANSACTION]: BroadcastChannelProcedureName.START_TRANSACTION,
- [ProcedureName.STOP_TRANSACTION]: BroadcastChannelProcedureName.STOP_TRANSACTION,
- [ProcedureName.AUTHORIZE]: BroadcastChannelProcedureName.AUTHORIZE,
- [ProcedureName.STATUS_NOTIFICATION]: BroadcastChannelProcedureName.STATUS_NOTIFICATION,
- [ProcedureName.HEARTBEAT]: BroadcastChannelProcedureName.HEARTBEAT,
- [ProcedureName.METER_VALUES]: BroadcastChannelProcedureName.METER_VALUES,
- };
-
constructor(uiServer: AbstractUIServer) {
super(uiServer, ProtocolVersion['0.0.1']);
this.requestHandlers.set(
this.handleProtocolRequest.bind(this) as ProtocolRequestHandler
);
}
-
- private handleProtocolRequest(
- uuid: string,
- procedureName: ProcedureName,
- payload: RequestPayload
- ): void {
- this.sendBroadcastChannelRequest(
- uuid,
- UIService001.ProcedureNameToBroadCastChannelProcedureNameMap[
- procedureName
- ] as BroadcastChannelProcedureName,
- payload
- );
- }
}
}
private addPerformanceEntryToStatistics(entry: PerformanceEntry): void {
- let entryName = entry.name;
- // Rename entry name
- const MAP_NAME: Record<string, string> = {};
- if (MAP_NAME[entryName]) {
- entryName = MAP_NAME[entryName];
- }
+ const entryName = entry.name;
// Initialize command statistics
if (!this.statistics.statisticsData.has(entryName)) {
this.statistics.statisticsData.set(entryName, {});