diff --git a/packages/node_modules/@node-red/nodes/core/function/90-exec.html b/packages/node_modules/@node-red/nodes/core/function/90-exec.html
index 137807d2f..1042a7808 100644
--- a/packages/node_modules/@node-red/nodes/core/function/90-exec.html
+++ b/packages/node_modules/@node-red/nodes/core/function/90-exec.html
@@ -23,6 +23,11 @@
+
+
@@ -57,6 +62,7 @@
defaults: {
command: {value:""},
addpay: {value:"", validate: RED.validators.typedInput({ type: 'msg', allowBlank: true })},
+ addpayTo: { value: "parameter" },
append: {value:""},
useSpawn: {value:"false"},
timer: {value:""},
@@ -84,10 +90,16 @@
if ($("#node-input-useSpawn").val() === null) {
$("#node-input-useSpawn").val(this.useSpawn.toString());
}
+
+ if ($("#node-input-addpayTo").val() === null) {
+ $("#node-input-addpayTo").val(this.addpayTo.toString());
+ }
+
$("#node-input-addpay-cb").prop("checked", this.addpay === true || (this.addpay !== false && this.addpay !== ""))
var addpayValue = (this.addpay === true)?"payload":((this.addpay === false || this.addpay === "")?"payload":this.addpay);
$("#node-input-addpay-cb").on("change", function(evt) {
$("#node-input-addpay").typedInput("disable",!$("#node-input-addpay-cb").prop("checked"));
+ $("#node-input-addpayTo").prop("disabled", !$("#node-input-addpay-cb").prop("checked"));
});
$("#node-input-addpay").val(addpayValue);
diff --git a/packages/node_modules/@node-red/nodes/core/function/90-exec.js b/packages/node_modules/@node-red/nodes/core/function/90-exec.js
index 70aec8d2b..64d235150 100644
--- a/packages/node_modules/@node-red/nodes/core/function/90-exec.js
+++ b/packages/node_modules/@node-red/nodes/core/function/90-exec.js
@@ -20,6 +20,8 @@ module.exports = function(RED) {
var exec = require('child_process').exec;
var fs = require('fs');
var isUtf8 = require('is-utf8');
+ var stream = require('stream')
+
const isWindows = process.platform === 'win32'
function ExecNode(n) {
@@ -30,6 +32,12 @@ module.exports = function(RED) {
if (this.addpay === true) {
this.addpay = "payload";
}
+
+ this.addpayTo = n.addpayTo;
+ if ( this.addpayTo === undefined ) {
+ this.addpayTo = "parameter"
+ }
+
this.append = (n.append || "").trim();
this.useSpawn = (n.useSpawn == "true");
this.timer = Number(n.timer || 0)*1000;
@@ -69,7 +77,7 @@ module.exports = function(RED) {
// make the extra args into an array
// then prepend with the msg.payload
var arg = node.cmd;
- if (node.addpay) {
+ if (node.addpay && node.addpayTo == "parameter") {
var value = RED.util.getMessageProperty(msg, node.addpay);
if (value !== undefined) {
arg += " " + value;
@@ -87,7 +95,7 @@ module.exports = function(RED) {
});
var cmd = arg.shift();
// Since 18.20.2/20.12.2, it is invalid to call spawn on Windows with a .bat/.cmd file
- // without using shell: true.
+ // without using shell: true.
const opts = isWindows ? { ...node.spawnOpt, shell: true } : node.spawnOpt
/* istanbul ignore else */
node.debug(cmd+" ["+arg+"]");
@@ -137,6 +145,19 @@ module.exports = function(RED) {
node.error(code,RED.util.cloneMessage(msg));
}
});
+
+ if (node.addpay && node.addpayTo == "stdin") {
+ var value = RED.util.getMessageProperty(msg, node.addpay);
+ if (value !== undefined) {
+ var stdinStream = new stream.Readable();
+ if (!Buffer.isBuffer(value) && (typeof value) !== 'string') {
+ value = JSON.stringify(value)
+ }
+ stdinStream.push(value); // Add data to the internal queue for users of the stream to consume
+ stdinStream.push(null); // Signals the end of the stream (EOF)
+ stdinStream.pipe(child.stdin);
+ }
+ }
}
else {
/* istanbul ignore else */
@@ -181,6 +202,19 @@ module.exports = function(RED) {
child.tout = setTimeout(function() { cleanup(child.pid); }, node.timer);
}
node.activeProcesses[child.pid] = child;
+
+ if (node.addpay && node.addpayTo == "stdin") {
+ var value = RED.util.getMessageProperty(msg, node.addpay);
+ if (value !== undefined) {
+ var stdinStream = new stream.Readable();
+ if (!Buffer.isBuffer(value) && (typeof value) !== 'string') {
+ value = JSON.stringify(value)
+ }
+ stdinStream.push(value); // Add data to the internal queue for users of the stream to consume
+ stdinStream.push(null); // Signals the end of the stream (EOF)
+ stdinStream.pipe(child.stdin);
+ }
+ }
}
}
});
diff --git a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
index d26f0f56b..c05742ddf 100644
--- a/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
+++ b/packages/node_modules/@node-red/nodes/locales/en-US/messages.json
@@ -233,14 +233,18 @@
"stdout": "stdout",
"stderr": "stderr",
"retcode": "return code",
- "winHide": "Hide console"
+ "winHide": "Hide console",
+ "as": "as"
+
},
"placeholder": {
"extraparams": "extra input parameters"
},
"opt": {
"exec": "when the command is complete - exec mode",
- "spawn": "while the command is running - spawn mode"
+ "spawn": "while the command is running - spawn mode",
+ "parameter": "parameter",
+ "stdin": "stdin"
},
"oldrc": "Use old style output (compatibility mode)"
},
diff --git a/test/nodes/core/function/90-exec_spec.js b/test/nodes/core/function/90-exec_spec.js
index c397ea27d..bd31ee126 100644
--- a/test/nodes/core/function/90-exec_spec.js
+++ b/test/nodes/core/function/90-exec_spec.js
@@ -970,4 +970,248 @@ describe('exec node', function() {
});
});
+
+ describe('calling exec with addpayTo', function() {
+ it('handle buffer payloads', function(done) {
+ var flow = [{
+ id:"n1",
+ type:"exec",
+ wires:[["n2"],["n3"],["n4"]],
+ command: undefined,
+ addpay: "payload",
+ addpayTo: "stdin",
+ append:"",
+ useSpawn:"false",
+ oldrc:"false"
+ },{
+ id:"n2",
+ type:"helper"
+ },{
+ id:"n3",
+ type:"helper"
+ },{
+ id:"n4",
+ type:"helper"
+ }];
+
+ var expected;
+ if (osType === "Windows_NT") {
+ flow[0].command = "cmd /C cat"
+ expected = "this payload goes to stdin\r\n";
+ } else {
+ flow[0].command = "cat"
+ expected = "this payload goes to stdin\n";
+ }
+
+ helper.load(execNode, flow, function() {
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ var n3 = helper.getNode("n3");
+ var n4 = helper.getNode("n4");
+ var received = 0;
+ var messages = [null,null];
+
+ var completeTest = function() {
+ received = received + 1;
+ if (received < 2) {
+ return;
+ }
+
+ try {
+ var msg = messages[0];
+ msg.should.have.property("payload");
+ Buffer.isBuffer(msg.payload).should.be.true();
+
+ msg.payload[0].should.be.eql(0x01)
+ msg.payload[1].should.be.eql(0x02)
+ msg.payload[2].should.be.eql(0x03)
+ msg.payload[3].should.be.eql(0x88)
+
+ msg = messages[1];
+ msg.should.have.property("payload");
+ msg.payload.should.have.property("code",0);
+
+ done();
+ }
+ catch(err) {
+ done(err);
+ }
+ };
+ n2.on("input", function(msg) {
+ messages[0] = msg;
+ completeTest();
+ });
+ n3.on("input", function(msg) {
+ // stderr wire should not receive msg
+ expect("should not be").to.eql("called")
+ });
+ n4.on("input", function(msg) {
+ messages[1] = msg;
+ completeTest();
+ });
+
+ n1.receive({payload:Buffer.from([0x01,0x02,0x03,0x88])});
+ })
+ })
+
+ it('handle string payloads', function(done) {
+ var flow = [{
+ id:"n1",
+ type:"exec",
+ wires:[["n2"],["n3"],["n4"]],
+ command: undefined,
+ addpay: "payload",
+ addpayTo: "stdin",
+ append:"",
+ useSpawn:"false",
+ oldrc:"false"
+ },{
+ id:"n2",
+ type:"helper"
+ },{
+ id:"n3",
+ type:"helper"
+ },{
+ id:"n4",
+ type:"helper"
+ }];
+
+ var expected;
+ if (osType === "Windows_NT") {
+ flow[0].command = "cmd /C cat"
+ expected = "this payload goes to stdin\r\n";
+ } else {
+ flow[0].command = "cat"
+ expected = "this payload goes to stdin\n";
+ }
+
+ helper.load(execNode, flow, function() {
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ var n3 = helper.getNode("n3");
+ var n4 = helper.getNode("n4");
+ var received = 0;
+ var messages = [null,null];
+
+ var completeTest = function() {
+ received = received + 1;
+ if (received < 2) {
+ return;
+ }
+
+ try {
+ var msg = messages[0];
+ msg.should.have.property("payload");
+ msg.payload.should.be.a.String();
+ msg.payload.should.equal("this payload goes to stdin");
+
+ msg = messages[1];
+ msg.should.have.property("payload");
+ msg.payload.should.have.property("code",0);
+
+ done();
+ }
+ catch(err) {
+ done(err);
+ }
+ };
+ n2.on("input", function(msg) {
+ messages[0] = msg;
+ completeTest();
+ });
+ n3.on("input", function(msg) {
+ // stderr wire should not receive msg
+ expect("should not be").to.eql("called")
+ });
+ n4.on("input", function(msg) {
+ messages[1] = msg;
+ completeTest();
+ });
+
+ n1.receive({payload:"this payload goes to stdin"});
+ })
+
+
+ })
+
+ it('handle array as type for payload', function(done) {
+ var flow = [{
+ id:"n1",
+ type:"exec",
+ wires:[["n2"],["n3"],["n4"]],
+ command: undefined,
+ addpay: "payload",
+ addpayTo: "stdin",
+ append:"",
+ useSpawn:"false",
+ oldrc:"false"
+ },{
+ id:"n2",
+ type:"helper"
+ },{
+ id:"n3",
+ type:"helper"
+ },{
+ id:"n4",
+ type:"helper"
+ }];
+
+ var expected;
+ if (osType === "Windows_NT") {
+ flow[0].command = "cmd /C cat"
+ expected = "this payload goes to stdin\r\n";
+ } else {
+ flow[0].command = "cat"
+ expected = "this payload goes to stdin\n";
+ }
+
+ helper.load(execNode, flow, function() {
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ var n3 = helper.getNode("n3");
+ var n4 = helper.getNode("n4");
+ var received = 0;
+ var messages = [null,null];
+
+ var completeTest = function() {
+ received = received + 1;
+ if (received < 2) {
+ return;
+ }
+
+ try {
+ var msg = messages[0];
+ msg.should.have.property("payload");
+ msg.payload.should.be.a.String();
+ msg.payload.should.equal('[1,2,3,136]');
+
+ msg = messages[1];
+ msg.should.have.property("payload");
+ msg.payload.should.have.property("code",0);
+
+ done();
+ }
+ catch(err) {
+ done(err);
+ }
+ };
+ n2.on("input", function(msg) {
+ messages[0] = msg;
+ completeTest();
+ });
+ n3.on("input", function(msg) {
+ // stderr wire should not receive msg
+ expect("should not be").to.eql("called")
+ });
+ n4.on("input", function(msg) {
+ messages[1] = msg;
+ completeTest();
+ });
+
+ n1.receive({payload:[0x01,0x02,0x03,0x88]});
+ })
+
+ })
+
+ })
});