From b3ec7bc1553759e915e590df6a91f0849f03514d Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Sun, 17 Apr 2022 12:25:06 +0200 Subject: [PATCH] Fix OCPP message type definition and usage MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- src/charging-station/ChargingStation.ts | 203 +++++++++--------- .../ocpp/1.6/OCPP16ResponseService.ts | 2 +- .../ocpp/OCPPRequestService.ts | 27 ++- .../ocpp/OCPPResponseService.ts | 2 +- src/exception/OCPPError.ts | 4 +- src/types/ocpp/Requests.ts | 30 +-- src/types/ocpp/Responses.ts | 8 +- 7 files changed, 147 insertions(+), 129 deletions(-) diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index 1efcf5c4..d2d509f0 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -14,9 +14,11 @@ import { } from '../types/ocpp/Requests'; import { BootNotificationResponse, + ErrorResponse, HeartbeatResponse, MeterValuesResponse, RegistrationStatus, + Response, StatusNotificationResponse, } from '../types/ocpp/Responses'; import { @@ -1468,117 +1470,116 @@ export default class ChargingStation { } private async onMessage(data: Data): Promise { - let [messageType, messageId, commandName, commandPayload, errorDetails]: IncomingRequest = [ - 0, - '', - '' as IncomingRequestCommand, - {}, - {}, - ]; - let responseCallback: ( - payload: JsonType | string, - requestPayload: JsonType | OCPPError - ) => void; + let messageType: number; + let messageId: string; + let commandName: IncomingRequestCommand; + let commandPayload: JsonType; + let errorType: ErrorType; + let errorMessage: string; + let errorDetails: JsonType; + let responseCallback: (payload: JsonType, requestPayload: JsonType) => void; let rejectCallback: (error: OCPPError, requestStatistic?: boolean) => void; let requestCommandName: RequestCommand | IncomingRequestCommand; - let requestPayload: JsonType | OCPPError; + let requestPayload: JsonType; let cachedRequest: CachedRequest; let errMsg: string; try { - const request = JSON.parse(data.toString()) as IncomingRequest; + const request = JSON.parse(data.toString()) as IncomingRequest | Response | ErrorResponse; if (Utils.isIterable(request)) { - // Parse the message - [messageType, messageId, commandName, commandPayload, errorDetails] = request; + [messageType] = request; + // Check the type of message + switch (messageType) { + // Incoming Message + case MessageType.CALL_MESSAGE: + [, messageId, commandName, commandPayload] = request as IncomingRequest; + if (this.getEnableStatistics()) { + this.performanceStatistics.addRequestStatistic(commandName, messageType); + } + logger.debug( + `${this.logPrefix()} << Command '${commandName}' received request payload: ${JSON.stringify( + request + )}` + ); + // Process the message + await this.ocppIncomingRequestService.incomingRequestHandler( + messageId, + commandName, + commandPayload + ); + break; + // Outcome Message + case MessageType.CALL_RESULT_MESSAGE: + [, messageId, commandPayload] = request as Response; + // Respond + cachedRequest = this.requests.get(messageId); + if (Utils.isIterable(cachedRequest)) { + [responseCallback, , requestCommandName, requestPayload] = cachedRequest; + } else { + throw new OCPPError( + ErrorType.PROTOCOL_ERROR, + `Cached request for message id ${messageId} response is not iterable`, + requestCommandName + ); + } + logger.debug( + `${this.logPrefix()} << Command '${requestCommandName}' received response payload: ${JSON.stringify( + request + )}` + ); + if (!responseCallback) { + // Error + throw new OCPPError( + ErrorType.INTERNAL_ERROR, + `Response for unknown message id ${messageId}`, + requestCommandName + ); + } + responseCallback(commandPayload, requestPayload); + break; + // Error Message + case MessageType.CALL_ERROR_MESSAGE: + [, messageId, errorType, errorMessage, errorDetails] = request as ErrorResponse; + cachedRequest = this.requests.get(messageId); + if (Utils.isIterable(cachedRequest)) { + [, rejectCallback, requestCommandName] = cachedRequest; + } else { + throw new OCPPError( + ErrorType.PROTOCOL_ERROR, + `Cached request for message id ${messageId} error response is not iterable` + ); + } + logger.debug( + `${this.logPrefix()} << Command '${requestCommandName}' received error payload: ${JSON.stringify( + request + )}` + ); + if (!rejectCallback) { + // Error + throw new OCPPError( + ErrorType.INTERNAL_ERROR, + `Error response for unknown message id ${messageId}`, + requestCommandName + ); + } + rejectCallback( + new OCPPError(errorType, errorMessage, requestCommandName, errorDetails) + ); + break; + // Error + default: + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + errMsg = `${this.logPrefix()} Wrong message type ${messageType}`; + logger.error(errMsg); + throw new OCPPError(ErrorType.PROTOCOL_ERROR, errMsg); + } } else { throw new OCPPError( ErrorType.PROTOCOL_ERROR, 'Incoming message is not iterable', - Utils.isString(commandName) && commandName, + Utils.isString(commandName) ? commandName : requestCommandName, { payload: request } ); } - // Check the Type of message - switch (messageType) { - // Incoming Message - case MessageType.CALL_MESSAGE: - if (this.getEnableStatistics()) { - this.performanceStatistics.addRequestStatistic(commandName, messageType); - } - logger.debug( - `${this.logPrefix()} << Command '${commandName}' received request payload: ${JSON.stringify( - request - )}` - ); - // Process the call - await this.ocppIncomingRequestService.incomingRequestHandler( - messageId, - commandName, - commandPayload - ); - break; - // Outcome Message - case MessageType.CALL_RESULT_MESSAGE: - // Respond - cachedRequest = this.requests.get(messageId); - if (Utils.isIterable(cachedRequest)) { - [responseCallback, , requestCommandName, requestPayload] = cachedRequest; - } else { - throw new OCPPError( - ErrorType.PROTOCOL_ERROR, - `Cached request for message id ${messageId} response is not iterable`, - requestCommandName - ); - } - logger.debug( - `${this.logPrefix()} << Command '${requestCommandName}' received response payload: ${JSON.stringify( - request - )}` - ); - if (!responseCallback) { - // Error - throw new OCPPError( - ErrorType.INTERNAL_ERROR, - `Response for unknown message id ${messageId}`, - requestCommandName - ); - } - responseCallback(commandName, requestPayload); - break; - // Error Message - case MessageType.CALL_ERROR_MESSAGE: - cachedRequest = this.requests.get(messageId); - if (Utils.isIterable(cachedRequest)) { - [, rejectCallback, requestCommandName] = cachedRequest; - } else { - throw new OCPPError( - ErrorType.PROTOCOL_ERROR, - `Cached request for message id ${messageId} error response is not iterable` - ); - } - logger.debug( - `${this.logPrefix()} << Command '${requestCommandName}' received error payload: ${JSON.stringify( - request - )}` - ); - if (!rejectCallback) { - // Error - throw new OCPPError( - ErrorType.INTERNAL_ERROR, - `Error response for unknown message id ${messageId}`, - requestCommandName - ); - } - rejectCallback( - new OCPPError(commandName, commandPayload.toString(), requestCommandName, errorDetails) - ); - break; - // Error - default: - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - errMsg = `${this.logPrefix()} Wrong message type ${messageType}`; - logger.error(errMsg); - throw new OCPPError(ErrorType.PROTOCOL_ERROR, errMsg); - } } catch (error) { // Log logger.error( @@ -1590,7 +1591,11 @@ export default class ChargingStation { ); // Send error messageType === MessageType.CALL_MESSAGE && - (await this.ocppRequestService.sendError(messageId, error as OCPPError, commandName)); + (await this.ocppRequestService.sendError( + messageId, + error as OCPPError, + Utils.isString(commandName) ? commandName : requestCommandName + )); } } diff --git a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts index c96cea3a..f2a08a16 100644 --- a/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts +++ b/src/charging-station/ocpp/1.6/OCPP16ResponseService.ts @@ -60,7 +60,7 @@ export default class OCPP16ResponseService extends OCPPResponseService { public async responseHandler( commandName: OCPP16RequestCommand, - payload: JsonType | string, + payload: JsonType, requestPayload: JsonType ): Promise { if ( diff --git a/src/charging-station/ocpp/OCPPRequestService.ts b/src/charging-station/ocpp/OCPPRequestService.ts index ef1e4749..704838e9 100644 --- a/src/charging-station/ocpp/OCPPRequestService.ts +++ b/src/charging-station/ocpp/OCPPRequestService.ts @@ -1,5 +1,7 @@ +import { ErrorResponse, Response } from '../../types/ocpp/Responses'; import { IncomingRequestCommand, + OutgoingRequest, RequestCommand, RequestParams, ResponseType, @@ -73,7 +75,7 @@ export default abstract class OCPPRequestService { public async sendError( messageId: string, ocppError: OCPPError, - commandName: IncomingRequestCommand + commandName: RequestCommand | IncomingRequestCommand ): Promise { try { // Send error message @@ -199,7 +201,7 @@ export default abstract class OCPPRequestService { * @param requestPayload */ async function responseCallback( - payload: JsonType | string, + payload: JsonType, requestPayload: JsonType ): Promise { if (self.chargingStation.getEnableStatistics()) { @@ -271,7 +273,7 @@ export default abstract class OCPPRequestService { messagePayload: JsonType | OCPPError, messageType: MessageType, commandName?: RequestCommand | IncomingRequestCommand, - responseCallback?: (payload: JsonType | string, requestPayload: JsonType) => Promise, + responseCallback?: (payload: JsonType, requestPayload: JsonType) => Promise, rejectCallback?: (error: OCPPError, requestStatistic?: boolean) => void ): string { let messageToSend: string; @@ -284,14 +286,19 @@ export default abstract class OCPPRequestService { responseCallback, rejectCallback, commandName, - messagePayload, + messagePayload as JsonType, ]); - messageToSend = JSON.stringify([messageType, messageId, commandName, messagePayload]); + messageToSend = JSON.stringify([ + messageType, + messageId, + commandName, + messagePayload, + ] as OutgoingRequest); break; // Response case MessageType.CALL_RESULT_MESSAGE: // Build response - messageToSend = JSON.stringify([messageType, messageId, messagePayload]); + messageToSend = JSON.stringify([messageType, messageId, messagePayload] as Response); break; // Error Message case MessageType.CALL_ERROR_MESSAGE: @@ -299,10 +306,10 @@ export default abstract class OCPPRequestService { messageToSend = JSON.stringify([ messageType, messageId, - messagePayload?.code ?? ErrorType.GENERIC_ERROR, - messagePayload?.message ?? '', - messagePayload?.details ?? { commandName }, - ]); + (messagePayload as OCPPError)?.code ?? ErrorType.GENERIC_ERROR, + (messagePayload as OCPPError)?.message ?? '', + (messagePayload as OCPPError)?.details ?? { commandName }, + ] as ErrorResponse); break; } return messageToSend; diff --git a/src/charging-station/ocpp/OCPPResponseService.ts b/src/charging-station/ocpp/OCPPResponseService.ts index cfb1aa08..e838bd9f 100644 --- a/src/charging-station/ocpp/OCPPResponseService.ts +++ b/src/charging-station/ocpp/OCPPResponseService.ts @@ -26,7 +26,7 @@ export default abstract class OCPPResponseService { public abstract responseHandler( commandName: RequestCommand, - payload: JsonType | string, + payload: JsonType, requestPayload: JsonType ): Promise; } diff --git a/src/exception/OCPPError.ts b/src/exception/OCPPError.ts index 9f2b2262..e67f3c95 100644 --- a/src/exception/OCPPError.ts +++ b/src/exception/OCPPError.ts @@ -7,12 +7,12 @@ import { ErrorType } from '../types/ocpp/ErrorType'; import { JsonType } from '../types/JsonType'; export default class OCPPError extends BaseError { - code: ErrorType | IncomingRequestCommand; + code: ErrorType; command?: RequestCommand | IncomingRequestCommand; details?: JsonType; constructor( - code: ErrorType | IncomingRequestCommand, + code: ErrorType, message: string, command?: RequestCommand | IncomingRequestCommand, details?: JsonType diff --git a/src/types/ocpp/Requests.ts b/src/types/ocpp/Requests.ts index 1683654c..16a79c05 100644 --- a/src/types/ocpp/Requests.ts +++ b/src/types/ocpp/Requests.ts @@ -13,15 +13,26 @@ import { OCPP16DiagnosticsStatus } from './1.6/DiagnosticsStatus'; import { OCPP16MeterValuesRequest } from './1.6/MeterValues'; import OCPPError from '../../exception/OCPPError'; +export type OutgoingRequest = [MessageType.CALL_MESSAGE, string, RequestCommand, JsonType]; + +export type IncomingRequest = [MessageType.CALL_MESSAGE, string, IncomingRequestCommand, JsonType]; + +export type CachedRequest = [ + (payload: JsonType, requestPayload: JsonType) => void, + (error: OCPPError, requestStatistic?: boolean) => void, + RequestCommand | IncomingRequestCommand, + JsonType +]; + +export type IncomingRequestHandler = (commandPayload: JsonType) => JsonType | Promise; + +export type ResponseType = JsonType | OCPPError; + export interface RequestParams { skipBufferingOnError?: boolean; triggerMessage?: boolean; } -export type IncomingRequestHandler = (commandPayload: JsonType) => JsonType | Promise; - -export type ResponseType = JsonType | OCPPError | string; - export type BootNotificationRequest = OCPP16BootNotificationRequest; export type HeartbeatRequest = OCPP16HeartbeatRequest; @@ -53,14 +64,3 @@ export type DiagnosticsStatus = OCPP16DiagnosticsStatus; export const DiagnosticsStatus = { ...OCPP16DiagnosticsStatus, }; - -export type Request = [MessageType, string, RequestCommand, JsonType, JsonType]; - -export type IncomingRequest = [MessageType, string, IncomingRequestCommand, JsonType, JsonType]; - -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 d7e6db55..baefc637 100644 --- a/src/types/ocpp/Responses.ts +++ b/src/types/ocpp/Responses.ts @@ -11,11 +11,17 @@ import { OCPP16UnlockStatus, } from './1.6/Responses'; +import { ErrorType } from './ErrorType'; import { JsonType } from '../JsonType'; +import { MessageType } from './MessageType'; import { OCPP16MeterValuesResponse } from './1.6/MeterValues'; +export type Response = [MessageType.CALL_RESULT_MESSAGE, string, JsonType]; + +export type ErrorResponse = [MessageType.CALL_ERROR_MESSAGE, string, ErrorType, string, JsonType]; + export type ResponseHandler = ( - payload: JsonType | string, + payload: JsonType, requestPayload?: JsonType ) => void | Promise; -- 2.34.1