From 750d33db1ff249b866c8319aa3170a2fe59d5b9f Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Fri, 3 Apr 2026 15:41:36 +0200 Subject: [PATCH] refactor: use utility helpers consistently across codebase Replace manual * 1000 with secondsToMilliseconds() in auth cache, remote strategy, and OCPP20 incoming request. Replace manual / 1000 with millisecondsToSeconds() in auth helpers, auth service, and cert signing retry. Replace 'in' operator with has() in auth service. Replace configurationKey find with getConfigurationKey() in OCPP20RequestService. Use formatDurationMilliSeconds for reconnect delay log. Keep ms precision in auth service logs (sub-second durations). --- src/charging-station/ChargingStation.ts | 6 +----- .../ocpp/2.0/OCPP20CertSigningRetryManager.ts | 4 ++-- .../ocpp/2.0/OCPP20IncomingRequestService.ts | 4 +++- .../ocpp/2.0/OCPP20RequestService.ts | 5 ++--- .../ocpp/auth/cache/InMemoryAuthCache.ts | 18 +++++++++++++----- .../ocpp/auth/services/OCPPAuthServiceImpl.ts | 9 ++++++--- .../ocpp/auth/strategies/RemoteAuthStrategy.ts | 4 +++- .../ocpp/auth/utils/AuthHelpers.ts | 4 +++- 8 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 30e46f4c..84277c64 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -100,7 +100,6 @@ import { min, once, promiseWithTimeout, - roundTo, secureRandom, sleep, watchJsonFile, @@ -2377,10 +2376,7 @@ export class ChargingStation extends EventEmitter { ? reconnectDelay - Constants.DEFAULT_WS_RECONNECT_TIMEOUT_OFFSET : 0 logger.error( - `${this.logPrefix()} WebSocket connection retry in ${roundTo( - reconnectDelay, - 2 - ).toString()}ms, timeout ${reconnectTimeout.toString()}ms` + `${this.logPrefix()} WebSocket connection retry in ${formatDurationMilliSeconds(reconnectDelay)}, timeout ${formatDurationMilliSeconds(reconnectTimeout)}` ) await sleep(reconnectDelay) logger.error( diff --git a/src/charging-station/ocpp/2.0/OCPP20CertSigningRetryManager.ts b/src/charging-station/ocpp/2.0/OCPP20CertSigningRetryManager.ts index 487f5775..3a4397c2 100644 --- a/src/charging-station/ocpp/2.0/OCPP20CertSigningRetryManager.ts +++ b/src/charging-station/ocpp/2.0/OCPP20CertSigningRetryManager.ts @@ -1,4 +1,4 @@ -import { secondsToMilliseconds } from 'date-fns' +import { millisecondsToSeconds, secondsToMilliseconds } from 'date-fns' import type { ChargingStation } from '../../../charging-station/index.js' import type { JsonType, OCPP20SignCertificateResponse } from '../../../types/index.js' @@ -100,7 +100,7 @@ export class OCPP20CertSigningRetryManager { }) logger.debug( - `${this.chargingStation.logPrefix()} ${moduleName}.scheduleNextRetry: Scheduling retry ${(this.retryCount + 1).toString()}/${maxRetries.toString()} in ${Math.round(delayMs / 1000).toString()}s` + `${this.chargingStation.logPrefix()} ${moduleName}.scheduleNextRetry: Scheduling retry ${(this.retryCount + 1).toString()}/${maxRetries.toString()} in ${millisecondsToSeconds(delayMs).toString()}s` ) this.retryTimer = setTimeout(() => { diff --git a/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts b/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts index d5c30e8b..03c3d3f6 100644 --- a/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts +++ b/src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts @@ -2,6 +2,8 @@ import type { ValidateFunction } from 'ajv' +import { secondsToMilliseconds } from 'date-fns' + import type { ChargingStation } from '../../../charging-station/index.js' import type { OCPP20IdTokenEnumType } from '../../../types/index.js' @@ -3479,7 +3481,7 @@ export class OCPP20IncomingRequestService extends OCPPIncomingRequestService { if (location.trim() === '' || !this.isValidFirmwareLocation(location)) { // L01.FR.30: Simulate download retries before reporting DownloadFailed const maxRetries = retries ?? 0 - const retryDelayMs = (retryInterval ?? 0) * 1000 + const retryDelayMs = secondsToMilliseconds(retryInterval ?? 0) for (let attempt = 1; attempt <= maxRetries; attempt++) { logger.warn( `${chargingStation.logPrefix()} ${moduleName}.simulateFirmwareUpdateLifecycle: Download failed for requestId ${requestId.toString()} - invalid location '${location}' (attempt ${attempt.toString()}/${maxRetries.toString()}, retrying in ${retryInterval?.toString() ?? '0'}s)` diff --git a/src/charging-station/ocpp/2.0/OCPP20RequestService.ts b/src/charging-station/ocpp/2.0/OCPP20RequestService.ts index 0b1a4e15..ab9640e0 100644 --- a/src/charging-station/ocpp/2.0/OCPP20RequestService.ts +++ b/src/charging-station/ocpp/2.0/OCPP20RequestService.ts @@ -3,6 +3,7 @@ import type { ValidateFunction } from 'ajv' import type { ChargingStation } from '../../../charging-station/index.js' import type { OCPPResponseService } from '../OCPPResponseService.js' +import { getConfigurationKey } from '../../../charging-station/index.js' import { OCPPError } from '../../../exception/index.js' import { type CertificateSigningUseEnumType, @@ -167,9 +168,7 @@ export class OCPP20RequestService extends OCPPRequestService { case OCPP20RequestCommand.SIGN_CERTIFICATE: { let csr: string try { - const configKey = chargingStation.ocppConfiguration?.configurationKey?.find( - key => key.key === 'SecurityCtrlr.OrganizationName' - ) + const configKey = getConfigurationKey(chargingStation, 'SecurityCtrlr.OrganizationName') const orgName = configKey?.value ?? 'Unknown' const stationId = chargingStation.stationInfo?.chargingStationId ?? 'Unknown' diff --git a/src/charging-station/ocpp/auth/cache/InMemoryAuthCache.ts b/src/charging-station/ocpp/auth/cache/InMemoryAuthCache.ts index 5698c03d..e46c10d2 100644 --- a/src/charging-station/ocpp/auth/cache/InMemoryAuthCache.ts +++ b/src/charging-station/ocpp/auth/cache/InMemoryAuthCache.ts @@ -1,3 +1,5 @@ +import { secondsToMilliseconds } from 'date-fns' + import type { AuthCache, CacheStats } from '../interfaces/OCPPAuthService.js' import type { AuthorizationResult } from '../types/AuthTypes.js' @@ -131,7 +133,7 @@ export class InMemoryAuthCache implements AuthCache { const cleanupSeconds = options?.cleanupIntervalSeconds ?? 300 if (cleanupSeconds > 0) { - const intervalMs = cleanupSeconds * 1000 + const intervalMs = secondsToMilliseconds(cleanupSeconds) this.cleanupInterval = setInterval(() => { this.runCleanup() }, intervalMs) @@ -193,7 +195,10 @@ export class InMemoryAuthCache implements AuthCache { if (!authCacheEntry.hasExplicitTtl) { const absoluteDeadline = authCacheEntry.createdAt + this.maxAbsoluteLifetimeMs if (absoluteDeadline > now) { - authCacheEntry.expiresAt = Math.min(now + this.defaultTtl * 1000, absoluteDeadline) + authCacheEntry.expiresAt = Math.min( + now + secondsToMilliseconds(this.defaultTtl), + absoluteDeadline + ) } } this.lruOrder.set(identifier, now) @@ -213,7 +218,7 @@ export class InMemoryAuthCache implements AuthCache { !authCacheEntry.hasExplicitTtl && authCacheEntry.createdAt + this.maxAbsoluteLifetimeMs > now ) { - authCacheEntry.expiresAt = now + this.defaultTtl * 1000 + authCacheEntry.expiresAt = now + secondsToMilliseconds(this.defaultTtl) } logger.debug(`${moduleName}: Cache hit for identifier: '${truncateId(identifier)}'`) @@ -297,7 +302,10 @@ export class InMemoryAuthCache implements AuthCache { if (!entry.hasExplicitTtl) { const absoluteDeadline = entry.createdAt + this.maxAbsoluteLifetimeMs if (absoluteDeadline > now) { - entry.expiresAt = Math.min(now + this.defaultTtl * 1000, absoluteDeadline) + entry.expiresAt = Math.min( + now + secondsToMilliseconds(this.defaultTtl), + absoluteDeadline + ) } } this.stats.expired++ @@ -332,7 +340,7 @@ export class InMemoryAuthCache implements AuthCache { const maxTtlSeconds = this.maxAbsoluteLifetimeMs / 1000 const clampedTtl = Math.min(Math.max(0, ttlSeconds), maxTtlSeconds) const now = Date.now() - const expiresAt = now + clampedTtl * 1000 + const expiresAt = now + secondsToMilliseconds(clampedTtl) this.cache.set(identifier, { createdAt: now, diff --git a/src/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.ts b/src/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.ts index bbd3e23c..e1958265 100644 --- a/src/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.ts +++ b/src/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.ts @@ -1,3 +1,5 @@ +import { millisecondsToSeconds } from 'date-fns' + import type { OCPPAuthAdapter } from '../interfaces/OCPPAuthService.js' import { OCPPError } from '../../../../exception/index.js' @@ -6,6 +8,7 @@ import { convertToDate, ensureError, getErrorMessage, + has, logger, truncateId, } from '../../../../utils/index.js' @@ -319,7 +322,7 @@ export class OCPPAuthServiceImpl implements OCPPAuthService { const remoteStrategy = this.strategies.get('remote') if (remoteStrategy?.getStats) { const strategyStatistics = remoteStrategy.getStats() - if ('cache' in strategyStatistics) { + if (has('cache', strategyStatistics)) { const cacheStatistics = strategyStatistics.cache as { rateLimit?: { blockedRequests: number @@ -489,7 +492,7 @@ export class OCPPAuthServiceImpl implements OCPPAuthService { if (expiryDate != null) { const expiry = convertToDate(expiryDate) if (expiry != null) { - const ttlSeconds = Math.floor((expiry.getTime() - Date.now()) / 1000) + const ttlSeconds = millisecondsToSeconds(expiry.getTime() - Date.now()) if (ttlSeconds <= 0) { logger.debug( `${this.chargingStation.logPrefix()} ${moduleName}.updateCacheEntry: Skipping expired entry for '${truncateId(identifier)}'` @@ -555,7 +558,7 @@ export class OCPPAuthServiceImpl implements OCPPAuthService { obj: AuthStrategy ): obj is AuthStrategy & { configure: (config: Record) => void } => { return ( - 'configure' in obj && + has('configure', obj) && typeof (obj as AuthStrategy & { configure?: unknown }).configure === 'function' ) } diff --git a/src/charging-station/ocpp/auth/strategies/RemoteAuthStrategy.ts b/src/charging-station/ocpp/auth/strategies/RemoteAuthStrategy.ts index 7cf28b9b..5374c102 100644 --- a/src/charging-station/ocpp/auth/strategies/RemoteAuthStrategy.ts +++ b/src/charging-station/ocpp/auth/strategies/RemoteAuthStrategy.ts @@ -1,3 +1,5 @@ +import { secondsToMilliseconds } from 'date-fns' + import type { JsonObject } from '../../../../types/index.js' import type { AuthCache, @@ -418,7 +420,7 @@ export class RemoteAuthStrategy implements AuthStrategy { config: AuthConfiguration, startTime: number ): Promise { - const timeout = config.authorizationTimeout * 1000 + const timeout = secondsToMilliseconds(config.authorizationTimeout) try { const authPromise = adapter.authorizeRemote( diff --git a/src/charging-station/ocpp/auth/utils/AuthHelpers.ts b/src/charging-station/ocpp/auth/utils/AuthHelpers.ts index 61cede25..f380dbe0 100644 --- a/src/charging-station/ocpp/auth/utils/AuthHelpers.ts +++ b/src/charging-station/ocpp/auth/utils/AuthHelpers.ts @@ -1,3 +1,5 @@ +import { millisecondsToSeconds } from 'date-fns' + import type { AuthContext, AuthenticationMethod, @@ -25,7 +27,7 @@ function calculateTTL (expiryDate?: Date): number | undefined { return undefined } - return Math.floor(ttlMs / 1000) + return millisecondsToSeconds(ttlMs) } /** -- 2.43.0