diff --git a/packages/node_modules/@node-red/nodes/core/storage/10-file.html b/packages/node_modules/@node-red/nodes/core/storage/10-file.html index b76a01615..ddddcb687 100755 --- a/packages/node_modules/@node-red/nodes/core/storage/10-file.html +++ b/packages/node_modules/@node-red/nodes/core/storage/10-file.html @@ -3,6 +3,7 @@
+
@@ -29,7 +30,7 @@
- +
@@ -37,7 +38,8 @@ @@ -196,7 +198,8 @@ category: 'storage', defaults: { name: {value:""}, - filename: {value:""}, + filename: {value:"filename"}, + filenameType: {value:"msg"}, appendNewline: {value:true}, createDir: {value:false}, overwriteFile: {value:"false"}, @@ -207,10 +210,13 @@ outputs:1, icon: "file-out.svg", label: function() { + var fn = this.filename; + if(this.filenameType != "str" && this.filenameType != "env" ) { fn = ""; } + if(this.filenameType === "env") { fn = "env."+fn; } if (this.overwriteFile === "delete") { - return this.name||this._("file.label.deletelabel",{file:this.filename}); + return this.name||this._("file.label.deletelabel",{file:fn}); } else { - return this.name||this.filename||this._("file.label.write"); + return this.name||fn||this._("file.label.write"); } }, paletteLabel: RED._("node-red:file.label.write"), @@ -229,6 +235,31 @@ value: "setbymsg", label: node._("file.encoding.setbymsg") }).text(label).appendTo(encSel); + $("#node-input-filename").typedInput({ + default: "msg", + types:[{ value: "str", label:"", icon:"red/images/typedInput/az.svg"}, "msg", "jsonata", "env"], + typeField: $("#node-input-filenameType") + }); + if(typeof node.filenameType == 'undefined') { + //existing node AND filenameType is not set - inplace (compatible) upgrade to new typedInput + if(node.filename == "") { //was using empty value to denote msg.filename - set typedInput to match + node.filename = "filename"; + node.filenameType = "msg"; + $("#node-input-filename").typedInput("type", node.filenameType); + $("#node-input-filename").typedInput("value", node.filename); + } else if(/^\${[^}]+}$/.test(node.filename)) { //was using an ${ENV_VAR} + node.filenameType = "env"; + node.filename = node.filename.replace(/\${([^}]+)}/g, function(match, name) { + return (name === undefined)?"":name; + }); + $("#node-input-filename").typedInput("type", node.filenameType); + $("#node-input-filename").typedInput("value", node.filename); + } else { //was using a static filename - set typedInput type to str + node.filenameType = "str"; + $("#node-input-filename").typedInput("type", node.filenameType); + $("#node-input-filename").typedInput("value", node.filename); + } + } encodings.forEach(function(item) { if(Array.isArray(item)) { var group = $("", { @@ -266,7 +297,8 @@ category: 'storage', defaults: { name: {value:""}, - filename: {value:""}, + filename: {value:"filename"}, + filenameType: {value:"msg"}, format: {value:"utf8"}, chunk: {value:false}, sendError: {value: false}, @@ -291,7 +323,10 @@ }, icon: "file-in.svg", label: function() { - return this.name||this.filename||this._("file.label.read"); + var fn = this.filename; + if(this.filenameType != "str" && this.filenameType != "env" ) { fn = ""; } + if(this.filenameType === "env") { fn = "env."+fn; } + return this.name||fn||this._("file.label.read"); }, paletteLabel: RED._("node-red:file.label.read"), labelStyle: function() { @@ -305,6 +340,31 @@ value: "none", label: label }).text(label).appendTo(encSel); + $("#node-input-filename").typedInput({ + default: "msg", + types:[{ value: "str", label:"", icon:"red/images/typedInput/az.svg"}, "msg", "jsonata", "env"], + typeField: $("#node-input-filenameType") + }); + if(typeof node.filenameType == 'undefined') { + //existing node AND filenameType is not set - inplace (compatible) upgrade to new typedInput + if(node.filename == "") { //was using empty value to denote msg.filename - set typedInput to match + node.filename = "filename"; + node.filenameType = "msg"; + $("#node-input-filename").typedInput("type", node.filenameType); + $("#node-input-filename").typedInput("value", node.filename); + } else if(/^\${[^}]+}$/.test(node.filename)) { //was using an ${ENV_VAR} + node.filenameType = "env"; + node.filename = node.filename.replace(/\${([^}]+)}/g, function(match, name) { + return (name === undefined)?"":name; + }); + $("#node-input-filename").typedInput("type", node.filenameType); + $("#node-input-filename").typedInput("value", node.filename); + } else { //was using a static filename - set typedInput type to str + node.filenameType = "str"; + $("#node-input-filename").typedInput("type", node.filenameType); + $("#node-input-filename").typedInput("value", node.filename); + } + } encodings.forEach(function(item) { if(Array.isArray(item)) { var group = $("", { diff --git a/packages/node_modules/@node-red/nodes/core/storage/10-file.js b/packages/node_modules/@node-red/nodes/core/storage/10-file.js index ba81125fe..d0db89d01 100644 --- a/packages/node_modules/@node-red/nodes/core/storage/10-file.js +++ b/packages/node_modules/@node-red/nodes/core/storage/10-file.js @@ -39,6 +39,7 @@ module.exports = function(RED) { // Write/delete a file RED.nodes.createNode(this,n); this.filename = n.filename; + this.filenameType = n.filenameType; this.appendNewline = n.appendNewline; this.overwriteFile = n.overwriteFile.toString(); this.createDir = n.createDir || false; @@ -50,7 +51,28 @@ module.exports = function(RED) { node.closeCallback = null; function processMsg(msg,nodeSend, done) { - var filename = node.filename || msg.filename || ""; + var filename = node.filename || ""; + //Pre V3 compatibility - if filenameType is empty, do in place upgrade + if(typeof node.filenameType == 'undefined' || node.filenameType == "") { + //existing node AND filenameType is not set - inplace (compatible) upgrade + if(filename == "") { //was using empty value to denote msg.filename + node.filename = "filename"; + node.filenameType = "msg"; + } else { //was using a static filename - set typedInput type to str + node.filenameType = "str"; + } + } + + RED.util.evaluateNodeProperty(node.filename,node.filenameType,node,msg,(err,value) => { + if (err) { + node.error(err,msg); + return done(); + } else { + filename = value; + } + }); + filename = filename || ""; + msg.filename = filename; var fullFilename = filename; if (filename && RED.settings.fileWorkingDirectory && !path.isAbsolute(filename)) { fullFilename = path.resolve(path.join(RED.settings.fileWorkingDirectory,filename)); @@ -158,7 +180,7 @@ module.exports = function(RED) { done(); }); } - if (node.filename) { + if (node.filenameType === "str" || node.filenameType === "env") { // Static filename - write and reuse the stream next time node.wstream.write(buf, function() { nodeSend(msg); @@ -256,6 +278,7 @@ module.exports = function(RED) { // Read a file RED.nodes.createNode(this,n); this.filename = n.filename; + this.filenameType = n.filenameType; this.format = n.format; this.chunk = false; this.encoding = n.encoding || "none"; @@ -270,8 +293,28 @@ module.exports = function(RED) { var node = this; this.on("input",function(msg, nodeSend, nodeDone) { - var filename = (node.filename || msg.filename || "").replace(/\t|\r|\n/g,''); + var filename = node.filename || ""; + //Pre V3 compatibility - if filenameType is empty, do in place upgrade + if(typeof node.filenameType == 'undefined' || node.filenameType == "") { + //existing node AND filenameType is not set - inplace (compatible) upgrade + if(filename == "") { //was using empty value to denote msg.filename + node.filename = "filename"; + node.filenameType = "msg"; + } else { //was using a static filename - set typedInput type to str + node.filenameType = "str"; + } + } + RED.util.evaluateNodeProperty(node.filename,node.filenameType,node,msg,(err,value) => { + if (err) { + node.error(err,msg); + return done(); + } else { + filename = (value || "").replace(/\t|\r|\n/g,''); + } + }); + filename = filename || ""; var fullFilename = filename; + var filePath = ""; if (filename && RED.settings.fileWorkingDirectory && !path.isAbsolute(filename)) { fullFilename = path.resolve(path.join(RED.settings.fileWorkingDirectory,filename)); } diff --git a/packages/node_modules/@node-red/nodes/locales/en-US/storage/10-file.html b/packages/node_modules/@node-red/nodes/locales/en-US/storage/10-file.html index 70400f676..d4a1fd39d 100644 --- a/packages/node_modules/@node-red/nodes/locales/en-US/storage/10-file.html +++ b/packages/node_modules/@node-red/nodes/locales/en-US/storage/10-file.html @@ -20,7 +20,9 @@

Inputs

filename string
-
If not configured in the node, this optional property sets the name of the file to be updated.
+
The name of the file to be updated can be provided in the node configuration, or as a message property. + By default it will use msg.filename but this can be customised in the node. +
encoding string
If encoding is configured to be set by msg, then this optional property can set the encoding.
@@ -43,7 +45,9 @@

Inputs

filename string
-
if not set in the node configuration, this property sets the filename to read.
+
The name of the file to be read can be provided in the node configuration, or as a message property. + By default it will use msg.filename but this can be customised in the node. +

Outputs

diff --git a/test/nodes/core/storage/10-file_spec.js b/test/nodes/core/storage/10-file_spec.js index 99ed23978..9d5aa033f 100644 --- a/test/nodes/core/storage/10-file_spec.js +++ b/test/nodes/core/storage/10-file_spec.js @@ -48,6 +48,7 @@ describe('file Nodes', function() { beforeEach(function(done) { //fs.writeFileSync(fileToTest, "File message line 1\File message line 2\n"); + process.env.TEST_FILE = fileToTest; helper.startServer(done); }); @@ -58,6 +59,7 @@ describe('file Nodes', function() { //fs.unlinkSync(fileToTest); helper.stopServer(done); }); + delete process.env.TEST_FILE }); it('should be loaded', function(done) { @@ -343,6 +345,64 @@ describe('file Nodes', function() { n1.receive({payload:"fine", filename:fileToTest}); }); }); + it('should use msg._user_specified_filename set in nodes typedInput', function(done) { + var flow = [{id:"fileNode1", type:"file", filename:"_user_specified_filename", filenameType: "msg", name: "fileNode", "appendNewline":true, "overwriteFile":true, wires: [["helperNode1"]]}, + {id:"helperNode1", type:"helper"}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileNode1"); + var n2 = helper.getNode("helperNode1"); + + n2.on("input", function (msg) { + try { + msg.should.have.property("payload", "typedInput"); + msg.should.have.property("filename", fileToTest); + + var f = fs.readFileSync(fileToTest).toString(); + if (os.type() !== "Windows_NT") { + f.should.equal("typedInput\n"); + } + else { + f.should.equal("typedInput\r\n"); + } + done(); + } + catch (e) { + done(e); + } + }); + + n1.receive({payload:"typedInput", _user_specified_filename:fileToTest}); + }); + }); + it('should use env.TEST_FILE set in nodes typedInput', function(done) { + var flow = [{id:"fileNode1", type:"file", filename:"TEST_FILE", filenameType: "env", name: "fileNode", "appendNewline":true, "overwriteFile":true, wires: [["helperNode1"]]}, + {id:"helperNode1", type:"helper"}]; + helper.load(fileNode, flow, function() { + var n1 = helper.getNode("fileNode1"); + var n2 = helper.getNode("helperNode1"); + + n2.on("input", function (msg) { + try { + msg.should.have.property("payload", "envTest"); + msg.should.have.property("filename", fileToTest); + + var f = fs.readFileSync(fileToTest).toString(); + if (os.type() !== "Windows_NT") { + f.should.equal("envTest\n"); + } + else { + f.should.equal("envTest\r\n"); + } + done(); + } + catch (e) { + done(e); + } + }); + + n1.receive({payload:"envTest"}); + }); + }); it('should be able to delete the file', function(done) { var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":"delete", wires: [["helperNode1"]]},