@node-red/nodes 2.2.2 → 3.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/99-sample.html.demo +1 -1
- package/core/common/05-junction.html +5 -0
- package/core/common/05-junction.js +12 -0
- package/core/common/20-inject.html +25 -13
- package/core/common/20-inject.js +3 -2
- package/core/common/21-debug.html +58 -5
- package/core/common/21-debug.js +57 -27
- package/core/common/60-link.html +65 -29
- package/core/common/60-link.js +169 -20
- package/core/common/lib/debug/debug-utils.js +34 -1
- package/core/function/10-function.html +58 -22
- package/core/function/10-switch.html +19 -12
- package/core/function/10-switch.js +1 -0
- package/core/function/15-change.html +40 -12
- package/core/function/16-range.html +14 -5
- package/core/function/80-template.html +16 -12
- package/core/function/89-delay.html +46 -6
- package/core/function/89-trigger.html +12 -4
- package/core/function/rbe.html +7 -3
- package/core/network/05-tls.html +10 -4
- package/core/network/06-httpproxy.html +10 -1
- package/core/network/10-mqtt.html +73 -17
- package/core/network/10-mqtt.js +239 -91
- package/core/network/21-httpin.html +10 -6
- package/core/network/21-httprequest.html +219 -12
- package/core/network/21-httprequest.js +98 -17
- package/core/network/22-websocket.html +19 -5
- package/core/network/22-websocket.js +16 -13
- package/core/network/31-tcpin.html +47 -10
- package/core/network/31-tcpin.js +23 -20
- package/core/network/32-udp.html +14 -2
- package/core/parsers/70-CSV.html +4 -1
- package/core/parsers/70-JSON.html +3 -2
- package/core/parsers/70-XML.html +2 -1
- package/core/parsers/70-YAML.html +2 -1
- package/core/sequence/17-split.html +6 -2
- package/core/sequence/19-batch.html +28 -4
- package/core/storage/10-file.html +66 -6
- package/core/storage/10-file.js +46 -3
- package/core/storage/23-watch.html +2 -1
- package/core/storage/23-watch.js +21 -43
- package/locales/de/messages.json +1 -0
- package/locales/en-US/common/60-link.html +19 -3
- package/locales/en-US/messages.json +136 -83
- package/locales/en-US/network/21-httprequest.html +1 -1
- package/locales/en-US/storage/10-file.html +6 -2
- package/locales/ja/common/60-link.html +13 -0
- package/locales/ja/messages.json +85 -32
- package/locales/ja/network/21-httprequest.html +1 -1
- package/locales/ja/storage/10-file.html +8 -6
- package/locales/ko/messages.json +1 -0
- package/locales/ru/messages.json +1 -0
- package/locales/zh-CN/messages.json +1 -0
- package/locales/zh-TW/messages.json +1 -0
- package/package.json +13 -13
|
@@ -50,7 +50,8 @@
|
|
|
50
50
|
</div>
|
|
51
51
|
|
|
52
52
|
<div id="node-row-newline" class="form-row hidden" style="padding-left:110px;">
|
|
53
|
-
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;" data-i18n="[placeholder]tcpin.label.optional"
|
|
53
|
+
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;" data-i18n="[placeholder]tcpin.label.optional"><br/>
|
|
54
|
+
<input type="checkbox" id="node-input-trim" style="display:inline-block; width:auto; vertical-align:top;"> <span data-i18n="tcpin.label.reattach"></span>
|
|
54
55
|
</div>
|
|
55
56
|
|
|
56
57
|
<div class="form-row">
|
|
@@ -70,14 +71,27 @@
|
|
|
70
71
|
defaults: {
|
|
71
72
|
name: {value:""},
|
|
72
73
|
server: {value:"server", required:true},
|
|
73
|
-
host: {
|
|
74
|
-
|
|
74
|
+
host: {
|
|
75
|
+
value:"",
|
|
76
|
+
validate:function(v, opt) {
|
|
77
|
+
if ((this.server == "server")||v.length > 0) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
return RED._("node-red:tcpin.errors.invalid-host");
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
port: {
|
|
84
|
+
value:"", required:true,
|
|
85
|
+
label:RED._("node-red:tcpin.label.port"),
|
|
86
|
+
validate:RED.validators.number(false)},
|
|
75
87
|
datamode:{value:"stream"},
|
|
76
88
|
datatype:{value:"buffer"},
|
|
77
89
|
newline:{value:""},
|
|
78
90
|
topic: {value:""},
|
|
91
|
+
trim: {value:false},
|
|
79
92
|
base64: {/*deprecated*/ value:false, required:true},
|
|
80
|
-
tls: {type:"tls-config", value:'', required:false
|
|
93
|
+
tls: {type:"tls-config", value:'', required:false,
|
|
94
|
+
label:RED._("node-red:httpin.tls-config") }
|
|
81
95
|
},
|
|
82
96
|
inputs:0,
|
|
83
97
|
outputs:1,
|
|
@@ -186,12 +200,29 @@
|
|
|
186
200
|
color: "Silver",
|
|
187
201
|
defaults: {
|
|
188
202
|
name: {value:""},
|
|
189
|
-
host: {
|
|
190
|
-
|
|
203
|
+
host: {
|
|
204
|
+
value:"",
|
|
205
|
+
validate:function(v, opt) {
|
|
206
|
+
if ((this.beserver != "client")||v.length > 0) {
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
return RED._("node-red:tcpin.errors.invalid-host");
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
port: {
|
|
213
|
+
value:"",
|
|
214
|
+
validate:function(v) {
|
|
215
|
+
if ((this.beserver == "reply")||RED.validators.number()(v)) {
|
|
216
|
+
return true;
|
|
217
|
+
}
|
|
218
|
+
return RED._("node-red:tcpin.errors.invalid-port");
|
|
219
|
+
}
|
|
220
|
+
},
|
|
191
221
|
beserver: {value:"client", required:true},
|
|
192
222
|
base64: {value:false, required:true},
|
|
193
223
|
end: {value:false, required:true},
|
|
194
|
-
tls: {type:"tls-config", value:'', required:false
|
|
224
|
+
tls: {type:"tls-config", value:'', required:false,
|
|
225
|
+
label:RED._("node-red:httpin.tls-config") }
|
|
195
226
|
},
|
|
196
227
|
inputs:1,
|
|
197
228
|
outputs:0,
|
|
@@ -286,7 +317,8 @@
|
|
|
286
317
|
<span id="node-units"></span>
|
|
287
318
|
</div>
|
|
288
319
|
<div id="node-row-newline" class="form-row hidden" style="padding-left:162px;">
|
|
289
|
-
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;" data-i18n="[placeholder]tcpin.label.optional"
|
|
320
|
+
<span data-i18n="tcpin.label.delimited"></span> <input type="text" id="node-input-newline" style="width:110px;" data-i18n="[placeholder]tcpin.label.optional"><br/>
|
|
321
|
+
<input type="checkbox" id="node-input-trim" style="display:inline-block; width:auto; vertical-align:top;"> <span data-i18n="tcpin.label.reattach"></span>
|
|
290
322
|
</div>
|
|
291
323
|
<div class="form-row">
|
|
292
324
|
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
|
@@ -301,12 +333,17 @@
|
|
|
301
333
|
defaults: {
|
|
302
334
|
name: {value:""},
|
|
303
335
|
server: {value:""},
|
|
304
|
-
port: {
|
|
336
|
+
port: {
|
|
337
|
+
value:"",
|
|
338
|
+
label: RED._("node-red:tcpin.label.port"),
|
|
339
|
+
validate:RED.validators.regex(/^(\d*|)$/)
|
|
340
|
+
},
|
|
305
341
|
out: {value:"time", required:true},
|
|
306
342
|
ret: {value:"buffer"},
|
|
307
343
|
splitc: {value:"0", required:true},
|
|
308
344
|
newline: {value:""},
|
|
309
|
-
|
|
345
|
+
trim: {value:false},
|
|
346
|
+
tls: {type:"tls-config", value:'', required:false, label:RED._("node-red:httpin.tls-config")}
|
|
310
347
|
},
|
|
311
348
|
inputs:1,
|
|
312
349
|
outputs:1,
|
package/core/network/31-tcpin.js
CHANGED
|
@@ -88,6 +88,7 @@ module.exports = function(RED) {
|
|
|
88
88
|
this.datatype = n.datatype||'buffer'; /* buffer,utf8,base64 */
|
|
89
89
|
this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r").replace("\\t","\t");
|
|
90
90
|
this.base64 = n.base64;
|
|
91
|
+
this.trim = n.trim || false;
|
|
91
92
|
this.server = (typeof n.server == 'boolean')?n.server:(n.server == "server");
|
|
92
93
|
this.closing = false;
|
|
93
94
|
this.connected = false;
|
|
@@ -135,7 +136,8 @@ module.exports = function(RED) {
|
|
|
135
136
|
buffer = buffer+data;
|
|
136
137
|
var parts = buffer.split(node.newline);
|
|
137
138
|
for (var i = 0; i<parts.length-1; i+=1) {
|
|
138
|
-
msg = {topic:node.topic, payload:parts[i]
|
|
139
|
+
msg = {topic:node.topic, payload:parts[i]};
|
|
140
|
+
if (node.trim == true) { msg.payload += node.newline; }
|
|
139
141
|
msg._session = {type:"tcp",id:id};
|
|
140
142
|
node.send(msg);
|
|
141
143
|
}
|
|
@@ -229,7 +231,8 @@ module.exports = function(RED) {
|
|
|
229
231
|
buffer = buffer+data;
|
|
230
232
|
var parts = buffer.split(node.newline);
|
|
231
233
|
for (var i = 0; i<parts.length-1; i+=1) {
|
|
232
|
-
msg = {topic:node.topic, payload:parts[i]
|
|
234
|
+
msg = {topic:node.topic, payload:parts[i], ip:socket.remoteAddress, port:socket.remotePort};
|
|
235
|
+
if (node.trim == true) { msg.payload += node.newline; }
|
|
233
236
|
msg._session = {type:"tcp",id:id};
|
|
234
237
|
node.send(msg);
|
|
235
238
|
}
|
|
@@ -432,7 +435,7 @@ module.exports = function(RED) {
|
|
|
432
435
|
});
|
|
433
436
|
}
|
|
434
437
|
else {
|
|
435
|
-
|
|
438
|
+
const connectedSockets = new Set();
|
|
436
439
|
node.status({text:RED._("tcpin.status.connections",{count:0})});
|
|
437
440
|
let srv = net;
|
|
438
441
|
let connOpts;
|
|
@@ -453,16 +456,16 @@ module.exports = function(RED) {
|
|
|
453
456
|
});
|
|
454
457
|
socket.on('close',function() {
|
|
455
458
|
node.log(RED._("tcpin.status.connection-closed",{host:socket.remoteAddress, port:socket.remotePort}));
|
|
456
|
-
connectedSockets.
|
|
457
|
-
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.
|
|
459
|
+
connectedSockets.delete(socket);
|
|
460
|
+
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.size})});
|
|
458
461
|
});
|
|
459
462
|
socket.on('error',function() {
|
|
460
463
|
node.log(RED._("tcpin.errors.socket-error",{host:socket.remoteAddress, port:socket.remotePort}));
|
|
461
|
-
connectedSockets.
|
|
462
|
-
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.
|
|
464
|
+
connectedSockets.delete(socket);
|
|
465
|
+
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.size})});
|
|
463
466
|
});
|
|
464
|
-
connectedSockets.
|
|
465
|
-
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.
|
|
467
|
+
connectedSockets.add(socket);
|
|
468
|
+
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.size})});
|
|
466
469
|
});
|
|
467
470
|
|
|
468
471
|
node.on("input", function(msg, nodeSend, nodeDone) {
|
|
@@ -475,10 +478,10 @@ module.exports = function(RED) {
|
|
|
475
478
|
} else {
|
|
476
479
|
buffer = Buffer.from(""+msg.payload);
|
|
477
480
|
}
|
|
478
|
-
|
|
479
|
-
if (node.doend === true) {
|
|
480
|
-
else {
|
|
481
|
-
}
|
|
481
|
+
connectedSockets.forEach(soc => {
|
|
482
|
+
if (node.doend === true) { soc.end(buffer); }
|
|
483
|
+
else { soc.write(buffer); }
|
|
484
|
+
})
|
|
482
485
|
}
|
|
483
486
|
nodeDone();
|
|
484
487
|
});
|
|
@@ -495,12 +498,10 @@ module.exports = function(RED) {
|
|
|
495
498
|
} else {
|
|
496
499
|
node.log(RED._("tcpin.status.listening-port",{port:node.port}));
|
|
497
500
|
node.on('close', function() {
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
}
|
|
503
|
-
}
|
|
501
|
+
connectedSockets.forEach(soc => {
|
|
502
|
+
soc.end();
|
|
503
|
+
soc.unref();
|
|
504
|
+
})
|
|
504
505
|
server.close();
|
|
505
506
|
node.log(RED._("tcpin.status.stopped-listening",{port:node.port}));
|
|
506
507
|
});
|
|
@@ -518,6 +519,7 @@ module.exports = function(RED) {
|
|
|
518
519
|
this.out = n.out;
|
|
519
520
|
this.ret = n.ret || "buffer";
|
|
520
521
|
this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r").replace("\\t","\t");
|
|
522
|
+
this.trim = n.trim || false;
|
|
521
523
|
this.splitc = n.splitc;
|
|
522
524
|
if (n.tls) {
|
|
523
525
|
var tlsNode = RED.nodes.getNode(n.tls);
|
|
@@ -653,7 +655,8 @@ module.exports = function(RED) {
|
|
|
653
655
|
let parts = chunk.split(node.newline);
|
|
654
656
|
for (var p=0; p<parts.length-1; p+=1) {
|
|
655
657
|
let m = RED.util.cloneMessage(msg);
|
|
656
|
-
m.payload = parts[p]
|
|
658
|
+
m.payload = parts[p];
|
|
659
|
+
if (node.trim == true) { m.payload += node.newline; }
|
|
657
660
|
nodeSend(m);
|
|
658
661
|
}
|
|
659
662
|
chunk = parts[parts.length-1];
|
package/core/network/32-udp.html
CHANGED
|
@@ -62,10 +62,22 @@
|
|
|
62
62
|
defaults: {
|
|
63
63
|
name: {value:""},
|
|
64
64
|
iface: {value:""},
|
|
65
|
-
port: {
|
|
65
|
+
port: {
|
|
66
|
+
value:"", required:true,
|
|
67
|
+
label:RED._("node-red:udp.label.port"),
|
|
68
|
+
validate:RED.validators.number(false)
|
|
69
|
+
},
|
|
66
70
|
ipv: {value:"udp4"},
|
|
67
71
|
multicast: {value:"false"},
|
|
68
|
-
group: {
|
|
72
|
+
group: {
|
|
73
|
+
value:"",
|
|
74
|
+
validate:function(v,opt) {
|
|
75
|
+
if ((this.multicast !== "true")||v.length > 0) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
return RED._("node-red:udp.errors.invalid-group");
|
|
79
|
+
}
|
|
80
|
+
},
|
|
69
81
|
datatype: {value:"buffer",required:true}
|
|
70
82
|
},
|
|
71
83
|
inputs:0,
|
package/core/parsers/70-CSV.html
CHANGED
|
@@ -75,7 +75,10 @@
|
|
|
75
75
|
color:"#DEBD5C",
|
|
76
76
|
defaults: {
|
|
77
77
|
name: {value:""},
|
|
78
|
-
sep: {
|
|
78
|
+
sep: {
|
|
79
|
+
value:',', required:true,
|
|
80
|
+
label:RED._("node-red:csv.label.separator"),
|
|
81
|
+
validate:RED.validators.regex(/^.{1,2}$/)},
|
|
79
82
|
//quo: {value:'"',required:true},
|
|
80
83
|
hdrin: {value:""},
|
|
81
84
|
hdrout: {value:"none"},
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<label style="width:100%;"><span data-i18n="json.label.o2j"></span></label>
|
|
22
22
|
</div>
|
|
23
23
|
<div class="form-row node-json-to-json-options" style="padding-left: 20px;">
|
|
24
|
-
<input style="width:20px; vertical-align:top; margin-right: 5px;" type="checkbox" id="node-input-pretty"><label style="width: auto;" for="node-input-pretty" data-i18n="json.label.pretty"></
|
|
24
|
+
<input style="width:20px; vertical-align:top; margin-right: 5px;" type="checkbox" id="node-input-pretty"><label style="width: auto;" for="node-input-pretty" data-i18n="json.label.pretty"></label>
|
|
25
25
|
</div>
|
|
26
26
|
</script>
|
|
27
27
|
|
|
@@ -31,7 +31,8 @@
|
|
|
31
31
|
color:"#DEBD5C",
|
|
32
32
|
defaults: {
|
|
33
33
|
name: {value:""},
|
|
34
|
-
property: {value:"payload",required:true
|
|
34
|
+
property: {value:"payload",required:true,
|
|
35
|
+
label:RED._("node-red:json.label.property")},
|
|
35
36
|
action: {value:""},
|
|
36
37
|
pretty: {value:false}
|
|
37
38
|
},
|
package/core/parsers/70-XML.html
CHANGED
|
@@ -202,7 +202,11 @@
|
|
|
202
202
|
name: {value:""},
|
|
203
203
|
mode: {value:"auto"},
|
|
204
204
|
build: { value:"object"},
|
|
205
|
-
property: {
|
|
205
|
+
property: {
|
|
206
|
+
value:"payload",
|
|
207
|
+
label: RED._("node-red:join.message-prop"),
|
|
208
|
+
validate:RED.validators.typedInput("propertyType", false)
|
|
209
|
+
},
|
|
206
210
|
propertyType: { value:"msg"},
|
|
207
211
|
key: {value:"topic"},
|
|
208
212
|
joiner: { value:"\\n"},
|
|
@@ -243,7 +247,7 @@
|
|
|
243
247
|
var jsonata_or_empty = {
|
|
244
248
|
value: "jsonata",
|
|
245
249
|
label: "expression",
|
|
246
|
-
icon: "red/images/typedInput/expr.
|
|
250
|
+
icon: "red/images/typedInput/expr.svg",
|
|
247
251
|
validate: function(v) {
|
|
248
252
|
try{
|
|
249
253
|
if(v !== "") {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
<div class="form-row">
|
|
48
48
|
<input type="checkbox" id="node-input-allowEmptySequence" style="margin-left:20px; margin-right: 10px; vertical-align:top; width:auto;">
|
|
49
49
|
<label for="node-input-allowEmptySequence" style="width:auto;" data-i18n="batch.interval.empty"></label>
|
|
50
|
-
|
|
50
|
+
</div>
|
|
51
51
|
</div>
|
|
52
52
|
|
|
53
53
|
<div class="node-row-msg-concat">
|
|
@@ -73,9 +73,33 @@
|
|
|
73
73
|
defaults: {
|
|
74
74
|
name: {value:""},
|
|
75
75
|
mode: {value:"count"},
|
|
76
|
-
count: {
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
count: {
|
|
77
|
+
value:10,
|
|
78
|
+
validate:function(v, opt) {
|
|
79
|
+
if (RED.validators.number(v) && (v >= 1)) {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
return RED._("node-red:batch.error.invalid-count");
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
overlap: {
|
|
86
|
+
value:0,
|
|
87
|
+
validate:function(v, opt) {
|
|
88
|
+
if (RED.validators.number(v) && (v >= 0)) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
return RED._("node-red:batch.error.invalid-overlap");
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
interval: {
|
|
95
|
+
value:10,
|
|
96
|
+
validate:function(v, opt) {
|
|
97
|
+
if (RED.validators.number(v) && (v >= 1)) {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
return RED._("node-red:batch.error.invalid-interval");
|
|
101
|
+
}
|
|
102
|
+
},
|
|
79
103
|
allowEmptySequence: {value:false},
|
|
80
104
|
topics: {value:[{topic:""}]}
|
|
81
105
|
},
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
<div class="form-row node-input-filename">
|
|
4
4
|
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="file.label.filename"></span></label>
|
|
5
5
|
<input id="node-input-filename" type="text">
|
|
6
|
+
<input type="hidden" id="node-input-filenameType">
|
|
6
7
|
</div>
|
|
7
8
|
<div class="form-row">
|
|
8
9
|
<label for="node-input-overwriteFile"><i class="fa fa-random"></i> <span data-i18n="file.label.action"></span></label>
|
|
@@ -29,7 +30,7 @@
|
|
|
29
30
|
</div>
|
|
30
31
|
<div class="form-row">
|
|
31
32
|
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
|
32
|
-
<input type="text" id="node-input-name"
|
|
33
|
+
<input type="text" id="node-input-name">
|
|
33
34
|
</div>
|
|
34
35
|
<div class="form-tips"><span data-i18n="file.tip"></span></div>
|
|
35
36
|
</script>
|
|
@@ -37,7 +38,8 @@
|
|
|
37
38
|
<script type="text/html" data-template-name="file in">
|
|
38
39
|
<div class="form-row">
|
|
39
40
|
<label for="node-input-filename"><i class="fa fa-file"></i> <span data-i18n="file.label.filename"></span></label>
|
|
40
|
-
<input id="node-input-filename" type="text"
|
|
41
|
+
<input id="node-input-filename" type="text">
|
|
42
|
+
<input type="hidden" id="node-input-filenameType">
|
|
41
43
|
</div>
|
|
42
44
|
<div class="form-row">
|
|
43
45
|
<label for="node-input-format"><i class="fa fa-sign-out"></i> <span data-i18n="file.label.outputas"></span></label>
|
|
@@ -60,7 +62,7 @@
|
|
|
60
62
|
</div>
|
|
61
63
|
<div class="form-row">
|
|
62
64
|
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
|
|
63
|
-
<input type="text" id="node-input-name"
|
|
65
|
+
<input type="text" id="node-input-name">
|
|
64
66
|
</div>
|
|
65
67
|
<div class="form-tips"><span data-i18n="file.tip"></span></div>
|
|
66
68
|
</script>
|
|
@@ -197,6 +199,7 @@
|
|
|
197
199
|
defaults: {
|
|
198
200
|
name: {value:""},
|
|
199
201
|
filename: {value:""},
|
|
202
|
+
filenameType: {value:"str"},
|
|
200
203
|
appendNewline: {value:true},
|
|
201
204
|
createDir: {value:false},
|
|
202
205
|
overwriteFile: {value:"false"},
|
|
@@ -207,10 +210,13 @@
|
|
|
207
210
|
outputs:1,
|
|
208
211
|
icon: "file-out.svg",
|
|
209
212
|
label: function() {
|
|
213
|
+
var fn = this.filename;
|
|
214
|
+
if(this.filenameType != "str" && this.filenameType != "env" ) { fn = ""; }
|
|
215
|
+
if(this.filenameType === "env") { fn = "env."+fn; }
|
|
210
216
|
if (this.overwriteFile === "delete") {
|
|
211
|
-
return this.name||this._("file.label.deletelabel",{file:
|
|
217
|
+
return this.name||this._("file.label.deletelabel",{file:fn});
|
|
212
218
|
} else {
|
|
213
|
-
return this.name||
|
|
219
|
+
return this.name||fn||this._("file.label.write");
|
|
214
220
|
}
|
|
215
221
|
},
|
|
216
222
|
paletteLabel: RED._("node-red:file.label.write"),
|
|
@@ -229,6 +235,31 @@
|
|
|
229
235
|
value: "setbymsg",
|
|
230
236
|
label: node._("file.encoding.setbymsg")
|
|
231
237
|
}).text(label).appendTo(encSel);
|
|
238
|
+
$("#node-input-filename").typedInput({
|
|
239
|
+
default: "str",
|
|
240
|
+
types: [{label:RED._("node-red:file.label.path"), value:"str", icon:""}, "msg", "jsonata", "env"],
|
|
241
|
+
typeField: $("#node-input-filenameType")
|
|
242
|
+
});
|
|
243
|
+
if(typeof node.filenameType == 'undefined') {
|
|
244
|
+
//existing node AND filenameType is not set - inplace (compatible) upgrade to new typedInput
|
|
245
|
+
if(node.filename == "") { //was using empty value to denote msg.filename - set typedInput to match
|
|
246
|
+
node.filename = "filename";
|
|
247
|
+
node.filenameType = "msg";
|
|
248
|
+
$("#node-input-filename").typedInput("type", node.filenameType);
|
|
249
|
+
$("#node-input-filename").typedInput("value", node.filename);
|
|
250
|
+
} else if(/^\${[^}]+}$/.test(node.filename)) { //was using an ${ENV_VAR}
|
|
251
|
+
node.filenameType = "env";
|
|
252
|
+
node.filename = node.filename.replace(/\${([^}]+)}/g, function(match, name) {
|
|
253
|
+
return (name === undefined)?"":name;
|
|
254
|
+
});
|
|
255
|
+
$("#node-input-filename").typedInput("type", node.filenameType);
|
|
256
|
+
$("#node-input-filename").typedInput("value", node.filename);
|
|
257
|
+
} else { //was using a static filename - set typedInput type to str
|
|
258
|
+
node.filenameType = "str";
|
|
259
|
+
$("#node-input-filename").typedInput("type", node.filenameType);
|
|
260
|
+
$("#node-input-filename").typedInput("value", node.filename);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
232
263
|
encodings.forEach(function(item) {
|
|
233
264
|
if(Array.isArray(item)) {
|
|
234
265
|
var group = $("<optgroup/>", {
|
|
@@ -267,6 +298,7 @@
|
|
|
267
298
|
defaults: {
|
|
268
299
|
name: {value:""},
|
|
269
300
|
filename: {value:""},
|
|
301
|
+
filenameType: {value:"str"},
|
|
270
302
|
format: {value:"utf8"},
|
|
271
303
|
chunk: {value:false},
|
|
272
304
|
sendError: {value: false},
|
|
@@ -291,7 +323,10 @@
|
|
|
291
323
|
},
|
|
292
324
|
icon: "file-in.svg",
|
|
293
325
|
label: function() {
|
|
294
|
-
|
|
326
|
+
var fn = this.filename;
|
|
327
|
+
if(this.filenameType != "str" && this.filenameType != "env" ) { fn = ""; }
|
|
328
|
+
if(this.filenameType === "env") { fn = "env."+fn; }
|
|
329
|
+
return this.name||fn||this._("file.label.read");
|
|
295
330
|
},
|
|
296
331
|
paletteLabel: RED._("node-red:file.label.read"),
|
|
297
332
|
labelStyle: function() {
|
|
@@ -305,6 +340,31 @@
|
|
|
305
340
|
value: "none",
|
|
306
341
|
label: label
|
|
307
342
|
}).text(label).appendTo(encSel);
|
|
343
|
+
$("#node-input-filename").typedInput({
|
|
344
|
+
default: "str",
|
|
345
|
+
types: [{label:RED._("node-red:file.label.path"), value:"str", icon:""}, "msg", "jsonata", "env"],
|
|
346
|
+
typeField: $("#node-input-filenameType")
|
|
347
|
+
});
|
|
348
|
+
if(typeof node.filenameType == 'undefined') {
|
|
349
|
+
//existing node AND filenameType is not set - inplace (compatible) upgrade to new typedInput
|
|
350
|
+
if(node.filename == "") { //was using empty value to denote msg.filename - set typedInput to match
|
|
351
|
+
node.filename = "filename";
|
|
352
|
+
node.filenameType = "msg";
|
|
353
|
+
$("#node-input-filename").typedInput("type", node.filenameType);
|
|
354
|
+
$("#node-input-filename").typedInput("value", node.filename);
|
|
355
|
+
} else if(/^\${[^}]+}$/.test(node.filename)) { //was using an ${ENV_VAR}
|
|
356
|
+
node.filenameType = "env";
|
|
357
|
+
node.filename = node.filename.replace(/\${([^}]+)}/g, function(match, name) {
|
|
358
|
+
return (name === undefined)?"":name;
|
|
359
|
+
});
|
|
360
|
+
$("#node-input-filename").typedInput("type", node.filenameType);
|
|
361
|
+
$("#node-input-filename").typedInput("value", node.filename);
|
|
362
|
+
} else { //was using a static filename - set typedInput type to str
|
|
363
|
+
node.filenameType = "str";
|
|
364
|
+
$("#node-input-filename").typedInput("type", node.filenameType);
|
|
365
|
+
$("#node-input-filename").typedInput("value", node.filename);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
308
368
|
encodings.forEach(function(item) {
|
|
309
369
|
if(Array.isArray(item)) {
|
|
310
370
|
var group = $("<optgroup/>", {
|
package/core/storage/10-file.js
CHANGED
|
@@ -39,6 +39,7 @@ module.exports = function(RED) {
|
|
|
39
39
|
// Write/delete a file
|
|
40
40
|
RED.nodes.createNode(this,n);
|
|
41
41
|
this.filename = n.filename;
|
|
42
|
+
this.filenameType = n.filenameType;
|
|
42
43
|
this.appendNewline = n.appendNewline;
|
|
43
44
|
this.overwriteFile = n.overwriteFile.toString();
|
|
44
45
|
this.createDir = n.createDir || false;
|
|
@@ -50,7 +51,28 @@ module.exports = function(RED) {
|
|
|
50
51
|
node.closeCallback = null;
|
|
51
52
|
|
|
52
53
|
function processMsg(msg,nodeSend, done) {
|
|
53
|
-
var filename = node.filename ||
|
|
54
|
+
var filename = node.filename || "";
|
|
55
|
+
//Pre V3 compatibility - if filenameType is empty, do in place upgrade
|
|
56
|
+
if(typeof node.filenameType == 'undefined' || node.filenameType == "") {
|
|
57
|
+
//existing node AND filenameType is not set - inplace (compatible) upgrade
|
|
58
|
+
if(filename == "") { //was using empty value to denote msg.filename
|
|
59
|
+
node.filename = "filename";
|
|
60
|
+
node.filenameType = "msg";
|
|
61
|
+
} else { //was using a static filename - set typedInput type to str
|
|
62
|
+
node.filenameType = "str";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
RED.util.evaluateNodeProperty(node.filename,node.filenameType,node,msg,(err,value) => {
|
|
67
|
+
if (err) {
|
|
68
|
+
node.error(err,msg);
|
|
69
|
+
return done();
|
|
70
|
+
} else {
|
|
71
|
+
filename = value;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
filename = filename || "";
|
|
75
|
+
msg.filename = filename;
|
|
54
76
|
var fullFilename = filename;
|
|
55
77
|
if (filename && RED.settings.fileWorkingDirectory && !path.isAbsolute(filename)) {
|
|
56
78
|
fullFilename = path.resolve(path.join(RED.settings.fileWorkingDirectory,filename));
|
|
@@ -158,7 +180,7 @@ module.exports = function(RED) {
|
|
|
158
180
|
done();
|
|
159
181
|
});
|
|
160
182
|
}
|
|
161
|
-
if (node.
|
|
183
|
+
if (node.filenameType === "str" || node.filenameType === "env") {
|
|
162
184
|
// Static filename - write and reuse the stream next time
|
|
163
185
|
node.wstream.write(buf, function() {
|
|
164
186
|
nodeSend(msg);
|
|
@@ -256,6 +278,7 @@ module.exports = function(RED) {
|
|
|
256
278
|
// Read a file
|
|
257
279
|
RED.nodes.createNode(this,n);
|
|
258
280
|
this.filename = n.filename;
|
|
281
|
+
this.filenameType = n.filenameType;
|
|
259
282
|
this.format = n.format;
|
|
260
283
|
this.chunk = false;
|
|
261
284
|
this.encoding = n.encoding || "none";
|
|
@@ -270,8 +293,28 @@ module.exports = function(RED) {
|
|
|
270
293
|
var node = this;
|
|
271
294
|
|
|
272
295
|
this.on("input",function(msg, nodeSend, nodeDone) {
|
|
273
|
-
var filename =
|
|
296
|
+
var filename = node.filename || "";
|
|
297
|
+
//Pre V3 compatibility - if filenameType is empty, do in place upgrade
|
|
298
|
+
if(typeof node.filenameType == 'undefined' || node.filenameType == "") {
|
|
299
|
+
//existing node AND filenameType is not set - inplace (compatible) upgrade
|
|
300
|
+
if(filename == "") { //was using empty value to denote msg.filename
|
|
301
|
+
node.filename = "filename";
|
|
302
|
+
node.filenameType = "msg";
|
|
303
|
+
} else { //was using a static filename - set typedInput type to str
|
|
304
|
+
node.filenameType = "str";
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
RED.util.evaluateNodeProperty(node.filename,node.filenameType,node,msg,(err,value) => {
|
|
308
|
+
if (err) {
|
|
309
|
+
node.error(err,msg);
|
|
310
|
+
return done();
|
|
311
|
+
} else {
|
|
312
|
+
filename = (value || "").replace(/\t|\r|\n/g,'');
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
filename = filename || "";
|
|
274
316
|
var fullFilename = filename;
|
|
317
|
+
var filePath = "";
|
|
275
318
|
if (filename && RED.settings.fileWorkingDirectory && !path.isAbsolute(filename)) {
|
|
276
319
|
fullFilename = path.resolve(path.join(RED.settings.fileWorkingDirectory,filename));
|
|
277
320
|
}
|