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