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