1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Add async to all paths that JSONata env var calls

This commit is contained in:
Steve-Mcl 2023-06-17 21:14:56 +01:00
parent fb5b470966
commit 4808cac89d
4 changed files with 184 additions and 69 deletions

View File

@ -416,23 +416,50 @@ class Flow {
return this.activeNodes; return this.activeNodes;
} }
/*!
* Get value of environment variable defined in group node. /**
* @param {String} group - group node * Group callback signature
* @param {String} name - name of variable *
* @return {Object} object containing the value in val property or null if not defined * @callback GroupEnvCallback
* @param {Error} err The error object (or null)
* @param {[result: {val:Any}, name: String]} result The result of the callback
* @returns {void}
*/ */
getGroupEnvSetting(node, group, name) {
/**
* @function getGroupEnvSetting
* Get a group setting value synchronously.
* This currently automatically defers to the parent
* @overload
* @param {Object} node
* @param {Object} group
* @param {String} name
* @returns {Any}
*
* Get a group setting value asynchronously.
* @overload
* @param {Object} node
* @param {Object} group
* @param {String} name
* @param {GroupEnvCallback} callback
* @returns {void}
*/
getGroupEnvSetting(node, group, name, callback) {
/** @type {GroupEnvCallback} */
const returnOrCallback = (err, [result, newName]) => {
if (callback) {
callback(err, [result, newName]);
return
}
return [result, newName];
}
if (group) { if (group) {
if (name === "NR_GROUP_NAME") { if (name === "NR_GROUP_NAME") {
return [{ return returnOrCallback(null, [{ val: group.name }, null]);
val: group.name
}, null];
} }
if (name === "NR_GROUP_ID") { if (name === "NR_GROUP_ID") {
return [{ return returnOrCallback(null, [{ val: group.id }, null]);
val: group.id
}, null];
} }
if (group.credentials === undefined) { if (group.credentials === undefined) {
@ -457,33 +484,32 @@ class Flow {
if (env) { if (env) {
let value = env.value; let value = env.value;
const type = env.type; const type = env.type;
if ((type !== "env") || if ((type !== "env") || (value !== name)) {
(value !== name)) {
if (type === "env") { if (type === "env") {
value = value.replace(new RegExp("\\${"+name+"}","g"),"${$parent."+name+"}"); value = value.replace(new RegExp("\\${"+name+"}","g"),"${$parent."+name+"}");
} } else if (type === "bool") {
if (type === "bool") { const val = ((value === "true") || (value === true));
const val return returnOrCallback(null, [{ val: val }, null])
= ((value === "true") ||
(value === true));
return [{
val: val
}, null];
} }
if (type === "cred") { if (type === "cred") {
return [{ return returnOrCallback(null, [{ val: value }, null])
val: value
}, null];
} }
try { try {
var val = redUtil.evaluateNodeProperty(value, type, node, null, null); if (!callback) {
return [{ var val = redUtil.evaluateNodeProperty(value, type, node, null, null);
val: val return [{ val: val }, null];
}, null]; } else {
redUtil.evaluateNodeProperty(value, type, node, null, (err, value) => {
return returnOrCallback(err, [{ val: value }, null])
});
return
}
} }
catch (e) { catch (e) {
this.error(e); if (!callback) {
return [null, null]; this.error(e);
}
return returnOrCallback(e, null);
} }
} }
} }
@ -494,27 +520,47 @@ class Flow {
} }
if (group.g) { if (group.g) {
const parent = this.getGroupNode(group.g); const parent = this.getGroupNode(group.g);
return this.getGroupEnvSetting(node, parent, name); const gVal = this.getGroupEnvSetting(node, parent, name, callback);
if (callback) {
return;
}
return gVal;
} }
} }
return [null, name]; return returnOrCallback(null, [null, name]);
} }
/**
* Settings callback signature
*
* @callback SettingsCallback
* @param {Error} err The error object (or null)
* @param {Any} result The result of the callback
* @returns {void}
*/
/** /**
* Get a flow setting value. This currently automatically defers to the parent * Get a flow setting value. This currently automatically defers to the parent
* flow which, as defined in ./index.js returns `process.env[key]`. * flow which, as defined in ./index.js returns `process.env[key]`.
* This lays the groundwork for Subflow to have instance-specific settings * This lays the groundwork for Subflow to have instance-specific settings
* @param {[type]} key [description] * @param {String} key The settings key
* @return {[type]} [description] * @param {SettingsCallback} callback Optional callback function
* @return {Any}
*/ */
getSetting(key) { getSetting(key, callback) {
/** @type {SettingsCallback} */
const returnOrCallback = (err, result) => {
if (callback) {
callback(err, result);
return
}
return result;
}
const flow = this.flow; const flow = this.flow;
if (key === "NR_FLOW_NAME") { if (key === "NR_FLOW_NAME") {
return flow.label; return returnOrCallback(null, flow.label);
} }
if (key === "NR_FLOW_ID") { if (key === "NR_FLOW_ID") {
return flow.id; return returnOrCallback(null, flow.id);
} }
if (flow.credentials === undefined) { if (flow.credentials === undefined) {
flow.credentials = credentials.get(flow.id) || {}; flow.credentials = credentials.get(flow.id) || {};
@ -544,15 +590,14 @@ class Flow {
} }
try { try {
if (type === "bool") { if (type === "bool") {
const val = ((value === "true") || const val = ((value === "true") || (value === true));
(value === true)); return returnOrCallback(null, val);
return val;
} }
if (type === "cred") { if (type === "cred") {
return value; return returnOrCallback(null, value);
} }
var val = redUtil.evaluateNodeProperty(value, type, null, null, null); var val = redUtil.evaluateNodeProperty(value, type, null, null, null);
return val; return returnOrCallback(null, val);
} }
catch (e) { catch (e) {
this.error(e); this.error(e);
@ -564,7 +609,11 @@ class Flow {
key = key.substring(8); key = key.substring(8);
} }
} }
return this.parent.getSetting(key); const pVal = this.parent.getSetting(key, callback);
if (callback) {
return;
}
return pVal;
} }
/** /**

View File

@ -780,7 +780,7 @@ const flowAPI = {
getNode: getNode, getNode: getNode,
handleError: () => false, handleError: () => false,
handleStatus: () => false, handleStatus: () => false,
getSetting: k => flowUtil.getEnvVar(k), getSetting: (k, callback) => flowUtil.getEnvVar(k, callback),
log: m => log.log(m) log: m => log.log(m)
} }

View File

@ -308,16 +308,34 @@ module.exports = {
runtime.settings.envVarExcludes.forEach(v => envVarExcludes[v] = true); runtime.settings.envVarExcludes.forEach(v => envVarExcludes[v] = true);
} }
}, },
getEnvVar: function(k) { /**
if (!envVarExcludes[k]) { * Get the value of an environment variable
const item = getGlobalEnv(k); * Call with a callback to get the value asynchronously
* or without to get the value synchronously
* @param {String} key The name of the environment variable
* @param {(err: Error, val: Any)} [callback] Optional callback for asynchronous call
* @returns {Any | void} The value of the environment variable or undefined if not found
*/
getEnvVar: function(key, callback) {
const returnOrCallback = function(err, val) {
if (callback) {
callback(err, val);
return;
}
return val;
}
if (!envVarExcludes[key]) {
const item = getGlobalEnv(key);
if (item) { if (item) {
const val = redUtil.evaluateNodeProperty(item.value, item.type, null, null, null); const val = redUtil.evaluateNodeProperty(item.value, item.type, null, null, callback);
if (callback) {
return;
}
return val; return val;
} }
return process.env[k]; return returnOrCallback(null, process.env[key]);
} }
return undefined; return returnOrCallback(undefined);
}, },
diffNodes: diffNodes, diffNodes: diffNodes,
mapEnvVarProperties: mapEnvVarProperties, mapEnvVarProperties: mapEnvVarProperties,

View File

@ -18,6 +18,7 @@
/** /**
* @mixin @node-red/util_util * @mixin @node-red/util_util
*/ */
/** @typedef {import('../../runtime/lib/flows/Flow.js').Flow} RuntimeLibFlowsFlow */
const clonedeep = require("lodash.clonedeep"); const clonedeep = require("lodash.clonedeep");
const jsonata = require("jsonata"); const jsonata = require("jsonata");
@ -526,37 +527,67 @@ function setObjectProperty(msg,prop,value,createMissing) {
return true; return true;
} }
/*! /**
* Get value of environment variable. * Get value of environment variable.
* @param {Node} node - accessing node * @param {Node} node - accessing node
* @param {String} name - name of variable * @param {String} name - name of variable
* @param {RuntimeLibFlowsFlow} flow_ - (optional) flow to check for setting
* @param {(err: Error, result: Any) => void} callback - (optional) called when the property is evaluated
* @return {String} value of env var * @return {String} value of env var
*/ */
function getSetting(node, name, flow_) { function getSetting(node, name, flow_, callback) {
const returnOrCallback = (err, result) => {
if (callback) {
callback(err, result);
return
}
return result;
}
if (node) { if (node) {
if (name === "NR_NODE_NAME") { if (name === "NR_NODE_NAME") {
return node.name; return returnOrCallback(null, node.name);
} }
if (name === "NR_NODE_ID") { if (name === "NR_NODE_ID") {
return node.id; return returnOrCallback(null, node.id);
} }
if (name === "NR_NODE_PATH") { if (name === "NR_NODE_PATH") {
return node._path; return returnOrCallback(null, node._path);
} }
} }
/** @type {RuntimeLibFlowsFlow} */
var flow = (flow_ ? flow_ : (node ? node._flow : null)); var flow = (flow_ ? flow_ : (node ? node._flow : null));
if (flow) { if (flow) {
if (node && node.g) { if (node && node.g) {
const group = flow.getGroupNode(node.g); const group = flow.getGroupNode(node.g);
const [result, newName] = flow.getGroupEnvSetting(node, group, name); if (callback) {
if (result) { flow.getGroupEnvSetting(node, group, name, (e, [result, newName]) => {
return result.val; if (e) {
callback(e);
return
}
if (result) {
callback(null, result.val);
}
name = newName;
flow.getSetting(name, callback);
});
return
} else {
const [result, newName] = flow.getGroupEnvSetting(node, group, name);
if (result) {
return result.val;
}
name = newName;
} }
name = newName;
} }
return flow.getSetting(name); const fVal = flow.getSetting(name, callback)
if (callback) {
return
}
return fVal;
} }
return process.env[name]; return returnOrCallback(null, process.env[name]);
} }
@ -568,19 +599,34 @@ function getSetting(node, name, flow_) {
* will return `Hello Joe!`. * will return `Hello Joe!`.
* @param {String} value - the string to parse * @param {String} value - the string to parse
* @param {Node} node - the node evaluating the property * @param {Node} node - the node evaluating the property
* @param {(err: Error, result: Any) => void} callback - (optional) called when the property is evaluated
* @return {String} The parsed string * @return {String} The parsed string
* @memberof @node-red/util_util * @memberof @node-red/util_util
*/ */
function evaluateEnvProperty(value, node) { function evaluateEnvProperty(value, node, callback) {
const returnOrCallback = (err, result) => {
if (callback) {
callback(err, result);
return
}
return result;
}
/** @type {RuntimeLibFlowsFlow} */
var flow = (node && hasOwnProperty.call(node, "_flow")) ? node._flow : null; var flow = (node && hasOwnProperty.call(node, "_flow")) ? node._flow : null;
var result; var result;
if (/^\${[^}]+}$/.test(value)) { if (/^\${[^}]+}$/.test(value)) {
// ${ENV_VAR} // ${ENV_VAR}
var name = value.substring(2,value.length-1); var name = value.substring(2,value.length-1);
result = getSetting(node, name, flow); result = getSetting(node, name, flow, callback);
if (callback) {
return
}
} else if (!/\${\S+}/.test(value)) { } else if (!/\${\S+}/.test(value)) {
// ENV_VAR // ENV_VAR
result = getSetting(node, value, flow); result = getSetting(node, value, flow, callback);
if (callback) {
return
}
} else { } else {
// FOO${ENV_VAR}BAR // FOO${ENV_VAR}BAR
return value.replace(/\${([^}]+)}/g, function(match, name) { return value.replace(/\${([^}]+)}/g, function(match, name) {
@ -588,8 +634,7 @@ function evaluateEnvProperty(value, node) {
return (val === undefined)?"":val; return (val === undefined)?"":val;
}); });
} }
return (result === undefined)?"":result; return returnOrCallback(null, (result === undefined)?"":result);
} }
@ -677,7 +722,10 @@ function evaluateNodeProperty(value, type, node, msg, callback) {
return return
} }
} else if (type === 'env') { } else if (type === 'env') {
result = evaluateEnvProperty(value, node); result = evaluateEnvProperty(value, node, callback);
if (callback) {
return
}
} }
if (callback) { if (callback) {
callback(null,result); callback(null,result);