-import { type FSWatcher, readFileSync, watch } from 'node:fs'
+import { existsSync, type FSWatcher, readFileSync, watch } from 'node:fs'
import { dirname, join } from 'node:path'
import { env } from 'node:process'
import { fileURLToPath } from 'node:url'
type WorkerConfiguration
} from '../types/index.js'
import {
- DEFAULT_ELEMENT_START_DELAY,
+ DEFAULT_ELEMENT_ADD_DELAY,
DEFAULT_POOL_MAX_SIZE,
DEFAULT_POOL_MIN_SIZE,
DEFAULT_WORKER_START_DELAY,
| WorkerConfiguration
| UIServerConfiguration
+const defaultUIServerConfiguration: UIServerConfiguration = {
+ enabled: false,
+ type: ApplicationProtocol.WS,
+ version: ApplicationProtocolVersion.VERSION_11,
+ options: {
+ host: Constants.DEFAULT_UI_SERVER_HOST,
+ port: Constants.DEFAULT_UI_SERVER_PORT
+ }
+}
+
+const defaultStorageConfiguration: StorageConfiguration = {
+ enabled: true,
+ type: StorageType.NONE
+}
+
+const defaultLogConfiguration: LogConfiguration = {
+ enabled: true,
+ file: 'logs/combined.log',
+ errorFile: 'logs/error.log',
+ statisticsInterval: Constants.DEFAULT_LOG_STATISTICS_INTERVAL,
+ level: 'info',
+ format: 'simple',
+ rotate: true
+}
+
+const defaultWorkerConfiguration: WorkerConfiguration = {
+ processType: WorkerProcessType.workerSet,
+ startDelay: DEFAULT_WORKER_START_DELAY,
+ elementsPerWorker: 'auto',
+ elementAddDelay: DEFAULT_ELEMENT_ADD_DELAY,
+ poolMinSize: DEFAULT_POOL_MIN_SIZE,
+ poolMaxSize: DEFAULT_POOL_MAX_SIZE
+}
+
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
export class Configuration {
public static configurationChangeCallback?: () => Promise<void>
- private static readonly configurationFile = join(
- dirname(fileURLToPath(import.meta.url)),
- 'assets',
- 'config.json'
- )
-
+ private static configurationFile: string | undefined
private static configurationFileReloading = false
private static configurationData?: ConfigurationData
private static configurationFileWatcher?: FSWatcher
- private static readonly configurationSectionCache = new Map<
- ConfigurationSection,
- ConfigurationSectionType
- >([
- [ConfigurationSection.log, Configuration.buildLogSection()],
- [ConfigurationSection.performanceStorage, Configuration.buildPerformanceStorageSection()],
- [ConfigurationSection.worker, Configuration.buildWorkerSection()],
- [ConfigurationSection.uiServer, Configuration.buildUIServerSection()]
- ])
+ private static configurationSectionCache: Map<ConfigurationSection, ConfigurationSectionType>
+
+ static {
+ const configurationFile = join(dirname(fileURLToPath(import.meta.url)), 'assets', 'config.json')
+ if (existsSync(configurationFile)) {
+ Configuration.configurationFile = configurationFile
+ } else {
+ console.error(
+ `${chalk.green(logPrefix())} ${chalk.red(
+ `Configuration file '${configurationFile}' not found, using default configuration`
+ )}`
+ )
+ Configuration.configurationData = {
+ stationTemplateUrls: [],
+ supervisionUrls: 'ws://localhost:8180/steve/websocket/CentralSystemService',
+ supervisionUrlDistribution: SupervisionUrlDistribution.ROUND_ROBIN,
+ uiServer: defaultUIServerConfiguration,
+ performanceStorage: defaultStorageConfiguration,
+ log: defaultLogConfiguration,
+ worker: defaultWorkerConfiguration
+ }
+ }
+ Configuration.configurationSectionCache = new Map<
+ ConfigurationSection,
+ ConfigurationSectionType
+ >([
+ [ConfigurationSection.log, Configuration.buildLogSection()],
+ [ConfigurationSection.performanceStorage, Configuration.buildPerformanceStorageSection()],
+ [ConfigurationSection.worker, Configuration.buildWorkerSection()],
+ [ConfigurationSection.uiServer, Configuration.buildUIServerSection()]
+ ])
+ }
private constructor () {
// This is intentional
}
private static buildUIServerSection (): UIServerConfiguration {
- let uiServerConfiguration: UIServerConfiguration = {
- enabled: false,
- type: ApplicationProtocol.WS,
- version: ApplicationProtocolVersion.VERSION_11,
- options: {
- host: Constants.DEFAULT_UI_SERVER_HOST,
- port: Constants.DEFAULT_UI_SERVER_PORT
- }
- }
+ let uiServerConfiguration: UIServerConfiguration = defaultUIServerConfiguration
if (hasOwnProp(Configuration.getConfigurationData(), ConfigurationSection.uiServer)) {
uiServerConfiguration = mergeDeepRight(
uiServerConfiguration,
if (isCFEnvironment()) {
delete uiServerConfiguration.options?.host
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- uiServerConfiguration.options!.port = parseInt(env.PORT!)
+ uiServerConfiguration.options!.port = Number.parseInt(env.PORT!)
}
return uiServerConfiguration
}
break
case StorageType.NONE:
default:
- storageConfiguration = {
- enabled: true,
- type: StorageType.NONE
- }
+ storageConfiguration = defaultStorageConfiguration
break
}
if (hasOwnProp(Configuration.getConfigurationData(), ConfigurationSection.performanceStorage)) {
}
private static buildLogSection (): LogConfiguration {
- const defaultLogConfiguration: LogConfiguration = {
- enabled: true,
- file: 'logs/combined.log',
- errorFile: 'logs/error.log',
- statisticsInterval: Constants.DEFAULT_LOG_STATISTICS_INTERVAL,
- level: 'info',
- format: 'simple',
- rotate: true
- }
const deprecatedLogConfiguration: LogConfiguration = {
...(hasOwnProp(Configuration.getConfigurationData(), 'logEnabled') && {
enabled: Configuration.getConfigurationData()?.logEnabled
}
private static buildWorkerSection (): WorkerConfiguration {
- const defaultWorkerConfiguration: WorkerConfiguration = {
- processType: WorkerProcessType.workerSet,
- startDelay: DEFAULT_WORKER_START_DELAY,
- elementsPerWorker: 'auto',
- elementStartDelay: DEFAULT_ELEMENT_START_DELAY,
- poolMinSize: DEFAULT_POOL_MIN_SIZE,
- poolMaxSize: DEFAULT_POOL_MAX_SIZE
- }
const deprecatedWorkerConfiguration: WorkerConfiguration = {
...(hasOwnProp(Configuration.getConfigurationData(), 'workerProcess') && {
processType: Configuration.getConfigurationData()?.workerProcess
...(hasOwnProp(Configuration.getConfigurationData(), 'chargingStationsPerWorker') && {
elementsPerWorker: Configuration.getConfigurationData()?.chargingStationsPerWorker
}),
- ...(hasOwnProp(Configuration.getConfigurationData(), 'elementStartDelay') && {
- elementStartDelay: Configuration.getConfigurationData()?.elementStartDelay
+ ...(hasOwnProp(Configuration.getConfigurationData(), 'elementAddDelay') && {
+ elementAddDelay: Configuration.getConfigurationData()?.elementAddDelay
+ }),
+ ...(hasOwnProp(Configuration.getConfigurationData()?.worker, 'elementStartDelay') && {
+ elementAddDelay: Configuration.getConfigurationData()?.worker?.elementStartDelay
}),
...(hasOwnProp(Configuration.getConfigurationData(), 'workerPoolMinSize') && {
poolMinSize: Configuration.getConfigurationData()?.workerPoolMinSize
`Use '${ConfigurationSection.worker}' section to define the number of element(s) per worker instead`
)
Configuration.warnDeprecatedConfigurationKey(
- 'elementStartDelay',
+ 'elementAddDelay',
undefined,
- `Use '${ConfigurationSection.worker}' section to define the worker's element start delay instead`
+ `Use '${ConfigurationSection.worker}' section to define the worker's element add delay instead`
)
Configuration.warnDeprecatedConfigurationKey(
'workerPoolMinSize',
ConfigurationSection.worker,
'Not publicly exposed to end users'
)
+ Configuration.warnDeprecatedConfigurationKey(
+ 'elementStartDelay',
+ ConfigurationSection.worker,
+ "Use 'elementAddDelay' instead"
+ )
if (
Configuration.getConfigurationData()?.worker?.processType ===
('staticPool' as WorkerProcessType)
private static warnDeprecatedConfigurationKey (
key: string,
- sectionName?: string,
+ configurationSection?: ConfigurationSection,
logMsgToAppend = ''
): void {
if (
- sectionName != null &&
- Configuration.getConfigurationData()?.[sectionName as keyof ConfigurationData] != null &&
+ configurationSection != null &&
+ Configuration.getConfigurationData()?.[configurationSection as keyof ConfigurationData] !=
+ null &&
(
- Configuration.getConfigurationData()?.[sectionName as keyof ConfigurationData] as Record<
- string,
- unknown
- >
+ Configuration.getConfigurationData()?.[
+ configurationSection as keyof ConfigurationData
+ ] as Record<string, unknown>
)[key] != null
) {
console.error(
`${chalk.green(logPrefix())} ${chalk.red(
- `Deprecated configuration key '${key}' usage in section '${sectionName}'${
+ `Deprecated configuration key '${key}' usage in section '${configurationSection}'${
logMsgToAppend.trim().length > 0 ? `. ${logMsgToAppend}` : ''
}`
)}`
}
}
- private static getConfigurationData (): ConfigurationData | undefined {
- if (Configuration.configurationData == null) {
+ public static getConfigurationData (): ConfigurationData | undefined {
+ if (
+ Configuration.configurationData == null &&
+ Configuration.configurationFile != null &&
+ Configuration.configurationFile.length > 0
+ ) {
try {
Configuration.configurationData = JSON.parse(
readFileSync(Configuration.configurationFile, 'utf8')
}
private static getConfigurationFileWatcher (): FSWatcher | undefined {
+ if (Configuration.configurationFile == null || Configuration.configurationFile.length === 0) {
+ return
+ }
try {
return watch(Configuration.configurationFile, (event, filename): void => {
if (