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