@isaac-platform/isaac-node-red
Version:
Set of Node-RED nodes to communicate with an ISAAC system
179 lines (178 loc) • 7.09 kB
JavaScript
const axios = require("axios"), utils = require("../../utils.js");
async function getAllVariables(server) {
if (!server.subsystemExternalId)
throw new Error("subsystemExternalId must be specified in the configuration node");
const response = await axios.get(
`${utils.getApiUrl(server)}/variables?subsystemExternalId=${server.subsystemExternalId}`
);
return {
payload: response.data,
statusCode: response.status
};
}
async function getVariable(server, mergedConfig) {
if (!mergedConfig.externalRef)
throw new Error("externalRef must be specified");
if (!server.subsystemExternalId)
throw new Error("subsystemExternalId must be specified in the configuration node");
const response = await axios.get(
`${utils.getApiUrl(server)}/variables?subsystemExternalId=${server.subsystemExternalId}&externalRef=${mergedConfig.externalRef}`
), variable = Array.isArray(response.data) && response.data.length && response.data[0];
if (variable)
return {
payload: variable,
statusCode: response.status
};
throw new Error(`Could not find variable by externalRef "${mergedConfig.externalRef}"`);
}
function getValueFromConfig(mergedConfig) {
return mergedConfig.payload !== "undefined" && mergedConfig.payload !== void 0 ? mergedConfig.payload : mergedConfig.value;
}
function stringifyValue(value) {
return value == null ? "" : typeof value == "string" ? value : JSON.stringify(value);
}
async function upsertVariable(server, mergedConfig) {
if (!server.subsystemExternalId)
throw new Error("subsystemExternalId must be specified in the configuration node");
if (!mergedConfig.externalRef)
throw new Error("externalRef must be specified");
let existingVariable;
try {
({ payload: existingVariable } = await getVariable(server, mergedConfig));
} catch {
}
let healthGracePeriod;
if (mergedConfig.healthGracePeriod) {
const parsedHealthGracePeriod = parseInt(mergedConfig.healthGracePeriod, 10);
Number.isNaN(parsedHealthGracePeriod) || (healthGracePeriod = parsedHealthGracePeriod);
}
let { healthRules } = mergedConfig;
if (healthRules && !Array.isArray(healthRules)) {
try {
healthRules = JSON.parse(healthRules);
} catch (e) {
throw new Error(`Error parsing healthRules: ${e.message}`);
}
if (!Array.isArray(healthRules))
throw new Error(`healthRules should be an array but is of type: ${typeof healthRules}`);
}
let { compositeDefinition } = mergedConfig;
if (compositeDefinition && !Array.isArray(compositeDefinition)) {
try {
compositeDefinition = JSON.parse(compositeDefinition);
} catch (e) {
throw new Error(`Error parsing compositeDefinition: ${e.message}`);
}
if (!Array.isArray(compositeDefinition))
throw new Error(`compositeDefinition should be an array but is of type: ${typeof compositeDefinition}`);
}
const commonPayload = {
subsystemExternalId: server.subsystemExternalId,
externalRef: mergedConfig.externalRef,
displayName: mergedConfig.displayName,
description: mergedConfig.description,
log: mergedConfig.log,
storeHistory: mergedConfig.storeHistory,
healthEnabled: mergedConfig.healthEnabled,
healthGracePeriod,
healthRules,
composite: mergedConfig.composite,
compositeDefinition,
tags: utils.parseStringArray(mergedConfig.tags)
}, value = getValueFromConfig(mergedConfig);
if (existingVariable) {
const payload2 = {
...existingVariable,
...commonPayload
};
mergedConfig.healthEnabled || (payload2.healthRules = existingVariable.healthRules, payload2.healthGracePeriod = existingVariable.healthGracePeriod), mergedConfig.composite || (payload2.compositeDefinition = existingVariable.compositeDefinition);
let response2 = await axios.put(`${utils.getApiUrl(server)}/variables/${existingVariable._id}`, payload2);
if (value !== void 0 && value !== "") {
const url = `${utils.getApiUrl(server)}/variables/${existingVariable._id}/value`, strValue = stringifyValue(value);
response2 = await axios.post(url, { value: strValue });
}
return {
payload: response2.data,
statusCode: response2.status
};
}
const payload = {
...commonPayload,
lastValue: stringifyValue(value)
}, response = await axios.post(`${utils.getApiUrl(server)}/variables`, payload);
return {
payload: response.data,
statusCode: response.status
};
}
async function updateValue(server, mergedConfig) {
if (!mergedConfig.externalRef)
throw new Error("externalRef must be specified");
if (!server.subsystemExternalId)
throw new Error("subsystemExternalId must be specified in the configuration node");
const value = getValueFromConfig(mergedConfig), payload = stringifyValue(value), url = `${utils.getApiUrl(server)}/subsystems/${server.subsystemExternalId}/variables/${mergedConfig.externalRef}/lastValue`, response = await axios.put(url, payload, {
headers: {
"Content-Type": "text/plain"
}
});
return {
payload: response.data,
statusCode: response.status
};
}
async function deleteVariable(server, mergedConfig) {
const { payload: variable } = await getVariable(server, mergedConfig), response = await axios.delete(`${utils.getApiUrl(server)}/variables/${variable._id}`);
return {
payload: response.data,
statusCode: response.status
};
}
module.exports = (RED) => {
function VariableNode(config) {
RED.nodes.createNode(this, config);
const node = this, server = RED.nodes.getNode(config.isaacConnection), didAddUsedConnection = utils.incrementConnectionUsage(node, server);
this.on("input", async (msg) => {
try {
if (!server)
throw new Error("No ISAAC connection configured");
const mergedConfig = utils.mergeConfig({ config, msg }), action = utils.getAction({ config, msg });
let promise;
switch (action) {
case "getOne":
promise = getVariable(server, mergedConfig);
break;
case "getAll":
promise = getAllVariables(server);
break;
case "upsert":
promise = upsertVariable(server, mergedConfig);
break;
case "updateValue":
promise = updateValue(server, mergedConfig);
break;
case "delete":
promise = deleteVariable(server, mergedConfig);
break;
default:
throw new Error(`Invalid action "${mergedConfig.action}"`);
}
const result = await promise;
node.send({
...msg,
...result
});
} catch (e) {
const niceMessage = utils.getNiceAxiosErrorMessage(e);
if (niceMessage) {
const error = new Error(niceMessage);
node.error(error, msg);
return;
}
node.error(e, msg);
}
}), this.on("close", () => {
didAddUsedConnection && utils.decrementConnectionUsage(node, server);
});
}
RED.nodes.registerType("isaac variable", VariableNode);
};