From: Jérôme Benoit Date: Sun, 6 Feb 2022 09:24:47 +0000 (+0100) Subject: Strong type protocols payloads X-Git-Tag: v1.1.45~6 X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=d18886407cdb8b8148c87492f2c953075e708401;p=e-mobility-charging-stations-simulator.git Strong type protocols payloads And fix related bugs Signed-off-by: Jérôme Benoit --- diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 6be15b83..99e8f5ee 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -20,6 +20,7 @@ import { ConnectorStatus } from '../types/ConnectorStatus'; import Constants from '../utils/Constants'; import { ErrorType } from '../types/ocpp/ErrorType'; import FileUtils from '../utils/FileUtils'; +import { JsonType } from '../types/JsonType'; import { MessageType } from '../types/ocpp/MessageType'; import OCPP16IncomingRequestService from './ocpp/1.6/OCPP16IncomingRequestService'; import OCPP16RequestService from './ocpp/1.6/OCPP16RequestService'; @@ -697,10 +698,10 @@ export default class ChargingStation { private async onMessage(data: Data): Promise { let [messageType, messageId, commandName, commandPayload, errorDetails]: IncomingRequest = [0, '', '' as IncomingRequestCommand, {}, {}]; - let responseCallback: (payload: Record | string, requestPayload: Record) => void; + let responseCallback: (payload: JsonType | string, requestPayload: JsonType | OCPPError) => void; let rejectCallback: (error: OCPPError, requestStatistic?: boolean) => void; let requestCommandName: RequestCommand | IncomingRequestCommand; - let requestPayload: Record; + let requestPayload: JsonType | OCPPError; let cachedRequest: CachedRequest; let errMsg: string; try { diff --git a/src/charging-station/UIWebSocketServer.ts b/src/charging-station/UIWebSocketServer.ts index dba59e92..083f95bc 100644 --- a/src/charging-station/UIWebSocketServer.ts +++ b/src/charging-station/UIWebSocketServer.ts @@ -5,6 +5,7 @@ import AbstractUIService from './ui-websocket-services/AbstractUIService'; import BaseError from '../exception/BaseError'; import Configuration from '../utils/Configuration'; import { IncomingMessage } from 'http'; +import { JsonType } from '../types/JsonType'; import UIServiceFactory from './ui-websocket-services/UIServiceFactory'; import Utils from '../utils/Utils'; import logger from '../utils/Logger'; @@ -23,7 +24,7 @@ export default class UIWebSocketServer extends Server { } } - public broadcastToClients(message: string | Record): void { + public broadcastToClients(message: string): void { for (const client of this.clients) { if (client?.readyState === OPEN) { client.send(message); diff --git a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts index 77bf637f..4988a9ef 100644 --- a/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts @@ -11,6 +11,7 @@ import Constants from '../../../utils/Constants'; import { DefaultResponse } from '../../../types/ocpp/Responses'; import { ErrorType } from '../../../types/ocpp/ErrorType'; import { IncomingRequestHandler } from '../../../types/ocpp/Requests'; +import { JsonType } from '../../../types/JsonType'; import { OCPP16ChargePointStatus } from '../../../types/ocpp/1.6/ChargePointStatus'; import { OCPP16DiagnosticsStatus } from '../../../types/ocpp/1.6/DiagnosticsStatus'; import { OCPP16StandardParametersKey } from '../../../types/ocpp/1.6/Configuration'; @@ -45,8 +46,8 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer ]); } - public async handleRequest(messageId: string, commandName: OCPP16IncomingRequestCommand, commandPayload: Record): Promise { - let result: Record; + public async handleRequest(messageId: string, commandName: OCPP16IncomingRequestCommand, commandPayload: JsonType): Promise { + let result: JsonType; if (this.chargingStation.isInPendingState() && (commandName === OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION || commandName === OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION)) { throw new OCPPError(ErrorType.SECURITY_ERROR, `${commandName} cannot be issued to handle request payload ${JSON.stringify(commandPayload, null, 2)} while charging station is in pending state`, commandName); @@ -433,7 +434,10 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer setTimeout(() => { this.chargingStation.ocppRequestService.sendBootNotification(this.chargingStation.getBootNotificationRequest().chargePointModel, this.chargingStation.getBootNotificationRequest().chargePointVendor, this.chargingStation.getBootNotificationRequest().chargeBoxSerialNumber, - this.chargingStation.getBootNotificationRequest().firmwareVersion, null, null, null, null, null, { triggerMessage: true }).catch(() => { /* This is intentional */ }); + this.chargingStation.getBootNotificationRequest().firmwareVersion, this.chargingStation.getBootNotificationRequest().chargePointSerialNumber, + this.chargingStation.getBootNotificationRequest().iccid, this.chargingStation.getBootNotificationRequest().imsi, + this.chargingStation.getBootNotificationRequest().meterSerialNumber, this.chargingStation.getBootNotificationRequest().meterType, + { triggerMessage: true }).catch(() => { /* This is intentional */ }); }, Constants.OCPP_TRIGGER_MESSAGE_DELAY); return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED; case MessageTrigger.Heartbeat: diff --git a/src/charging-station/ocpp/1.6/OCPP16RequestService.ts b/src/charging-station/ocpp/1.6/OCPP16RequestService.ts index 6ae6cf32..1fc89fa8 100644 --- a/src/charging-station/ocpp/1.6/OCPP16RequestService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16RequestService.ts @@ -8,6 +8,7 @@ import { MeterValueUnit, MeterValuesRequest, OCPP16MeterValue, OCPP16MeterValueM import Constants from '../../../utils/Constants'; import { ErrorType } from '../../../types/ocpp/ErrorType'; +import { JsonType } from '../../../types/JsonType'; import MeasurandPerPhaseSampledValueTemplates from '../../../types/MeasurandPerPhaseSampledValueTemplates'; import MeasurandValues from '../../../types/MeasurandValues'; import { MessageType } from '../../../types/ocpp/MessageType'; @@ -381,21 +382,21 @@ export default class OCPP16RequestService extends OCPPRequestService { } } - public async sendResult(messageId: string, resultMessageData: Record, commandName: OCPP16RequestCommand | OCPP16IncomingRequestCommand): Promise { + public async sendResult(messageId: string, resultMessageData: JsonType, commandName: OCPP16RequestCommand | OCPP16IncomingRequestCommand): Promise { try { // Send error - return await this.sendMessage(messageId, resultMessageData, MessageType.CALL_RESULT_MESSAGE, commandName); - } catch (err) { - this.handleRequestError(commandName as OCPP16RequestCommand, err as Error); + return await this.sendMessage(messageId, resultMessageData, MessageType.CALL_RESULT_MESSAGE, commandName) as JsonType; + } catch (error) { + this.handleRequestError(commandName as OCPP16RequestCommand, error as Error); } } - public async sendError(messageId: string, error: OCPPError, commandName: OCPP16RequestCommand | OCPP16IncomingRequestCommand): Promise { + public async sendError(messageId: string, ocppError: OCPPError, commandName: OCPP16RequestCommand | OCPP16IncomingRequestCommand): Promise { try { // Send error - return await this.sendMessage(messageId, error, MessageType.CALL_ERROR_MESSAGE, commandName); - } catch (err) { - this.handleRequestError(commandName as OCPP16RequestCommand, err as Error); + return await this.sendMessage(messageId, ocppError, MessageType.CALL_ERROR_MESSAGE, commandName) as JsonType; + } catch (error) { + this.handleRequestError(commandName as OCPP16RequestCommand, error as Error); } } } diff --git a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts index 5b6a3fec..05e2ed9a 100644 --- a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts @@ -7,6 +7,7 @@ import { MeterValuesRequest, MeterValuesResponse } from '../../../types/ocpp/1.6 import ChargingStation from '../../ChargingStation'; import { ErrorType } from '../../../types/ocpp/ErrorType'; +import { JsonType } from '../../../types/JsonType'; import { OCPP16ChargePointStatus } from '../../../types/ocpp/1.6/ChargePointStatus'; import { OCPP16ServiceUtils } from './OCPP16ServiceUtils'; import { OCPP16StandardParametersKey } from '../../../types/ocpp/1.6/Configuration'; @@ -32,7 +33,7 @@ export default class OCPP16ResponseService extends OCPPResponseService { ]); } - public async handleResponse(commandName: OCPP16RequestCommand, payload: Record | string, requestPayload: Record): Promise { + public async handleResponse(commandName: OCPP16RequestCommand, payload: JsonType | string, requestPayload: JsonType): Promise { if (this.chargingStation.isRegistered() || commandName === OCPP16RequestCommand.BOOT_NOTIFICATION) { if (this.responseHandlers.has(commandName)) { try { diff --git a/src/charging-station/ocpp/OCPPIncomingRequestService.ts b/src/charging-station/ocpp/OCPPIncomingRequestService.ts index dcef4028..e815fe29 100644 --- a/src/charging-station/ocpp/OCPPIncomingRequestService.ts +++ b/src/charging-station/ocpp/OCPPIncomingRequestService.ts @@ -1,5 +1,6 @@ import ChargingStation from '../ChargingStation'; import { IncomingRequestCommand } from '../../types/ocpp/Requests'; +import { JsonType } from '../../types/JsonType'; import logger from '../../utils/Logger'; export default abstract class OCPPIncomingRequestService { @@ -17,5 +18,5 @@ export default abstract class OCPPIncomingRequestService { throw error; } - public abstract handleRequest(messageId: string, commandName: IncomingRequestCommand, commandPayload: Record): Promise; + public abstract handleRequest(messageId: string, commandName: IncomingRequestCommand, commandPayload: JsonType): Promise; } diff --git a/src/charging-station/ocpp/OCPPRequestService.ts b/src/charging-station/ocpp/OCPPRequestService.ts index e459bc07..14cab283 100644 --- a/src/charging-station/ocpp/OCPPRequestService.ts +++ b/src/charging-station/ocpp/OCPPRequestService.ts @@ -7,6 +7,7 @@ import { ChargePointStatus } from '../../types/ocpp/ChargePointStatus'; import ChargingStation from '../ChargingStation'; import Constants from '../../utils/Constants'; import { ErrorType } from '../../types/ocpp/ErrorType'; +import { JsonType } from '../../types/JsonType'; import { MessageType } from '../../types/ocpp/MessageType'; import { MeterValue } from '../../types/ocpp/MeterValues'; import OCPPError from '../../exception/OCPPError'; @@ -24,11 +25,11 @@ export default abstract class OCPPRequestService { this.ocppResponseService = ocppResponseService; } - public async sendMessage(messageId: string, messageData: any, messageType: MessageType, commandName: RequestCommand | IncomingRequestCommand, + public async sendMessage(messageId: string, messageData: JsonType | OCPPError, messageType: MessageType, commandName: RequestCommand | IncomingRequestCommand, params: SendParams = { skipBufferingOnError: false, triggerMessage: false - }): Promise { + }): Promise { if (this.chargingStation.isInRejectedState() || (this.chargingStation.isInPendingState() && !params.triggerMessage)) { throw new OCPPError(ErrorType.SECURITY_ERROR, 'Cannot send command payload if the charging station is not in accepted state', commandName); } else if (this.chargingStation.isInAcceptedState() || (this.chargingStation.isInPendingState() && params.triggerMessage)) { @@ -50,7 +51,7 @@ export default abstract class OCPPRequestService { } else if (!params.skipBufferingOnError) { // Buffer it this.chargingStation.bufferMessage(messageToSend); - const ocppError = new OCPPError(ErrorType.GENERIC_ERROR, `WebSocket closed for buffered message id '${messageId}' with content '${messageToSend}'`, messageData?.details ?? {}); + const ocppError = new OCPPError(ErrorType.GENERIC_ERROR, `WebSocket closed for buffered message id '${messageId}' with content '${messageToSend}'`, commandName, messageData?.details as JsonType ?? {}); if (messageType === MessageType.CALL_MESSAGE) { // Reject it but keep the request in the cache return reject(ocppError); @@ -58,7 +59,7 @@ export default abstract class OCPPRequestService { return rejectCallback(ocppError, false); } else { // Reject it - return rejectCallback(new OCPPError(ErrorType.GENERIC_ERROR, `WebSocket closed for non buffered message id '${messageId}' with content '${messageToSend}'`, messageData?.details ?? {}), false); + return rejectCallback(new OCPPError(ErrorType.GENERIC_ERROR, `WebSocket closed for non buffered message id '${messageId}' with content '${messageToSend}'`, commandName, messageData?.details as JsonType ?? {}), false); } // Response? if (messageType !== MessageType.CALL_MESSAGE) { @@ -72,7 +73,7 @@ export default abstract class OCPPRequestService { * @param payload * @param requestPayload */ - async function responseCallback(payload: Record | string, requestPayload: Record): Promise { + async function responseCallback(payload: JsonType | string, requestPayload: JsonType): Promise { if (self.chargingStation.getEnableStatistics()) { self.chargingStation.performanceStatistics.addRequestStatistic(commandName, MessageType.CALL_RESULT_MESSAGE); } @@ -102,7 +103,7 @@ export default abstract class OCPPRequestService { self.chargingStation.requests.delete(messageId); reject(error); } - }), Constants.OCPP_WEBSOCKET_TIMEOUT, new OCPPError(ErrorType.GENERIC_ERROR, `Timeout for message id '${messageId}'`, messageData?.details ?? {}), () => { + }), Constants.OCPP_WEBSOCKET_TIMEOUT, new OCPPError(ErrorType.GENERIC_ERROR, `Timeout for message id '${messageId}'`, commandName, messageData?.details as JsonType ?? {}), () => { messageType === MessageType.CALL_MESSAGE && this.chargingStation.requests.delete(messageId); }); } else { @@ -115,8 +116,8 @@ export default abstract class OCPPRequestService { throw error; } - private buildMessageToSend(messageId: string, messageData: Record, messageType: MessageType, commandName: RequestCommand | IncomingRequestCommand, - responseCallback: (payload: Record | string, requestPayload: Record) => Promise, + private buildMessageToSend(messageId: string, messageData: JsonType | OCPPError, messageType: MessageType, commandName: RequestCommand | IncomingRequestCommand, + responseCallback: (payload: JsonType | string, requestPayload: JsonType) => Promise, rejectCallback: (error: OCPPError, requestStatistic?: boolean) => void): string { let messageToSend: string; // Type of message @@ -151,6 +152,6 @@ export default abstract class OCPPRequestService { public abstract sendTransactionBeginMeterValues(connectorId: number, transactionId: number, beginMeterValue: MeterValue): Promise; public abstract sendTransactionEndMeterValues(connectorId: number, transactionId: number, endMeterValue: MeterValue): Promise; public abstract sendDiagnosticsStatusNotification(diagnosticsStatus: DiagnosticsStatus): Promise; - public abstract sendResult(messageId: string, resultMessageData: Record, commandName: RequestCommand | IncomingRequestCommand): Promise; - public abstract sendError(messageId: string, error: OCPPError, commandName: RequestCommand | IncomingRequestCommand): Promise; + public abstract sendResult(messageId: string, resultMessageData: JsonType, commandName: RequestCommand | IncomingRequestCommand): Promise; + public abstract sendError(messageId: string, error: OCPPError, commandName: RequestCommand | IncomingRequestCommand): Promise; } diff --git a/src/charging-station/ocpp/OCPPResponseService.ts b/src/charging-station/ocpp/OCPPResponseService.ts index 0a1cd0c6..17bf8065 100644 --- a/src/charging-station/ocpp/OCPPResponseService.ts +++ b/src/charging-station/ocpp/OCPPResponseService.ts @@ -1,4 +1,5 @@ import ChargingStation from '../ChargingStation'; +import { JsonType } from '../../types/JsonType'; import { RequestCommand } from '../../types/ocpp/Requests'; export default abstract class OCPPResponseService { @@ -8,5 +9,5 @@ export default abstract class OCPPResponseService { this.chargingStation = chargingStation; } - public abstract handleResponse(commandName: RequestCommand, payload: Record | string, requestPayload: Record): Promise; + public abstract handleResponse(commandName: RequestCommand, payload: JsonType | string, requestPayload: JsonType): Promise; } diff --git a/src/charging-station/ui-websocket-services/AbstractUIService.ts b/src/charging-station/ui-websocket-services/AbstractUIService.ts index 130c8a5a..2dd6a200 100644 --- a/src/charging-station/ui-websocket-services/AbstractUIService.ts +++ b/src/charging-station/ui-websocket-services/AbstractUIService.ts @@ -1,6 +1,7 @@ import { ProtocolCommand, ProtocolRequestHandler } from '../../types/UIProtocol'; import BaseError from '../../exception/BaseError'; +import { JsonType } from '../../types/JsonType'; import UIWebSocketServer from '../UIWebSocketServer'; import logger from '../../utils/Logger'; @@ -15,12 +16,12 @@ export default abstract class AbstractUIService { ]); } - public async handleMessage(command: ProtocolCommand, payload: Record): Promise { - let messageResponse: Record; + public async handleMessage(command: ProtocolCommand, payload: JsonType): Promise { + let messageResponse: JsonType; if (this.messageHandlers.has(command)) { try { // Call the method to build the message response - messageResponse = await this.messageHandlers.get(command)(payload) as Record; + messageResponse = await this.messageHandlers.get(command)(payload) as JsonType; } catch (error) { // Log logger.error(this.uiWebSocketServer.logPrefix() + ' Handle message error: %j', error); @@ -36,7 +37,7 @@ export default abstract class AbstractUIService { protected buildProtocolMessage( command: ProtocolCommand, - payload: Record, + payload: JsonType, ): string { return JSON.stringify([command, payload]); } diff --git a/src/charging-station/ui-websocket-services/UIService001.ts b/src/charging-station/ui-websocket-services/UIService001.ts index 3270aaf3..a9bc401c 100644 --- a/src/charging-station/ui-websocket-services/UIService001.ts +++ b/src/charging-station/ui-websocket-services/UIService001.ts @@ -1,6 +1,7 @@ import { ProtocolCommand, ProtocolRequestHandler } from '../../types/UIProtocol'; import AbstractUIService from './AbstractUIService'; +import { JsonType } from '../../types/JsonType'; import UIWebSocketServer from '../UIWebSocketServer'; export default class UIService001 extends AbstractUIService { @@ -10,6 +11,6 @@ export default class UIService001 extends AbstractUIService { this.messageHandlers.set(ProtocolCommand.STOP_TRANSACTION, this.handleStopTransaction.bind(this) as ProtocolRequestHandler); } - private handleStartTransaction(payload: Record): void { } - private handleStopTransaction(payload: Record): void { } + private handleStartTransaction(payload: JsonType): void { } + private handleStopTransaction(payload: JsonType): void { } } diff --git a/src/exception/OCPPError.ts b/src/exception/OCPPError.ts index cfcc4f40..8b108aec 100644 --- a/src/exception/OCPPError.ts +++ b/src/exception/OCPPError.ts @@ -4,13 +4,14 @@ import { IncomingRequestCommand, RequestCommand } from '../types/ocpp/Requests'; import BaseError from './BaseError'; import { ErrorType } from '../types/ocpp/ErrorType'; +import { JsonType } from '../types/JsonType'; export default class OCPPError extends BaseError { code: ErrorType | IncomingRequestCommand; command?: RequestCommand | IncomingRequestCommand; - details?: Record; + details?: JsonType; - constructor(code: ErrorType | IncomingRequestCommand, message: string, command?: RequestCommand | IncomingRequestCommand, details?: Record) { + constructor(code: ErrorType | IncomingRequestCommand, message: string, command?: RequestCommand | IncomingRequestCommand, details?: JsonType) { super(message); this.code = code ?? ErrorType.GENERIC_ERROR; diff --git a/src/types/UIProtocol.ts b/src/types/UIProtocol.ts index 05ddaa23..ea01b4fc 100644 --- a/src/types/UIProtocol.ts +++ b/src/types/UIProtocol.ts @@ -1,3 +1,5 @@ +import { JsonType } from './JsonType'; + export enum Protocol { UI = 'ui', } @@ -13,6 +15,6 @@ export enum ProtocolCommand { UNKNOWN = 'unknown', } -export type ProtocolRequest = [ProtocolCommand, Record]; +export type ProtocolRequest = [ProtocolCommand, JsonType]; -export type ProtocolRequestHandler = (payload: Record) => void | Promise | Record | Promise>; +export type ProtocolRequestHandler = (payload: JsonType) => void | Promise | JsonType | Promise; diff --git a/src/types/ocpp/Requests.ts b/src/types/ocpp/Requests.ts index 7f295584..fcd39a01 100644 --- a/src/types/ocpp/Requests.ts +++ b/src/types/ocpp/Requests.ts @@ -1,5 +1,6 @@ import { OCPP16AvailabilityType, OCPP16BootNotificationRequest, OCPP16IncomingRequestCommand, OCPP16RequestCommand } from './1.6/Requests'; +import { JsonType } from '../JsonType'; import { MessageType } from './MessageType'; import { OCPP16DiagnosticsStatus } from './1.6/DiagnosticsStatus'; import OCPPError from '../../exception/OCPPError'; @@ -9,7 +10,7 @@ export interface SendParams { triggerMessage?: boolean } -export type IncomingRequestHandler = (commandPayload: Record) => Record | Promise>; +export type IncomingRequestHandler = (commandPayload: JsonType) => JsonType | Promise; export type BootNotificationRequest = OCPP16BootNotificationRequest; @@ -37,8 +38,8 @@ export const DiagnosticsStatus = { ...OCPP16DiagnosticsStatus }; -export type Request = [MessageType, string, RequestCommand, Record, Record]; +export type Request = [MessageType, string, RequestCommand, JsonType, JsonType]; -export type IncomingRequest = [MessageType, string, IncomingRequestCommand, Record, Record]; +export type IncomingRequest = [MessageType, string, IncomingRequestCommand, JsonType, JsonType]; -export type CachedRequest = [(payload: Record | string, requestPayload: Record) => void, (error: OCPPError, requestStatistic?: boolean) => void, RequestCommand | IncomingRequestCommand, Record]; +export type CachedRequest = [(payload: JsonType, requestPayload: JsonType) => void, (error: OCPPError, requestStatistic?: boolean) => void, RequestCommand | IncomingRequestCommand, JsonType | OCPPError]; diff --git a/src/types/ocpp/Responses.ts b/src/types/ocpp/Responses.ts index 7a851170..21ddd903 100644 --- a/src/types/ocpp/Responses.ts +++ b/src/types/ocpp/Responses.ts @@ -1,6 +1,8 @@ import { OCPP16AvailabilityStatus, OCPP16BootNotificationResponse, OCPP16ChargingProfileStatus, OCPP16ClearChargingProfileStatus, OCPP16ConfigurationStatus, OCPP16RegistrationStatus, OCPP16TriggerMessageStatus, OCPP16UnlockStatus } from './1.6/Responses'; -export type ResponseHandler = (payload: Record | string, requestPayload?: Record) => void | Promise; +import { JsonType } from '../JsonType'; + +export type ResponseHandler = (payload: JsonType | string, requestPayload?: JsonType) => void | Promise; export type BootNotificationResponse = OCPP16BootNotificationResponse;