UNPKG

@isaac-platform/isaac-node-red

Version:

Set of Node-RED nodes to communicate with an ISAAC system

179 lines (178 loc) 7.09 kB
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); };