fix: ensure persistence configuration override is taken in all case
[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:
789007bd
JB
190 storageConfiguration = {
191 enabled: false,
192 type: StorageType.JSON_FILE,
193 uri: getDefaultPerformanceStorageUri(StorageType.JSON_FILE)
194 }
195 break
a66bbcfe
JB
196 case StorageType.NONE:
197 default:
198 storageConfiguration = {
199 enabled: true,
200 type: StorageType.NONE
201 }
202 break
66a7748d 203 }
f74e97ac 204 if (hasOwnProp(Configuration.getConfigurationData(), ConfigurationSection.performanceStorage)) {
e7aeea18 205 storageConfiguration = {
1ba1e8fb 206 ...storageConfiguration,
f74e97ac 207 ...Configuration.getConfigurationData()?.performanceStorage,
789007bd
JB
208 ...((Configuration.getConfigurationData()?.performanceStorage?.type ===
209 StorageType.JSON_FILE ||
210 Configuration.getConfigurationData()?.performanceStorage?.type === StorageType.SQLITE) &&
66a7748d
JB
211 Configuration.getConfigurationData()?.performanceStorage?.uri != null && {
212 uri: buildPerformanceUriFilePath(
213 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
214 new URL(Configuration.getConfigurationData()!.performanceStorage!.uri!).pathname
215 )
216 })
217 }
72f041bd 218 }
66a7748d 219 return storageConfiguration
7dde0b73
JB
220 }
221
66a7748d 222 private static buildLogSection (): LogConfiguration {
3d48c1c1
JB
223 const defaultLogConfiguration: LogConfiguration = {
224 enabled: true,
225 file: 'logs/combined.log',
226 errorFile: 'logs/error.log',
227 statisticsInterval: Constants.DEFAULT_LOG_STATISTICS_INTERVAL,
228 level: 'info',
229 format: 'simple',
66a7748d
JB
230 rotate: true
231 }
3d48c1c1 232 const deprecatedLogConfiguration: LogConfiguration = {
f74e97ac 233 ...(hasOwnProp(Configuration.getConfigurationData(), 'logEnabled') && {
66a7748d 234 enabled: Configuration.getConfigurationData()?.logEnabled
3d48c1c1 235 }),
f74e97ac 236 ...(hasOwnProp(Configuration.getConfigurationData(), 'logFile') && {
66a7748d 237 file: Configuration.getConfigurationData()?.logFile
3d48c1c1 238 }),
f74e97ac 239 ...(hasOwnProp(Configuration.getConfigurationData(), 'logErrorFile') && {
66a7748d 240 errorFile: Configuration.getConfigurationData()?.logErrorFile
3d48c1c1 241 }),
f74e97ac 242 ...(hasOwnProp(Configuration.getConfigurationData(), 'logStatisticsInterval') && {
66a7748d 243 statisticsInterval: Configuration.getConfigurationData()?.logStatisticsInterval
3d48c1c1 244 }),
f74e97ac 245 ...(hasOwnProp(Configuration.getConfigurationData(), 'logLevel') && {
66a7748d 246 level: Configuration.getConfigurationData()?.logLevel
3d48c1c1 247 }),
f74e97ac 248 ...(hasOwnProp(Configuration.getConfigurationData(), 'logConsole') && {
66a7748d 249 console: Configuration.getConfigurationData()?.logConsole
3d48c1c1 250 }),
f74e97ac 251 ...(hasOwnProp(Configuration.getConfigurationData(), 'logFormat') && {
66a7748d 252 format: Configuration.getConfigurationData()?.logFormat
3d48c1c1 253 }),
f74e97ac 254 ...(hasOwnProp(Configuration.getConfigurationData(), 'logRotate') && {
66a7748d 255 rotate: Configuration.getConfigurationData()?.logRotate
3d48c1c1 256 }),
f74e97ac 257 ...(hasOwnProp(Configuration.getConfigurationData(), 'logMaxFiles') && {
66a7748d 258 maxFiles: Configuration.getConfigurationData()?.logMaxFiles
3d48c1c1 259 }),
f74e97ac 260 ...(hasOwnProp(Configuration.getConfigurationData(), 'logMaxSize') && {
66a7748d
JB
261 maxSize: Configuration.getConfigurationData()?.logMaxSize
262 })
263 }
3d48c1c1
JB
264 const logConfiguration: LogConfiguration = {
265 ...defaultLogConfiguration,
266 ...deprecatedLogConfiguration,
f74e97ac 267 ...(hasOwnProp(Configuration.getConfigurationData(), ConfigurationSection.log) &&
66a7748d
JB
268 Configuration.getConfigurationData()?.log)
269 }
270 return logConfiguration
3d48c1c1
JB
271 }
272
66a7748d 273 private static buildWorkerSection (): WorkerConfiguration {
3602e107
JB
274 const defaultWorkerConfiguration: WorkerConfiguration = {
275 processType: WorkerProcessType.workerSet,
276 startDelay: DEFAULT_WORKER_START_DELAY,
277 elementsPerWorker: 'auto',
278 elementStartDelay: DEFAULT_ELEMENT_START_DELAY,
279 poolMinSize: DEFAULT_POOL_MIN_SIZE,
66a7748d
JB
280 poolMaxSize: DEFAULT_POOL_MAX_SIZE
281 }
3602e107
JB
282 const deprecatedWorkerConfiguration: WorkerConfiguration = {
283 ...(hasOwnProp(Configuration.getConfigurationData(), 'workerProcess') && {
66a7748d 284 processType: Configuration.getConfigurationData()?.workerProcess
3602e107
JB
285 }),
286 ...(hasOwnProp(Configuration.getConfigurationData(), 'workerStartDelay') && {
66a7748d 287 startDelay: Configuration.getConfigurationData()?.workerStartDelay
3602e107
JB
288 }),
289 ...(hasOwnProp(Configuration.getConfigurationData(), 'chargingStationsPerWorker') && {
66a7748d 290 elementsPerWorker: Configuration.getConfigurationData()?.chargingStationsPerWorker
3602e107
JB
291 }),
292 ...(hasOwnProp(Configuration.getConfigurationData(), 'elementStartDelay') && {
66a7748d 293 elementStartDelay: Configuration.getConfigurationData()?.elementStartDelay
3602e107
JB
294 }),
295 ...(hasOwnProp(Configuration.getConfigurationData(), 'workerPoolMinSize') && {
66a7748d 296 poolMinSize: Configuration.getConfigurationData()?.workerPoolMinSize
3602e107
JB
297 }),
298 ...(hasOwnProp(Configuration.getConfigurationData(), 'workerPoolMaxSize') && {
66a7748d
JB
299 poolMaxSize: Configuration.getConfigurationData()?.workerPoolMaxSize
300 })
301 }
3602e107 302 hasOwnProp(Configuration.getConfigurationData(), 'workerPoolStrategy') &&
66a7748d 303 delete Configuration.getConfigurationData()?.workerPoolStrategy
3602e107
JB
304 const workerConfiguration: WorkerConfiguration = {
305 ...defaultWorkerConfiguration,
306 ...deprecatedWorkerConfiguration,
307 ...(hasOwnProp(Configuration.getConfigurationData(), ConfigurationSection.worker) &&
66a7748d
JB
308 Configuration.getConfigurationData()?.worker)
309 }
310 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
311 checkWorkerProcessType(workerConfiguration.processType!)
312 checkWorkerElementsPerWorker(workerConfiguration.elementsPerWorker)
313 return workerConfiguration
3602e107
JB
314 }
315
66a7748d 316 private static checkDeprecatedConfigurationKeys (): void {
3602e107
JB
317 // connection timeout
318 Configuration.warnDeprecatedConfigurationKey(
319 'autoReconnectTimeout',
320 undefined,
66a7748d
JB
321 "Use 'ConnectionTimeOut' OCPP parameter in charging station template instead"
322 )
3602e107
JB
323 Configuration.warnDeprecatedConfigurationKey(
324 'connectionTimeout',
325 undefined,
66a7748d
JB
326 "Use 'ConnectionTimeOut' OCPP parameter in charging station template instead"
327 )
3602e107
JB
328 // connection retries
329 Configuration.warnDeprecatedConfigurationKey(
330 'autoReconnectMaxRetries',
331 undefined,
66a7748d
JB
332 'Use it in charging station template instead'
333 )
3602e107
JB
334 // station template url(s)
335 Configuration.warnDeprecatedConfigurationKey(
336 'stationTemplateURLs',
337 undefined,
66a7748d
JB
338 "Use 'stationTemplateUrls' instead"
339 )
300418e9
JB
340 Configuration.getConfigurationData()?.['stationTemplateURLs' as keyof ConfigurationData] !==
341 undefined &&
66a7748d 342 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
3602e107 343 (Configuration.getConfigurationData()!.stationTemplateUrls =
66a7748d 344 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
3602e107
JB
345 Configuration.getConfigurationData()![
346 'stationTemplateURLs' as keyof ConfigurationData
66a7748d 347 ] as StationTemplateUrl[])
1c9de2b9 348 Configuration.getConfigurationData()?.stationTemplateUrls.forEach(
3602e107 349 (stationTemplateUrl: StationTemplateUrl) => {
5199f9fd
JB
350 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
351 if (stationTemplateUrl['numberOfStation' as keyof StationTemplateUrl] !== undefined) {
3602e107 352 console.error(
4354af5a 353 `${chalk.green(logPrefix())} ${chalk.red(
66a7748d
JB
354 `Deprecated configuration key 'numberOfStation' usage for template file '${stationTemplateUrl.file}' in 'stationTemplateUrls'. Use 'numberOfStations' instead`
355 )}`
356 )
3602e107 357 }
66a7748d
JB
358 }
359 )
3602e107
JB
360 // supervision url(s)
361 Configuration.warnDeprecatedConfigurationKey(
362 'supervisionURLs',
363 undefined,
66a7748d
JB
364 "Use 'supervisionUrls' instead"
365 )
3602e107
JB
366 // supervision urls distribution
367 Configuration.warnDeprecatedConfigurationKey(
368 'distributeStationToTenantEqually',
369 undefined,
66a7748d
JB
370 "Use 'supervisionUrlDistribution' instead"
371 )
3602e107
JB
372 Configuration.warnDeprecatedConfigurationKey(
373 'distributeStationsToTenantsEqually',
374 undefined,
66a7748d
JB
375 "Use 'supervisionUrlDistribution' instead"
376 )
3602e107 377 // worker section
e7aeea18 378 Configuration.warnDeprecatedConfigurationKey(
e80bc579 379 'useWorkerPool',
1895299d 380 undefined,
66a7748d
JB
381 `Use '${ConfigurationSection.worker}' section to define the type of worker process model instead`
382 )
cf2a5d9b
JB
383 Configuration.warnDeprecatedConfigurationKey(
384 'workerProcess',
1895299d 385 undefined,
66a7748d
JB
386 `Use '${ConfigurationSection.worker}' section to define the type of worker process model instead`
387 )
cf2a5d9b
JB
388 Configuration.warnDeprecatedConfigurationKey(
389 'workerStartDelay',
1895299d 390 undefined,
66a7748d
JB
391 `Use '${ConfigurationSection.worker}' section to define the worker start delay instead`
392 )
cf2a5d9b
JB
393 Configuration.warnDeprecatedConfigurationKey(
394 'chargingStationsPerWorker',
1895299d 395 undefined,
66a7748d
JB
396 `Use '${ConfigurationSection.worker}' section to define the number of element(s) per worker instead`
397 )
cf2a5d9b
JB
398 Configuration.warnDeprecatedConfigurationKey(
399 'elementStartDelay',
1895299d 400 undefined,
66a7748d
JB
401 `Use '${ConfigurationSection.worker}' section to define the worker's element start delay instead`
402 )
cf2a5d9b
JB
403 Configuration.warnDeprecatedConfigurationKey(
404 'workerPoolMinSize',
1895299d 405 undefined,
66a7748d
JB
406 `Use '${ConfigurationSection.worker}' section to define the worker pool minimum size instead`
407 )
e7aeea18 408 Configuration.warnDeprecatedConfigurationKey(
1d8f226b 409 'workerPoolSize',
1895299d 410 undefined,
66a7748d
JB
411 `Use '${ConfigurationSection.worker}' section to define the worker pool maximum size instead`
412 )
cf2a5d9b 413 Configuration.warnDeprecatedConfigurationKey(
1d8f226b 414 'workerPoolMaxSize',
1895299d 415 undefined,
66a7748d
JB
416 `Use '${ConfigurationSection.worker}' section to define the worker pool maximum size instead`
417 )
cf2a5d9b 418 Configuration.warnDeprecatedConfigurationKey(
1d8f226b 419 'workerPoolStrategy',
1895299d 420 undefined,
66a7748d
JB
421 `Use '${ConfigurationSection.worker}' section to define the worker pool strategy instead`
422 )
eda9c451
JB
423 Configuration.warnDeprecatedConfigurationKey(
424 'poolStrategy',
974efe6c 425 ConfigurationSection.worker,
66a7748d
JB
426 'Not publicly exposed to end users'
427 )
1d8f226b
JB
428 if (
429 Configuration.getConfigurationData()?.worker?.processType ===
430 ('staticPool' as WorkerProcessType)
431 ) {
432 console.error(
4354af5a 433 `${chalk.green(logPrefix())} ${chalk.red(
66a7748d
JB
434 `Deprecated configuration 'staticPool' value usage in worker section 'processType' field. Use '${WorkerProcessType.fixedPool}' value instead`
435 )}`
436 )
1d8f226b 437 }
3602e107
JB
438 // log section
439 Configuration.warnDeprecatedConfigurationKey(
440 'logEnabled',
441 undefined,
66a7748d
JB
442 `Use '${ConfigurationSection.log}' section to define the logging enablement instead`
443 )
3602e107
JB
444 Configuration.warnDeprecatedConfigurationKey(
445 'logFile',
446 undefined,
66a7748d
JB
447 `Use '${ConfigurationSection.log}' section to define the log file instead`
448 )
3602e107
JB
449 Configuration.warnDeprecatedConfigurationKey(
450 'logErrorFile',
451 undefined,
66a7748d
JB
452 `Use '${ConfigurationSection.log}' section to define the log error file instead`
453 )
3602e107
JB
454 Configuration.warnDeprecatedConfigurationKey(
455 'logConsole',
456 undefined,
66a7748d
JB
457 `Use '${ConfigurationSection.log}' section to define the console logging enablement instead`
458 )
3602e107
JB
459 Configuration.warnDeprecatedConfigurationKey(
460 'logStatisticsInterval',
461 undefined,
66a7748d
JB
462 `Use '${ConfigurationSection.log}' section to define the log statistics interval instead`
463 )
3602e107
JB
464 Configuration.warnDeprecatedConfigurationKey(
465 'logLevel',
466 undefined,
66a7748d
JB
467 `Use '${ConfigurationSection.log}' section to define the log level instead`
468 )
3602e107
JB
469 Configuration.warnDeprecatedConfigurationKey(
470 'logFormat',
471 undefined,
66a7748d
JB
472 `Use '${ConfigurationSection.log}' section to define the log format instead`
473 )
3602e107
JB
474 Configuration.warnDeprecatedConfigurationKey(
475 'logRotate',
476 undefined,
66a7748d
JB
477 `Use '${ConfigurationSection.log}' section to define the log rotation enablement instead`
478 )
3602e107
JB
479 Configuration.warnDeprecatedConfigurationKey(
480 'logMaxFiles',
481 undefined,
66a7748d
JB
482 `Use '${ConfigurationSection.log}' section to define the log maximum files instead`
483 )
3602e107
JB
484 Configuration.warnDeprecatedConfigurationKey(
485 'logMaxSize',
486 undefined,
66a7748d
JB
487 `Use '${ConfigurationSection.log}' section to define the log maximum size instead`
488 )
3602e107
JB
489 // performanceStorage section
490 Configuration.warnDeprecatedConfigurationKey(
491 'URI',
492 ConfigurationSection.performanceStorage,
66a7748d
JB
493 "Use 'uri' instead"
494 )
3602e107
JB
495 // uiServer section
496 if (hasOwnProp(Configuration.getConfigurationData(), 'uiWebSocketServer')) {
497 console.error(
4354af5a 498 `${chalk.green(logPrefix())} ${chalk.red(
66a7748d
JB
499 `Deprecated configuration section 'uiWebSocketServer' usage. Use '${ConfigurationSection.uiServer}' instead`
500 )}`
501 )
b5b2c3e8 502 }
7dde0b73 503 }
eb3937cb 504
66a7748d 505 private static warnDeprecatedConfigurationKey (
e7aeea18
JB
506 key: string,
507 sectionName?: string,
66a7748d
JB
508 logMsgToAppend = ''
509 ): void {
e7aeea18 510 if (
66a7748d 511 sectionName != null &&
300418e9
JB
512 Configuration.getConfigurationData()?.[sectionName as keyof ConfigurationData] !==
513 undefined &&
514 (
515 Configuration.getConfigurationData()?.[sectionName as keyof ConfigurationData] as Record<
516 string,
517 unknown
518 >
5199f9fd 519 )[key] !== undefined
e7aeea18
JB
520 ) {
521 console.error(
4354af5a 522 `${chalk.green(logPrefix())} ${chalk.red(
c5e52a07
JB
523 `Deprecated configuration key '${key}' usage in section '${sectionName}'${
524 logMsgToAppend.trim().length > 0 ? `. ${logMsgToAppend}` : ''
66a7748d
JB
525 }`
526 )}`
527 )
a37fc6dc 528 } else if (
300418e9 529 Configuration.getConfigurationData()?.[key as keyof ConfigurationData] !== undefined
a37fc6dc 530 ) {
e7aeea18 531 console.error(
4354af5a 532 `${chalk.green(logPrefix())} ${chalk.red(
c5e52a07
JB
533 `Deprecated configuration key '${key}' usage${
534 logMsgToAppend.trim().length > 0 ? `. ${logMsgToAppend}` : ''
66a7748d
JB
535 }`
536 )}`
537 )
eb3937cb
JB
538 }
539 }
540
66a7748d
JB
541 private static getConfigurationData (): ConfigurationData | undefined {
542 if (Configuration.configurationData == null) {
23132a44 543 try {
f74e97ac 544 Configuration.configurationData = JSON.parse(
66a7748d
JB
545 readFileSync(Configuration.configurationFile, 'utf8')
546 ) as ConfigurationData
547 if (Configuration.configurationFileWatcher == null) {
548 Configuration.configurationFileWatcher = Configuration.getConfigurationFileWatcher()
1f8f6332 549 }
23132a44 550 } catch (error) {
4354af5a 551 handleFileException(
a95873d8 552 Configuration.configurationFile,
7164966d
JB
553 FileType.Configuration,
554 error as NodeJS.ErrnoException,
66a7748d
JB
555 logPrefix()
556 )
23132a44 557 }
eb3937cb 558 }
66a7748d 559 return Configuration.configurationData
eb3937cb 560 }
963ee397 561
66a7748d 562 private static getConfigurationFileWatcher (): FSWatcher | undefined {
23132a44 563 try {
d972af76 564 return watch(Configuration.configurationFile, (event, filename): void => {
1b4ccee3
JB
565 if (
566 !Configuration.configurationFileReloading &&
66a7748d 567 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
aafba9d8 568 filename!.trim().length > 0 &&
1b4ccee3
JB
569 event === 'change'
570 ) {
66a7748d
JB
571 Configuration.configurationFileReloading = true
572 const consoleWarnOnce = once(console.warn, this)
1b4ccee3 573 consoleWarnOnce(
4354af5a 574 `${chalk.green(logPrefix())} ${chalk.yellow(
66a7748d
JB
575 `${FileType.Configuration} ${this.configurationFile} file have changed, reload`
576 )}`
577 )
578 delete Configuration.configurationData
579 Configuration.configurationSectionCache.clear()
300418e9 580 if (Configuration.configurationChangeCallback !== undefined) {
1b4ccee3 581 Configuration.configurationChangeCallback()
a974c8e4 582 .catch(error => {
66a7748d 583 throw typeof error === 'string' ? new Error(error) : error
1b4ccee3
JB
584 })
585 .finally(() => {
66a7748d
JB
586 Configuration.configurationFileReloading = false
587 })
41d95b76 588 } else {
66a7748d 589 Configuration.configurationFileReloading = false
3ec10737 590 }
23132a44 591 }
66a7748d 592 })
23132a44 593 } catch (error) {
4354af5a 594 handleFileException(
a95873d8 595 Configuration.configurationFile,
7164966d
JB
596 FileType.Configuration,
597 error as NodeJS.ErrnoException,
66a7748d
JB
598 logPrefix()
599 )
23132a44 600 }
ded13d97 601 }
7dde0b73 602}