mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Merge remote-tracking branch 'nodered/master' into exec-with-stdin
This commit is contained in:
@@ -148,7 +148,7 @@ module.exports = function(RED) {
|
||||
var st = (typeof output === 'string') ? output : util.inspect(output);
|
||||
var fill = "grey";
|
||||
var shape = "dot";
|
||||
if (typeof output === 'object' && hasOwnProperty.call(output, "fill") && hasOwnProperty.call(output, "shape") && hasOwnProperty.call(output, "text")) {
|
||||
if (typeof output === 'object' && output?.fill && output?.shape && output?.text) {
|
||||
fill = output.fill;
|
||||
shape = output.shape;
|
||||
st = output.text;
|
||||
|
||||
@@ -511,9 +511,10 @@ RED.debug = (function() {
|
||||
typeHint: format,
|
||||
hideKey: false,
|
||||
path: path,
|
||||
sourceId: sourceNode&&sourceNode.id,
|
||||
sourceId: sourceNode && sourceNode.id,
|
||||
rootPath: path,
|
||||
nodeSelector: config.messageSourceClick,
|
||||
enablePinning: true
|
||||
});
|
||||
// Do this in a separate step so the element functions aren't stripped
|
||||
debugMessage.appendTo(el);
|
||||
|
||||
@@ -111,8 +111,6 @@ module.exports = function(RED) {
|
||||
throw new Error(RED._("function.error.externalModuleNotAllowed"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
var functionText = "var results = null;"+
|
||||
"results = (async function(msg,__send__,__done__){ "+
|
||||
"var __msgid__ = msg._msgid;"+
|
||||
@@ -166,7 +164,13 @@ module.exports = function(RED) {
|
||||
Buffer:Buffer,
|
||||
Date: Date,
|
||||
RED: {
|
||||
util: RED.util
|
||||
util: {
|
||||
...RED.util,
|
||||
getSetting: function (_node, name, _flow) {
|
||||
// Ensure `node` argument is the Function node and do not allow flow to be overridden.
|
||||
return RED.util.getSetting(node, name);
|
||||
}
|
||||
}
|
||||
},
|
||||
__node__: {
|
||||
id: node.id,
|
||||
|
||||
@@ -352,7 +352,9 @@ module.exports = function(RED) {
|
||||
if (msgs.length === 0) {
|
||||
done()
|
||||
} else {
|
||||
drainMessageGroup(msgs,count,done);
|
||||
setImmediate(() => {
|
||||
drainMessageGroup(msgs,count,done);
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -505,7 +507,9 @@ module.exports = function(RED) {
|
||||
if (err) {
|
||||
node.error(err,nextMsg);
|
||||
}
|
||||
processMessageQueue()
|
||||
setImmediate(() => {
|
||||
processMessageQueue()
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -253,7 +253,13 @@ module.exports = function(RED) {
|
||||
if (node.allowrate && m.hasOwnProperty("rate") && !isNaN(parseFloat(m.rate))) {
|
||||
node.rate = m.rate;
|
||||
}
|
||||
send(m);
|
||||
if (msg.hasOwnProperty("reset")) {
|
||||
if (msg.hasOwnProperty("flush")) {
|
||||
node.buffer.push({msg: m, send: send, done: done});
|
||||
}
|
||||
}
|
||||
else { send(m); }
|
||||
|
||||
node.reportDepth();
|
||||
node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
|
||||
done();
|
||||
@@ -285,42 +291,23 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
else if (!msg.hasOwnProperty("reset")) {
|
||||
if (maxKeptMsgsCount(node) > 0) {
|
||||
if (node.intervalID === -1) {
|
||||
node.send(msg);
|
||||
node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
|
||||
} else {
|
||||
if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate)) && node.rate !== msg.rate) {
|
||||
node.rate = msg.rate;
|
||||
clearInterval(node.intervalID);
|
||||
node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
|
||||
}
|
||||
if (node.buffer.length < _maxKeptMsgsCount) {
|
||||
var m = RED.util.cloneMessage(msg);
|
||||
node.buffer.push({msg: m, send: send, done: done});
|
||||
} else {
|
||||
node.trace("dropped due to buffer overflow. msg._msgid = " + msg._msgid);
|
||||
node.droppedMsgs++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate))) {
|
||||
node.rate = msg.rate;
|
||||
}
|
||||
var timeSinceLast;
|
||||
if (node.lastSent) {
|
||||
timeSinceLast = process.hrtime(node.lastSent);
|
||||
}
|
||||
if (!node.lastSent) { // ensuring that we always send the first message
|
||||
node.lastSent = process.hrtime();
|
||||
send(msg);
|
||||
}
|
||||
else if ( ( (timeSinceLast[0] * SECONDS_TO_NANOS) + timeSinceLast[1] ) > (node.rate * MILLIS_TO_NANOS) ) {
|
||||
node.lastSent = process.hrtime();
|
||||
send(msg);
|
||||
} else if (node.outputs === 2) {
|
||||
send([null,msg])
|
||||
}
|
||||
if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate))) {
|
||||
node.rate = msg.rate;
|
||||
}
|
||||
var timeSinceLast;
|
||||
if (node.lastSent) {
|
||||
timeSinceLast = process.hrtime(node.lastSent);
|
||||
}
|
||||
if (!node.lastSent) { // ensuring that we always send the first message
|
||||
node.lastSent = process.hrtime();
|
||||
send(msg);
|
||||
}
|
||||
else if ( ( (timeSinceLast[0] * SECONDS_TO_NANOS) + timeSinceLast[1] ) > (node.rate * MILLIS_TO_NANOS) ) {
|
||||
node.lastSent = process.hrtime();
|
||||
send(msg);
|
||||
}
|
||||
else if (node.outputs === 2) {
|
||||
send([null,msg])
|
||||
}
|
||||
done();
|
||||
}
|
||||
|
||||
@@ -24,6 +24,14 @@ module.exports = function(RED) {
|
||||
this.op2 = n.op2 || "0";
|
||||
this.op1type = n.op1type || "str";
|
||||
this.op2type = n.op2type || "str";
|
||||
// If the op1/2type is 'date', then we need to leave op1/2 alone so that
|
||||
// evaluateNodeProperty works as expected.
|
||||
if (this.op1type === 'date' && this.op1 === '1') {
|
||||
this.op1 = ''
|
||||
}
|
||||
if (this.op2type === 'date' && this.op2 === '0') {
|
||||
this.op2 = ''
|
||||
}
|
||||
this.second = (n.outputs == 2) ? true : false;
|
||||
this.topic = n.topic || "topic";
|
||||
|
||||
@@ -193,7 +201,7 @@ module.exports = function(RED) {
|
||||
if (node.op2type !== "nul") {
|
||||
var promise = Promise.resolve();
|
||||
msg2 = RED.util.cloneMessage(msg);
|
||||
if (node.op2type === "flow" || node.op2type === "global") {
|
||||
if (node.op2type === "flow" || node.op2type === "global" || node.op2type === "date") {
|
||||
promise = new Promise((resolve,reject) => {
|
||||
RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg,(err,value) => {
|
||||
if (err) {
|
||||
@@ -213,7 +221,6 @@ module.exports = function(RED) {
|
||||
}
|
||||
else {
|
||||
msg2.payload = node.topics[topic].m2;
|
||||
if (node.op2type === "date") { msg2.payload = Date.now(); }
|
||||
if (node.second === true) { msgInfo.send([null,msg2]); }
|
||||
else { msgInfo.send(msg2); }
|
||||
}
|
||||
|
||||
@@ -104,14 +104,14 @@ module.exports = function(RED) {
|
||||
if (this.credentials && this.credentials.passphrase) {
|
||||
opts.passphrase = this.credentials.passphrase;
|
||||
}
|
||||
if (this.servername) {
|
||||
opts.servername = this.servername;
|
||||
}
|
||||
if (this.alpnprotocol) {
|
||||
opts.ALPNProtocols = [this.alpnprotocol];
|
||||
}
|
||||
opts.rejectUnauthorized = this.verifyservercert;
|
||||
}
|
||||
if (this.servername) {
|
||||
opts.servername = this.servername;
|
||||
}
|
||||
if (this.alpnprotocol) {
|
||||
opts.ALPNProtocols = [this.alpnprotocol];
|
||||
}
|
||||
opts.rejectUnauthorized = this.verifyservercert;
|
||||
return opts;
|
||||
}
|
||||
|
||||
|
||||
@@ -158,9 +158,16 @@ module.exports = function(RED) {
|
||||
if(!keys || !keys.length) return null;
|
||||
keys.forEach(key => {
|
||||
let val = srcUserProperties[key];
|
||||
if(typeof val == "string") {
|
||||
if(typeof val === "string") {
|
||||
count++;
|
||||
_clone[key] = val;
|
||||
} else if (val !== undefined && val !== null) {
|
||||
try {
|
||||
_clone[key] = JSON.stringify(val)
|
||||
count++;
|
||||
} catch (err) {
|
||||
// Silently drop property
|
||||
}
|
||||
}
|
||||
});
|
||||
if(count) properties.userProperties = _clone;
|
||||
|
||||
@@ -367,20 +367,21 @@ module.exports = function(RED) {
|
||||
const sendHeadersAlways = node.hdrout === "all"
|
||||
const sendHeaders = !dontSendHeaders && (sendHeadersOnce || sendHeadersAlways)
|
||||
const quoteables = [node.sep, node.quo, "\n", "\r"]
|
||||
const templateQuoteables = [',', '"', "\n", "\r"]
|
||||
const templateQuoteables = [node.sep, node.quo, "\n", "\r"]
|
||||
const templateQuoteablesStrict = [',', '"', "\n", "\r"]
|
||||
let badTemplateWarnOnce = true
|
||||
|
||||
const columnStringToTemplateArray = function (col, sep) {
|
||||
// NOTE: enforce strict column template parsing in RFC4180 mode
|
||||
const parsed = csv.parse(col, { separator: sep, quote: node.quo, outputStyle: 'array', strict: true })
|
||||
if (parsed.headers.length > 0) { node.goodtmpl = true } else { node.goodtmpl = false }
|
||||
return parsed.headers.length ? parsed.headers : null
|
||||
if (parsed.data?.length === 1) { node.goodtmpl = true } else { node.goodtmpl = false }
|
||||
return node.goodtmpl ? parsed.data[0] : null
|
||||
}
|
||||
const templateArrayToColumnString = function (template, keepEmptyColumns) {
|
||||
// NOTE: enforce strict column template parsing in RFC4180 mode
|
||||
const parsed = csv.parse('', {headers: template, headersOnly:true, separator: ',', quote: node.quo, outputStyle: 'array', strict: true })
|
||||
const templateArrayToColumnString = function (template, keepEmptyColumns, separator = ',', quotables = templateQuoteablesStrict) {
|
||||
// NOTE: defaults to strict column template parsing (commas and double quotes)
|
||||
const parsed = csv.parse('', {headers: template, headersOnly:true, separator, quote: node.quo, outputStyle: 'array', strict: true })
|
||||
return keepEmptyColumns
|
||||
? parsed.headers.map(e => addQuotes(e || '', { separator: ',', quoteables: templateQuoteables}))
|
||||
? parsed.headers.map(e => addQuotes(e || '', { separator, quoteables: quotables })).join(separator)
|
||||
: parsed.header // exclues empty columns
|
||||
// TODO: resolve inconsistency between CSV->JSON and JSON->CSV
|
||||
// CSV->JSON: empty columns are excluded
|
||||
@@ -447,7 +448,7 @@ module.exports = function(RED) {
|
||||
template = Object.keys(inputData[0]) || ['']
|
||||
}
|
||||
}
|
||||
stringBuilder.push(templateArrayToColumnString(template, true))
|
||||
stringBuilder.push(templateArrayToColumnString(template, true, node.sep, templateQuoteables)) // use user set separator for output data.
|
||||
if (sendHeadersOnce) { node.hdrSent = true }
|
||||
}
|
||||
|
||||
@@ -483,6 +484,7 @@ module.exports = function(RED) {
|
||||
node.warn(RED._("csv.errors.obj_csv"))
|
||||
badTemplateWarnOnce = false
|
||||
}
|
||||
template = Object.keys(row) || ['']
|
||||
const rowData = []
|
||||
for (let header in inputData[0]) {
|
||||
if (row.hasOwnProperty(header)) {
|
||||
@@ -518,7 +520,7 @@ module.exports = function(RED) {
|
||||
|
||||
// join lines, don't forget to add the last new line
|
||||
msg.payload = stringBuilder.join(node.ret) + node.ret
|
||||
msg.columns = templateArrayToColumnString(template)
|
||||
msg.columns = templateArrayToColumnString(template) // always strict commas + double quotes for
|
||||
if (msg.payload !== '') { send(msg) }
|
||||
done()
|
||||
}
|
||||
@@ -615,16 +617,15 @@ module.exports = function(RED) {
|
||||
}
|
||||
if (msg.parts.index + 1 === msg.parts.count) {
|
||||
msg.payload = node.store
|
||||
msg.columns = csvParseResult.header
|
||||
// msg._mode = 'RFC4180 mode'
|
||||
// msg.columns = csvParseResult.header
|
||||
msg.columns = templateArrayToColumnString(csvParseResult.headers) // always strict commas + double quotes for msg.columns
|
||||
delete msg.parts
|
||||
send(msg)
|
||||
node.store = []
|
||||
}
|
||||
}
|
||||
else {
|
||||
msg.columns = csvParseResult.header
|
||||
// msg._mode = 'RFC4180 mode'
|
||||
msg.columns = templateArrayToColumnString(csvParseResult.headers) // always strict commas + double quotes for msg.columns
|
||||
msg.payload = data
|
||||
send(msg); // finally send the array
|
||||
}
|
||||
@@ -633,7 +634,8 @@ module.exports = function(RED) {
|
||||
const len = data.length
|
||||
for (let row = 0; row < len; row++) {
|
||||
const newMessage = RED.util.cloneMessage(msg)
|
||||
newMessage.columns = csvParseResult.header
|
||||
// newMessage.columns = csvParseResult.header
|
||||
newMessage.columns = templateArrayToColumnString(csvParseResult.headers) // always strict commas + double quotes for msg.columns
|
||||
newMessage.payload = data[row]
|
||||
if (!has_parts) {
|
||||
newMessage.parts = {
|
||||
|
||||
@@ -339,7 +339,7 @@ module.exports = function(RED) {
|
||||
}
|
||||
else {
|
||||
msg.filename = filename;
|
||||
var lines = Buffer.from([]);
|
||||
const bufferArray = [];
|
||||
var spare = "";
|
||||
var count = 0;
|
||||
var type = "buffer";
|
||||
@@ -397,7 +397,7 @@ module.exports = function(RED) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
lines = Buffer.concat([lines,chunk]);
|
||||
bufferArray.push(chunk);
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -413,10 +413,11 @@ module.exports = function(RED) {
|
||||
})
|
||||
.on('end', function() {
|
||||
if (node.chunk === false) {
|
||||
const buffer = Buffer.concat(bufferArray);
|
||||
if (node.format === "utf8") {
|
||||
msg.payload = decode(lines, node.encoding);
|
||||
msg.payload = decode(buffer, node.encoding);
|
||||
}
|
||||
else { msg.payload = lines; }
|
||||
else { msg.payload = buffer; }
|
||||
nodeSend(msg);
|
||||
}
|
||||
else if (node.format === "lines") {
|
||||
|
||||
Reference in New Issue
Block a user