import { ChargingStationWorkerData, ChargingStationWorkerMessage, ChargingStationWorkerMessageEvents } from '../types/ChargingStationWorker';
import Configuration from '../utils/Configuration';
+import Statistics from '../types/Statistics';
import { Storage } from '../performance/storage/Storage';
import { StorageFactory } from '../performance/storage/StorageFactory';
import { UIServiceUtils } from './ui-websocket-services/UIServiceUtils';
export default class Bootstrap {
private static instance: Bootstrap | null = null;
- private workerImplementation: WorkerAbstract | null = null;
+ private workerImplementation: WorkerAbstract<ChargingStationWorkerData> | null = null;
private readonly uiWebSocketServer!: UIWebSocketServer;
private readonly storage!: Storage;
private numberOfChargingStations: number;
},
messageHandler: async (msg: ChargingStationWorkerMessage) => {
if (msg.id === ChargingStationWorkerMessageEvents.STARTED) {
- this.uiWebSocketServer.chargingStations.add(msg.data.id);
+ this.uiWebSocketServer.chargingStations.add(msg.data.id as string);
} else if (msg.id === ChargingStationWorkerMessageEvents.STOPPED) {
- this.uiWebSocketServer.chargingStations.delete(msg.data.id);
+ this.uiWebSocketServer.chargingStations.delete(msg.data.id as string);
} else if (msg.id === ChargingStationWorkerMessageEvents.PERFORMANCE_STATISTICS) {
- await this.storage.storePerformanceStatistics(msg.data);
+ await this.storage.storePerformanceStatistics(msg.data as unknown as Statistics);
}
}
});
};
-export interface ChargingStationWorkerMessage extends Omit<WorkerMessage, 'id'> {
+export interface ChargingStationWorkerMessage extends Omit<WorkerMessage<ChargingStationWorkerData>, 'id'> {
id: ChargingStationWorkerMessageEvents;
}
--- /dev/null
+export interface JsonType {
+ [x: string]: string | number | boolean | Date | JsonType | JsonArray;
+}
+
+type JsonArray = Array<string | number | boolean | Date | JsonType | JsonArray>;
+import { JsonType } from './JsonType';
import { PoolOptions } from 'poolifier';
import { Worker } from 'worker_threads';
messageHandler?: (message: unknown) => void | Promise<void>;
}
-// eslint-disable-next-line @typescript-eslint/no-empty-interface
-export interface WorkerData {}
+export type WorkerData = JsonType;
export interface WorkerSetElement {
worker: Worker;
numberOfWorkerElements: number;
}
-export interface WorkerMessage {
+export interface WorkerMessage<T extends WorkerData> {
id: WorkerMessageEvents;
- data: any;
+ data: T;
}
export enum WorkerMessageEvents {
-export interface OCPP16ChargingProfile {
+import { JsonType } from '../../JsonType';
+
+export interface OCPP16ChargingProfile extends JsonType {
chargingProfileId: number;
transactionId?: number;
stackLevel: number;
chargingSchedule: ChargingSchedule;
}
-export interface ChargingSchedule {
+export interface ChargingSchedule extends JsonType {
duration?: number;
startSchedule?: Date;
chargingRateUnit: ChargingRateUnitType;
minChargeRate?: number;
}
-export interface ChargingSchedulePeriod {
+export interface ChargingSchedulePeriod extends JsonType {
startPeriod: number;
limit: number;
numberPhases?: number;
import { EmptyObject } from '../../EmptyObject';
+import { JsonType } from '../../JsonType';
export enum MeterValueUnit {
WATT_HOUR = 'Wh',
SIGNED_DATA = 'SignedData',
}
-export interface OCPP16SampledValue {
+export interface OCPP16SampledValue extends JsonType {
value?: string;
unit?: MeterValueUnit;
context?: MeterValueContext;
format?: MeterValueFormat;
}
-export interface OCPP16MeterValue {
+export interface OCPP16MeterValue extends JsonType {
timestamp: string;
sampledValue: OCPP16SampledValue[];
}
-export interface MeterValuesRequest {
+export interface MeterValuesRequest extends JsonType {
connectorId: number;
transactionId?: number;
meterValue: OCPP16MeterValue[];
import { ChargingProfilePurposeType, OCPP16ChargingProfile } from './ChargingProfile';
import { EmptyObject } from '../../EmptyObject';
+import { JsonType } from '../../JsonType';
import { OCPP16ChargePointErrorCode } from './ChargePointErrorCode';
import { OCPP16ChargePointStatus } from './ChargePointStatus';
import { OCPP16DiagnosticsStatus } from './DiagnosticsStatus';
export type HeartbeatRequest = EmptyObject;
-export interface OCPP16BootNotificationRequest {
+export interface OCPP16BootNotificationRequest extends JsonType {
chargeBoxSerialNumber?: string;
chargePointModel: string;
chargePointSerialNumber?: string;
meterType?: string;
}
-export interface StatusNotificationRequest {
+export interface StatusNotificationRequest extends JsonType {
connectorId: number;
errorCode: OCPP16ChargePointErrorCode;
info?: string;
vendorErrorCode?: string;
}
-export interface ChangeConfigurationRequest {
+export interface ChangeConfigurationRequest extends JsonType {
key: string | OCPP16StandardParametersKey;
value: string;
}
-export interface RemoteStartTransactionRequest {
+export interface RemoteStartTransactionRequest extends JsonType {
connectorId: number;
idTag: string;
chargingProfile?: OCPP16ChargingProfile;
}
-export interface RemoteStopTransactionRequest {
+export interface RemoteStopTransactionRequest extends JsonType {
transactionId: number;
}
-export interface UnlockConnectorRequest {
+export interface UnlockConnectorRequest extends JsonType {
connectorId: number;
}
-export interface GetConfigurationRequest {
+export interface GetConfigurationRequest extends JsonType {
key?: string | OCPP16StandardParametersKey[];
}
SOFT = 'Soft'
}
-export interface ResetRequest {
+export interface ResetRequest extends JsonType {
type: ResetType;
}
-export interface SetChargingProfileRequest {
+export interface SetChargingProfileRequest extends JsonType {
connectorId: number;
csChargingProfiles: OCPP16ChargingProfile;
}
OPERATIVE = 'Operative'
}
-export interface ChangeAvailabilityRequest {
+export interface ChangeAvailabilityRequest extends JsonType {
connectorId: number;
type: OCPP16AvailabilityType;
}
-export interface ClearChargingProfileRequest {
+export interface ClearChargingProfileRequest extends JsonType {
id?: number;
connectorId?: number;
chargingProfilePurpose?: ChargingProfilePurposeType;
stackLevel?: number;
}
-export interface GetDiagnosticsRequest {
+export interface GetDiagnosticsRequest extends JsonType {
location: string;
retries?: number;
retryInterval?: number;
stopTime?: Date;
}
-export interface DiagnosticsStatusNotificationRequest {
+export interface DiagnosticsStatusNotificationRequest extends JsonType {
status: OCPP16DiagnosticsStatus
}
StatusNotification = 'StatusNotification'
}
-export interface OCPP16TriggerMessageRequest {
+export interface OCPP16TriggerMessageRequest extends JsonType {
requestedMessage: MessageTrigger;
connectorId?: number
}
import { EmptyObject } from '../../EmptyObject';
+import { JsonType } from '../../JsonType';
import { OCPPConfigurationKey } from '../Configuration';
-export interface HeartbeatResponse {
+export interface HeartbeatResponse extends JsonType {
currentTime: string;
}
NOT_SUPPORTED = 'NotSupported'
}
-export interface UnlockConnectorResponse {
+export interface UnlockConnectorResponse extends JsonType {
status: OCPP16UnlockStatus;
}
NOT_SUPPORTED = 'NotSupported'
}
-export interface ChangeConfigurationResponse {
+export interface ChangeConfigurationResponse extends JsonType {
status: OCPP16ConfigurationStatus;
}
REJECTED = 'Rejected'
}
-export interface OCPP16BootNotificationResponse {
+export interface OCPP16BootNotificationResponse extends JsonType {
status: OCPP16RegistrationStatus;
currentTime: string;
interval: number;
export type StatusNotificationResponse = EmptyObject;
-export interface GetConfigurationResponse {
+export interface GetConfigurationResponse extends JsonType {
configurationKey: OCPPConfigurationKey[];
unknownKey: string[];
}
NOT_SUPPORTED = 'NotSupported',
}
-export interface SetChargingProfileResponse {
+export interface SetChargingProfileResponse extends JsonType {
status: OCPP16ChargingProfileStatus;
}
SCHEDULED = 'Scheduled'
}
-export interface ChangeAvailabilityResponse {
+export interface ChangeAvailabilityResponse extends JsonType {
status: OCPP16AvailabilityStatus;
}
UNKNOWN = 'Unknown'
}
-export interface ClearChargingProfileResponse {
+export interface ClearChargingProfileResponse extends JsonType {
status: OCPP16ClearChargingProfileStatus;
}
-export interface GetDiagnosticsResponse {
+export interface GetDiagnosticsResponse extends JsonType {
fileName?: string;
}
NOT_IMPLEMENTED = 'NotImplemented'
}
-export interface OCPP16TriggerMessageResponse {
+export interface OCPP16TriggerMessageResponse extends JsonType {
status: OCPP16TriggerMessageStatus
}
+import { JsonType } from '../../JsonType';
import { OCPP16MeterValue } from './MeterValues';
export enum OCPP16StopTransactionReason {
CONCURRENT_TX = 'ConcurrentTx'
}
-export interface IdTagInfo {
+export interface IdTagInfo extends JsonType {
status: OCPP16AuthorizationStatus;
parentIdTag?: string;
expiryDate?: Date;
}
-export interface AuthorizeRequest {
+export interface AuthorizeRequest extends JsonType {
idTag: string;
}
-export interface OCPP16AuthorizeResponse {
+export interface OCPP16AuthorizeResponse extends JsonType {
idTagInfo: IdTagInfo;
}
-export interface StartTransactionRequest {
+export interface StartTransactionRequest extends JsonType {
connectorId: number;
idTag: string;
meterStart: number;
timestamp: string;
}
-export interface OCPP16StartTransactionResponse {
+export interface OCPP16StartTransactionResponse extends JsonType {
idTagInfo: IdTagInfo;
transactionId: number;
}
-export interface StopTransactionRequest {
+export interface StopTransactionRequest extends JsonType {
idTag?: string;
meterStop: number;
timestamp: string;
transactionData?: OCPP16MeterValue[];
}
-export interface OCPP16StopTransactionResponse {
+export interface OCPP16StopTransactionResponse extends JsonType {
idTagInfo?: IdTagInfo;
}
import { OCPP16StandardParametersKey, OCPP16SupportedFeatureProfiles, OCPP16VendorDefaultParametersKey } from './1.6/Configuration';
+import { JsonType } from '../JsonType';
+
export type StandardParametersKey = OCPP16StandardParametersKey;
export const StandardParametersKey = {
TSR = 'TSR'
}
-export interface OCPPConfigurationKey {
+export interface OCPPConfigurationKey extends JsonType {
key: string | StandardParametersKey;
readonly: boolean;
value?: string;
import Constants from '../utils/Constants';
import { WorkerData } from '../types/Worker';
-export default abstract class WorkerAbstract {
+export default abstract class WorkerAbstract<T extends WorkerData> {
protected readonly workerScript: string;
protected readonly workerStartDelay: number;
public abstract readonly size: number;
public abstract start(): Promise<void>;
public abstract stop(): Promise<void>;
- public abstract addElement(elementData: WorkerData): Promise<void>;
+ public abstract addElement(elementData: T): Promise<void>;
}
import { WorkerData } from '../types/Worker';
import { WorkerUtils } from './WorkerUtils';
-export default class WorkerDynamicPool<T> extends WorkerAbstract {
+export default class WorkerDynamicPool extends WorkerAbstract<WorkerData> {
private readonly pool: DynamicThreadPool<WorkerData>;
/**
* @returns
* @public
*/
- public async addElement(elementData: T): Promise<void> {
+ public async addElement(elementData: WorkerData): Promise<void> {
await this.pool.execute(elementData);
// Start worker sequentially to optimize memory at startup
await Utils.sleep(this.workerStartDelay);
import { Worker, isMainThread } from 'worker_threads';
-import { WorkerOptions, WorkerProcessType } from '../types/Worker';
+import { WorkerData, WorkerOptions, WorkerProcessType } from '../types/Worker';
import Constants from '../utils/Constants';
import { PoolOptions } from 'poolifier';
// This is intentional
}
- public static getWorkerImplementation<T>(workerScript: string, workerProcessType: WorkerProcessType, options?: WorkerOptions): WorkerAbstract | null {
+ public static getWorkerImplementation<T extends WorkerData>(workerScript: string, workerProcessType: WorkerProcessType, options?: WorkerOptions): WorkerAbstract<T> | null {
if (!isMainThread) {
throw new Error('Trying to get a worker implementation outside the main thread');
}
options.startDelay = options?.startDelay ?? Constants.WORKER_START_DELAY;
options.poolOptions = options?.poolOptions ?? {} as PoolOptions<Worker>;
options?.messageHandler && (options.poolOptions.messageHandler = options.messageHandler);
- let workerImplementation: WorkerAbstract = null;
+ let workerImplementation: WorkerAbstract<T> = null;
switch (workerProcessType) {
case WorkerProcessType.WORKER_SET:
options.elementsPerWorker = options.elementsPerWorker ?? Constants.DEFAULT_CHARGING_STATIONS_PER_WORKER;
- workerImplementation = new WorkerSet<T>(workerScript, options.elementsPerWorker, options.startDelay, options);
+ workerImplementation = new WorkerSet(workerScript, options.elementsPerWorker, options.startDelay, options);
break;
case WorkerProcessType.STATIC_POOL:
options.poolMaxSize = options.poolMaxSize ?? Constants.DEFAULT_WORKER_POOL_MAX_SIZE;
- workerImplementation = new WorkerStaticPool<T>(workerScript, options.poolMaxSize, options.startDelay, options.poolOptions);
+ workerImplementation = new WorkerStaticPool(workerScript, options.poolMaxSize, options.startDelay, options.poolOptions);
break;
case WorkerProcessType.DYNAMIC_POOL:
options.poolMinSize = options.poolMinSize ?? Constants.DEFAULT_WORKER_POOL_MIN_SIZE;
options.poolMaxSize = options.poolMaxSize ?? Constants.DEFAULT_WORKER_POOL_MAX_SIZE;
- workerImplementation = new WorkerDynamicPool<T>(workerScript, options.poolMinSize, options.poolMaxSize, options.startDelay, options.poolOptions);
+ workerImplementation = new WorkerDynamicPool(workerScript, options.poolMinSize, options.poolMaxSize, options.startDelay, options.poolOptions);
break;
default:
throw new Error(`Worker implementation type '${workerProcessType}' not found`);
// Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
-import { WorkerMessageEvents, WorkerOptions, WorkerSetElement } from '../types/Worker';
+import { WorkerData, WorkerMessageEvents, WorkerOptions, WorkerSetElement } from '../types/Worker';
import Utils from '../utils/Utils';
import { Worker } from 'worker_threads';
import WorkerAbstract from './WorkerAbstract';
import { WorkerUtils } from './WorkerUtils';
-export default class WorkerSet<T> extends WorkerAbstract {
+export default class WorkerSet extends WorkerAbstract<WorkerData> {
public readonly maxElementsPerWorker: number;
private readonly messageHandler: (message: unknown) => void | Promise<void>;
private readonly workerSet: Set<WorkerSetElement>;
* @returns
* @public
*/
- public async addElement(elementData: T): Promise<void> {
+ public async addElement(elementData: WorkerData): Promise<void> {
if (!this.workerSet) {
throw new Error('Cannot add a WorkerSet element: workers\' set does not exist');
}
import { WorkerData } from '../types/Worker';
import { WorkerUtils } from './WorkerUtils';
-export default class WorkerStaticPool<T> extends WorkerAbstract {
+export default class WorkerStaticPool extends WorkerAbstract<WorkerData> {
private readonly pool: FixedThreadPool<WorkerData>;
/**
* @returns
* @public
*/
- public async addElement(elementData: T): Promise<void> {
+ public async addElement(elementData: WorkerData): Promise<void> {
await this.pool.execute(elementData);
// Start worker sequentially to optimize memory at startup
await Utils.sleep(this.workerStartDelay);