@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.
189 lines • 7.78 kB
JavaScript
"use strict";
// Copyright (c) 2023 S44, LLC
// Copyright Contributors to the CitrineOS Project
//
// SPDX-License-Identifier: Apache 2.0
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AbstractMessageRouter = void 0;
const ajv_1 = require("ajv");
const __1 = require("../..");
const tslog_1 = require("tslog");
class AbstractMessageRouter {
/**
* Constructor of abstract ocpp router.
*
* @param {Ajv} ajv - The Ajv instance to use for schema validation.
*/
constructor(config, cache, handler, sender, networkHook, logger, ajv) {
this._config = config;
this._cache = cache;
this._handler = handler;
this._sender = sender;
this._networkHook = networkHook;
this._ajv =
ajv ||
new ajv_1.Ajv({
removeAdditional: 'all',
useDefaults: true,
coerceTypes: 'array',
strict: false,
});
this._logger = logger
? logger.getSubLogger({ name: this.constructor.name })
: new tslog_1.Logger({ name: this.constructor.name });
// Set module for proper message flow.
this._handler.module = this;
}
/**
* Getters & Setters
*/
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
*/
handle(message) {
return __awaiter(this, void 0, void 0, function* () {
this._logger.debug('Received message:', message);
if (message.state === __1.MessageState.Response) {
if (message.payload instanceof __1.OcppError) {
yield this.sendCallError(message.context.correlationId, message.context.stationId, message.context.tenantId, message.protocol, message.action, message.payload, message.origin);
}
else {
yield this.sendCallResult(message.context.correlationId, message.context.stationId, message.context.tenantId, message.protocol, message.action, message.payload, message.origin);
}
}
else if (message.state === __1.MessageState.Request) {
yield this.sendCall(message.context.stationId, message.context.tenantId, message.protocol, message.action, message.payload, message.context.correlationId, message.origin);
}
});
}
/**
* 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 schema;
switch (protocol) {
case __1.OCPPVersion.OCPP1_6:
schema = __1.OCPP1_6_CALL_SCHEMA_MAP.get(action);
break;
case __1.OCPPVersion.OCPP2_0_1:
schema = __1.OCPP2_0_1_CALL_SCHEMA_MAP.get(action);
break;
default:
this._logger.error('Unknown subprotocol', protocol);
return { isValid: false };
}
if (schema) {
let validate = this._ajv.getSchema(schema['$id']);
if (!validate) {
schema['$id'] = `${protocol}-${schema['$id']}`;
this._logger.debug(`Updated call result schema id: ${schema['$id']}`);
validate = this._ajv.compile(schema);
}
const result = validate(payload);
if (!result) {
const validationErrorsDeepCopy = JSON.parse(JSON.stringify(validate.errors));
this._logger.debug('Validate CallResult failed', validationErrorsDeepCopy);
return { isValid: false, errors: validationErrorsDeepCopy };
}
else {
return { isValid: true };
}
}
else {
this._logger.error('No schema found for action', action, message);
return { isValid: false }; // TODO: Implement config for this behavior
}
}
/**
* 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 schema;
switch (protocol) {
case __1.OCPPVersion.OCPP1_6:
schema = __1.OCPP1_6_CALL_RESULT_SCHEMA_MAP.get(action);
break;
case __1.OCPPVersion.OCPP2_0_1:
schema = __1.OCPP2_0_1_CALL_RESULT_SCHEMA_MAP.get(action);
break;
default:
this._logger.error('Unknown subprotocol', protocol);
return { isValid: false };
}
if (schema) {
let validate = this._ajv.getSchema(schema['$id']);
if (!validate) {
schema['$id'] = `${protocol}-${schema['$id']}`;
this._logger.debug(`Updated call result schema id: ${schema['$id']}`);
validate = this._ajv.compile(schema);
}
const result = validate(payload);
if (!result) {
const validationErrorsDeepCopy = JSON.parse(JSON.stringify(validate.errors));
this._logger.debug('Validate CallResult failed', validationErrorsDeepCopy);
return { isValid: false, errors: validationErrorsDeepCopy };
}
else {
return { isValid: true };
}
}
else {
this._logger.error('No schema found for call result with action', action, message);
return { isValid: false }; // TODO: Implement config for this behavior
}
}
}
exports.AbstractMessageRouter = AbstractMessageRouter;
//# sourceMappingURL=AbstractRouter.js.map