-import path from 'node:path';
+import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { TsMorphMetadataProvider } from '@mikro-orm/reflection';
metadataProvider: TsMorphMetadataProvider,
entities: [PerformanceRecord, PerformanceData],
type: 'sqlite',
- clientUrl: `file://${path.join(
- path.dirname(fileURLToPath(import.meta.url)),
+ clientUrl: `file://${join(
+ dirname(fileURLToPath(import.meta.url)),
`${Constants.DEFAULT_PERFORMANCE_RECORDS_DB_NAME}.db`
)}`,
};
// Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
import { EventEmitter } from 'node:events';
-import path from 'node:path';
+import { dirname, extname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { isMainThread } from 'node:worker_threads';
this.initializedCounters = false;
this.initializeCounters();
this.workerImplementation = null;
- this.workerScript = path.join(
- path.dirname(fileURLToPath(import.meta.url)),
- `ChargingStationWorker${path.extname(fileURLToPath(import.meta.url))}`
+ this.workerScript = join(
+ dirname(fileURLToPath(import.meta.url)),
+ `ChargingStationWorker${extname(fileURLToPath(import.meta.url))}`
);
Configuration.getUIServer().enabled === true &&
(this.uiServer = UIServerFactory.getUIServerImplementation(Configuration.getUIServer()));
): Promise<void> {
await this.workerImplementation?.addElement({
index,
- templateFile: path.join(
- path.dirname(fileURLToPath(import.meta.url)),
+ templateFile: join(
+ dirname(fileURLToPath(import.meta.url)),
'assets',
'station-templates',
stationTemplateUrl.file
// Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
-import crypto from 'node:crypto';
-import fs from 'node:fs';
-import path from 'node:path';
+import { createHash } from 'node:crypto';
+import {
+ type FSWatcher,
+ closeSync,
+ existsSync,
+ mkdirSync,
+ openSync,
+ readFileSync,
+ writeFileSync,
+} from 'node:fs';
+import { dirname, join } from 'node:path';
import { URL } from 'node:url';
import { parentPort } from 'node:worker_threads';
import merge from 'just-merge';
-import WebSocket, { type RawData } from 'ws';
+import { type RawData, WebSocket } from 'ws';
import { AutomaticTransactionGenerator } from './AutomaticTransactionGenerator';
import { ChargingStationWorkerBroadcastChannel } from './broadcast-channel/ChargingStationWorkerBroadcastChannel';
private configuredSupervisionUrl!: URL;
private wsConnectionRestarted: boolean;
private autoReconnectRetryCount: number;
- private templateFileWatcher!: fs.FSWatcher | undefined;
+ private templateFileWatcher!: FSWatcher | undefined;
private templateFileHash!: string;
private readonly sharedLRUCache: SharedLRUCache;
private webSocketPingSetInterval!: NodeJS.Timeout;
} else {
const measureId = `${FileType.ChargingStationTemplate} read`;
const beginId = PerformanceStatistics.beginMeasure(measureId);
- template = JSON.parse(
- fs.readFileSync(this.templateFile, 'utf8')
- ) as ChargingStationTemplate;
+ template = JSON.parse(readFileSync(this.templateFile, 'utf8')) as ChargingStationTemplate;
PerformanceStatistics.endMeasure(measureId, beginId);
- template.templateHash = crypto
- .createHash(Constants.DEFAULT_HASH_ALGORITHM)
+ template.templateHash = createHash(Constants.DEFAULT_HASH_ALGORITHM)
.update(JSON.stringify(template))
.digest('hex');
this.sharedLRUCache.setChargingStationTemplate(template);
private initialize(): void {
const stationTemplate = this.getTemplateFromFile();
ChargingStationUtils.checkTemplate(stationTemplate, this.logPrefix(), this.templateFile);
- this.configurationFile = path.join(
- path.dirname(this.templateFile.replace('station-templates', 'configurations')),
+ this.configurationFile = join(
+ dirname(this.templateFile.replace('station-templates', 'configurations')),
`${ChargingStationUtils.getHashId(this.index, stationTemplate)}.json`
);
const chargingStationConfiguration = this.getConfigurationFromFile();
this.logPrefix(),
this.templateFile
);
- const connectorsConfigHash = crypto
- .createHash(Constants.DEFAULT_HASH_ALGORITHM)
+ const connectorsConfigHash = createHash(Constants.DEFAULT_HASH_ALGORITHM)
.update(
`${JSON.stringify(stationTemplate?.Connectors)}${configuredMaxConnectors.toString()}`
)
);
}
if (stationTemplate?.Evses) {
- const evsesConfigHash = crypto
- .createHash(Constants.DEFAULT_HASH_ALGORITHM)
+ const evsesConfigHash = createHash(Constants.DEFAULT_HASH_ALGORITHM)
.update(JSON.stringify(stationTemplate?.Evses))
.digest('hex');
const evsesConfigChanged =
private getConfigurationFromFile(): ChargingStationConfiguration | undefined {
let configuration: ChargingStationConfiguration | undefined;
- if (Utils.isNotEmptyString(this.configurationFile) && fs.existsSync(this.configurationFile)) {
+ if (Utils.isNotEmptyString(this.configurationFile) && existsSync(this.configurationFile)) {
try {
if (this.sharedLRUCache.hasChargingStationConfiguration(this.configurationFileHash)) {
configuration = this.sharedLRUCache.getChargingStationConfiguration(
const measureId = `${FileType.ChargingStationConfiguration} read`;
const beginId = PerformanceStatistics.beginMeasure(measureId);
configuration = JSON.parse(
- fs.readFileSync(this.configurationFile, 'utf8')
+ readFileSync(this.configurationFile, 'utf8')
) as ChargingStationConfiguration;
PerformanceStatistics.endMeasure(measureId, beginId);
this.sharedLRUCache.setChargingStationConfiguration(configuration);
private saveConfiguration(): void {
if (Utils.isNotEmptyString(this.configurationFile)) {
try {
- if (!fs.existsSync(path.dirname(this.configurationFile))) {
- fs.mkdirSync(path.dirname(this.configurationFile), { recursive: true });
+ if (!existsSync(dirname(this.configurationFile))) {
+ mkdirSync(dirname(this.configurationFile), { recursive: true });
}
let configurationData: ChargingStationConfiguration =
Utils.cloneObject<ChargingStationConfiguration>(this.getConfigurationFromFile()) ?? {};
delete configurationData.evsesStatus;
}
delete configurationData.configurationHash;
- const configurationHash = crypto
- .createHash(Constants.DEFAULT_HASH_ALGORITHM)
+ const configurationHash = createHash(Constants.DEFAULT_HASH_ALGORITHM)
.update(
JSON.stringify({
stationInfo: configurationData.stationInfo,
configurationData.configurationHash = configurationHash;
const measureId = `${FileType.ChargingStationConfiguration} write`;
const beginId = PerformanceStatistics.beginMeasure(measureId);
- const fileDescriptor = fs.openSync(this.configurationFile, 'w');
- fs.writeFileSync(fileDescriptor, JSON.stringify(configurationData, null, 2), 'utf8');
- fs.closeSync(fileDescriptor);
+ const fileDescriptor = openSync(this.configurationFile, 'w');
+ writeFileSync(fileDescriptor, JSON.stringify(configurationData, null, 2), 'utf8');
+ closeSync(fileDescriptor);
PerformanceStatistics.endMeasure(measureId, beginId);
this.sharedLRUCache.deleteChargingStationConfiguration(this.configurationFileHash);
this.sharedLRUCache.setChargingStationConfiguration(configurationData);
-import crypto from 'node:crypto';
-import type EventEmitter from 'node:events';
-import path from 'node:path';
+import { createHash, randomBytes } from 'node:crypto';
+import type { EventEmitter } from 'node:events';
+import { basename, dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import chalk from 'chalk';
meterType: stationTemplate.meterType,
}),
};
- return crypto
- .createHash(Constants.DEFAULT_HASH_ALGORITHM)
+ return createHash(Constants.DEFAULT_HASH_ALGORITHM)
.update(
`${JSON.stringify(chargingStationInfo)}${ChargingStationUtils.getChargingStationId(
index,
public static getIdTagsFile(stationInfo: ChargingStationInfo): string | undefined {
return (
stationInfo.idTagsFile &&
- path.join(
- path.dirname(fileURLToPath(import.meta.url)),
- 'assets',
- path.basename(stationInfo.idTagsFile)
- )
+ join(dirname(fileURLToPath(import.meta.url)), 'assets', basename(stationInfo.idTagsFile))
);
}
randomBytesLength?: number;
upperCase?: boolean;
}): string {
- const randomSerialNumberSuffix = crypto
- .randomBytes(params?.randomBytesLength ?? 16)
- .toString('hex');
+ const randomSerialNumberSuffix = randomBytes(params?.randomBytesLength ?? 16).toString('hex');
if (params?.upperCase) {
return randomSerialNumberSuffix.toUpperCase();
}
-import fs from 'node:fs';
+import { type FSWatcher, readFileSync } from 'node:fs';
import type { ChargingStation } from './ChargingStation';
import { ChargingStationUtils } from './ChargingStationUtils';
type IdTagsCacheValueType = {
idTags: string[];
- idTagsFileWatcher: fs.FSWatcher | undefined;
+ idTagsFileWatcher: FSWatcher | undefined;
};
export class IdTagsCache {
private getIdTagsFromFile(file: string): string[] {
if (Utils.isNotEmptyString(file)) {
try {
- return JSON.parse(fs.readFileSync(file, 'utf8')) as string[];
+ return JSON.parse(readFileSync(file, 'utf8')) as string[];
} catch (error) {
handleFileException(
file,
// Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
-import fs from 'node:fs';
-import path from 'node:path';
+import { createWriteStream, readdirSync } from 'node:fs';
+import { dirname, join, resolve } from 'node:path';
import { URL, fileURLToPath } from 'node:url';
import type { JSONSchemaType } from 'ajv';
import { Client, type FTPResponse } from 'basic-ftp';
-import tar from 'tar';
+import { create } from 'tar';
import { OCPP16Constants } from './OCPP16Constants';
import { OCPP16ServiceUtils } from './OCPP16ServiceUtils';
if (uri.protocol.startsWith('ftp:')) {
let ftpClient: Client;
try {
- const logFiles = fs
- .readdirSync(path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../'))
+ const logFiles = readdirSync(resolve(dirname(fileURLToPath(import.meta.url)), '../'))
.filter((file) => file.endsWith('.log'))
- .map((file) => path.join('./', file));
+ .map((file) => join('./', file));
const diagnosticsArchive = `${chargingStation.stationInfo.chargingStationId}_logs.tar.gz`;
- tar.create({ gzip: true }, logFiles).pipe(fs.createWriteStream(diagnosticsArchive));
+ create({ gzip: true }, logFiles).pipe(createWriteStream(diagnosticsArchive));
ftpClient = new Client();
const accessResponse = await ftpClient.access({
host: uri.host,
});
});
uploadResponse = await ftpClient.uploadFrom(
- path.join(
- path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../'),
- diagnosticsArchive
- ),
+ join(resolve(dirname(fileURLToPath(import.meta.url)), '../'), diagnosticsArchive),
`${uri.pathname}${diagnosticsArchive}`
);
if (uploadResponse.code === 226) {
-import fs from 'node:fs';
-import path from 'node:path';
+import { readFileSync } from 'node:fs';
+import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import type { DefinedError, ErrorObject, JSONSchemaType } from 'ajv';
moduleName?: string,
methodName?: string
): JSONSchemaType<T> {
- const filePath = path.join(path.dirname(fileURLToPath(import.meta.url)), relativePath);
+ const filePath = join(dirname(fileURLToPath(import.meta.url)), relativePath);
try {
- return JSON.parse(fs.readFileSync(filePath, 'utf8')) as JSONSchemaType<T>;
+ return JSON.parse(readFileSync(filePath, 'utf8')) as JSONSchemaType<T>;
} catch (error) {
handleFileException(
filePath,
import type { Duplex } from 'node:stream';
import { StatusCodes } from 'http-status-codes';
-import WebSocket, { type RawData, WebSocketServer } from 'ws';
+import { type RawData, WebSocket, WebSocketServer } from 'ws';
import { AbstractUIServer } from './AbstractUIServer';
import { UIServerUtils } from './UIServerUtils';
// Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
-import fs from 'node:fs';
-import path from 'node:path';
+import { closeSync, existsSync, mkdirSync, openSync, readFileSync, writeFileSync } from 'node:fs';
+import { dirname } from 'node:path';
import { Storage } from './Storage';
import { BaseError } from '../../exception';
this.checkPerformanceRecordsFile();
AsyncLock.acquire(AsyncLockType.performance)
.then(() => {
- const fileData = fs.readFileSync(this.dbName, 'utf8');
+ const fileData = readFileSync(this.dbName, 'utf8');
const performanceRecords: Statistics[] = fileData
? (JSON.parse(fileData) as Statistics[])
: [];
performanceRecords.push(performanceStatistics);
- fs.writeFileSync(
+ writeFileSync(
this.dbName,
Utils.JSONStringifyWithMapSupport(performanceRecords, 2),
'utf8'
public open(): void {
try {
if (Utils.isNullOrUndefined(this?.fd)) {
- if (!fs.existsSync(path.dirname(this.dbName))) {
- fs.mkdirSync(path.dirname(this.dbName), { recursive: true });
+ if (!existsSync(dirname(this.dbName))) {
+ mkdirSync(dirname(this.dbName), { recursive: true });
}
- this.fd = fs.openSync(this.dbName, 'a+');
+ this.fd = openSync(this.dbName, 'a+');
}
} catch (error) {
handleFileException(
public close(): void {
try {
if (this?.fd) {
- fs.closeSync(this.fd);
+ closeSync(this.fd);
this.fd = null;
}
} catch (error) {
-import fs from 'node:fs';
-import path from 'node:path';
+import { type FSWatcher, readFileSync, watch } from 'node:fs';
+import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import chalk from 'chalk';
import { WorkerConstants, WorkerProcessType } from '../worker';
export class Configuration {
- private static configurationFile = path.join(
- path.dirname(fileURLToPath(import.meta.url)),
+ private static configurationFile = join(
+ dirname(fileURLToPath(import.meta.url)),
'assets',
'config.json'
);
- private static configurationFileWatcher: fs.FSWatcher | undefined;
+ private static configurationFileWatcher: FSWatcher | undefined;
private static configuration: ConfigurationData | null = null;
private static configurationChangeCallback: () => Promise<void>;
if (!Configuration.configuration) {
try {
Configuration.configuration = JSON.parse(
- fs.readFileSync(Configuration.configurationFile, 'utf8')
+ readFileSync(Configuration.configurationFile, 'utf8')
) as ConfigurationData;
} catch (error) {
Configuration.handleFileException(
return Configuration.configuration;
}
- private static getConfigurationFileWatcher(): fs.FSWatcher | undefined {
+ private static getConfigurationFileWatcher(): FSWatcher | undefined {
try {
- return fs.watch(Configuration.configurationFile, (event, filename): void => {
+ return watch(Configuration.configurationFile, (event, filename): void => {
if (filename?.trim().length > 0 && event === 'change') {
// Nullify to force configuration file reading
Configuration.configuration = null;
}
private static buildPerformanceUriFilePath(file: string) {
- return `file://${path.join(
- path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../'),
- file
- )}`;
+ return `file://${join(resolve(dirname(fileURLToPath(import.meta.url)), '../'), file)}`;
}
}
-import fs from 'node:fs';
+import { type FSWatcher, type WatchListener, readFileSync, watch } from 'node:fs';
import { handleFileException } from './ErrorUtils';
import { logger } from './Logger';
fileType: FileType,
logPrefix: string,
refreshedVariable?: T,
- listener: fs.WatchListener<string> = (event, filename) => {
+ listener: WatchListener<string> = (event, filename) => {
if (Utils.isNotEmptyString(filename) && event === 'change') {
try {
logger.debug(`${logPrefix} ${fileType} file ${file} have changed, reload`);
- refreshedVariable && (refreshedVariable = JSON.parse(fs.readFileSync(file, 'utf8')) as T);
+ refreshedVariable && (refreshedVariable = JSON.parse(readFileSync(file, 'utf8')) as T);
} catch (error) {
handleFileException(file, fileType, error as NodeJS.ErrnoException, logPrefix, {
throwError: false,
}
}
}
-): fs.FSWatcher | undefined => {
+): FSWatcher | undefined => {
if (Utils.isNotEmptyString(file)) {
try {
- return fs.watch(file, listener);
+ return watch(file, listener);
} catch (error) {
handleFileException(file, fileType, error as NodeJS.ErrnoException, logPrefix, {
throwError: false,
-import crypto from 'node:crypto';
-import util from 'node:util';
+import { randomBytes, randomInt, randomUUID } from 'node:crypto';
+import { inspect } from 'node:util';
import clone from 'just-clone';
};
public static generateUUID(): string {
- return crypto.randomUUID();
+ return randomUUID();
}
public static validateUUID(uuid: string): boolean {
if (max - min === Infinity) {
throw new RangeError('Invalid interval');
}
- return (crypto.randomBytes(4).readUInt32LE() / 0xffffffff) * (max - min) + min;
+ return (randomBytes(4).readUInt32LE() / 0xffffffff) * (max - min) + min;
}
public static getRandomInteger(max = Constants.MAX_RANDOM_INTEGER, min = 0): number {
max = Math.floor(max);
if (!Utils.isNullOrUndefined(min) && min !== 0) {
min = Math.ceil(min);
- return Math.floor(crypto.randomInt(min, max + 1));
+ return Math.floor(randomInt(min, max + 1));
}
- return Math.floor(crypto.randomInt(max + 1));
+ return Math.floor(randomInt(max + 1));
}
/**
}
public static isPromisePending(promise: Promise<unknown>): boolean {
- return util.inspect(promise).includes('pending');
+ return inspect(promise).includes('pending');
}
public static async promiseWithTimeout<T>(
* @returns
*/
public static secureRandom(): number {
- return crypto.randomBytes(4).readUInt32LE() / 0x100000000;
+ return randomBytes(4).readUInt32LE() / 0x100000000;
}
public static JSONStringifyWithMapSupport(
-import type EventEmitterAsyncResource from 'node:events';
-import fs from 'node:fs';
+import type { EventEmitter } from 'node:events';
+import { existsSync } from 'node:fs';
import type { Worker } from 'node:worker_threads';
-import type { ErrorHandler, ExitHandler, PoolInfo } from 'poolifier';
+import type { ErrorHandler, ExitHandler, PoolEmitter, PoolInfo } from 'poolifier';
import { WorkerConstants } from './WorkerConstants';
import type { SetInfo, WorkerData, WorkerOptions } from './WorkerTypes';
public abstract readonly info: PoolInfo | SetInfo;
public abstract readonly size: number;
public abstract readonly maxElementsPerWorker: number | undefined;
- public abstract readonly emitter: EventEmitterAsyncResource | undefined;
+ public abstract readonly emitter: EventEmitter | PoolEmitter | undefined;
/**
* `WorkerAbstract` constructor.
if (typeof workerScript === 'string' && workerScript.trim().length === 0) {
throw new Error('Worker script is empty');
}
- if (!fs.existsSync(workerScript)) {
+ if (!existsSync(workerScript)) {
throw new Error('Worker script file does not exist');
}
this.workerScript = workerScript;
-import type EventEmitterAsyncResource from 'node:events';
-
-import { DynamicThreadPool, type PoolInfo } from 'poolifier';
+import { DynamicThreadPool, type PoolEmitter, type PoolInfo } from 'poolifier';
import { WorkerAbstract } from './WorkerAbstract';
import type { WorkerData, WorkerOptions } from './WorkerTypes';
return undefined;
}
- get emitter(): EventEmitterAsyncResource | undefined {
+ get emitter(): PoolEmitter | undefined {
return this.pool?.emitter;
}
// Partial Copyright Jerome Benoit. 2021-2023. All Rights Reserved.
-import EventEmitterAsyncResource from 'node:events';
+import { EventEmitter } from 'node:events';
import { SHARE_ENV, Worker } from 'node:worker_threads';
import { WorkerAbstract } from './WorkerAbstract';
import { sleep } from './WorkerUtils';
export class WorkerSet extends WorkerAbstract<WorkerData> {
- public readonly emitter: EventEmitterAsyncResource;
+ public readonly emitter: EventEmitter;
private readonly workerSet: Set<WorkerSetElement>;
/**
};
this.workerSet = new Set<WorkerSetElement>();
if (this.workerOptions?.poolOptions?.enableEvents) {
- this.emitter = new EventEmitterAsyncResource();
+ this.emitter = new EventEmitter();
}
}
-import type EventEmitterAsyncResource from 'node:events';
-
-import { FixedThreadPool, type PoolInfo } from 'poolifier';
+import { FixedThreadPool, type PoolEmitter, type PoolInfo } from 'poolifier';
import { WorkerAbstract } from './WorkerAbstract';
import type { WorkerData, WorkerOptions } from './WorkerTypes';
return undefined;
}
- get emitter(): EventEmitterAsyncResource | undefined {
+ get emitter(): PoolEmitter | undefined {
return this.pool?.emitter;
}
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
- // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
- "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
+ "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
+ // "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */