X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Fcharging-station%2FAuthorizedTagsCache.ts;h=edb695386c8609b8927460e628d03a3c57144faa;hb=ba62a535da8d31400787113da1f77282967abb65;hp=fd085890f2359af34b8ff1a5580f9d3323c84137;hpb=8b7072dca602c80ec6ef9a3463b6d53b43aa8fa5;p=e-mobility-charging-stations-simulator.git diff --git a/src/charging-station/AuthorizedTagsCache.ts b/src/charging-station/AuthorizedTagsCache.ts index fd085890..edb69538 100644 --- a/src/charging-station/AuthorizedTagsCache.ts +++ b/src/charging-station/AuthorizedTagsCache.ts @@ -1,18 +1,22 @@ import fs from 'node:fs'; -import { FileType } from '../types/FileType'; -import FileUtils from '../utils/FileUtils'; -import logger from '../utils/Logger'; -import Utils from '../utils/Utils'; +import { type ChargingStation, ChargingStationUtils } from './internal'; +import { FileType, IdTagDistribution } from '../types'; +import { FileUtils, Utils, logger } from '../utils'; -export default class AuthorizedTagsCache { +type TagsCacheValueType = { + tags: string[]; + tagsFileWatcher: fs.FSWatcher | undefined; +}; + +export class AuthorizedTagsCache { private static instance: AuthorizedTagsCache | null = null; - private readonly tagsCaches: Map; - private readonly FSWatchers: Map; + private readonly tagsCaches: Map; + private readonly tagsCachesAddressableIndexes: Map; private constructor() { - this.tagsCaches = new Map(); - this.FSWatchers = new Map(); + this.tagsCaches = new Map(); + this.tagsCachesAddressableIndexes = new Map(); } public static getInstance(): AuthorizedTagsCache { @@ -22,41 +26,30 @@ export default class AuthorizedTagsCache { return AuthorizedTagsCache.instance; } + public getIdTag( + distribution: IdTagDistribution, + chargingStation: ChargingStation, + connectorId: number + ): string { + const hashId = chargingStation.stationInfo.hashId; + const authorizationFile = ChargingStationUtils.getAuthorizationFile( + chargingStation.stationInfo + ); + switch (distribution) { + case IdTagDistribution.RANDOM: + return this.getRandomIdTag(hashId, authorizationFile); + case IdTagDistribution.ROUND_ROBIN: + return this.getRoundRobinIdTag(hashId, authorizationFile); + case IdTagDistribution.CONNECTOR_AFFINITY: + return this.getConnectorAffinityIdTag(chargingStation, connectorId); + default: + return this.getRoundRobinIdTag(hashId, authorizationFile); + } + } + public getAuthorizedTags(file: string): string[] | undefined { if (this.hasTags(file) === false) { this.setTags(file, this.getAuthorizedTagsFromFile(file)); - // Monitor authorization file - this.FSWatchers.has(file) === false && - this.FSWatchers.set( - file, - FileUtils.watchJsonFile( - file, - FileType.Authorization, - this.logPrefix(file), - undefined, - (event, filename) => { - if (!Utils.isEmptyString(filename) && event === 'change') { - try { - logger.debug( - `${this.logPrefix(file)} ${FileType.Authorization} file have changed, reload` - ); - this.deleteTags(file); - this.deleteFSWatcher(file); - } catch (error) { - FileUtils.handleFileException( - file, - FileType.Authorization, - error as NodeJS.ErrnoException, - this.logPrefix(file), - { - throwError: false, - } - ); - } - } - } - ) - ); } return this.getTags(file); } @@ -65,25 +58,92 @@ export default class AuthorizedTagsCache { return this.deleteTags(file); } + private getRandomIdTag(hashId: string, file: string): string { + const tags = this.getAuthorizedTags(file); + const addressableKey = file + hashId; + this.tagsCachesAddressableIndexes.set( + addressableKey, + Math.floor(Utils.secureRandom() * tags.length) + ); + return tags[this.tagsCachesAddressableIndexes.get(addressableKey)]; + } + + private getRoundRobinIdTag(hashId: string, file: string): string { + const tags = this.getAuthorizedTags(file); + const addressableKey = file + hashId; + const idTagIndex = this.tagsCachesAddressableIndexes.get(addressableKey) ?? 0; + const idTag = tags[idTagIndex]; + this.tagsCachesAddressableIndexes.set( + addressableKey, + idTagIndex === tags.length - 1 ? 0 : idTagIndex + 1 + ); + return idTag; + } + + private getConnectorAffinityIdTag(chargingStation: ChargingStation, connectorId: number): string { + const file = ChargingStationUtils.getAuthorizationFile(chargingStation.stationInfo); + const tags = this.getAuthorizedTags(file); + const hashId = chargingStation.stationInfo.hashId; + const addressableKey = file + hashId; + this.tagsCachesAddressableIndexes.set( + addressableKey, + (chargingStation.index - 1 + (connectorId - 1)) % tags.length + ); + return tags[this.tagsCachesAddressableIndexes.get(addressableKey)]; + } + private hasTags(file: string): boolean { return this.tagsCaches.has(file); } private setTags(file: string, tags: string[]) { - return this.tagsCaches.set(file, tags); + return this.tagsCaches.set(file, { + tags, + tagsFileWatcher: FileUtils.watchJsonFile( + file, + FileType.Authorization, + this.logPrefix(file), + undefined, + (event, filename) => { + if (Utils.isNotEmptyString(filename) && event === 'change') { + try { + logger.debug( + `${this.logPrefix(file)} ${FileType.Authorization} file have changed, reload` + ); + this.deleteTags(file); + this.deleteTagsIndexes(file); + } catch (error) { + FileUtils.handleFileException( + file, + FileType.Authorization, + error as NodeJS.ErrnoException, + this.logPrefix(file), + { + throwError: false, + } + ); + } + } + } + ), + }); } private getTags(file: string): string[] | undefined { - return this.tagsCaches.get(file); + return this.tagsCaches.get(file)?.tags; } private deleteTags(file: string): boolean { + this.tagsCaches.get(file)?.tagsFileWatcher?.close(); return this.tagsCaches.delete(file); } - private deleteFSWatcher(file: string): boolean { - this.FSWatchers.get(file)?.close(); - return this.FSWatchers.delete(file); + private deleteTagsIndexes(file: string): void { + for (const [key] of this.tagsCachesAddressableIndexes) { + if (key.startsWith(file)) { + this.tagsCachesAddressableIndexes.delete(key); + } + } } private getAuthorizedTagsFromFile(file: string): string[] {