]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/commitdiff
refactor: use utility helpers consistently across codebase
authorJérôme Benoit <jerome.benoit@sap.com>
Fri, 3 Apr 2026 13:41:36 +0000 (15:41 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Fri, 3 Apr 2026 13:41:36 +0000 (15:41 +0200)
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
src/charging-station/ocpp/2.0/OCPP20CertSigningRetryManager.ts
src/charging-station/ocpp/2.0/OCPP20IncomingRequestService.ts
src/charging-station/ocpp/2.0/OCPP20RequestService.ts
src/charging-station/ocpp/auth/cache/InMemoryAuthCache.ts
src/charging-station/ocpp/auth/services/OCPPAuthServiceImpl.ts
src/charging-station/ocpp/auth/strategies/RemoteAuthStrategy.ts
src/charging-station/ocpp/auth/utils/AuthHelpers.ts

index 30e46f4cdd245afb0824364b689c551144524286..84277c64febb699bc7ba44b6fe5571d0e8a77a8a 100644 (file)
@@ -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(
index 487f5775ab4cf0332210601c369436fbdda42309..3a4397c2837d750ab0184fd2ae74e289950f0495 100644 (file)
@@ -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(() => {
index d5c30e8b77ad1b6a9c427bb1d49c312c094ec214..03c3d3f6bc22aaff405a510994222f906d1d7ab5 100644 (file)
@@ -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)`
index 0b1a4e1539b46cee2a26c915dc9d719e454f465b..ab9640e07dbbfc73e58ccbb9c99af441c71bfdf1 100644 (file)
@@ -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'
 
index 5698c03de41d5ac060d3b7618e361d74c8aad7be..e46c10d2bd522a72536380fbbb4c8fc8c8a1f066 100644 (file)
@@ -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,
index bbd3e23c3470caf4b47156e845c2837961a8ae02..e195826507f3f80fd2d84ccaa99d1a7bbd67cf1d 100644 (file)
@@ -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<string, unknown>) => void } => {
       return (
-        'configure' in obj &&
+        has('configure', obj) &&
         typeof (obj as AuthStrategy & { configure?: unknown }).configure === 'function'
       )
     }
index 7cf28b9b77042b4ada69c990d3137505f1774bbe..5374c102a4fe71b5cd20f9de58392add40ac80de 100644 (file)
@@ -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<AuthorizationResult | undefined> {
-    const timeout = config.authorizationTimeout * 1000
+    const timeout = secondsToMilliseconds(config.authorizationTimeout)
 
     try {
       const authPromise = adapter.authorizeRemote(
index 61cede25b075e0c42ab3186bb15a3a49e93aaf29..f380dbe0ca655d6de71c02cfc7702ae852f8ade1 100644 (file)
@@ -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)
 }
 
 /**