UNPKG

@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
// 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