ocpp-rpc
Version:
A client & server implementation of the WAMP-like RPC-over-websocket system defined in the OCPP protocols (e.g. OCPP1.6-J and OCPP2.0.1).
83 lines (70 loc) • 2.87 kB
JavaScript
const Ajv = require('ajv');
const addFormats = require('ajv-formats');
const { createRPCError } = require('./util');
const errorCodeLUT = {
'maximum' : "FormatViolation",
'minimum' : "FormatViolation",
'maxLength' : "FormatViolation",
'minLength' : "FormatViolation",
'exclusiveMaximum' : "OccurenceConstraintViolation",
'exclusiveMinimum' : "OccurenceConstraintViolation",
'multipleOf' : "OccurenceConstraintViolation",
'maxItems' : "OccurenceConstraintViolation",
'minItems' : "OccurenceConstraintViolation",
'maxProperties' : "OccurenceConstraintViolation",
'minProperties' : "OccurenceConstraintViolation",
'additionalItems' : "OccurenceConstraintViolation",
'required' : "OccurenceConstraintViolation",
'pattern' : "PropertyConstraintViolation",
'propertyNames' : "PropertyConstraintViolation",
'additionalProperties' : "PropertyConstraintViolation",
'type' : "TypeConstraintViolation",
};
class Validator {
constructor(subprotocol, ajv) {
this._subprotocol = subprotocol;
this._ajv = ajv;
}
get subprotocol() {
return this._subprotocol;
}
validate(schemaId, params) {
const validator = this._ajv.getSchema(schemaId);
if (!validator) {
throw createRPCError("ProtocolError", `Schema '${schemaId}' is missing from subprotocol schema '${this._subprotocol}'`);
}
const res = validator(params);
if (!res && validator.errors?.length > 0) {
const [first] = validator.errors;
const rpcErrorCode = errorCodeLUT[first.keyword] ?? "FormatViolation";
throw createRPCError(rpcErrorCode, this._ajv.errorsText(validator.errors), {
errors: validator.errors,
data: params,
});
}
return res;
}
}
function createValidator(subprotocol, json) {
const ajv = new Ajv({strictSchema: false});
addFormats(ajv);
ajv.addSchema(json);
ajv.removeKeyword("multipleOf");
ajv.addKeyword({
keyword: "multipleOf",
type: "number",
compile(schema) {
return data => {
const result = data / schema;
const epsilon = 1e-6; // small value to account for floating point precision errors
return Math.abs(Math.round(result) - result) < epsilon;
};
},
errors: false,
metaSchema: {
type: "number",
},
});
return new Validator(subprotocol, ajv);
}
module.exports = {Validator, createValidator};