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