type ChargingStationWorkerMessageData,
ChargingStationWorkerMessageEvents,
ConfigurationSection,
- type InternalTemplateStatistics,
ProcedureName,
type SimulatorState,
type Statistics,
type StorageConfiguration,
+ type TemplateStatistics,
type UIServerConfiguration,
type WorkerConfiguration
} from '../types/index.js'
import {
- buildTemplateStatisticsPayload,
Configuration,
Constants,
formatDurationMilliSeconds,
private workerImplementation?: WorkerAbstract<ChargingStationWorkerData>
private readonly uiServer: AbstractUIServer
private storage?: Storage
- private readonly templateStatistics: Map<string, InternalTemplateStatistics>
+ private readonly templateStatistics: Map<string, TemplateStatistics>
private readonly version: string = version
private initializedCounters: boolean
private started: boolean
this.uiServer = UIServerFactory.getUIServerImplementation(
Configuration.getConfigurationSection<UIServerConfiguration>(ConfigurationSection.uiServer)
)
- this.templateStatistics = new Map<string, InternalTemplateStatistics>()
+ this.templateStatistics = new Map<string, TemplateStatistics>()
this.initializedCounters = false
this.initializeCounters()
Configuration.configurationChangeCallback = async () => {
return {
version: this.version,
started: this.started,
- templateStatistics: buildTemplateStatisticsPayload(this.templateStatistics)
+ templateStatistics: this.templateStatistics
}
}
import { BaseError } from '../../exception/index.js'
import {
ApplicationProtocolVersion,
+ MapStringifyFormat,
type ProcedureName,
type Protocol,
type ProtocolRequest,
Constants,
generateUUID,
isNotEmptyString,
- JSONStringifyWithMapSupport,
+ JSONStringify,
logger,
logPrefix
} from '../../utils/index.js'
.writeHead(this.responseStatusToStatusCode(payload.status), {
'Content-Type': 'application/json'
})
- .end(JSONStringifyWithMapSupport(payload))
+ .end(JSONStringify(payload, undefined, MapStringifyFormat.object))
} else {
logger.error(
`${this.logPrefix(moduleName, 'sendResponse')} Response for unknown request id: ${uuid}`
import { type RawData, WebSocket, WebSocketServer } from 'ws'
import {
+ MapStringifyFormat,
type ProtocolRequest,
type ProtocolResponse,
type UIServerConfiguration,
Constants,
getWebSocketCloseEventStatusString,
isNotEmptyString,
- JSONStringifyWithMapSupport,
+ JSONStringify,
logger,
logPrefix,
validateUUID
if (this.hasResponseHandler(responseId)) {
const ws = this.responseHandlers.get(responseId) as WebSocket
if (ws.readyState === WebSocket.OPEN) {
- ws.send(JSONStringifyWithMapSupport(response))
+ ws.send(JSONStringify(response, undefined, MapStringifyFormat.object))
} else {
logger.error(
`${this.logPrefix(
ConfigurationSection,
type IncomingRequestCommand,
type LogConfiguration,
+ MapStringifyFormat,
MessageType,
type RequestCommand,
type Statistics,
extractTimeSeriesValues,
formatDurationSeconds,
generateUUID,
- JSONStringifyWithMapSupport,
+ JSONStringify,
logger,
logPrefix,
max,
logger.info(this.logPrefix(), {
...this.statistics,
statisticsData: JSON.parse(
- JSONStringifyWithMapSupport(this.statistics.statisticsData)
+ JSONStringify(this.statistics.statisticsData, undefined, MapStringifyFormat.object)
) as Map<string | RequestCommand | IncomingRequestCommand, StatisticsData>
})
}
import { dirname } from 'node:path'
import { BaseError } from '../../exception/index.js'
-import { FileType, type Statistics } from '../../types/index.js'
-import {
- AsyncLock,
- AsyncLockType,
- handleFileException,
- JSONStringifyWithMapSupport
-} from '../../utils/index.js'
+import { FileType, MapStringifyFormat, type Statistics } from '../../types/index.js'
+import { AsyncLock, AsyncLockType, handleFileException, JSONStringify } from '../../utils/index.js'
import { Storage } from './Storage.js'
export class JsonFileStorage extends Storage {
writeSync(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.fd!,
- JSONStringifyWithMapSupport([...this.getPerformanceStatistics()], 2),
+ JSONStringify([...this.getPerformanceStatistics()], 2, MapStringifyFormat.object),
0,
'utf8'
)
--- /dev/null
+export enum MapStringifyFormat {
+ array = 'array',
+ object = 'object'
+}
--- /dev/null
+import type { TemplateStatistics } from './Statistics.js'
+
+export interface SimulatorState {
+ version: string
+ started: boolean
+ templateStatistics: Map<string, TemplateStatistics>
+}
statisticsData: Map<string | RequestCommand | IncomingRequestCommand, StatisticsData>
}
-export interface InternalTemplateStatistics {
+export interface TemplateStatistics {
configured: number
added: number
started: number
started: number
indexes: number[]
}
-
-export interface SimulatorState extends JsonObject {
- version: string
- started: boolean
- templateStatistics: Record<string, TemplateStatistics>
-}
export type { EvseStatus, EvseTemplate } from './Evse.js'
export { FileType } from './FileType.js'
export type { JsonObject, JsonType } from './JsonType.js'
+export { MapStringifyFormat } from './MapStringifyFormat.js'
export type {
MeasurandPerPhaseSampledValueTemplates,
SampledValueTemplate
type StopTransactionResponse
} from './ocpp/Transaction.js'
export { PerformanceRecord } from './orm/entities/PerformanceRecord.js'
+export type { SimulatorState } from './SimulatorState.js'
export type {
- InternalTemplateStatistics,
Statistics,
StatisticsData,
+ TemplateStatistics,
TimestampedData
} from './Statistics.js'
export { DBName, StorageType } from './Storage.js'
ProtocolVersion,
type RequestPayload,
type ResponsePayload,
- ResponseStatus,
- type SimulatorState,
- type TemplateStatistics
+ ResponseStatus
} from './UIProtocol.js'
export {
WebSocketCloseEventStatusCode,
type ChargingStationData,
type ChargingStationWorkerMessage,
ChargingStationWorkerMessageEvents,
- type InternalTemplateStatistics,
- type Statistics,
- type TemplateStatistics
+ type Statistics
} from '../types/index.js'
import {
buildChargingStationAutomaticTransactionGeneratorConfiguration,
buildEvsesStatus,
OutputFormat
} from './ChargingStationConfigurationUtils.js'
-import { clone } from './Utils.js'
export const buildAddedMessage = (
chargingStation: ChargingStation
})
}
}
-
-export const buildTemplateStatisticsPayload = (
- map: Map<string, InternalTemplateStatistics>
-): Record<string, TemplateStatistics> => {
- map = clone(map)
- for (const value of map.values()) {
- (value as unknown as TemplateStatistics).indexes = [...value.indexes]
- }
- return Object.fromEntries(map.entries() as unknown as Array<[string, TemplateStatistics]>)
-}
import {
type EmptyObject,
- type ProtocolResponse,
+ type JsonType,
+ MapStringifyFormat,
type TimestampedData,
WebSocketCloseEventStatusString
} from '../types/index.js'
return getRandomValues(new Uint32Array(1))[0] / 0x100000000
}
-export const JSONStringifyWithMapSupport = (
- object:
- | Record<string, unknown>
- | Array<Record<string, unknown>>
- | Map<unknown, unknown>
- | ProtocolResponse,
- space?: string | number
-): string => {
+export const JSONStringify = <
+ T extends JsonType | Array<Record<string, unknown>> | Map<string, Record<string, unknown>>
+>(
+ object: T,
+ space?: string | number,
+ mapFormat?: MapStringifyFormat
+ ): string => {
return JSON.stringify(
object,
(_, value: Record<string, unknown>) => {
if (value instanceof Map) {
- return {
- dataType: 'Map',
- value: [...value]
+ switch (mapFormat) {
+ case MapStringifyFormat.object:
+ return { ...Object.fromEntries<Map<string, T>>(value.entries()) }
+ case MapStringifyFormat.array:
+ default:
+ return [...value]
}
+ } else if (value instanceof Set) {
+ return [...value] as unknown[]
}
return value
},
buildPerformanceStatisticsMessage,
buildStartedMessage,
buildStoppedMessage,
- buildTemplateStatisticsPayload,
buildUpdatedMessage
} from './MessageChannelUtils.js'
export { average, median, nthPercentile, stdDeviation } from './StatisticUtils.js'
isNotEmptyArray,
isNotEmptyString,
isValidDate,
- JSONStringifyWithMapSupport,
+ JSONStringify,
logPrefix,
max,
min,
}
if (!Array.isArray(response)) {
- useToast().error(`Response not an array`)
- console.error(`Response not an array:`, response)
+ useToast().error('Response not an array')
+ console.error('Response not an array:', response)
return
}
const [uuid, responsePayload] = response
+ console.log('responsePayload', responsePayload.state?.templateStatistics)
+
if (this.responseHandlers.has(uuid)) {
const { procedureName, resolve, reject } = this.responseHandlers.get(uuid)!
switch (responsePayload.status) {
const serve = serveStatic(uiPath)
-const server = createServer(function onRequest(req, res) {
- serve(req, res, finalhandler(req, res))
-})
+const server = createServer((req, res) => serve(req, res, finalhandler(req, res)))
server.listen(PORT, () => console.info(`Web UI running at: http://localhost:${PORT}`))