@node-red/nodes 3.0.0-beta.2 → 3.0.0
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/core/common/20-inject.html +1 -1
- package/core/common/20-inject.js +3 -2
- package/core/common/21-debug.html +15 -22
- package/core/common/60-link.html +1 -1
- package/core/common/60-link.js +43 -46
- package/core/common/lib/debug/debug-utils.js +30 -22
- package/core/function/10-function.html +6 -6
- package/core/function/15-change.js +2 -2
- package/core/function/80-template.js +24 -0
- package/core/function/89-delay.js +13 -9
- package/core/network/10-mqtt.js +1 -1
- package/core/network/22-websocket.js +1 -0
- package/core/network/31-tcpin.js +15 -17
- package/core/parsers/70-CSV.js +5 -2
- package/core/sequence/17-split.js +4 -2
- package/core/storage/10-file.html +8 -8
- package/examples/function/delay/06 - Simple Queue with release +149 -0
- package/locales/en-US/messages.json +108 -108
- package/locales/ja/function/10-function.html +1 -1
- package/locales/ja/messages.json +4 -2
- package/locales/ja/network/10-mqtt.html +1 -1
- package/package.json +3 -3
package/core/common/20-inject.js
CHANGED
|
@@ -109,9 +109,10 @@ module.exports = function(RED) {
|
|
|
109
109
|
if (!property) return;
|
|
110
110
|
|
|
111
111
|
if (valueType === "jsonata") {
|
|
112
|
-
if (p.
|
|
112
|
+
if (p.v) {
|
|
113
113
|
try {
|
|
114
|
-
var
|
|
114
|
+
var exp = RED.util.prepareJSONataExpression(p.v, node);
|
|
115
|
+
var val = RED.util.evaluateJSONataExpression(exp, msg);
|
|
115
116
|
RED.util.setMessageProperty(msg, property, val, true);
|
|
116
117
|
}
|
|
117
118
|
catch (err) {
|
|
@@ -245,44 +245,37 @@
|
|
|
245
245
|
// complete parentage of the node that generated this message.
|
|
246
246
|
// flow-id/subflow-A-instance/subflow-B-instance
|
|
247
247
|
|
|
248
|
-
// If it has one id, that is a top level flow
|
|
248
|
+
// If it has one id, that is a top level flow or config node/global
|
|
249
249
|
// each subsequent id is the instance id of a subflow node
|
|
250
250
|
//
|
|
251
251
|
pathParts = o.path.split("/");
|
|
252
252
|
if (pathParts.length === 1) {
|
|
253
|
-
// The source node is on a flow - so can use its id to find
|
|
253
|
+
// The source node is on a flow or is a global/config - so can use its id to find
|
|
254
254
|
sourceNode = RED.nodes.node(o.id);
|
|
255
255
|
} else if (pathParts.length > 1) {
|
|
256
256
|
// Highlight the subflow instance node.
|
|
257
257
|
sourceNode = RED.nodes.node(pathParts[1]);
|
|
258
258
|
}
|
|
259
|
+
const getNodeLabel = (n) => n.name || (typeof n.label === "function" && n.label()) || (typeof n.label === "string" && n.label) || (n.type + ":" + n.id);
|
|
259
260
|
pathHierarchy = pathParts.map((id,index) => {
|
|
260
261
|
if (index === 0) {
|
|
261
|
-
|
|
262
|
-
id: id,
|
|
263
|
-
|
|
264
|
-
}
|
|
262
|
+
if (id === "global") {
|
|
263
|
+
return { id: sourceNode.id, label: getNodeLabel(sourceNode) }
|
|
264
|
+
}
|
|
265
|
+
return { id: id, label: RED.nodes.workspace(id).label } //flow id + name
|
|
265
266
|
} else {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
label: (instanceNode.name || RED.nodes.subflow(instanceNode.type.substring(8)).name)
|
|
270
|
-
}
|
|
267
|
+
const instanceNode = RED.nodes.node(id)
|
|
268
|
+
const pathLabel = (instanceNode.name || RED.nodes.subflow(instanceNode.type.substring(8)).name)
|
|
269
|
+
return { id: id, label: pathLabel }
|
|
271
270
|
}
|
|
272
271
|
})
|
|
273
|
-
if (pathParts.length === 1) {
|
|
274
|
-
pathHierarchy.push({
|
|
275
|
-
id: o.id,
|
|
276
|
-
label: sourceNode.name || sourceNode.type+":"+sourceNode.id
|
|
277
|
-
})
|
|
272
|
+
if (pathParts.length === 1 && pathParts[0] !== "global") {
|
|
273
|
+
pathHierarchy.push({ id: o.id, label: getNodeLabel(sourceNode) })
|
|
278
274
|
}
|
|
279
275
|
if (o._alias) {
|
|
280
276
|
let aliasNode = RED.nodes.node(o._alias)
|
|
281
277
|
if (aliasNode) {
|
|
282
|
-
pathHierarchy.push({
|
|
283
|
-
id: o._alias,
|
|
284
|
-
label: aliasNode.name || aliasNode.type+":"+aliasNode.id
|
|
285
|
-
})
|
|
278
|
+
pathHierarchy.push({ id: o._alias, label: getNodeLabel(aliasNode) })
|
|
286
279
|
}
|
|
287
280
|
}
|
|
288
281
|
} else {
|
|
@@ -499,7 +492,7 @@
|
|
|
499
492
|
types:['msg', fullType, "jsonata"],
|
|
500
493
|
typeField: $("#node-input-targetType")
|
|
501
494
|
});
|
|
502
|
-
|
|
495
|
+
if (this.targetType === "jsonata") {
|
|
503
496
|
var property = this.complete || "";
|
|
504
497
|
$("#node-input-typed-complete").typedInput('type','jsonata');
|
|
505
498
|
$("#node-input-typed-complete").typedInput('value',property);
|
|
@@ -558,7 +551,7 @@
|
|
|
558
551
|
onadd: function() {
|
|
559
552
|
if (this.name === '_DEFAULT_') {
|
|
560
553
|
this.name = ''
|
|
561
|
-
RED.actions.invoke("core:generate-node-names", this)
|
|
554
|
+
RED.actions.invoke("core:generate-node-names", this, {generateHistory: false})
|
|
562
555
|
}
|
|
563
556
|
}
|
|
564
557
|
});
|
package/core/common/60-link.html
CHANGED
|
@@ -221,7 +221,7 @@
|
|
|
221
221
|
function onAdd() {
|
|
222
222
|
if (this.name === '_DEFAULT_') {
|
|
223
223
|
this.name = ''
|
|
224
|
-
RED.actions.invoke("core:generate-node-names", this)
|
|
224
|
+
RED.actions.invoke("core:generate-node-names", this, {generateHistory: false})
|
|
225
225
|
}
|
|
226
226
|
for (var i=0;i<this.links.length;i++) {
|
|
227
227
|
var n = RED.nodes.node(this.links[i]);
|
package/core/common/60-link.js
CHANGED
|
@@ -29,23 +29,23 @@ module.exports = function(RED) {
|
|
|
29
29
|
"use strict";
|
|
30
30
|
const crypto = require("crypto");
|
|
31
31
|
const targetCache = (function () {
|
|
32
|
-
|
|
33
|
-
function getIndex(/** @type {[LinkTarget]}*/ targets, id) {
|
|
32
|
+
let registry = { id: {}, name: {} }
|
|
33
|
+
function getIndex (/** @type {[LinkTarget]} */ targets, id) {
|
|
34
34
|
for (let index = 0; index < (targets || []).length; index++) {
|
|
35
|
-
const element = targets[index]
|
|
35
|
+
const element = targets[index]
|
|
36
36
|
if (element.id === id) {
|
|
37
|
-
return index
|
|
37
|
+
return index
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
-
return -1
|
|
40
|
+
return -1
|
|
41
41
|
}
|
|
42
42
|
/**
|
|
43
43
|
* Generate a target object from a node
|
|
44
|
-
* @param {LinkInNode} node
|
|
44
|
+
* @param {LinkInNode} node
|
|
45
45
|
* @returns {LinkTarget} a link target object
|
|
46
46
|
*/
|
|
47
|
-
function generateTarget(node) {
|
|
48
|
-
const isSubFlow = node._flow.TYPE ===
|
|
47
|
+
function generateTarget (node) {
|
|
48
|
+
const isSubFlow = node._flow.TYPE === 'subflow'
|
|
49
49
|
return {
|
|
50
50
|
id: node.id,
|
|
51
51
|
name: node.name || node.id,
|
|
@@ -58,75 +58,72 @@ module.exports = function(RED) {
|
|
|
58
58
|
/**
|
|
59
59
|
* Get a list of targets registerd to this name
|
|
60
60
|
* @param {string} name Name of the target
|
|
61
|
-
* @param {boolean} [excludeSubflows] set `true` to exclude
|
|
61
|
+
* @param {boolean} [excludeSubflows] set `true` to exclude
|
|
62
62
|
* @returns {[LinkTarget]} Targets registerd to this name.
|
|
63
63
|
*/
|
|
64
|
-
getTargets(name, excludeSubflows) {
|
|
65
|
-
const targets = registry.name[name] || []
|
|
64
|
+
getTargets (name, excludeSubflows) {
|
|
65
|
+
const targets = registry.name[name] || []
|
|
66
66
|
if (excludeSubflows) {
|
|
67
|
-
return targets.filter(e => e.isSubFlow
|
|
67
|
+
return targets.filter(e => e.isSubFlow !== true)
|
|
68
68
|
}
|
|
69
|
-
return targets
|
|
69
|
+
return targets
|
|
70
70
|
},
|
|
71
71
|
/**
|
|
72
72
|
* Get a single target by registered name.
|
|
73
73
|
* To restrict to a single flow, include the `flowId`
|
|
74
74
|
* If there is no targets OR more than one target, null is returned
|
|
75
75
|
* @param {string} name Name of the node
|
|
76
|
-
* @param {string} [flowId]
|
|
76
|
+
* @param {string} [flowId]
|
|
77
77
|
* @returns {LinkTarget} target
|
|
78
78
|
*/
|
|
79
|
-
getTarget(name, flowId) {
|
|
80
|
-
/** @type {[LinkTarget]}*/
|
|
81
|
-
let possibleTargets = this.getTargets(name)
|
|
82
|
-
/** @type {LinkTarget}*/
|
|
83
|
-
let target
|
|
79
|
+
getTarget (name, flowId) {
|
|
80
|
+
/** @type {[LinkTarget]} */
|
|
81
|
+
let possibleTargets = this.getTargets(name)
|
|
82
|
+
/** @type {LinkTarget} */
|
|
83
|
+
let target
|
|
84
84
|
if (possibleTargets.length && flowId) {
|
|
85
|
-
possibleTargets = possibleTargets.filter(e => e.flowId
|
|
85
|
+
possibleTargets = possibleTargets.filter(e => e.flowId === flowId)
|
|
86
86
|
}
|
|
87
87
|
if (possibleTargets.length === 1) {
|
|
88
|
-
target = possibleTargets[0]
|
|
88
|
+
target = possibleTargets[0]
|
|
89
89
|
}
|
|
90
|
-
return target
|
|
90
|
+
return target
|
|
91
91
|
},
|
|
92
92
|
/**
|
|
93
93
|
* Get a target by node ID
|
|
94
94
|
* @param {string} nodeId ID of the node
|
|
95
95
|
* @returns {LinkTarget} target
|
|
96
96
|
*/
|
|
97
|
-
getTargetById(nodeId) {
|
|
98
|
-
return registry.id[nodeId]
|
|
97
|
+
getTargetById (nodeId) {
|
|
98
|
+
return registry.id[nodeId]
|
|
99
99
|
},
|
|
100
|
-
register(/** @type {LinkInNode} */ node) {
|
|
101
|
-
const target = generateTarget(node)
|
|
102
|
-
const tByName = this.getTarget(target.name, target.flowId)
|
|
100
|
+
register (/** @type {LinkInNode} */ node) {
|
|
101
|
+
const target = generateTarget(node)
|
|
102
|
+
const tByName = this.getTarget(target.name, target.flowId)
|
|
103
103
|
if (!tByName || tByName.id !== target.id) {
|
|
104
|
-
registry.name[target.name] = registry.name[target.name] || []
|
|
104
|
+
registry.name[target.name] = registry.name[target.name] || []
|
|
105
105
|
registry.name[target.name].push(target)
|
|
106
106
|
}
|
|
107
|
-
registry.id[target.id] = target
|
|
108
|
-
return target
|
|
107
|
+
registry.id[target.id] = target
|
|
108
|
+
return target
|
|
109
109
|
},
|
|
110
|
-
remove(node) {
|
|
111
|
-
const target = generateTarget(node)
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
if (targs.length === 0) {
|
|
120
|
-
delete registry.name[tn.name];
|
|
121
|
-
}
|
|
110
|
+
remove (node) {
|
|
111
|
+
const target = generateTarget(node)
|
|
112
|
+
const targs = this.getTargets(target.name)
|
|
113
|
+
const idx = getIndex(targs, target.id)
|
|
114
|
+
if (idx > -1) {
|
|
115
|
+
targs.splice(idx, 1)
|
|
116
|
+
}
|
|
117
|
+
if (targs.length === 0) {
|
|
118
|
+
delete registry.name[target.name]
|
|
122
119
|
}
|
|
123
|
-
delete registry.id[target.id]
|
|
120
|
+
delete registry.id[target.id]
|
|
124
121
|
},
|
|
125
|
-
clear() {
|
|
126
|
-
registry = { id: {}, name: {} }
|
|
122
|
+
clear () {
|
|
123
|
+
registry = { id: {}, name: {} }
|
|
127
124
|
}
|
|
128
125
|
}
|
|
129
|
-
})()
|
|
126
|
+
})()
|
|
130
127
|
|
|
131
128
|
function LinkInNode(n) {
|
|
132
129
|
RED.nodes.createNode(this,n);
|
|
@@ -459,30 +459,38 @@ RED.debug = (function() {
|
|
|
459
459
|
function showMessageMenu(button,dbgMessage,sourceId) {
|
|
460
460
|
activeMenuMessage = dbgMessage;
|
|
461
461
|
if (!menuOptionMenu) {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
462
|
+
var opts = [
|
|
463
|
+
{id:"red-ui-debug-msg-menu-item-collapse",label:RED._("node-red:debug.messageMenu.collapseAll"),onselect:function(){
|
|
464
|
+
activeMenuMessage.collapse();
|
|
465
|
+
}},
|
|
466
|
+
];
|
|
467
|
+
if (activeMenuMessage.clearPinned) {
|
|
468
|
+
opts.push(
|
|
467
469
|
{id:"red-ui-debug-msg-menu-item-clear-pins",label:RED._("node-red:debug.messageMenu.clearPinned"),onselect:function(){
|
|
468
470
|
activeMenuMessage.clearPinned();
|
|
469
471
|
}},
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
opts.push(
|
|
475
|
+
null,
|
|
476
|
+
{id:"red-ui-debug-msg-menu-item-filter", label:RED._("node-red:debug.messageMenu.filterNode"),onselect:function(){
|
|
477
|
+
var candidateNodes = RED.nodes.filterNodes({type:'debug'});
|
|
478
|
+
candidateNodes.forEach(function(n) {
|
|
479
|
+
filteredNodes[n.id] = true;
|
|
480
|
+
});
|
|
481
|
+
delete filteredNodes[sourceId];
|
|
482
|
+
$("#red-ui-sidebar-debug-filterSelected").trigger("click");
|
|
483
|
+
RED.settings.set('debug.filteredNodes',Object.keys(filteredNodes))
|
|
484
|
+
refreshMessageList();
|
|
485
|
+
}},
|
|
486
|
+
{id:"red-ui-debug-msg-menu-item-clear-filter",label:RED._("node-red:debug.messageMenu.clearFilter"),onselect:function(){
|
|
487
|
+
$("#red-ui-sidebar-debug-filterAll").trigger("click");
|
|
488
|
+
refreshMessageList();
|
|
489
|
+
}}
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
menuOptionMenu = RED.menu.init({id:"red-ui-debug-msg-option-menu",
|
|
493
|
+
options: opts
|
|
486
494
|
});
|
|
487
495
|
menuOptionMenu.css({
|
|
488
496
|
position: "absolute"
|
|
@@ -582,7 +590,7 @@ RED.debug = (function() {
|
|
|
582
590
|
$('<span class="red-ui-debug-msg-date">'+ getTimestamp()+'</span>').appendTo(metaRow);
|
|
583
591
|
if (sourceNode) {
|
|
584
592
|
|
|
585
|
-
var nodeLink = $('<a>',{href:"#",class:"red-ui-debug-msg-name"}).text("node: "+(o.name||sourceNode.name||sourceNode.id))
|
|
593
|
+
var nodeLink = $('<a>',{href:"#",class:"red-ui-debug-msg-name"}).text(RED._("node-red:debug.node")+": "+(o.name||sourceNode.name||sourceNode.id))
|
|
586
594
|
.appendTo(metaRow)
|
|
587
595
|
.on("click", function(evt) {
|
|
588
596
|
evt.preventDefault();
|
|
@@ -460,7 +460,7 @@
|
|
|
460
460
|
}
|
|
461
461
|
});
|
|
462
462
|
|
|
463
|
-
var buildEditor = function(id, stateId, focus, value, defaultValue, extraLibs) {
|
|
463
|
+
var buildEditor = function(id, stateId, focus, value, defaultValue, extraLibs, offset) {
|
|
464
464
|
var editor = RED.editor.createEditor({
|
|
465
465
|
id: id,
|
|
466
466
|
mode: 'ace/mode/nrjavascript',
|
|
@@ -484,14 +484,14 @@
|
|
|
484
484
|
extraLibs: extraLibs
|
|
485
485
|
});
|
|
486
486
|
if (defaultValue && value === "") {
|
|
487
|
-
editor.moveCursorTo(defaultValue.split("\n").length
|
|
487
|
+
editor.moveCursorTo(defaultValue.split("\n").length +offset, 0);
|
|
488
488
|
}
|
|
489
489
|
editor.__stateId = stateId;
|
|
490
490
|
return editor;
|
|
491
491
|
}
|
|
492
|
-
this.initEditor = buildEditor('node-input-init-editor', this.id + "/" + "initEditor", false, $("#node-input-initialize").val(), RED._("node-red:function.text.initialize"))
|
|
493
|
-
this.editor = buildEditor('node-input-func-editor', this.id + "/" + "editor", true, $("#node-input-func").val(), undefined, that.libs || [])
|
|
494
|
-
this.finalizeEditor = buildEditor('node-input-finalize-editor', this.id + "/" + "finalizeEditor", false, $("#node-input-finalize").val(), RED._("node-red:function.text.finalize"))
|
|
492
|
+
this.initEditor = buildEditor('node-input-init-editor', this.id + "/" + "initEditor", false, $("#node-input-initialize").val(), RED._("node-red:function.text.initialize"), undefined, 0);
|
|
493
|
+
this.editor = buildEditor('node-input-func-editor', this.id + "/" + "editor", true, $("#node-input-func").val(), undefined, that.libs || [], undefined, -1);
|
|
494
|
+
this.finalizeEditor = buildEditor('node-input-finalize-editor', this.id + "/" + "finalizeEditor", false, $("#node-input-finalize").val(), RED._("node-red:function.text.finalize"), undefined, 0);
|
|
495
495
|
|
|
496
496
|
RED.library.create({
|
|
497
497
|
url:"functions", // where to get the data from
|
|
@@ -639,7 +639,7 @@
|
|
|
639
639
|
onadd: function() {
|
|
640
640
|
if (this.name === '_DEFAULT_') {
|
|
641
641
|
this.name = ''
|
|
642
|
-
RED.actions.invoke("core:generate-node-names", this)
|
|
642
|
+
RED.actions.invoke("core:generate-node-names", this, {generateHistory: false})
|
|
643
643
|
}
|
|
644
644
|
}
|
|
645
645
|
});
|
|
@@ -168,9 +168,9 @@ module.exports = function(RED) {
|
|
|
168
168
|
return getFromValueType(RED.util.getMessageProperty(msg,rule.from),done);
|
|
169
169
|
} else if (rule.fromt === 'flow' || rule.fromt === 'global') {
|
|
170
170
|
var contextKey = RED.util.parseContextStore(rule.from);
|
|
171
|
-
if (/\[msg\./.test(
|
|
171
|
+
if (/\[msg\./.test(contextKey.key)) {
|
|
172
172
|
// The key has a nest msg. reference to evaluate first
|
|
173
|
-
|
|
173
|
+
contextKey.key = RED.util.normalisePropertyExpression(contextKey.key,msg,true);
|
|
174
174
|
}
|
|
175
175
|
node.context()[rule.fromt].get(contextKey.key, contextKey.store, (err,fromValue) => {
|
|
176
176
|
if (err) {
|
|
@@ -44,6 +44,14 @@ module.exports = function(RED) {
|
|
|
44
44
|
return undefined;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
function parseEnv(key) {
|
|
48
|
+
var match = /^env\.(.+)/.exec(key);
|
|
49
|
+
if (match) {
|
|
50
|
+
return match[1];
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
47
55
|
/**
|
|
48
56
|
* Custom Mustache Context capable to collect message property and node
|
|
49
57
|
* flow and global context
|
|
@@ -74,6 +82,11 @@ module.exports = function(RED) {
|
|
|
74
82
|
return value;
|
|
75
83
|
}
|
|
76
84
|
|
|
85
|
+
// try env
|
|
86
|
+
if (parseEnv(name)) {
|
|
87
|
+
return this.cachedContextTokens[name];
|
|
88
|
+
}
|
|
89
|
+
|
|
77
90
|
// try flow/global context:
|
|
78
91
|
var context = parseContext(name);
|
|
79
92
|
if (context) {
|
|
@@ -156,6 +169,17 @@ module.exports = function(RED) {
|
|
|
156
169
|
var tokens = extractTokens(mustache.parse(template));
|
|
157
170
|
var resolvedTokens = {};
|
|
158
171
|
tokens.forEach(function(name) {
|
|
172
|
+
var env_name = parseEnv(name);
|
|
173
|
+
if (env_name) {
|
|
174
|
+
var promise = new Promise((resolve, reject) => {
|
|
175
|
+
var val = RED.util.evaluateNodeProperty(env_name, 'env', node)
|
|
176
|
+
resolvedTokens[name] = val;
|
|
177
|
+
resolve();
|
|
178
|
+
});
|
|
179
|
+
promises.push(promise);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
159
183
|
var context = parseContext(name);
|
|
160
184
|
if (context) {
|
|
161
185
|
var type = context.type;
|
|
@@ -275,18 +275,22 @@ module.exports = function(RED) {
|
|
|
275
275
|
if (msg.hasOwnProperty("flush")) {
|
|
276
276
|
var len = node.buffer.length;
|
|
277
277
|
if (typeof(msg.flush) == 'number') { len = Math.min(Math.floor(msg.flush),len); }
|
|
278
|
-
|
|
279
|
-
const msgInfo = node.buffer.shift();
|
|
280
|
-
if (Object.keys(msgInfo.msg).length > 1) {
|
|
281
|
-
node.send(msgInfo.msg);
|
|
282
|
-
msgInfo.done();
|
|
283
|
-
}
|
|
284
|
-
len = len - 1;
|
|
285
|
-
}
|
|
286
|
-
if (node.buffer.length === 0) {
|
|
278
|
+
if (len === 0) {
|
|
287
279
|
clearInterval(node.intervalID);
|
|
288
280
|
node.intervalID = -1;
|
|
289
281
|
}
|
|
282
|
+
else {
|
|
283
|
+
while (len > 0) {
|
|
284
|
+
const msgInfo = node.buffer.shift();
|
|
285
|
+
if (Object.keys(msgInfo.msg).length > 1) {
|
|
286
|
+
node.send(msgInfo.msg);
|
|
287
|
+
msgInfo.done();
|
|
288
|
+
}
|
|
289
|
+
len = len - 1;
|
|
290
|
+
}
|
|
291
|
+
clearInterval(node.intervalID);
|
|
292
|
+
node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
|
|
293
|
+
}
|
|
290
294
|
node.status({fill:"blue",shape:"dot",text:node.buffer.length});
|
|
291
295
|
done();
|
|
292
296
|
}
|
package/core/network/10-mqtt.js
CHANGED
|
@@ -592,7 +592,7 @@ module.exports = function(RED) {
|
|
|
592
592
|
// Only for ws or wss, check if proxy env var for additional configuration
|
|
593
593
|
if (node.brokerurl.indexOf("wss://") > -1 || node.brokerurl.indexOf("ws://") > -1) {
|
|
594
594
|
// check if proxy is set in env
|
|
595
|
-
let prox, noprox;
|
|
595
|
+
let prox, noprox, noproxy;
|
|
596
596
|
if (process.env.http_proxy) { prox = process.env.http_proxy; }
|
|
597
597
|
if (process.env.HTTP_PROXY) { prox = process.env.HTTP_PROXY; }
|
|
598
598
|
if (process.env.no_proxy) { noprox = process.env.no_proxy.split(","); }
|
package/core/network/31-tcpin.js
CHANGED
|
@@ -435,7 +435,7 @@ module.exports = function(RED) {
|
|
|
435
435
|
});
|
|
436
436
|
}
|
|
437
437
|
else {
|
|
438
|
-
|
|
438
|
+
const connectedSockets = new Set();
|
|
439
439
|
node.status({text:RED._("tcpin.status.connections",{count:0})});
|
|
440
440
|
let srv = net;
|
|
441
441
|
let connOpts;
|
|
@@ -456,16 +456,16 @@ module.exports = function(RED) {
|
|
|
456
456
|
});
|
|
457
457
|
socket.on('close',function() {
|
|
458
458
|
node.log(RED._("tcpin.status.connection-closed",{host:socket.remoteAddress, port:socket.remotePort}));
|
|
459
|
-
connectedSockets.
|
|
460
|
-
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.
|
|
459
|
+
connectedSockets.delete(socket);
|
|
460
|
+
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.size})});
|
|
461
461
|
});
|
|
462
462
|
socket.on('error',function() {
|
|
463
463
|
node.log(RED._("tcpin.errors.socket-error",{host:socket.remoteAddress, port:socket.remotePort}));
|
|
464
|
-
connectedSockets.
|
|
465
|
-
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.
|
|
464
|
+
connectedSockets.delete(socket);
|
|
465
|
+
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.size})});
|
|
466
466
|
});
|
|
467
|
-
connectedSockets.
|
|
468
|
-
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.
|
|
467
|
+
connectedSockets.add(socket);
|
|
468
|
+
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.size})});
|
|
469
469
|
});
|
|
470
470
|
|
|
471
471
|
node.on("input", function(msg, nodeSend, nodeDone) {
|
|
@@ -478,10 +478,10 @@ module.exports = function(RED) {
|
|
|
478
478
|
} else {
|
|
479
479
|
buffer = Buffer.from(""+msg.payload);
|
|
480
480
|
}
|
|
481
|
-
|
|
482
|
-
if (node.doend === true) {
|
|
483
|
-
else {
|
|
484
|
-
}
|
|
481
|
+
connectedSockets.forEach(soc => {
|
|
482
|
+
if (node.doend === true) { soc.end(buffer); }
|
|
483
|
+
else { soc.write(buffer); }
|
|
484
|
+
})
|
|
485
485
|
}
|
|
486
486
|
nodeDone();
|
|
487
487
|
});
|
|
@@ -498,12 +498,10 @@ module.exports = function(RED) {
|
|
|
498
498
|
} else {
|
|
499
499
|
node.log(RED._("tcpin.status.listening-port",{port:node.port}));
|
|
500
500
|
node.on('close', function() {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
}
|
|
506
|
-
}
|
|
501
|
+
connectedSockets.forEach(soc => {
|
|
502
|
+
soc.end();
|
|
503
|
+
soc.unref();
|
|
504
|
+
})
|
|
507
505
|
server.close();
|
|
508
506
|
node.log(RED._("tcpin.status.stopped-listening",{port:node.port}));
|
|
509
507
|
});
|
package/core/parsers/70-CSV.js
CHANGED
|
@@ -89,6 +89,9 @@ module.exports = function(RED) {
|
|
|
89
89
|
else if (msg.payload[s][t].toString().indexOf(node.sep) !== -1) { // add quotes if any "commas"
|
|
90
90
|
msg.payload[s][t] = node.quo + msg.payload[s][t].toString() + node.quo;
|
|
91
91
|
}
|
|
92
|
+
else if (msg.payload[s][t].toString().indexOf("\n") !== -1) { // add quotes if any "\n"
|
|
93
|
+
msg.payload[s][t] = node.quo + msg.payload[s][t].toString() + node.quo;
|
|
94
|
+
}
|
|
92
95
|
}
|
|
93
96
|
ou += msg.payload[s].join(node.sep) + node.ret;
|
|
94
97
|
}
|
|
@@ -112,7 +115,7 @@ module.exports = function(RED) {
|
|
|
112
115
|
q = q.replace(/"/g, '""');
|
|
113
116
|
ou += node.quo + q + node.quo + node.sep;
|
|
114
117
|
}
|
|
115
|
-
else if (q.indexOf(node.sep) !== -1) { // add quotes if any "commas"
|
|
118
|
+
else if (q.indexOf(node.sep) !== -1 || p.indexOf("\n") !== -1) { // add quotes if any "commas" or "\n"
|
|
116
119
|
ou += node.quo + q + node.quo + node.sep;
|
|
117
120
|
}
|
|
118
121
|
else { ou += q + node.sep; } // otherwise just add
|
|
@@ -134,7 +137,7 @@ module.exports = function(RED) {
|
|
|
134
137
|
p = p.replace(/"/g, '""');
|
|
135
138
|
ou += node.quo + p + node.quo + node.sep;
|
|
136
139
|
}
|
|
137
|
-
else if (p.indexOf(node.sep) !== -1) { // add quotes if any "commas"
|
|
140
|
+
else if (p.indexOf(node.sep) !== -1 || p.indexOf("\n") !== -1) { // add quotes if any "commas" or "\n"
|
|
138
141
|
ou += node.quo + p + node.quo + node.sep;
|
|
139
142
|
}
|
|
140
143
|
else { ou += p + node.sep; } // otherwise just add
|
|
@@ -314,11 +314,13 @@ module.exports = function(RED) {
|
|
|
314
314
|
if (err) {
|
|
315
315
|
return done(err);
|
|
316
316
|
}
|
|
317
|
-
msgInfo.
|
|
317
|
+
msgInfo.msg.payload = result;
|
|
318
|
+
msgInfo.send(msgInfo.msg);
|
|
318
319
|
done();
|
|
319
320
|
});
|
|
320
321
|
} else {
|
|
321
|
-
msgInfo.
|
|
322
|
+
msgInfo.msg.payload = result;
|
|
323
|
+
msgInfo.send(msgInfo.msg);
|
|
322
324
|
done();
|
|
323
325
|
}
|
|
324
326
|
} else {
|
|
@@ -198,8 +198,8 @@
|
|
|
198
198
|
category: 'storage',
|
|
199
199
|
defaults: {
|
|
200
200
|
name: {value:""},
|
|
201
|
-
filename: {value:"
|
|
202
|
-
filenameType: {value:"
|
|
201
|
+
filename: {value:""},
|
|
202
|
+
filenameType: {value:"str"},
|
|
203
203
|
appendNewline: {value:true},
|
|
204
204
|
createDir: {value:false},
|
|
205
205
|
overwriteFile: {value:"false"},
|
|
@@ -236,8 +236,8 @@
|
|
|
236
236
|
label: node._("file.encoding.setbymsg")
|
|
237
237
|
}).text(label).appendTo(encSel);
|
|
238
238
|
$("#node-input-filename").typedInput({
|
|
239
|
-
default: "
|
|
240
|
-
types:[{
|
|
239
|
+
default: "str",
|
|
240
|
+
types: [{label:RED._("node-red:file.label.path"), value:"str", icon:""}, "msg", "jsonata", "env"],
|
|
241
241
|
typeField: $("#node-input-filenameType")
|
|
242
242
|
});
|
|
243
243
|
if(typeof node.filenameType == 'undefined') {
|
|
@@ -297,8 +297,8 @@
|
|
|
297
297
|
category: 'storage',
|
|
298
298
|
defaults: {
|
|
299
299
|
name: {value:""},
|
|
300
|
-
filename: {value:"
|
|
301
|
-
filenameType: {value:"
|
|
300
|
+
filename: {value:""},
|
|
301
|
+
filenameType: {value:"str"},
|
|
302
302
|
format: {value:"utf8"},
|
|
303
303
|
chunk: {value:false},
|
|
304
304
|
sendError: {value: false},
|
|
@@ -341,8 +341,8 @@
|
|
|
341
341
|
label: label
|
|
342
342
|
}).text(label).appendTo(encSel);
|
|
343
343
|
$("#node-input-filename").typedInput({
|
|
344
|
-
default: "
|
|
345
|
-
types:[{
|
|
344
|
+
default: "str",
|
|
345
|
+
types: [{label:RED._("node-red:file.label.path"), value:"str", icon:""}, "msg", "jsonata", "env"],
|
|
346
346
|
typeField: $("#node-input-filenameType")
|
|
347
347
|
});
|
|
348
348
|
if(typeof node.filenameType == 'undefined') {
|