X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2FBootstrap.ts;h=9247ab3deb5112925a4a7f8f215c31a5823712ff;hb=6027002ff1398a1cb3bb55d4994e4615efded2c0;hp=ddf8ee7016c7ab5bf82f09d9f80ca1bec32ee68b;hpb=1feac591544c625c56086abe1f14dbdc706280fb;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/Bootstrap.ts b/src/charging-station/Bootstrap.ts index ddf8ee70..9247ab3d 100644 --- a/src/charging-station/Bootstrap.ts +++ b/src/charging-station/Bootstrap.ts @@ -41,8 +41,7 @@ import { isAsyncFunction, isNotEmptyArray, logPrefix, - logger, - max + logger } from '../utils/index.js' import { type WorkerAbstract, WorkerFactory } from '../worker/index.js' @@ -60,20 +59,21 @@ interface TemplateChargingStations { configured: number added: number started: number - lastIndex: number + indexes: Set } export class Bootstrap extends EventEmitter { private static instance: Bootstrap | null = null private workerImplementation?: WorkerAbstract - private readonly uiServer?: AbstractUIServer + private readonly uiServer: AbstractUIServer private storage?: Storage - private readonly chargingStationsByTemplate: Map + private readonly templatesChargingStations: Map private readonly version: string = version private initializedCounters: boolean private started: boolean private starting: boolean private stopping: boolean + private uiServerStarted: boolean private constructor () { super() @@ -86,10 +86,11 @@ export class Bootstrap extends EventEmitter { this.started = false this.starting = false this.stopping = false - this.chargingStationsByTemplate = new Map() + this.uiServerStarted = false this.uiServer = UIServerFactory.getUIServerImplementation( Configuration.getConfigurationSection(ConfigurationSection.uiServer) ) + this.templatesChargingStations = new Map() this.initializedCounters = false this.initializeCounters() Configuration.configurationChangeCallback = async () => { @@ -107,18 +108,33 @@ export class Bootstrap extends EventEmitter { } public get numberOfChargingStationTemplates (): number { - return this.chargingStationsByTemplate.size + return this.templatesChargingStations.size } public get numberOfConfiguredChargingStations (): number { - return [...this.chargingStationsByTemplate.values()].reduce( + return [...this.templatesChargingStations.values()].reduce( (accumulator, value) => accumulator + value.configured, 0 ) } + public getState (): { started: boolean } { + return { + started: this.started + } + } + public getLastIndex (templateName: string): number { - return this.chargingStationsByTemplate.get(templateName)?.lastIndex ?? 0 + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const indexes = [...this.templatesChargingStations.get(templateName)!.indexes] + .concat(0) + .sort((a, b) => a - b) + for (let i = 0; i < indexes.length - 1; i++) { + if (indexes[i + 1] - indexes[i] !== 1) { + return indexes[i] + } + } + return indexes[indexes.length - 1] } public getPerformanceStatistics (): IterableIterator | undefined { @@ -126,14 +142,14 @@ export class Bootstrap extends EventEmitter { } private get numberOfAddedChargingStations (): number { - return [...this.chargingStationsByTemplate.values()].reduce( + return [...this.templatesChargingStations.values()].reduce( (accumulator, value) => accumulator + value.added, 0 ) } private get numberOfStartedChargingStations (): number { - return [...this.chargingStationsByTemplate.values()].reduce( + return [...this.templatesChargingStations.values()].reduce( (accumulator, value) => accumulator + value.started, 0 ) @@ -144,6 +160,7 @@ export class Bootstrap extends EventEmitter { if (!this.starting) { this.starting = true this.on(ChargingStationWorkerMessageEvents.added, this.workerEventAdded) + this.on(ChargingStationWorkerMessageEvents.deleted, this.workerEventDeleted) this.on(ChargingStationWorkerMessageEvents.started, this.workerEventStarted) this.on(ChargingStationWorkerMessageEvents.stopped, this.workerEventStopped) this.on(ChargingStationWorkerMessageEvents.updated, this.workerEventUpdated) @@ -180,15 +197,22 @@ export class Bootstrap extends EventEmitter { ) await this.storage?.open() } - Configuration.getConfigurationSection(ConfigurationSection.uiServer) - .enabled === true && this.uiServer?.start() + if ( + !this.uiServerStarted && + Configuration.getConfigurationSection( + ConfigurationSection.uiServer + ).enabled === true + ) { + this.uiServer.start() + this.uiServerStarted = true + } // Start ChargingStation object instance in worker thread // eslint-disable-next-line @typescript-eslint/no-non-null-assertion for (const stationTemplateUrl of Configuration.getStationTemplateUrls()!) { try { const nbStations = - this.chargingStationsByTemplate.get(parse(stationTemplateUrl.file).name) - ?.configured ?? stationTemplateUrl.numberOfStations + this.templatesChargingStations.get(parse(stationTemplateUrl.file).name)?.configured ?? + stationTemplateUrl.numberOfStations for (let index = 1; index <= nbStations; index++) { await this.addChargingStation(index, stationTemplateUrl.file) } @@ -237,7 +261,7 @@ export class Bootstrap extends EventEmitter { if (this.started) { if (!this.stopping) { this.stopping = true - await this.uiServer?.sendInternalRequest( + await this.uiServer.sendInternalRequest( this.uiServer.buildProtocolRequest( generateUUID(), ProcedureName.STOP_CHARGING_STATION, @@ -252,6 +276,8 @@ export class Bootstrap extends EventEmitter { await this.workerImplementation?.stop() delete this.workerImplementation this.removeAllListeners() + this.uiServer.clearCaches() + this.initializedCounters = false await this.storage?.close() delete this.storage this.started = false @@ -266,9 +292,14 @@ export class Bootstrap extends EventEmitter { private async restart (): Promise { await this.stop() - Configuration.getConfigurationSection(ConfigurationSection.uiServer) - .enabled !== true && this.uiServer?.stop() - this.initializedCounters = false + if ( + this.uiServerStarted && + Configuration.getConfigurationSection(ConfigurationSection.uiServer) + .enabled !== true + ) { + this.uiServer.stop() + this.uiServerStarted = false + } await this.start() } @@ -351,6 +382,9 @@ export class Bootstrap extends EventEmitter { case ChargingStationWorkerMessageEvents.added: this.emit(ChargingStationWorkerMessageEvents.added, msg.data) break + case ChargingStationWorkerMessageEvents.deleted: + this.emit(ChargingStationWorkerMessageEvents.deleted, msg.data) + break case ChargingStationWorkerMessageEvents.started: this.emit(ChargingStationWorkerMessageEvents.started, msg.data) break @@ -387,9 +421,7 @@ export class Bootstrap extends EventEmitter { } private readonly workerEventAdded = (data: ChargingStationData): void => { - this.uiServer?.chargingStations.set(data.stationInfo.hashId, data) - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - ++this.chargingStationsByTemplate.get(data.stationInfo.templateName)!.added + this.uiServer.chargingStations.set(data.stationInfo.hashId, data) logger.info( `${this.logPrefix()} ${moduleName}.workerEventAdded: Charging station ${ data.stationInfo.chargingStationId @@ -399,10 +431,27 @@ export class Bootstrap extends EventEmitter { ) } + private readonly workerEventDeleted = (data: ChargingStationData): void => { + this.uiServer.chargingStations.delete(data.stationInfo.hashId) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const templateChargingStations = this.templatesChargingStations.get( + data.stationInfo.templateName + )! + --templateChargingStations.added + templateChargingStations.indexes.delete(data.stationInfo.templateIndex) + logger.info( + `${this.logPrefix()} ${moduleName}.workerEventDeleted: Charging station ${ + data.stationInfo.chargingStationId + } (hashId: ${data.stationInfo.hashId}) deleted (${ + this.numberOfAddedChargingStations + } added from ${this.numberOfConfiguredChargingStations} configured charging station(s))` + ) + } + private readonly workerEventStarted = (data: ChargingStationData): void => { - this.uiServer?.chargingStations.set(data.stationInfo.hashId, data) + this.uiServer.chargingStations.set(data.stationInfo.hashId, data) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - ++this.chargingStationsByTemplate.get(data.stationInfo.templateName)!.started + ++this.templatesChargingStations.get(data.stationInfo.templateName)!.started logger.info( `${this.logPrefix()} ${moduleName}.workerEventStarted: Charging station ${ data.stationInfo.chargingStationId @@ -413,9 +462,9 @@ export class Bootstrap extends EventEmitter { } private readonly workerEventStopped = (data: ChargingStationData): void => { - this.uiServer?.chargingStations.set(data.stationInfo.hashId, data) + this.uiServer.chargingStations.set(data.stationInfo.hashId, data) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - --this.chargingStationsByTemplate.get(data.stationInfo.templateName)!.started + --this.templatesChargingStations.get(data.stationInfo.templateName)!.started logger.info( `${this.logPrefix()} ${moduleName}.workerEventStopped: Charging station ${ data.stationInfo.chargingStationId @@ -426,7 +475,7 @@ export class Bootstrap extends EventEmitter { } private readonly workerEventUpdated = (data: ChargingStationData): void => { - this.uiServer?.chargingStations.set(data.stationInfo.hashId, data) + this.uiServer.chargingStations.set(data.stationInfo.hashId, data) } private readonly workerEventPerformanceStatistics = (data: Statistics): void => { @@ -451,15 +500,15 @@ export class Bootstrap extends EventEmitter { if (isNotEmptyArray(stationTemplateUrls)) { for (const stationTemplateUrl of stationTemplateUrls) { const templateName = parse(stationTemplateUrl.file).name - this.chargingStationsByTemplate.set(templateName, { + this.templatesChargingStations.set(templateName, { configured: stationTemplateUrl.numberOfStations, added: 0, started: 0, - lastIndex: 0 + indexes: new Set() }) - this.uiServer?.chargingStationTemplates.add(templateName) + this.uiServer.chargingStationTemplates.add(templateName) } - if (this.chargingStationsByTemplate.size !== stationTemplateUrls.length) { + if (this.templatesChargingStations.size !== stationTemplateUrls.length) { console.error( chalk.red( "'stationTemplateUrls' contains duplicate entries, please check your configuration" @@ -505,17 +554,19 @@ export class Bootstrap extends EventEmitter { options }) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - this.chargingStationsByTemplate.get(parse(stationTemplateFile).name)!.lastIndex = max( - index, - this.chargingStationsByTemplate.get(parse(stationTemplateFile).name)?.lastIndex ?? -Infinity - ) + const templateChargingStations = this.templatesChargingStations.get( + parse(stationTemplateFile).name + )! + ++templateChargingStations.added + templateChargingStations.indexes.add(index) } private gracefulShutdown (): void { this.stop() .then(() => { console.info(chalk.green('Graceful shutdown')) - this.uiServer?.stop() + this.uiServer.stop() + this.uiServerStarted = false this.waitChargingStationsStopped() .then(() => { exit(exitCodes.succeeded)