export default class Bootstrap {
private static instance: Bootstrap | null = null;
private workerImplementation: WorkerAbstract | null = null;
- private readonly uiWebSocketServer: UIWebSocketServer;
- private readonly storage: Storage;
+ private readonly uiWebSocketServer!: UIWebSocketServer;
+ private readonly storage!: Storage;
private numberOfChargingStations: number;
private readonly version: string = version;
private started: boolean;
this.started = false;
this.workerScript = path.join(path.resolve(__dirname, '../'), 'charging-station', 'ChargingStationWorker.js');
this.initWorkerImplementation();
- this.uiWebSocketServer = new UIWebSocketServer({ port: 80, handleProtocols: UIServiceUtils.handleProtocols });
- this.storage = StorageFactory.getStorage(Configuration.getPerformanceStorage().type, Configuration.getPerformanceStorage().URI, this.logPrefix());
+ Configuration.getUIWebSocketServer().enabled && (this.uiWebSocketServer = new UIWebSocketServer({
+ ...Configuration.getUIWebSocketServer().options, handleProtocols: UIServiceUtils.handleProtocols
+ }));
+ Configuration.getPerformanceStorage().enabled && (this.storage = StorageFactory.getStorage(
+ Configuration.getPerformanceStorage().type,
+ Configuration.getPerformanceStorage().URI,
+ this.logPrefix()
+ ));
Configuration.setConfigurationChangeCallback(async () => Bootstrap.getInstance().restart());
}
if (isMainThread && !this.started) {
try {
this.numberOfChargingStations = 0;
- await this.storage.open();
+ await this.storage?.open();
await this.workerImplementation.start();
- this.uiWebSocketServer.start();
+ this.uiWebSocketServer?.start();
// Start ChargingStation object in worker thread
if (Configuration.getStationTemplateURLs()) {
for (const stationURL of Configuration.getStationTemplateURLs()) {
public async stop(): Promise<void> {
if (isMainThread && this.started) {
await this.workerImplementation.stop();
- this.uiWebSocketServer.stop();
- await this.storage.close();
+ this.uiWebSocketServer?.stop();
+ await this.storage?.close();
} else {
console.error(chalk.red('Trying to stop the charging stations simulator while not started'));
}
import { Protocol, ProtocolCommand, ProtocolRequest, ProtocolVersion } from '../types/UIProtocol';
+import WebSocket, { OPEN, Server, ServerOptions } from 'ws';
import AbstractUIService from './UIWebSocketServices/AbstractUIService';
import BaseError from '../exception/BaseError';
+import Configuration from '../utils/Configuration';
import { IncomingMessage } from 'http';
import UIServiceFactory from './UIWebSocketServices/UIServiceFactory';
import Utils from '../utils/Utils';
-import WebSocket from 'ws';
import logger from '../utils/Logger';
-export default class UIWebSocketServer extends WebSocket.Server {
+export default class UIWebSocketServer extends Server {
public uiService: AbstractUIService;
- public constructor(options?: WebSocket.ServerOptions, callback?: () => void) {
+ public constructor(options?: ServerOptions, callback?: () => void) {
// Create the WebSocket Server
- super(options ?? { port: 80 }, callback);
+ super(options ?? Configuration.getUIWebSocketServer().options, callback);
}
public broadcastToClients(message: string | Record<string, unknown>): void {
for (const client of this.clients) {
- if (client?.readyState === WebSocket.OPEN) {
+ if (client?.readyState === OPEN) {
client.send(message);
}
}
+import { ServerOptions } from 'ws';
import { StorageType } from './Storage';
import type { WorkerChoiceStrategy } from 'poolifier';
import { WorkerProcessType } from './Worker';
numberOfStations: number;
}
+export interface UIWebSocketServerConfiguration {
+ enabled?: boolean;
+ options?: ServerOptions;
+}
+
export interface StorageConfiguration {
enabled?: boolean;
type?: StorageType;
export default interface ConfigurationData {
supervisionURLs?: string[];
stationTemplateURLs: StationTemplateURL[];
+ uiWebSocketServer?: UIWebSocketServerConfiguration;
performanceStorage?: StorageConfiguration;
autoReconnectMaxRetries?: number;
distributeStationsToTenantsEqually?: boolean;
-import ConfigurationData, { StationTemplateURL, StorageConfiguration } from '../types/ConfigurationData';
+import ConfigurationData, { StationTemplateURL, StorageConfiguration, UIWebSocketServerConfiguration } from '../types/ConfigurationData';
import Constants from './Constants';
+import { ServerOptions } from 'ws';
import { StorageType } from '../types/Storage';
import type { WorkerChoiceStrategy } from 'poolifier';
import { WorkerProcessType } from '../types/Worker';
return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logStatisticsInterval') ? Configuration.getConfig().logStatisticsInterval : 60;
}
+ static getUIWebSocketServer(): UIWebSocketServerConfiguration {
+ let options: ServerOptions = {
+ host: Constants.DEFAULT_UI_WEBSOCKET_SERVER_HOST,
+ port: Constants.DEFAULT_UI_WEBSOCKET_SERVER_PORT
+ };
+ let uiWebSocketServerConfiguration: UIWebSocketServerConfiguration = {
+ enabled: true,
+ options
+ };
+ if (Configuration.objectHasOwnProperty(Configuration.getConfig(), 'uiWebSocketServer')) {
+ if (Configuration.objectHasOwnProperty(Configuration.getConfig().uiWebSocketServer, 'options')) {
+ options = {
+ ...Configuration.objectHasOwnProperty(Configuration.getConfig().uiWebSocketServer.options, 'host') && { host: Configuration.getConfig().uiWebSocketServer.options.host },
+ ...Configuration.objectHasOwnProperty(Configuration.getConfig().uiWebSocketServer.options, 'port') && { port: Configuration.getConfig().uiWebSocketServer.options.port }
+ };
+ }
+ uiWebSocketServerConfiguration =
+ {
+ ...Configuration.objectHasOwnProperty(Configuration.getConfig().uiWebSocketServer, 'enabled') && { enabled: Configuration.getConfig().uiWebSocketServer.enabled },
+ options
+ };
+ }
+ return uiWebSocketServerConfiguration;
+ }
+
static getPerformanceStorage(): StorageConfiguration {
- let storageConfiguration: StorageConfiguration;
+ let storageConfiguration: StorageConfiguration = {
+ enabled: false,
+ type: StorageType.JSON_FILE,
+ URI: this.getDefaultPerformanceStorageURI(StorageType.JSON_FILE)
+ };
if (Configuration.objectHasOwnProperty(Configuration.getConfig(), 'performanceStorage')) {
storageConfiguration =
{
- ...Configuration.objectHasOwnProperty(Configuration.getConfig().performanceStorage, 'enabled') ? { enabled: Configuration.getConfig().performanceStorage.enabled } : { enabled: false },
- ...Configuration.objectHasOwnProperty(Configuration.getConfig().performanceStorage, 'type') ? { type: Configuration.getConfig().performanceStorage.type } : { type: StorageType.JSON_FILE },
+ ...Configuration.objectHasOwnProperty(Configuration.getConfig().performanceStorage, 'enabled') && { enabled: Configuration.getConfig().performanceStorage.enabled },
+ ...Configuration.objectHasOwnProperty(Configuration.getConfig().performanceStorage, 'type') && { type: Configuration.getConfig().performanceStorage.type },
...Configuration.objectHasOwnProperty(Configuration.getConfig().performanceStorage, 'URI')
? { URI: Configuration.getConfig().performanceStorage.URI }
: { URI: this.getDefaultPerformanceStorageURI(Configuration.getConfig()?.performanceStorage?.type ?? StorageType.JSON_FILE) }
};
- } else {
- storageConfiguration =
- {
- enabled: false,
- type: StorageType.JSON_FILE,
- URI: this.getDefaultPerformanceStorageURI(StorageType.JSON_FILE)
- };
}
return storageConfiguration;
}
static readonly DEFAULT_HEARTBEAT_INTERVAL = 60000; // Ms
- static readonly SUPPORTED_MEASURANDS = Object.freeze([MeterValueMeasurand.STATE_OF_CHARGE, MeterValueMeasurand.VOLTAGE,
- MeterValueMeasurand.POWER_ACTIVE_IMPORT, MeterValueMeasurand.CURRENT_IMPORT, MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER]);
+ static readonly SUPPORTED_MEASURANDS = Object.freeze([
+ MeterValueMeasurand.STATE_OF_CHARGE,
+ MeterValueMeasurand.VOLTAGE,
+ MeterValueMeasurand.POWER_ACTIVE_IMPORT,
+ MeterValueMeasurand.CURRENT_IMPORT,
+ MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+ ]);
static readonly DEFAULT_FLUCTUATION_PERCENT = 5;
static readonly DEFAULT_PERFORMANCE_RECORDS_FILENAME = 'performanceRecords.json';
static readonly DEFAULT_PERFORMANCE_RECORDS_DB_NAME = 'charging-stations-simulator';
static readonly PERFORMANCE_RECORDS_TABLE = 'performance_records';
+
+ static readonly DEFAULT_UI_WEBSOCKET_SERVER_HOST = 'localhost';
+ static readonly DEFAULT_UI_WEBSOCKET_SERVER_PORT = 80;
}