From 7b5dbe910fc30484324da90ee209ab7002bc5071 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Mon, 22 May 2023 10:48:13 +0200 Subject: [PATCH] fix: various fixes to files handling and their content caching MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- .vscode/settings.json | 1 + src/charging-station/ChargingStation.ts | 4 +-- .../ChargingStationConfigurationUtils.ts | 1 + src/charging-station/IdTagsCache.ts | 32 ++++++++++++++----- .../ocpp/OCPPIncomingRequestService.ts | 7 ++-- .../ocpp/OCPPRequestService.ts | 9 ++++++ .../ui-server/AbstractUIServer.ts | 3 +- src/performance/storage/JsonFileStorage.ts | 3 +- src/performance/storage/MongoDBStorage.ts | 5 +-- src/performance/storage/Storage.ts | 5 +-- src/performance/storage/StorageFactory.ts | 3 +- src/types/Error.ts | 4 ++- src/utils/Configuration.ts | 6 +++- src/utils/ErrorUtils.ts | 31 +++++++++++++++--- 14 files changed, 87 insertions(+), 27 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index b8f730ca..47a0799f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -21,6 +21,7 @@ "evses", "iccid", "idtag", + "idtags", "imsi", "lcov", "logform", diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 1e95df4d..e7bf5059 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -1493,7 +1493,7 @@ export class ChargingStation { private getConfigurationFromFile(): ChargingStationConfiguration | undefined { let configuration: ChargingStationConfiguration | undefined; - if (this.configurationFile && fs.existsSync(this.configurationFile)) { + if (Utils.isNotEmptyString(this.configurationFile) && fs.existsSync(this.configurationFile)) { try { if (this.sharedLRUCache.hasChargingStationConfiguration(this.configurationFileHash)) { configuration = this.sharedLRUCache.getChargingStationConfiguration( @@ -1546,7 +1546,7 @@ export class ChargingStation { private saveConfiguration( chargingStationAutomaticTransactionGeneratorConfiguration?: ChargingStationAutomaticTransactionGeneratorConfiguration ): void { - if (this.configurationFile) { + if (Utils.isNotEmptyString(this.configurationFile)) { try { if (!fs.existsSync(path.dirname(this.configurationFile))) { fs.mkdirSync(path.dirname(this.configurationFile), { recursive: true }); diff --git a/src/charging-station/ChargingStationConfigurationUtils.ts b/src/charging-station/ChargingStationConfigurationUtils.ts index e529aa7f..7ffb4e21 100644 --- a/src/charging-station/ChargingStationConfigurationUtils.ts +++ b/src/charging-station/ChargingStationConfigurationUtils.ts @@ -97,6 +97,7 @@ export class ChargingStationConfigurationUtils { key: ConfigurationKeyType, params: DeleteConfigurationKeyParams = { save: true, caseInsensitive: false } ): ConfigurationKey[] | undefined { + params = { ...{ save: true, caseInsensitive: false }, ...params }; const keyFound = ChargingStationConfigurationUtils.getConfigurationKey( chargingStation, key, diff --git a/src/charging-station/IdTagsCache.ts b/src/charging-station/IdTagsCache.ts index 7d766a40..a4ce9a10 100644 --- a/src/charging-station/IdTagsCache.ts +++ b/src/charging-station/IdTagsCache.ts @@ -27,6 +27,15 @@ export class IdTagsCache { return IdTagsCache.instance; } + /** + * Get one idtag from the cache given the distribution + * Must be called after checking the cache is not an empty array + * + * @param distribution + * @param chargingStation + * @param connectorId + * @returns + */ public getIdTag( distribution: IdTagDistribution, chargingStation: ChargingStation, @@ -46,9 +55,19 @@ export class IdTagsCache { } } + /** + * Get all idtags from the cache + * Must be called after checking the cache is not an empty array + * + * @param file + * @returns + */ public getIdTags(file: string): string[] | undefined { if (this.hasIdTagsCache(file) === false) { - this.setIdTagsCache(file, this.getIdTagsFromFile(file)); + this.setIdTagsCache( + Utils.isNotEmptyString(file) ? file : 'empty', + this.getIdTagsFromFile(file) + ); } return this.getIdTagsCache(file); } @@ -152,11 +171,9 @@ export class IdTagsCache { } private getIdTagsFromFile(file: string): string[] { - let idTags: string[] = []; - if (file) { + if (Utils.isNotEmptyString(file)) { try { - // Load id tags file - idTags = JSON.parse(fs.readFileSync(file, 'utf8')) as string[]; + return JSON.parse(fs.readFileSync(file, 'utf8')) as string[]; } catch (error) { ErrorUtils.handleFileException( file, @@ -165,10 +182,9 @@ export class IdTagsCache { this.logPrefix(file) ); } - } else { - logger.info(`${this.logPrefix(file)} No id tags file given`); } - return idTags; + logger.info(`${this.logPrefix(file)} No id tags file given in configuration`); + return []; } private logPrefix = (file: string): string => { diff --git a/src/charging-station/ocpp/OCPPIncomingRequestService.ts b/src/charging-station/ocpp/OCPPIncomingRequestService.ts index c98c28b8..1206cede 100644 --- a/src/charging-station/ocpp/OCPPIncomingRequestService.ts +++ b/src/charging-station/ocpp/OCPPIncomingRequestService.ts @@ -15,7 +15,7 @@ import type { JsonType, OCPPVersion, } from '../../types'; -import { logger } from '../../utils'; +import { ErrorUtils, logger } from '../../utils'; const moduleName = 'OCPPIncomingRequestService'; @@ -56,12 +56,13 @@ export abstract class OCPPIncomingRequestService extends AsyncResource { return OCPPIncomingRequestService.instance as T; } - protected handleIncomingRequestError( + protected handleIncomingRequestError( chargingStation: ChargingStation, commandName: IncomingRequestCommand, error: Error, - params: HandleErrorParams = { throwError: true } + params: HandleErrorParams = { throwError: true, consoleOut: false } ): T | undefined { + ErrorUtils.handleErrorParams(params); logger.error( `${chargingStation.logPrefix()} ${moduleName}.handleIncomingRequestError: Incoming request command '${commandName}' error:`, error diff --git a/src/charging-station/ocpp/OCPPRequestService.ts b/src/charging-station/ocpp/OCPPRequestService.ts index 06258fe4..d2122a65 100644 --- a/src/charging-station/ocpp/OCPPRequestService.ts +++ b/src/charging-station/ocpp/OCPPRequestService.ts @@ -164,6 +164,10 @@ export abstract class OCPPRequestService { throwError: false, } ): Promise { + params = { + ...{ skipBufferingOnError: false, triggerMessage: false, throwError: false }, + ...params, + }; try { return await this.internalSendMessage( chargingStation, @@ -263,8 +267,13 @@ export abstract class OCPPRequestService { params: RequestParams = { skipBufferingOnError: false, triggerMessage: false, + throwError: false, } ): Promise { + params = { + ...{ skipBufferingOnError: false, triggerMessage: false, throwError: false }, + ...params, + }; if ( (chargingStation.inUnknownState() === true && commandName === RequestCommand.BOOT_NOTIFICATION) || diff --git a/src/charging-station/ui-server/AbstractUIServer.ts b/src/charging-station/ui-server/AbstractUIServer.ts index f2429ae1..643b1883 100644 --- a/src/charging-station/ui-server/AbstractUIServer.ts +++ b/src/charging-station/ui-server/AbstractUIServer.ts @@ -4,6 +4,7 @@ import type { WebSocket } from 'ws'; import type { AbstractUIService } from './ui-services/AbstractUIService'; import { UIServiceFactory } from './ui-services/UIServiceFactory'; +import { BaseError } from '../../exception'; import { AuthenticationType, type ChargingStationData, @@ -60,7 +61,7 @@ export abstract class AbstractUIServer { protected authenticate(req: IncomingMessage, next: (err?: Error) => void): void { if (this.isBasicAuthEnabled() === true) { if (this.isValidBasicAuth(req) === false) { - next(new Error('Unauthorized')); + next(new BaseError('Unauthorized')); } next(); } diff --git a/src/performance/storage/JsonFileStorage.ts b/src/performance/storage/JsonFileStorage.ts index 50d1a8b9..2a712a60 100644 --- a/src/performance/storage/JsonFileStorage.ts +++ b/src/performance/storage/JsonFileStorage.ts @@ -4,6 +4,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { Storage } from './Storage'; +import { BaseError } from '../../exception'; import { FileType, type Statistics } from '../../types'; import { AsyncLock, AsyncLockType, Constants, ErrorUtils, Utils } from '../../utils'; @@ -79,7 +80,7 @@ export class JsonFileStorage extends Storage { private checkPerformanceRecordsFile(): void { if (!this?.fd) { - throw new Error( + throw new BaseError( `${this.logPrefix} Performance records '${this.dbName}' file descriptor not found` ); } diff --git a/src/performance/storage/MongoDBStorage.ts b/src/performance/storage/MongoDBStorage.ts index aff757b5..7dd505d3 100644 --- a/src/performance/storage/MongoDBStorage.ts +++ b/src/performance/storage/MongoDBStorage.ts @@ -3,6 +3,7 @@ import { MongoClient } from 'mongodb'; import { Storage } from './Storage'; +import { BaseError } from '../../exception'; import { type Statistics, StorageType } from '../../types'; import { Constants } from '../../utils'; @@ -55,14 +56,14 @@ export class MongoDBStorage extends Storage { private checkDBConnection() { if (!this?.client) { - throw new Error( + throw new BaseError( `${this.logPrefix} ${this.getDBNameFromStorageType( StorageType.MONGO_DB )} client initialization failed while trying to issue a request` ); } if (!this.connected) { - throw new Error( + throw new BaseError( `${this.logPrefix} ${this.getDBNameFromStorageType( StorageType.MONGO_DB )} connection not opened while trying to issue a request` diff --git a/src/performance/storage/Storage.ts b/src/performance/storage/Storage.ts index ba177524..9df2ebca 100644 --- a/src/performance/storage/Storage.ts +++ b/src/performance/storage/Storage.ts @@ -9,7 +9,7 @@ import { type Statistics, StorageType, } from '../../types'; -import { Utils, logger } from '../../utils'; +import { ErrorUtils, Utils, logger } from '../../utils'; export abstract class Storage { protected readonly storageUri: URL; @@ -25,8 +25,9 @@ export abstract class Storage { type: StorageType, error: Error, table?: string, - params: HandleErrorParams = { throwError: false } + params: HandleErrorParams = { throwError: false, consoleOut: false } ): void { + ErrorUtils.handleErrorParams(params, { throwError: false, consoleOut: false }); const inTableOrCollectionStr = (!Utils.isNullOrUndefined(table) || !table) && ` in table or collection '${table}'`; logger.error( diff --git a/src/performance/storage/StorageFactory.ts b/src/performance/storage/StorageFactory.ts index 09b58a15..1c109e1b 100644 --- a/src/performance/storage/StorageFactory.ts +++ b/src/performance/storage/StorageFactory.ts @@ -4,6 +4,7 @@ import { JsonFileStorage } from './JsonFileStorage'; import { MikroOrmStorage } from './MikroOrmStorage'; import { MongoDBStorage } from './MongoDBStorage'; import type { Storage } from './Storage'; +import { BaseError } from '../../exception'; import { StorageType } from '../../types'; export class StorageFactory { @@ -26,7 +27,7 @@ export class StorageFactory { // storageInstance = new MikroOrmStorage(connectionUri, logPrefix, type); // break; default: - throw new Error(`${logPrefix} Unknown storage type: ${type}`); + throw new BaseError(`${logPrefix} Unknown storage type: ${type}`); } return storageInstance; } diff --git a/src/types/Error.ts b/src/types/Error.ts index 76e3005f..885edfdb 100644 --- a/src/types/Error.ts +++ b/src/types/Error.ts @@ -1,4 +1,6 @@ -export type HandleErrorParams = { +import type { JsonType } from './JsonType'; + +export type HandleErrorParams = { throwError?: boolean; consoleOut?: boolean; errorResponse?: T; diff --git a/src/utils/Configuration.ts b/src/utils/Configuration.ts index 21426070..e4215f94 100644 --- a/src/utils/Configuration.ts +++ b/src/utils/Configuration.ts @@ -413,10 +413,14 @@ export class Configuration { case 'EACCES': logMsg = `${fileType} file ${file} access denied:`; break; + case 'EPERM': + logMsg = `${fileType} file ${file} permission denied:`; + break; default: logMsg = `${fileType} file ${file} error:`; } - console.warn(`${chalk.green(prefix)}${chalk.yellow(`${logMsg} `)}`, error); + console.error(`${chalk.green(prefix)}${chalk.red(`${logMsg} `)}`, error); + throw error; } private static getDefaultPerformanceStorageUri(storageType: StorageType) { diff --git a/src/utils/ErrorUtils.ts b/src/utils/ErrorUtils.ts index 7efbe514..254bd9ec 100644 --- a/src/utils/ErrorUtils.ts +++ b/src/utils/ErrorUtils.ts @@ -8,6 +8,7 @@ import type { FileType, HandleErrorParams, IncomingRequestCommand, + JsonType, RequestCommand, } from '../types'; @@ -35,6 +36,7 @@ export class ErrorUtils { logPrefix: string, params: HandleErrorParams = { throwError: true, consoleOut: false } ): void { + ErrorUtils.handleErrorParams(params); const prefix = Utils.isNotEmptyString(logPrefix) ? `${logPrefix} ` : ''; let logMsg: string; switch (error.code) { @@ -47,13 +49,24 @@ export class ErrorUtils { case 'EACCES': logMsg = `${fileType} file ${file} access denied:`; break; + case 'EPERM': + logMsg = `${fileType} file ${file} permission denied:`; + break; default: logMsg = `${fileType} file ${file} error:`; } - if (params?.consoleOut) { - console.warn(`${chalk.green(prefix)}${chalk.yellow(`${logMsg} `)}`, error); - } else { - logger.warn(`${prefix}${logMsg}`, error); + if (params?.consoleOut === true) { + if (params?.throwError) { + console.error(`${chalk.green(prefix)}${chalk.red(`${logMsg} `)}`, error); + } else { + console.warn(`${chalk.green(prefix)}${chalk.yellow(`${logMsg} `)}`, error); + } + } else if (params?.consoleOut === false) { + if (params?.throwError) { + logger.error(`${prefix}${logMsg}`, error); + } else { + logger.warn(`${prefix}${logMsg}`, error); + } } if (params?.throwError) { throw error; @@ -64,11 +77,19 @@ export class ErrorUtils { chargingStation: ChargingStation, commandName: RequestCommand | IncomingRequestCommand, error: Error, - params: HandleErrorParams = { throwError: false } + params: HandleErrorParams = { throwError: false, consoleOut: false } ): void { + ErrorUtils.handleErrorParams(params, { throwError: false, consoleOut: false }); logger.error(`${chargingStation.logPrefix()} Request command '${commandName}' error:`, error); if (params?.throwError === true) { throw error; } } + + public static handleErrorParams( + params: HandleErrorParams, + defaultParams: HandleErrorParams = { throwError: true, consoleOut: false } + ): HandleErrorParams { + return { ...defaultParams, ...params }; + } } -- 2.34.1