build(deps-dev): apply updates
[e-mobility-charging-stations-simulator.git] / src / utils / Configuration.ts
CommitLineData
d972af76
JB
1import { type FSWatcher, readFileSync, watch } from 'node:fs';
2import { dirname, join, resolve } from 'node:path';
130783a7 3import { fileURLToPath } from 'node:url';
8114d10e
JB
4
5import chalk from 'chalk';
088ee3c1 6import merge from 'just-merge';
156cab2c 7import { WorkerChoiceStrategies } from 'poolifier';
8114d10e 8
878e026c 9import { Constants } from './Constants';
9bf0ef23 10import { hasOwnProp, isCFEnvironment, isNotEmptyString, isUndefined } from './Utils';
83e00df1 11import {
268a74bb 12 ApplicationProtocol,
83e00df1 13 type ConfigurationData,
268a74bb 14 FileType,
3d48c1c1 15 type LogConfiguration,
83e00df1
JB
16 type StationTemplateUrl,
17 type StorageConfiguration,
268a74bb 18 StorageType,
e7aeea18 19 SupervisionUrlDistribution,
83e00df1
JB
20 type UIServerConfiguration,
21 type WorkerConfiguration,
268a74bb
JB
22} from '../types';
23import { WorkerConstants, WorkerProcessType } from '../worker';
7dde0b73 24
268a74bb 25export class Configuration {
d972af76
JB
26 private static configurationFile = join(
27 dirname(fileURLToPath(import.meta.url)),
e7aeea18 28 'assets',
5edd8ba0 29 'config.json',
e7aeea18 30 );
10068088 31
d972af76 32 private static configurationFileWatcher: FSWatcher | undefined;
6e0964c8 33 private static configuration: ConfigurationData | null = null;
e57acf6a
JB
34 private static configurationChangeCallback: () => Promise<void>;
35
d5bd1c00
JB
36 private constructor() {
37 // This is intentional
38 }
39
aa7d6d95 40 public static setConfigurationChangeCallback(cb: () => Promise<void>): void {
e57acf6a
JB
41 Configuration.configurationChangeCallback = cb;
42 }
7dde0b73 43
aa7d6d95 44 public static getUIServer(): UIServerConfiguration {
9bf0ef23 45 if (hasOwnProp(Configuration.getConfig(), 'uiWebSocketServer')) {
66271092 46 console.error(
c5e52a07 47 `${chalk.green(Configuration.logPrefix())} ${chalk.red(
5edd8ba0
JB
48 "Deprecated configuration section 'uiWebSocketServer' usage. Use 'uiServer' instead",
49 )}`,
66271092
JB
50 );
51 }
675fa8e3 52 let uiServerConfiguration: UIServerConfiguration = {
b803eefa 53 enabled: false,
1f7fa4de 54 type: ApplicationProtocol.WS,
c127bd64 55 options: {
adbddcb4
JB
56 host: Constants.DEFAULT_UI_SERVER_HOST,
57 port: Constants.DEFAULT_UI_SERVER_PORT,
c127bd64 58 },
6a49ad23 59 };
9bf0ef23 60 if (hasOwnProp(Configuration.getConfig(), 'uiServer')) {
598c886d
JB
61 uiServerConfiguration = merge<UIServerConfiguration>(
62 uiServerConfiguration,
5edd8ba0 63 Configuration.getConfig()?.uiServer,
598c886d 64 );
6a49ad23 65 }
9bf0ef23 66 if (isCFEnvironment() === true) {
72092cfc 67 delete uiServerConfiguration.options?.host;
b803eefa
JB
68 uiServerConfiguration.options.port = parseInt(process.env.PORT);
69 }
675fa8e3 70 return uiServerConfiguration;
6a49ad23
JB
71 }
72
aa7d6d95 73 public static getPerformanceStorage(): StorageConfiguration {
e7aeea18 74 Configuration.warnDeprecatedConfigurationKey('URI', 'performanceStorage', "Use 'uri' instead");
6a49ad23
JB
75 let storageConfiguration: StorageConfiguration = {
76 enabled: false,
77 type: StorageType.JSON_FILE,
e7aeea18 78 uri: this.getDefaultPerformanceStorageUri(StorageType.JSON_FILE),
6a49ad23 79 };
9bf0ef23 80 if (hasOwnProp(Configuration.getConfig(), 'performanceStorage')) {
e7aeea18 81 storageConfiguration = {
1ba1e8fb 82 ...storageConfiguration,
1895299d 83 ...Configuration.getConfig()?.performanceStorage,
f682b2dc
JB
84 ...(Configuration.getConfig()?.performanceStorage?.type === StorageType.JSON_FILE &&
85 Configuration.getConfig()?.performanceStorage?.uri && {
e8044a69 86 uri: Configuration.buildPerformanceUriFilePath(
5edd8ba0 87 new URL(Configuration.getConfig()?.performanceStorage?.uri).pathname,
e8044a69 88 ),
f682b2dc 89 }),
72f041bd 90 };
72f041bd
JB
91 }
92 return storageConfiguration;
7dde0b73
JB
93 }
94
aa7d6d95 95 public static getAutoReconnectMaxRetries(): number | undefined {
e7aeea18
JB
96 Configuration.warnDeprecatedConfigurationKey(
97 'autoReconnectTimeout',
1895299d 98 undefined,
5edd8ba0 99 "Use 'ConnectionTimeOut' OCPP parameter in charging station template instead",
e7aeea18
JB
100 );
101 Configuration.warnDeprecatedConfigurationKey(
102 'connectionTimeout',
1895299d 103 undefined,
5edd8ba0 104 "Use 'ConnectionTimeOut' OCPP parameter in charging station template instead",
e7aeea18
JB
105 );
106 Configuration.warnDeprecatedConfigurationKey(
107 'autoReconnectMaxRetries',
1895299d 108 undefined,
5edd8ba0 109 'Use it in charging station template instead',
e7aeea18 110 );
7dde0b73 111 // Read conf
9bf0ef23 112 if (hasOwnProp(Configuration.getConfig(), 'autoReconnectMaxRetries')) {
1895299d 113 return Configuration.getConfig()?.autoReconnectMaxRetries;
3574dfd3 114 }
7dde0b73
JB
115 }
116
aa7d6d95 117 public static getStationTemplateUrls(): StationTemplateUrl[] | undefined {
e7aeea18
JB
118 Configuration.warnDeprecatedConfigurationKey(
119 'stationTemplateURLs',
1895299d 120 undefined,
5edd8ba0 121 "Use 'stationTemplateUrls' instead",
e7aeea18 122 );
9bf0ef23 123 !isUndefined(Configuration.getConfig()['stationTemplateURLs']) &&
e7aeea18
JB
124 (Configuration.getConfig().stationTemplateUrls = Configuration.getConfig()[
125 'stationTemplateURLs'
617cad0c 126 ] as StationTemplateUrl[]);
7436ee0d
JB
127 Configuration.getConfig().stationTemplateUrls.forEach(
128 (stationTemplateUrl: StationTemplateUrl) => {
9bf0ef23 129 if (!isUndefined(stationTemplateUrl['numberOfStation'])) {
7436ee0d 130 console.error(
c5e52a07 131 `${chalk.green(Configuration.logPrefix())} ${chalk.red(
5edd8ba0
JB
132 `Deprecated configuration key 'numberOfStation' usage for template file '${stationTemplateUrl.file}' in 'stationTemplateUrls'. Use 'numberOfStations' instead`,
133 )}`,
7436ee0d
JB
134 );
135 }
5edd8ba0 136 },
7436ee0d 137 );
7dde0b73 138 // Read conf
1895299d 139 return Configuration.getConfig()?.stationTemplateUrls;
7dde0b73
JB
140 }
141
3d48c1c1
JB
142 public static getLog(): LogConfiguration {
143 Configuration.warnDeprecatedConfigurationKey(
144 'logEnabled',
145 undefined,
5edd8ba0 146 "Use 'log' section to define the logging enablement instead",
3d48c1c1
JB
147 );
148 Configuration.warnDeprecatedConfigurationKey(
149 'logFile',
150 undefined,
5edd8ba0 151 "Use 'log' section to define the log file instead",
3d48c1c1
JB
152 );
153 Configuration.warnDeprecatedConfigurationKey(
154 'logErrorFile',
155 undefined,
5edd8ba0 156 "Use 'log' section to define the log error file instead",
3d48c1c1
JB
157 );
158 Configuration.warnDeprecatedConfigurationKey(
159 'logConsole',
160 undefined,
5edd8ba0 161 "Use 'log' section to define the console logging enablement instead",
3d48c1c1
JB
162 );
163 Configuration.warnDeprecatedConfigurationKey(
164 'logStatisticsInterval',
165 undefined,
5edd8ba0 166 "Use 'log' section to define the log statistics interval instead",
3d48c1c1
JB
167 );
168 Configuration.warnDeprecatedConfigurationKey(
169 'logLevel',
170 undefined,
5edd8ba0 171 "Use 'log' section to define the log level instead",
3d48c1c1
JB
172 );
173 Configuration.warnDeprecatedConfigurationKey(
174 'logFormat',
175 undefined,
5edd8ba0 176 "Use 'log' section to define the log format instead",
3d48c1c1
JB
177 );
178 Configuration.warnDeprecatedConfigurationKey(
179 'logRotate',
180 undefined,
5edd8ba0 181 "Use 'log' section to define the log rotation enablement instead",
3d48c1c1
JB
182 );
183 Configuration.warnDeprecatedConfigurationKey(
184 'logMaxFiles',
185 undefined,
5edd8ba0 186 "Use 'log' section to define the log maximum files instead",
3d48c1c1
JB
187 );
188 Configuration.warnDeprecatedConfigurationKey(
189 'logMaxSize',
190 undefined,
5edd8ba0 191 "Use 'log' section to define the log maximum size instead",
3d48c1c1
JB
192 );
193 const defaultLogConfiguration: LogConfiguration = {
194 enabled: true,
195 file: 'logs/combined.log',
196 errorFile: 'logs/error.log',
197 statisticsInterval: Constants.DEFAULT_LOG_STATISTICS_INTERVAL,
198 level: 'info',
199 format: 'simple',
200 rotate: true,
201 };
202 const deprecatedLogConfiguration: LogConfiguration = {
9bf0ef23 203 ...(hasOwnProp(Configuration.getConfig(), 'logEnabled') && {
3d48c1c1
JB
204 enabled: Configuration.getConfig()?.logEnabled,
205 }),
9bf0ef23 206 ...(hasOwnProp(Configuration.getConfig(), 'logFile') && {
3d48c1c1
JB
207 file: Configuration.getConfig()?.logFile,
208 }),
9bf0ef23 209 ...(hasOwnProp(Configuration.getConfig(), 'logErrorFile') && {
3d48c1c1
JB
210 errorFile: Configuration.getConfig()?.logErrorFile,
211 }),
9bf0ef23 212 ...(hasOwnProp(Configuration.getConfig(), 'logStatisticsInterval') && {
3d48c1c1
JB
213 statisticsInterval: Configuration.getConfig()?.logStatisticsInterval,
214 }),
9bf0ef23 215 ...(hasOwnProp(Configuration.getConfig(), 'logLevel') && {
3d48c1c1
JB
216 level: Configuration.getConfig()?.logLevel,
217 }),
9bf0ef23 218 ...(hasOwnProp(Configuration.getConfig(), 'logConsole') && {
3d48c1c1
JB
219 console: Configuration.getConfig()?.logConsole,
220 }),
9bf0ef23 221 ...(hasOwnProp(Configuration.getConfig(), 'logFormat') && {
3d48c1c1
JB
222 format: Configuration.getConfig()?.logFormat,
223 }),
9bf0ef23 224 ...(hasOwnProp(Configuration.getConfig(), 'logRotate') && {
3d48c1c1
JB
225 rotate: Configuration.getConfig()?.logRotate,
226 }),
9bf0ef23 227 ...(hasOwnProp(Configuration.getConfig(), 'logMaxFiles') && {
3d48c1c1
JB
228 maxFiles: Configuration.getConfig()?.logMaxFiles,
229 }),
9bf0ef23 230 ...(hasOwnProp(Configuration.getConfig(), 'logMaxSize') && {
3d48c1c1
JB
231 maxSize: Configuration.getConfig()?.logMaxSize,
232 }),
233 };
234 const logConfiguration: LogConfiguration = {
235 ...defaultLogConfiguration,
236 ...deprecatedLogConfiguration,
9bf0ef23 237 ...(hasOwnProp(Configuration.getConfig(), 'log') && Configuration.getConfig()?.log),
3d48c1c1
JB
238 };
239 return logConfiguration;
240 }
241
aa7d6d95 242 public static getWorker(): WorkerConfiguration {
e7aeea18 243 Configuration.warnDeprecatedConfigurationKey(
e80bc579 244 'useWorkerPool',
1895299d 245 undefined,
5edd8ba0 246 "Use 'worker' section to define the type of worker process model instead",
cf2a5d9b
JB
247 );
248 Configuration.warnDeprecatedConfigurationKey(
249 'workerProcess',
1895299d 250 undefined,
5edd8ba0 251 "Use 'worker' section to define the type of worker process model instead",
cf2a5d9b
JB
252 );
253 Configuration.warnDeprecatedConfigurationKey(
254 'workerStartDelay',
1895299d 255 undefined,
5edd8ba0 256 "Use 'worker' section to define the worker start delay instead",
cf2a5d9b
JB
257 );
258 Configuration.warnDeprecatedConfigurationKey(
259 'chargingStationsPerWorker',
1895299d 260 undefined,
5edd8ba0 261 "Use 'worker' section to define the number of element(s) per worker instead",
cf2a5d9b
JB
262 );
263 Configuration.warnDeprecatedConfigurationKey(
264 'elementStartDelay',
1895299d 265 undefined,
5edd8ba0 266 "Use 'worker' section to define the worker's element start delay instead",
cf2a5d9b
JB
267 );
268 Configuration.warnDeprecatedConfigurationKey(
269 'workerPoolMinSize',
1895299d 270 undefined,
5edd8ba0 271 "Use 'worker' section to define the worker pool minimum size instead",
e7aeea18 272 );
e7aeea18
JB
273 Configuration.warnDeprecatedConfigurationKey(
274 'workerPoolSize;',
1895299d 275 undefined,
5edd8ba0 276 "Use 'worker' section to define the worker pool maximum size instead",
e7aeea18 277 );
cf2a5d9b
JB
278 Configuration.warnDeprecatedConfigurationKey(
279 'workerPoolMaxSize;',
1895299d 280 undefined,
5edd8ba0 281 "Use 'worker' section to define the worker pool maximum size instead",
cf2a5d9b
JB
282 );
283 Configuration.warnDeprecatedConfigurationKey(
284 'workerPoolStrategy;',
1895299d 285 undefined,
5edd8ba0 286 "Use 'worker' section to define the worker pool strategy instead",
cf2a5d9b 287 );
3d48c1c1
JB
288 const defaultWorkerConfiguration: WorkerConfiguration = {
289 processType: WorkerProcessType.workerSet,
290 startDelay: WorkerConstants.DEFAULT_WORKER_START_DELAY,
291 elementsPerWorker: WorkerConstants.DEFAULT_ELEMENTS_PER_WORKER,
292 elementStartDelay: WorkerConstants.DEFAULT_ELEMENT_START_DELAY,
293 poolMinSize: WorkerConstants.DEFAULT_POOL_MIN_SIZE,
294 poolMaxSize: WorkerConstants.DEFAULT_POOL_MAX_SIZE,
295 poolStrategy: WorkerChoiceStrategies.ROUND_ROBIN,
296 };
297 const deprecatedWorkerConfiguration: WorkerConfiguration = {
9bf0ef23 298 ...(hasOwnProp(Configuration.getConfig(), 'workerProcess') && {
3d48c1c1
JB
299 processType: Configuration.getConfig()?.workerProcess,
300 }),
9bf0ef23 301 ...(hasOwnProp(Configuration.getConfig(), 'workerStartDelay') && {
3d48c1c1
JB
302 startDelay: Configuration.getConfig()?.workerStartDelay,
303 }),
9bf0ef23 304 ...(hasOwnProp(Configuration.getConfig(), 'chargingStationsPerWorker') && {
3d48c1c1
JB
305 elementsPerWorker: Configuration.getConfig()?.chargingStationsPerWorker,
306 }),
9bf0ef23 307 ...(hasOwnProp(Configuration.getConfig(), 'elementStartDelay') && {
3d48c1c1
JB
308 elementStartDelay: Configuration.getConfig()?.elementStartDelay,
309 }),
9bf0ef23 310 ...(hasOwnProp(Configuration.getConfig(), 'workerPoolMinSize') && {
3d48c1c1
JB
311 poolMinSize: Configuration.getConfig()?.workerPoolMinSize,
312 }),
9bf0ef23 313 ...(hasOwnProp(Configuration.getConfig(), 'workerPoolMaxSize') && {
3d48c1c1
JB
314 poolMaxSize: Configuration.getConfig()?.workerPoolMaxSize,
315 }),
9bf0ef23 316 ...(hasOwnProp(Configuration.getConfig(), 'workerPoolStrategy') && {
3d48c1c1
JB
317 poolStrategy:
318 Configuration.getConfig()?.workerPoolStrategy ?? WorkerChoiceStrategies.ROUND_ROBIN,
319 }),
320 };
321 const workerConfiguration: WorkerConfiguration = {
322 ...defaultWorkerConfiguration,
323 ...deprecatedWorkerConfiguration,
9bf0ef23 324 ...(hasOwnProp(Configuration.getConfig(), 'worker') && Configuration.getConfig()?.worker),
cf2a5d9b 325 };
cf2a5d9b 326 return workerConfiguration;
3d2ff9e4
J
327 }
328
aa7d6d95
JB
329 public static workerPoolInUse(): boolean {
330 return [WorkerProcessType.dynamicPool, WorkerProcessType.staticPool].includes(
5edd8ba0 331 Configuration.getWorker().processType,
aa7d6d95
JB
332 );
333 }
334
335 public static workerDynamicPoolInUse(): boolean {
336 return Configuration.getWorker().processType === WorkerProcessType.dynamicPool;
337 }
338
aa7d6d95 339 public static getSupervisionUrls(): string | string[] | undefined {
e7aeea18
JB
340 Configuration.warnDeprecatedConfigurationKey(
341 'supervisionURLs',
1895299d 342 undefined,
5edd8ba0 343 "Use 'supervisionUrls' instead",
e7aeea18 344 );
9bf0ef23 345 !isUndefined(Configuration.getConfig()['supervisionURLs']) &&
1895299d
JB
346 (Configuration.getConfig().supervisionUrls = Configuration.getConfig()['supervisionURLs'] as
347 | string
348 | string[]);
7dde0b73 349 // Read conf
1895299d 350 return Configuration.getConfig()?.supervisionUrls;
7dde0b73
JB
351 }
352
aa7d6d95 353 public static getSupervisionUrlDistribution(): SupervisionUrlDistribution | undefined {
e7aeea18
JB
354 Configuration.warnDeprecatedConfigurationKey(
355 'distributeStationToTenantEqually',
1895299d 356 undefined,
5edd8ba0 357 "Use 'supervisionUrlDistribution' instead",
e7aeea18
JB
358 );
359 Configuration.warnDeprecatedConfigurationKey(
360 'distributeStationsToTenantsEqually',
1895299d 361 undefined,
5edd8ba0 362 "Use 'supervisionUrlDistribution' instead",
e7aeea18 363 );
9bf0ef23 364 return hasOwnProp(Configuration.getConfig(), 'supervisionUrlDistribution')
1895299d 365 ? Configuration.getConfig()?.supervisionUrlDistribution
e7aeea18 366 : SupervisionUrlDistribution.ROUND_ROBIN;
7dde0b73 367 }
eb3937cb 368
8b7072dc 369 private static logPrefix = (): string => {
14ecae6a 370 return `${new Date().toLocaleString()} Simulator configuration |`;
8b7072dc 371 };
23132a44 372
e7aeea18
JB
373 private static warnDeprecatedConfigurationKey(
374 key: string,
375 sectionName?: string,
5edd8ba0 376 logMsgToAppend = '',
e7aeea18 377 ) {
e7aeea18
JB
378 if (
379 sectionName &&
9bf0ef23
JB
380 !isUndefined(Configuration.getConfig()[sectionName]) &&
381 !isUndefined((Configuration.getConfig()[sectionName] as Record<string, unknown>)[key])
e7aeea18
JB
382 ) {
383 console.error(
c5e52a07
JB
384 `${chalk.green(Configuration.logPrefix())} ${chalk.red(
385 `Deprecated configuration key '${key}' usage in section '${sectionName}'${
386 logMsgToAppend.trim().length > 0 ? `. ${logMsgToAppend}` : ''
5edd8ba0
JB
387 }`,
388 )}`,
e7aeea18 389 );
9bf0ef23 390 } else if (!isUndefined(Configuration.getConfig()[key])) {
e7aeea18 391 console.error(
c5e52a07
JB
392 `${chalk.green(Configuration.logPrefix())} ${chalk.red(
393 `Deprecated configuration key '${key}' usage${
394 logMsgToAppend.trim().length > 0 ? `. ${logMsgToAppend}` : ''
5edd8ba0
JB
395 }`,
396 )}`,
e7aeea18 397 );
eb3937cb
JB
398 }
399 }
400
401 // Read the config file
1895299d 402 private static getConfig(): ConfigurationData | null {
eb3937cb 403 if (!Configuration.configuration) {
23132a44 404 try {
e7aeea18 405 Configuration.configuration = JSON.parse(
5edd8ba0 406 readFileSync(Configuration.configurationFile, 'utf8'),
e7aeea18 407 ) as ConfigurationData;
23132a44 408 } catch (error) {
69074173 409 Configuration.handleFileException(
a95873d8 410 Configuration.configurationFile,
7164966d
JB
411 FileType.Configuration,
412 error as NodeJS.ErrnoException,
5edd8ba0 413 Configuration.logPrefix(),
e7aeea18 414 );
23132a44 415 }
ded13d97
JB
416 if (!Configuration.configurationFileWatcher) {
417 Configuration.configurationFileWatcher = Configuration.getConfigurationFileWatcher();
418 }
eb3937cb
JB
419 }
420 return Configuration.configuration;
421 }
963ee397 422
d972af76 423 private static getConfigurationFileWatcher(): FSWatcher | undefined {
23132a44 424 try {
d972af76 425 return watch(Configuration.configurationFile, (event, filename): void => {
8d54dcc0 426 if (filename?.trim().length > 0 && event === 'change') {
3ec10737
JB
427 // Nullify to force configuration file reading
428 Configuration.configuration = null;
9bf0ef23 429 if (!isUndefined(Configuration.configurationChangeCallback)) {
72092cfc 430 Configuration.configurationChangeCallback().catch((error) => {
dcaf96dc
JB
431 throw typeof error === 'string' ? new Error(error) : error;
432 });
3ec10737 433 }
23132a44
JB
434 }
435 });
436 } catch (error) {
69074173 437 Configuration.handleFileException(
a95873d8 438 Configuration.configurationFile,
7164966d
JB
439 FileType.Configuration,
440 error as NodeJS.ErrnoException,
5edd8ba0 441 Configuration.logPrefix(),
e7aeea18 442 );
23132a44 443 }
ded13d97
JB
444 }
445
69074173
JB
446 private static handleFileException(
447 file: string,
448 fileType: FileType,
449 error: NodeJS.ErrnoException,
5edd8ba0 450 logPrefix: string,
69074173 451 ): void {
9bf0ef23 452 const prefix = isNotEmptyString(logPrefix) ? `${logPrefix} ` : '';
69074173
JB
453 let logMsg: string;
454 switch (error.code) {
455 case 'ENOENT':
456 logMsg = `${fileType} file ${file} not found:`;
457 break;
458 case 'EEXIST':
459 logMsg = `${fileType} file ${file} already exists:`;
460 break;
461 case 'EACCES':
462 logMsg = `${fileType} file ${file} access denied:`;
463 break;
7b5dbe91
JB
464 case 'EPERM':
465 logMsg = `${fileType} file ${file} permission denied:`;
466 break;
69074173
JB
467 default:
468 logMsg = `${fileType} file ${file} error:`;
469 }
7b5dbe91
JB
470 console.error(`${chalk.green(prefix)}${chalk.red(`${logMsg} `)}`, error);
471 throw error;
69074173
JB
472 }
473
1f5df42a 474 private static getDefaultPerformanceStorageUri(storageType: StorageType) {
d5603918
JB
475 switch (storageType) {
476 case StorageType.JSON_FILE:
e8044a69 477 return Configuration.buildPerformanceUriFilePath(
5edd8ba0 478 `${Constants.DEFAULT_PERFORMANCE_DIRECTORY}/${Constants.DEFAULT_PERFORMANCE_RECORDS_FILENAME}`,
e8044a69 479 );
d5603918 480 case StorageType.SQLITE:
e8044a69 481 return Configuration.buildPerformanceUriFilePath(
5edd8ba0 482 `${Constants.DEFAULT_PERFORMANCE_DIRECTORY}/${Constants.DEFAULT_PERFORMANCE_RECORDS_DB_NAME}.db`,
e8044a69 483 );
d5603918
JB
484 default:
485 throw new Error(`Performance storage URI is mandatory with storage type '${storageType}'`);
486 }
487 }
e8044a69
JB
488
489 private static buildPerformanceUriFilePath(file: string) {
d972af76 490 return `file://${join(resolve(dirname(fileURLToPath(import.meta.url)), '../'), file)}`;
e8044a69 491 }
7dde0b73 492}