@citrineos/base
Version:
The base module for OCPP v2.0.1 including all interfaces. This module is not intended to be used directly, but rather as a dependency for other modules.
168 lines • 6.82 kB
JavaScript
// SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
//
// SPDX-License-Identifier: Apache-2.0
import { Logger } from 'tslog';
import { ErrorCode, OcppError, OCPPVersion } from '../../ocpp/rpc/message.js';
import { MessageOrigin, MessageState } from '../messages/internal-types.js';
import { OCPPValidator } from '../modules/OCPPValidator.js';
export class AbstractMessageRouter {
/**
* Fields
*/
_ocppValidator;
_cache;
_config;
_logger;
_handler;
_sender;
_networkHook;
/**
* Constructor of abstract ocpp router.
*
* @param {OCPPValidator} ocppValidator - The OCPPValidator instance to use for message validation.
*/
constructor(config, cache, handler, sender, networkHook, logger, ocppValidator) {
this._config = config;
this._cache = cache;
this._handler = handler;
this._sender = sender;
this._networkHook = networkHook;
this._ocppValidator = ocppValidator ? ocppValidator : new OCPPValidator(logger);
this._logger = logger
? logger.getSubLogger({ name: this.constructor.name })
: new Logger({ name: this.constructor.name });
// Set module for proper message flow.
this._handler.module = this;
}
/**
* Getters & Setters
*/
get ocppValidator() {
return this._ocppValidator;
}
get cache() {
return this._cache;
}
get sender() {
return this._sender;
}
get handler() {
return this._handler;
}
get config() {
return this._config;
}
set networkHook(value) {
this._networkHook = value;
}
/**
* Sets the system configuration for the module.
*
* @param {SystemConfig} config - The new configuration to set.
*/
set config(config) {
this._config = config;
// Update all necessary settings for hot reload
this._logger.info('Updating system configuration for ocpp router...');
this._logger.settings.minLevel = this._config.logLevel;
}
/**
* Public Methods
*/
async handle(message) {
message.payload = this._ocppValidator.sanitizeOCPPPayload(message.payload);
switch (message.state) {
case MessageState.Request: {
const { isValid, errors } = this._ocppValidator.validateOCPPRequest(message.action, message.payload, message.protocol);
if (!isValid || errors) {
throw new OcppError(message.context.correlationId, ErrorCode.FormatViolation, 'Invalid message format', {
errors: errors,
});
}
await this.sendCall(message.context.ocppConnectionName, message.context.tenantId, message.protocol, message.action, message.payload, message.context.correlationId, message.origin);
break;
}
case MessageState.Response: {
const { isValid, errors } = this._ocppValidator.validateOCPPResponse(message.action, message.payload, message.protocol);
if (!isValid || errors) {
throw new OcppError(message.context.correlationId, ErrorCode.FormatViolation, 'Invalid message format', {
errors: errors,
});
}
if (message.payload && message.payload._errorCode) {
// Create OcppError from payload properties for sendCallError method
const errorPayload = message.payload;
const ocppError = new OcppError(errorPayload._messageId, errorPayload._errorCode, errorPayload.message || '', errorPayload._errorDetails || {});
await this.sendCallError(message.context.correlationId, message.context.ocppConnectionName, message.context.tenantId, message.protocol, message.action, ocppError, message.origin);
}
else {
await this.sendCallResult(message.context.correlationId, message.context.ocppConnectionName, message.context.tenantId, message.protocol, message.action, message.payload, message.origin);
}
break;
}
default:
this._logger.error('Unknown message state', message);
throw new Error('Unknown message state: ' + message.state);
}
}
/**
* Protected Methods
*/
/**
* Validates a Call object against its schema.
*
* @param {string} identifier - The identifier of the EVSE.
* @param {Call} message - The Call object to validate.
* @param {string} protocol - The subprotocol of the Websocket, i.e. "ocpp1.6" or "ocpp2.0.1".
* @return {boolean} - Returns true if the Call object is valid, false otherwise.
*/
_validateCall(identifier, message, protocol) {
const action = message[2];
const payload = message[3];
let protocolEnum;
switch (protocol) {
case OCPPVersion.OCPP1_6:
protocolEnum = OCPPVersion.OCPP1_6;
break;
case OCPPVersion.OCPP2_0_1:
protocolEnum = OCPPVersion.OCPP2_0_1;
break;
case OCPPVersion.OCPP2_1:
protocolEnum = OCPPVersion.OCPP2_1;
break;
default:
this._logger.error('Unknown subprotocol', protocol);
return { isValid: false };
}
return this._ocppValidator.validateOCPPRequest(action, payload, protocolEnum);
}
/**
* Validates a CallResult object against its schema.
*
* @param {string} identifier - The identifier of the EVSE.
* @param {CallAction} action - The original CallAction.
* @param {CallResult} message - The CallResult object to validate.
* @param {string} protocol - The protocol of the Websocket.
* @return {boolean} - Returns true if the CallResult object is valid, false otherwise.
*/
_validateCallResult(identifier, action, message, protocol) {
const payload = message[2];
let protocolEnum;
switch (protocol) {
case OCPPVersion.OCPP1_6:
protocolEnum = OCPPVersion.OCPP1_6;
break;
case OCPPVersion.OCPP2_0_1:
protocolEnum = OCPPVersion.OCPP2_0_1;
break;
case OCPPVersion.OCPP2_1:
protocolEnum = OCPPVersion.OCPP2_1;
break;
default:
this._logger.error('Unknown subprotocol', protocol);
return { isValid: false };
}
return this._ocppValidator.validateOCPPResponse(action, payload, protocolEnum);
}
}
//# sourceMappingURL=AbstractRouter.js.map