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