test: trivial refinements
[e-mobility-charging-stations-simulator.git] / src / utils / Configuration.ts
CommitLineData
d05b53c7 1import { existsSync, type FSWatcher, readFileSync, watch } from 'node:fs'
66a7748d
JB
2import { dirname, join } from 'node:path'
3import { env } from 'node:process'
4import { fileURLToPath } from 'node:url'
8114d10e 5
66a7748d 6import chalk from 'chalk'
38ae4ce2 7import { mergeDeepRight, once } from 'rambda'
8114d10e 8
83e00df1 9import {
268a74bb 10 ApplicationProtocol,
329eab0e 11 ApplicationProtocolVersion,
83e00df1 12 type ConfigurationData,
5d049829 13 ConfigurationSection,
268a74bb 14 FileType,
3d48c1c1 15 type LogConfiguration,
83e00df1
JB
16 type StationTemplateUrl,
17 type StorageConfiguration,
268a74bb 18 StorageType,
e7aeea18 19 SupervisionUrlDistribution,
83e00df1 20 type UIServerConfiguration,
66a7748d
JB
21 type WorkerConfiguration
22} from '../types/index.js'
769d3b10 23import {
da47bc29 24 DEFAULT_ELEMENT_ADD_DELAY,
769d3b10
JB
25 DEFAULT_POOL_MAX_SIZE,
26 DEFAULT_POOL_MIN_SIZE,
27 DEFAULT_WORKER_START_DELAY,
66a7748d
JB
28 WorkerProcessType
29} from '../worker/index.js'
4c3f6c20
JB
30import {
31 buildPerformanceUriFilePath,
32 checkWorkerElementsPerWorker,
33 checkWorkerProcessType,
34 getDefaultPerformanceStorageUri,
35 handleFileException,
36 logPrefix
37} from './ConfigurationUtils.js'
38import { Constants } from './Constants.js'
38ae4ce2 39import { hasOwnProp, isCFEnvironment } from './Utils.js'
7dde0b73 40
e7c0fce0
JB
41type ConfigurationSectionType =
42 | LogConfiguration
43 | StorageConfiguration
44 | WorkerConfiguration
66a7748d 45 | UIServerConfiguration
e7c0fce0 46
d05b53c7
JB
47const defaultUIServerConfiguration: UIServerConfiguration = {
48 enabled: false,
49 type: ApplicationProtocol.WS,
50 version: ApplicationProtocolVersion.VERSION_11,
51 options: {
52 host: Constants.DEFAULT_UI_SERVER_HOST,
53 port: Constants.DEFAULT_UI_SERVER_PORT
54 }
55}
56
57const defaultStorageConfiguration: StorageConfiguration = {
58 enabled: true,
59 type: StorageType.NONE
60}
61
62const defaultLogConfiguration: LogConfiguration = {
63 enabled: true,
64 file: 'logs/combined.log',
65 errorFile: 'logs/error.log',
66 statisticsInterval: Constants.DEFAULT_LOG_STATISTICS_INTERVAL,
67 level: 'info',
68 format: 'simple',
69 rotate: true
70}
71
72const defaultWorkerConfiguration: WorkerConfiguration = {
73 processType: WorkerProcessType.workerSet,
74 startDelay: DEFAULT_WORKER_START_DELAY,
75 elementsPerWorker: 'auto',
76 elementAddDelay: DEFAULT_ELEMENT_ADD_DELAY,
77 poolMinSize: DEFAULT_POOL_MIN_SIZE,
78 poolMaxSize: DEFAULT_POOL_MAX_SIZE
79}
80
66a7748d 81// eslint-disable-next-line @typescript-eslint/no-extraneous-class
268a74bb 82export class Configuration {
5199f9fd 83 public static configurationChangeCallback?: () => Promise<void>
6501eda9 84
d05b53c7 85 private static configurationFile: string | undefined
66a7748d
JB
86 private static configurationFileReloading = false
87 private static configurationData?: ConfigurationData
88 private static configurationFileWatcher?: FSWatcher
d05b53c7
JB
89 private static configurationSectionCache: Map<ConfigurationSection, ConfigurationSectionType>
90
91 static {
92 const configurationFile = join(dirname(fileURLToPath(import.meta.url)), 'assets', 'config.json')
93 if (existsSync(configurationFile)) {
94 Configuration.configurationFile = configurationFile
95 } else {
96 console.error(
97 `${chalk.green(logPrefix())} ${chalk.red(
a9babd50 98 "Configuration file './src/assets/config.json' not found, using default configuration"
d05b53c7
JB
99 )}`
100 )
101 Configuration.configurationData = {
a9babd50
JB
102 stationTemplateUrls: [
103 {
104 file: 'siemens.station-template.json',
105 numberOfStations: 1
106 }
107 ],
d05b53c7
JB
108 supervisionUrls: 'ws://localhost:8180/steve/websocket/CentralSystemService',
109 supervisionUrlDistribution: SupervisionUrlDistribution.ROUND_ROBIN,
110 uiServer: defaultUIServerConfiguration,
111 performanceStorage: defaultStorageConfiguration,
112 log: defaultLogConfiguration,
113 worker: defaultWorkerConfiguration
114 }
115 }
116 Configuration.configurationSectionCache = new Map<
117 ConfigurationSection,
118 ConfigurationSectionType
119 >([
120 [ConfigurationSection.log, Configuration.buildLogSection()],
121 [ConfigurationSection.performanceStorage, Configuration.buildPerformanceStorageSection()],
122 [ConfigurationSection.worker, Configuration.buildWorkerSection()],
123 [ConfigurationSection.uiServer, Configuration.buildUIServerSection()]
124 ])
125 }
974efe6c 126
66a7748d 127 private constructor () {
d5bd1c00
JB
128 // This is intentional
129 }
130
e7c0fce0 131 public static getConfigurationSection<T extends ConfigurationSectionType>(
66a7748d 132 sectionName: ConfigurationSection
e7c0fce0 133 ): T {
81b9a105 134 if (!Configuration.isConfigurationSectionCached(sectionName)) {
66a7748d 135 Configuration.cacheConfigurationSection(sectionName)
c1c97db8 136 }
66a7748d 137 return Configuration.configurationSectionCache.get(sectionName) as T
5d049829
JB
138 }
139
66a7748d 140 public static getStationTemplateUrls (): StationTemplateUrl[] | undefined {
5f742aac 141 const checkDeprecatedConfigurationKeysOnce = once(
38ae4ce2 142 Configuration.checkDeprecatedConfigurationKeys.bind(Configuration)
66a7748d
JB
143 )
144 checkDeprecatedConfigurationKeysOnce()
145 return Configuration.getConfigurationData()?.stationTemplateUrls
5d049829
JB
146 }
147
66a7748d 148 public static getSupervisionUrls (): string | string[] | undefined {
a37fc6dc 149 if (
d760a0a6 150 Configuration.getConfigurationData()?.['supervisionURLs' as keyof ConfigurationData] != null
a37fc6dc 151 ) {
66a7748d 152 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
5d049829 153 Configuration.getConfigurationData()!.supervisionUrls = Configuration.getConfigurationData()![
a37fc6dc 154 'supervisionURLs' as keyof ConfigurationData
66a7748d 155 ] as string | string[]
5d049829 156 }
66a7748d 157 return Configuration.getConfigurationData()?.supervisionUrls
5d049829
JB
158 }
159
66a7748d 160 public static getSupervisionUrlDistribution (): SupervisionUrlDistribution | undefined {
5d049829
JB
161 return hasOwnProp(Configuration.getConfigurationData(), 'supervisionUrlDistribution')
162 ? Configuration.getConfigurationData()?.supervisionUrlDistribution
66a7748d 163 : SupervisionUrlDistribution.ROUND_ROBIN
5d049829
JB
164 }
165
66a7748d 166 public static workerPoolInUse (): boolean {
1d8f226b 167 return [WorkerProcessType.dynamicPool, WorkerProcessType.fixedPool].includes(
66a7748d 168 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
eb979012 169 Configuration.getConfigurationSection<WorkerConfiguration>(ConfigurationSection.worker)
66a7748d
JB
170 .processType!
171 )
c831d2bc
JB
172 }
173
66a7748d 174 public static workerDynamicPoolInUse (): boolean {
eb979012
JB
175 return (
176 Configuration.getConfigurationSection<WorkerConfiguration>(ConfigurationSection.worker)
177 .processType === WorkerProcessType.dynamicPool
66a7748d 178 )
c831d2bc
JB
179 }
180
66a7748d
JB
181 private static isConfigurationSectionCached (sectionName: ConfigurationSection): boolean {
182 return Configuration.configurationSectionCache.has(sectionName)
81b9a105
JB
183 }
184
66a7748d 185 private static cacheConfigurationSection (sectionName: ConfigurationSection): void {
81b9a105
JB
186 switch (sectionName) {
187 case ConfigurationSection.log:
66a7748d
JB
188 Configuration.configurationSectionCache.set(sectionName, Configuration.buildLogSection())
189 break
81b9a105
JB
190 case ConfigurationSection.performanceStorage:
191 Configuration.configurationSectionCache.set(
192 sectionName,
66a7748d
JB
193 Configuration.buildPerformanceStorageSection()
194 )
195 break
81b9a105 196 case ConfigurationSection.worker:
66a7748d
JB
197 Configuration.configurationSectionCache.set(sectionName, Configuration.buildWorkerSection())
198 break
81b9a105
JB
199 case ConfigurationSection.uiServer:
200 Configuration.configurationSectionCache.set(
201 sectionName,
66a7748d
JB
202 Configuration.buildUIServerSection()
203 )
204 break
81b9a105
JB
205 default:
206 // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
66a7748d 207 throw new Error(`Unknown configuration section '${sectionName}'`)
81b9a105
JB
208 }
209 }
210
66a7748d 211 private static buildUIServerSection (): UIServerConfiguration {
d05b53c7 212 let uiServerConfiguration: UIServerConfiguration = defaultUIServerConfiguration
f74e97ac 213 if (hasOwnProp(Configuration.getConfigurationData(), ConfigurationSection.uiServer)) {
b4c82e73 214 uiServerConfiguration = mergeDeepRight(
598c886d 215 uiServerConfiguration,
66a7748d
JB
216 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
217 Configuration.getConfigurationData()!.uiServer!
218 )
6a49ad23 219 }
66a7748d
JB
220 if (isCFEnvironment()) {
221 delete uiServerConfiguration.options?.host
222 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
48847bc0 223 uiServerConfiguration.options!.port = Number.parseInt(env.PORT!)
b803eefa 224 }
66a7748d 225 return uiServerConfiguration
6a49ad23
JB
226 }
227
66a7748d 228 private static buildPerformanceStorageSection (): StorageConfiguration {
789007bd
JB
229 let storageConfiguration: StorageConfiguration
230 switch (Configuration.getConfigurationData()?.performanceStorage?.type) {
231 case StorageType.SQLITE:
232 storageConfiguration = {
233 enabled: false,
234 type: StorageType.SQLITE,
235 uri: getDefaultPerformanceStorageUri(StorageType.SQLITE)
236 }
237 break
238 case StorageType.JSON_FILE:
789007bd
JB
239 storageConfiguration = {
240 enabled: false,
241 type: StorageType.JSON_FILE,
242 uri: getDefaultPerformanceStorageUri(StorageType.JSON_FILE)
243 }
244 break
a66bbcfe
JB
245 case StorageType.NONE:
246 default:
d05b53c7 247 storageConfiguration = defaultStorageConfiguration
a66bbcfe 248 break
66a7748d 249 }
f74e97ac 250 if (hasOwnProp(Configuration.getConfigurationData(), ConfigurationSection.performanceStorage)) {
e7aeea18 251 storageConfiguration = {
1ba1e8fb 252 ...storageConfiguration,
f74e97ac 253 ...Configuration.getConfigurationData()?.performanceStorage,
789007bd
JB
254 ...((Configuration.getConfigurationData()?.performanceStorage?.type ===
255 StorageType.JSON_FILE ||
256 Configuration.getConfigurationData()?.performanceStorage?.type === StorageType.SQLITE) &&
66a7748d
JB
257 Configuration.getConfigurationData()?.performanceStorage?.uri != null && {
258 uri: buildPerformanceUriFilePath(
259 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
260 new URL(Configuration.getConfigurationData()!.performanceStorage!.uri!).pathname
261 )
262 })
263 }
72f041bd 264 }
66a7748d 265 return storageConfiguration
7dde0b73
JB
266 }
267
66a7748d 268 private static buildLogSection (): LogConfiguration {
3d48c1c1 269 const deprecatedLogConfiguration: LogConfiguration = {
f74e97ac 270 ...(hasOwnProp(Configuration.getConfigurationData(), 'logEnabled') && {
66a7748d 271 enabled: Configuration.getConfigurationData()?.logEnabled
3d48c1c1 272 }),
f74e97ac 273 ...(hasOwnProp(Configuration.getConfigurationData(), 'logFile') && {
66a7748d 274 file: Configuration.getConfigurationData()?.logFile
3d48c1c1 275 }),
f74e97ac 276 ...(hasOwnProp(Configuration.getConfigurationData(), 'logErrorFile') && {
66a7748d 277 errorFile: Configuration.getConfigurationData()?.logErrorFile
3d48c1c1 278 }),
f74e97ac 279 ...(hasOwnProp(Configuration.getConfigurationData(), 'logStatisticsInterval') && {
66a7748d 280 statisticsInterval: Configuration.getConfigurationData()?.logStatisticsInterval
3d48c1c1 281 }),
f74e97ac 282 ...(hasOwnProp(Configuration.getConfigurationData(), 'logLevel') && {
66a7748d 283 level: Configuration.getConfigurationData()?.logLevel
3d48c1c1 284 }),
f74e97ac 285 ...(hasOwnProp(Configuration.getConfigurationData(), 'logConsole') && {
66a7748d 286 console: Configuration.getConfigurationData()?.logConsole
3d48c1c1 287 }),
f74e97ac 288 ...(hasOwnProp(Configuration.getConfigurationData(), 'logFormat') && {
66a7748d 289 format: Configuration.getConfigurationData()?.logFormat
3d48c1c1 290 }),
f74e97ac 291 ...(hasOwnProp(Configuration.getConfigurationData(), 'logRotate') && {
66a7748d 292 rotate: Configuration.getConfigurationData()?.logRotate
3d48c1c1 293 }),
f74e97ac 294 ...(hasOwnProp(Configuration.getConfigurationData(), 'logMaxFiles') && {
66a7748d 295 maxFiles: Configuration.getConfigurationData()?.logMaxFiles
3d48c1c1 296 }),
f74e97ac 297 ...(hasOwnProp(Configuration.getConfigurationData(), 'logMaxSize') && {
66a7748d
JB
298 maxSize: Configuration.getConfigurationData()?.logMaxSize
299 })
300 }
3d48c1c1
JB
301 const logConfiguration: LogConfiguration = {
302 ...defaultLogConfiguration,
303 ...deprecatedLogConfiguration,
f74e97ac 304 ...(hasOwnProp(Configuration.getConfigurationData(), ConfigurationSection.log) &&
66a7748d
JB
305 Configuration.getConfigurationData()?.log)
306 }
307 return logConfiguration
3d48c1c1
JB
308 }
309
66a7748d 310 private static buildWorkerSection (): WorkerConfiguration {
3602e107
JB
311 const deprecatedWorkerConfiguration: WorkerConfiguration = {
312 ...(hasOwnProp(Configuration.getConfigurationData(), 'workerProcess') && {
66a7748d 313 processType: Configuration.getConfigurationData()?.workerProcess
3602e107
JB
314 }),
315 ...(hasOwnProp(Configuration.getConfigurationData(), 'workerStartDelay') && {
66a7748d 316 startDelay: Configuration.getConfigurationData()?.workerStartDelay
3602e107
JB
317 }),
318 ...(hasOwnProp(Configuration.getConfigurationData(), 'chargingStationsPerWorker') && {
66a7748d 319 elementsPerWorker: Configuration.getConfigurationData()?.chargingStationsPerWorker
3602e107 320 }),
da47bc29
JB
321 ...(hasOwnProp(Configuration.getConfigurationData(), 'elementAddDelay') && {
322 elementAddDelay: Configuration.getConfigurationData()?.elementAddDelay
323 }),
324 ...(hasOwnProp(Configuration.getConfigurationData()?.worker, 'elementStartDelay') && {
325 elementAddDelay: Configuration.getConfigurationData()?.worker?.elementStartDelay
3602e107
JB
326 }),
327 ...(hasOwnProp(Configuration.getConfigurationData(), 'workerPoolMinSize') && {
66a7748d 328 poolMinSize: Configuration.getConfigurationData()?.workerPoolMinSize
3602e107
JB
329 }),
330 ...(hasOwnProp(Configuration.getConfigurationData(), 'workerPoolMaxSize') && {
66a7748d
JB
331 poolMaxSize: Configuration.getConfigurationData()?.workerPoolMaxSize
332 })
333 }
3602e107 334 hasOwnProp(Configuration.getConfigurationData(), 'workerPoolStrategy') &&
66a7748d 335 delete Configuration.getConfigurationData()?.workerPoolStrategy
3602e107
JB
336 const workerConfiguration: WorkerConfiguration = {
337 ...defaultWorkerConfiguration,
338 ...deprecatedWorkerConfiguration,
339 ...(hasOwnProp(Configuration.getConfigurationData(), ConfigurationSection.worker) &&
66a7748d
JB
340 Configuration.getConfigurationData()?.worker)
341 }
342 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
343 checkWorkerProcessType(workerConfiguration.processType!)
344 checkWorkerElementsPerWorker(workerConfiguration.elementsPerWorker)
345 return workerConfiguration
3602e107
JB
346 }
347
66a7748d 348 private static checkDeprecatedConfigurationKeys (): void {
3602e107
JB
349 // connection timeout
350 Configuration.warnDeprecatedConfigurationKey(
351 'autoReconnectTimeout',
352 undefined,
66a7748d
JB
353 "Use 'ConnectionTimeOut' OCPP parameter in charging station template instead"
354 )
3602e107
JB
355 Configuration.warnDeprecatedConfigurationKey(
356 'connectionTimeout',
357 undefined,
66a7748d
JB
358 "Use 'ConnectionTimeOut' OCPP parameter in charging station template instead"
359 )
3602e107
JB
360 // connection retries
361 Configuration.warnDeprecatedConfigurationKey(
362 'autoReconnectMaxRetries',
363 undefined,
66a7748d
JB
364 'Use it in charging station template instead'
365 )
3602e107
JB
366 // station template url(s)
367 Configuration.warnDeprecatedConfigurationKey(
368 'stationTemplateURLs',
369 undefined,
66a7748d
JB
370 "Use 'stationTemplateUrls' instead"
371 )
d760a0a6
JB
372 Configuration.getConfigurationData()?.['stationTemplateURLs' as keyof ConfigurationData] !=
373 null &&
66a7748d 374 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
3602e107 375 (Configuration.getConfigurationData()!.stationTemplateUrls =
66a7748d 376 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
3602e107
JB
377 Configuration.getConfigurationData()![
378 'stationTemplateURLs' as keyof ConfigurationData
66a7748d 379 ] as StationTemplateUrl[])
1c9de2b9 380 Configuration.getConfigurationData()?.stationTemplateUrls.forEach(
3602e107 381 (stationTemplateUrl: StationTemplateUrl) => {
5199f9fd 382 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
d760a0a6 383 if (stationTemplateUrl['numberOfStation' as keyof StationTemplateUrl] != null) {
3602e107 384 console.error(
4354af5a 385 `${chalk.green(logPrefix())} ${chalk.red(
66a7748d
JB
386 `Deprecated configuration key 'numberOfStation' usage for template file '${stationTemplateUrl.file}' in 'stationTemplateUrls'. Use 'numberOfStations' instead`
387 )}`
388 )
3602e107 389 }
66a7748d
JB
390 }
391 )
3602e107
JB
392 // supervision url(s)
393 Configuration.warnDeprecatedConfigurationKey(
394 'supervisionURLs',
395 undefined,
66a7748d
JB
396 "Use 'supervisionUrls' instead"
397 )
3602e107
JB
398 // supervision urls distribution
399 Configuration.warnDeprecatedConfigurationKey(
400 'distributeStationToTenantEqually',
401 undefined,
66a7748d
JB
402 "Use 'supervisionUrlDistribution' instead"
403 )
3602e107
JB
404 Configuration.warnDeprecatedConfigurationKey(
405 'distributeStationsToTenantsEqually',
406 undefined,
66a7748d
JB
407 "Use 'supervisionUrlDistribution' instead"
408 )
3602e107 409 // worker section
e7aeea18 410 Configuration.warnDeprecatedConfigurationKey(
e80bc579 411 'useWorkerPool',
1895299d 412 undefined,
66a7748d
JB
413 `Use '${ConfigurationSection.worker}' section to define the type of worker process model instead`
414 )
cf2a5d9b
JB
415 Configuration.warnDeprecatedConfigurationKey(
416 'workerProcess',
1895299d 417 undefined,
66a7748d
JB
418 `Use '${ConfigurationSection.worker}' section to define the type of worker process model instead`
419 )
cf2a5d9b
JB
420 Configuration.warnDeprecatedConfigurationKey(
421 'workerStartDelay',
1895299d 422 undefined,
66a7748d
JB
423 `Use '${ConfigurationSection.worker}' section to define the worker start delay instead`
424 )
cf2a5d9b
JB
425 Configuration.warnDeprecatedConfigurationKey(
426 'chargingStationsPerWorker',
1895299d 427 undefined,
66a7748d
JB
428 `Use '${ConfigurationSection.worker}' section to define the number of element(s) per worker instead`
429 )
cf2a5d9b 430 Configuration.warnDeprecatedConfigurationKey(
da47bc29 431 'elementAddDelay',
1895299d 432 undefined,
da47bc29 433 `Use '${ConfigurationSection.worker}' section to define the worker's element add delay instead`
66a7748d 434 )
cf2a5d9b
JB
435 Configuration.warnDeprecatedConfigurationKey(
436 'workerPoolMinSize',
1895299d 437 undefined,
66a7748d
JB
438 `Use '${ConfigurationSection.worker}' section to define the worker pool minimum size instead`
439 )
e7aeea18 440 Configuration.warnDeprecatedConfigurationKey(
1d8f226b 441 'workerPoolSize',
1895299d 442 undefined,
66a7748d
JB
443 `Use '${ConfigurationSection.worker}' section to define the worker pool maximum size instead`
444 )
cf2a5d9b 445 Configuration.warnDeprecatedConfigurationKey(
1d8f226b 446 'workerPoolMaxSize',
1895299d 447 undefined,
66a7748d
JB
448 `Use '${ConfigurationSection.worker}' section to define the worker pool maximum size instead`
449 )
cf2a5d9b 450 Configuration.warnDeprecatedConfigurationKey(
1d8f226b 451 'workerPoolStrategy',
1895299d 452 undefined,
66a7748d
JB
453 `Use '${ConfigurationSection.worker}' section to define the worker pool strategy instead`
454 )
eda9c451
JB
455 Configuration.warnDeprecatedConfigurationKey(
456 'poolStrategy',
974efe6c 457 ConfigurationSection.worker,
66a7748d
JB
458 'Not publicly exposed to end users'
459 )
da47bc29
JB
460 Configuration.warnDeprecatedConfigurationKey(
461 'elementStartDelay',
462 ConfigurationSection.worker,
463 "Use 'elementAddDelay' instead"
464 )
1d8f226b
JB
465 if (
466 Configuration.getConfigurationData()?.worker?.processType ===
467 ('staticPool' as WorkerProcessType)
468 ) {
469 console.error(
4354af5a 470 `${chalk.green(logPrefix())} ${chalk.red(
66a7748d
JB
471 `Deprecated configuration 'staticPool' value usage in worker section 'processType' field. Use '${WorkerProcessType.fixedPool}' value instead`
472 )}`
473 )
1d8f226b 474 }
3602e107
JB
475 // log section
476 Configuration.warnDeprecatedConfigurationKey(
477 'logEnabled',
478 undefined,
66a7748d
JB
479 `Use '${ConfigurationSection.log}' section to define the logging enablement instead`
480 )
3602e107
JB
481 Configuration.warnDeprecatedConfigurationKey(
482 'logFile',
483 undefined,
66a7748d
JB
484 `Use '${ConfigurationSection.log}' section to define the log file instead`
485 )
3602e107
JB
486 Configuration.warnDeprecatedConfigurationKey(
487 'logErrorFile',
488 undefined,
66a7748d
JB
489 `Use '${ConfigurationSection.log}' section to define the log error file instead`
490 )
3602e107
JB
491 Configuration.warnDeprecatedConfigurationKey(
492 'logConsole',
493 undefined,
66a7748d
JB
494 `Use '${ConfigurationSection.log}' section to define the console logging enablement instead`
495 )
3602e107
JB
496 Configuration.warnDeprecatedConfigurationKey(
497 'logStatisticsInterval',
498 undefined,
66a7748d
JB
499 `Use '${ConfigurationSection.log}' section to define the log statistics interval instead`
500 )
3602e107
JB
501 Configuration.warnDeprecatedConfigurationKey(
502 'logLevel',
503 undefined,
66a7748d
JB
504 `Use '${ConfigurationSection.log}' section to define the log level instead`
505 )
3602e107
JB
506 Configuration.warnDeprecatedConfigurationKey(
507 'logFormat',
508 undefined,
66a7748d
JB
509 `Use '${ConfigurationSection.log}' section to define the log format instead`
510 )
3602e107
JB
511 Configuration.warnDeprecatedConfigurationKey(
512 'logRotate',
513 undefined,
66a7748d
JB
514 `Use '${ConfigurationSection.log}' section to define the log rotation enablement instead`
515 )
3602e107
JB
516 Configuration.warnDeprecatedConfigurationKey(
517 'logMaxFiles',
518 undefined,
66a7748d
JB
519 `Use '${ConfigurationSection.log}' section to define the log maximum files instead`
520 )
3602e107
JB
521 Configuration.warnDeprecatedConfigurationKey(
522 'logMaxSize',
523 undefined,
66a7748d
JB
524 `Use '${ConfigurationSection.log}' section to define the log maximum size instead`
525 )
3602e107
JB
526 // performanceStorage section
527 Configuration.warnDeprecatedConfigurationKey(
528 'URI',
529 ConfigurationSection.performanceStorage,
66a7748d
JB
530 "Use 'uri' instead"
531 )
3602e107
JB
532 // uiServer section
533 if (hasOwnProp(Configuration.getConfigurationData(), 'uiWebSocketServer')) {
534 console.error(
4354af5a 535 `${chalk.green(logPrefix())} ${chalk.red(
66a7748d
JB
536 `Deprecated configuration section 'uiWebSocketServer' usage. Use '${ConfigurationSection.uiServer}' instead`
537 )}`
538 )
b5b2c3e8 539 }
7dde0b73 540 }
eb3937cb 541
66a7748d 542 private static warnDeprecatedConfigurationKey (
e7aeea18 543 key: string,
23c97c47 544 configurationSection?: ConfigurationSection,
66a7748d
JB
545 logMsgToAppend = ''
546 ): void {
e7aeea18 547 if (
23c97c47
JB
548 configurationSection != null &&
549 Configuration.getConfigurationData()?.[configurationSection as keyof ConfigurationData] !=
550 null &&
300418e9 551 (
23c97c47
JB
552 Configuration.getConfigurationData()?.[
553 configurationSection as keyof ConfigurationData
554 ] as Record<string, unknown>
d760a0a6 555 )[key] != null
e7aeea18
JB
556 ) {
557 console.error(
4354af5a 558 `${chalk.green(logPrefix())} ${chalk.red(
23c97c47 559 `Deprecated configuration key '${key}' usage in section '${configurationSection}'${
c5e52a07 560 logMsgToAppend.trim().length > 0 ? `. ${logMsgToAppend}` : ''
66a7748d
JB
561 }`
562 )}`
563 )
d760a0a6 564 } else if (Configuration.getConfigurationData()?.[key as keyof ConfigurationData] != null) {
e7aeea18 565 console.error(
4354af5a 566 `${chalk.green(logPrefix())} ${chalk.red(
c5e52a07
JB
567 `Deprecated configuration key '${key}' usage${
568 logMsgToAppend.trim().length > 0 ? `. ${logMsgToAppend}` : ''
66a7748d
JB
569 }`
570 )}`
571 )
eb3937cb
JB
572 }
573 }
574
8f8f87c4 575 public static getConfigurationData (): ConfigurationData | undefined {
d05b53c7
JB
576 if (
577 Configuration.configurationData == null &&
578 Configuration.configurationFile != null &&
579 Configuration.configurationFile.length > 0
580 ) {
23132a44 581 try {
f74e97ac 582 Configuration.configurationData = JSON.parse(
66a7748d
JB
583 readFileSync(Configuration.configurationFile, 'utf8')
584 ) as ConfigurationData
585 if (Configuration.configurationFileWatcher == null) {
586 Configuration.configurationFileWatcher = Configuration.getConfigurationFileWatcher()
1f8f6332 587 }
23132a44 588 } catch (error) {
4354af5a 589 handleFileException(
a95873d8 590 Configuration.configurationFile,
7164966d
JB
591 FileType.Configuration,
592 error as NodeJS.ErrnoException,
66a7748d
JB
593 logPrefix()
594 )
23132a44 595 }
eb3937cb 596 }
66a7748d 597 return Configuration.configurationData
eb3937cb 598 }
963ee397 599
66a7748d 600 private static getConfigurationFileWatcher (): FSWatcher | undefined {
d05b53c7
JB
601 if (Configuration.configurationFile == null || Configuration.configurationFile.length === 0) {
602 return
603 }
23132a44 604 try {
d972af76 605 return watch(Configuration.configurationFile, (event, filename): void => {
1b4ccee3
JB
606 if (
607 !Configuration.configurationFileReloading &&
66a7748d 608 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
aafba9d8 609 filename!.trim().length > 0 &&
1b4ccee3
JB
610 event === 'change'
611 ) {
66a7748d 612 Configuration.configurationFileReloading = true
38ae4ce2 613 const consoleWarnOnce = once(console.warn)
1b4ccee3 614 consoleWarnOnce(
4354af5a 615 `${chalk.green(logPrefix())} ${chalk.yellow(
66a7748d
JB
616 `${FileType.Configuration} ${this.configurationFile} file have changed, reload`
617 )}`
618 )
619 delete Configuration.configurationData
620 Configuration.configurationSectionCache.clear()
d760a0a6 621 if (Configuration.configurationChangeCallback != null) {
1b4ccee3 622 Configuration.configurationChangeCallback()
ea32ea05 623 .catch((error: unknown) => {
66a7748d 624 throw typeof error === 'string' ? new Error(error) : error
1b4ccee3
JB
625 })
626 .finally(() => {
66a7748d
JB
627 Configuration.configurationFileReloading = false
628 })
41d95b76 629 } else {
66a7748d 630 Configuration.configurationFileReloading = false
3ec10737 631 }
23132a44 632 }
66a7748d 633 })
23132a44 634 } catch (error) {
4354af5a 635 handleFileException(
a95873d8 636 Configuration.configurationFile,
7164966d
JB
637 FileType.Configuration,
638 error as NodeJS.ErrnoException,
66a7748d
JB
639 logPrefix()
640 )
23132a44 641 }
ded13d97 642 }
7dde0b73 643}