@node-red/nodes 2.2.0 → 2.2.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/core/common/20-inject.js +3 -2
- package/core/common/21-debug.js +9 -5
- package/core/function/10-function.html +1 -1
- package/core/function/15-change.js +2 -2
- package/core/function/89-delay.html +1 -1
- package/core/function/89-delay.js +13 -9
- package/core/network/10-mqtt.html +21 -1
- package/core/network/10-mqtt.js +154 -60
- package/core/network/21-httprequest.html +12 -0
- package/core/network/21-httprequest.js +4 -0
- package/core/network/22-websocket.js +16 -13
- package/core/network/31-tcpin.js +17 -19
- package/core/parsers/70-CSV.js +5 -2
- package/core/parsers/70-JSON.html +1 -1
- package/core/sequence/17-split.js +4 -2
- package/core/sequence/19-batch.html +1 -1
- package/examples/function/delay/06 - Simple Queue with release +149 -0
- package/locales/en-US/messages.json +2 -1
- package/locales/ja/function/10-function.html +1 -1
- package/locales/ja/messages.json +2 -2
- package/locales/ja/network/10-mqtt.html +1 -1
- package/package.json +5 -5
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) {
|
package/core/common/21-debug.js
CHANGED
|
@@ -7,6 +7,7 @@ module.exports = function(RED) {
|
|
|
7
7
|
var debuglength = RED.settings.debugMaxLength || 1000;
|
|
8
8
|
var useColors = RED.settings.debugUseColors || false;
|
|
9
9
|
util.inspect.styles.boolean = "red";
|
|
10
|
+
const { hasOwnProperty } = Object.prototype;
|
|
10
11
|
|
|
11
12
|
function DebugNode(n) {
|
|
12
13
|
var hasEditExpression = (n.targetType === "jsonata");
|
|
@@ -107,7 +108,9 @@ module.exports = function(RED) {
|
|
|
107
108
|
}
|
|
108
109
|
})
|
|
109
110
|
this.on("input", function(msg, send, done) {
|
|
110
|
-
if (
|
|
111
|
+
if (hasOwnProperty.call(msg, "status") && msg.status &&
|
|
112
|
+
hasOwnProperty.call(msg.status, "source") && msg.status.source &&
|
|
113
|
+
hasOwnProperty.call(msg.status.source, "id") && (msg.status.source.id === node.id)) {
|
|
111
114
|
done();
|
|
112
115
|
return;
|
|
113
116
|
}
|
|
@@ -118,17 +121,18 @@ module.exports = function(RED) {
|
|
|
118
121
|
var st = (typeof output === 'string') ? output : util.inspect(output);
|
|
119
122
|
var fill = "grey";
|
|
120
123
|
var shape = "dot";
|
|
121
|
-
if (typeof output === 'object' &&
|
|
124
|
+
if (typeof output === 'object' && hasOwnProperty.call(output, "fill") && hasOwnProperty.call(output, "shape") && hasOwnProperty.call(output, "text")) {
|
|
122
125
|
fill = output.fill;
|
|
123
126
|
shape = output.shape;
|
|
124
127
|
st = output.text;
|
|
125
128
|
}
|
|
126
129
|
if (node.statusType === "auto") {
|
|
127
|
-
if (
|
|
130
|
+
if (hasOwnProperty.call(msg, "error")) {
|
|
128
131
|
fill = "red";
|
|
129
132
|
st = msg.error.message;
|
|
130
133
|
}
|
|
131
|
-
if (
|
|
134
|
+
if (hasOwnProperty.call(msg, "status") &&
|
|
135
|
+
msg.status) {
|
|
132
136
|
fill = msg.status.fill || "grey";
|
|
133
137
|
shape = msg.status.shape || "ring";
|
|
134
138
|
st = msg.status.text || "";
|
|
@@ -194,7 +198,7 @@ module.exports = function(RED) {
|
|
|
194
198
|
|
|
195
199
|
function sendDebug(msg) {
|
|
196
200
|
// don't put blank errors in sidebar (but do add to logs)
|
|
197
|
-
//if ((msg.msg === "") && (
|
|
201
|
+
//if ((msg.msg === "") && (hasOwnProperty.call(msg, "level")) && (msg.level === 20)) { return; }
|
|
198
202
|
msg = RED.util.encodeObject(msg,{maxLength:debuglength});
|
|
199
203
|
RED.comms.publish("debug",msg);
|
|
200
204
|
}
|
|
@@ -399,7 +399,7 @@
|
|
|
399
399
|
$("#func-tabs-content").children().hide();
|
|
400
400
|
$("#" + tab.id).show();
|
|
401
401
|
let editor = $("#" + tab.id).find('.monaco-editor').first();
|
|
402
|
-
|
|
402
|
+
if(editor.length) {
|
|
403
403
|
if(that.editor.nodered && that.editor.type == "monaco") {
|
|
404
404
|
that.editor.nodered.refreshModuleLibs(getLibsList());
|
|
405
405
|
}
|
|
@@ -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) {
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
timeoutUnits: {value:"seconds"},
|
|
116
116
|
rate: {value:"1", required:true, validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
|
|
117
117
|
nbRateUnits: {value:"1", required:false,
|
|
118
|
-
validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
|
|
118
|
+
validate:function(v) { return v === undefined || (RED.validators.number(v) && (v >= 0)); }},
|
|
119
119
|
rateUnits: {value: "second"},
|
|
120
120
|
randomFirst: {value:"1", required:true, validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
|
|
121
121
|
randomLast: {value:"5", required:true, validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
|
|
@@ -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
|
}
|
|
@@ -442,7 +442,17 @@
|
|
|
442
442
|
}
|
|
443
443
|
return defaultContentType || 'none'
|
|
444
444
|
}
|
|
445
|
-
|
|
445
|
+
/**
|
|
446
|
+
* Test a topic string is valid for publishing
|
|
447
|
+
* @param {string} topic
|
|
448
|
+
* @returns `true` if it is a valid topic
|
|
449
|
+
*/
|
|
450
|
+
function validateMQTTPublishTopic(topic, opts) {
|
|
451
|
+
if(!topic || topic == "" || !/[\+#\b\f\n\r\t\v\0]/.test(topic)) {
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
return RED._("node-red:mqtt.errors.invalid-topic");
|
|
455
|
+
}
|
|
446
456
|
RED.nodes.registerType('mqtt-broker',{
|
|
447
457
|
category: 'config',
|
|
448
458
|
defaults: {
|
|
@@ -480,6 +490,7 @@
|
|
|
480
490
|
willRetain: {value:false},
|
|
481
491
|
willPayload: {value:""},
|
|
482
492
|
willMsg: { value: {}},
|
|
493
|
+
userProps: { value: ""},
|
|
483
494
|
sessionExpiry: {value:0}
|
|
484
495
|
},
|
|
485
496
|
credentials: {
|
|
@@ -609,6 +620,7 @@
|
|
|
609
620
|
default: !this.userProps ? 'none':'json',
|
|
610
621
|
types: [typedInputNoneOpt, 'json']
|
|
611
622
|
});
|
|
623
|
+
$("#node-config-input-userProps").typedInput('value',this.userProps);
|
|
612
624
|
if (typeof this.keepalive === 'undefined') {
|
|
613
625
|
this.keepalive = 15;
|
|
614
626
|
$("#node-config-input-keepalive").val(this.keepalive);
|
|
@@ -718,6 +730,14 @@
|
|
|
718
730
|
}
|
|
719
731
|
|
|
720
732
|
if (v5) {
|
|
733
|
+
this.userProps = "";
|
|
734
|
+
const userPropsType = $("#node-config-input-userProps").typedInput("type");
|
|
735
|
+
if(userPropsType == "json") {
|
|
736
|
+
const userProps = $("#node-config-input-userProps").val();
|
|
737
|
+
if (userProps && typeof userProps === "string") {
|
|
738
|
+
this.userProps = userProps.trim();
|
|
739
|
+
}
|
|
740
|
+
}
|
|
721
741
|
this.birthMsg = saveV5Message("birth");
|
|
722
742
|
this.closeMsg = saveV5Message("close");
|
|
723
743
|
this.willMsg = saveV5Message("will");
|
package/core/network/10-mqtt.js
CHANGED
|
@@ -68,12 +68,21 @@ module.exports = function(RED) {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
/**
|
|
71
|
-
* Test a topic string is valid
|
|
71
|
+
* Test a topic string is valid for subscription
|
|
72
72
|
* @param {string} topic
|
|
73
73
|
* @returns `true` if it is a valid topic
|
|
74
74
|
*/
|
|
75
75
|
function isValidSubscriptionTopic(topic) {
|
|
76
|
-
return /^(#$|(\+|[^+#]*)(\/(\+|[^+#]*))*(\/(\+|#|[^+#]*))?$)/.test(topic)
|
|
76
|
+
return /^(#$|(\+|[^+#]*)(\/(\+|[^+#]*))*(\/(\+|#|[^+#]*))?$)/.test(topic);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Test a topic string is valid for publishing
|
|
81
|
+
* @param {string} topic
|
|
82
|
+
* @returns `true` if it is a valid topic
|
|
83
|
+
*/
|
|
84
|
+
function isValidPublishTopic(topic) {
|
|
85
|
+
return !/[\+#\b\f\n\r\t\v\0]/.test(topic);
|
|
77
86
|
}
|
|
78
87
|
|
|
79
88
|
/**
|
|
@@ -103,7 +112,7 @@ module.exports = function(RED) {
|
|
|
103
112
|
if(src[propName] === "true" || src[propName] === true) {
|
|
104
113
|
dst[propName] = true;
|
|
105
114
|
} else if(src[propName] === "false" || src[propName] === false) {
|
|
106
|
-
dst[propName] =
|
|
115
|
+
dst[propName] = false;
|
|
107
116
|
}
|
|
108
117
|
} else {
|
|
109
118
|
if(def != undefined) dst[propName] = def;
|
|
@@ -288,7 +297,7 @@ module.exports = function(RED) {
|
|
|
288
297
|
//TODO: delete msg.responseTopic - to prevent it being resent?
|
|
289
298
|
}
|
|
290
299
|
}
|
|
291
|
-
topicOK = topicOK &&
|
|
300
|
+
topicOK = topicOK && isValidPublishTopic(msg.topic);
|
|
292
301
|
|
|
293
302
|
if (topicOK) {
|
|
294
303
|
node.brokerConn.publish(msg, done); // send the message
|
|
@@ -391,6 +400,7 @@ module.exports = function(RED) {
|
|
|
391
400
|
node.options = {};
|
|
392
401
|
node.queue = [];
|
|
393
402
|
node.subscriptions = {};
|
|
403
|
+
node.clientListeners = []
|
|
394
404
|
/** @type {mqtt.MqttClient}*/ this.client;
|
|
395
405
|
node.setOptions = function(opts, init) {
|
|
396
406
|
if(!opts || typeof opts !== "object") {
|
|
@@ -415,8 +425,12 @@ module.exports = function(RED) {
|
|
|
415
425
|
setIfHasProperty(opts, node, "topicAliasMaximum", init);
|
|
416
426
|
setIfHasProperty(opts, node, "maximumPacketSize", init);
|
|
417
427
|
setIfHasProperty(opts, node, "receiveMaximum", init);
|
|
418
|
-
|
|
419
|
-
|
|
428
|
+
//https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116
|
|
429
|
+
if (hasProperty(opts, "userProperties")) {
|
|
430
|
+
node.userProperties = opts.userProperties;
|
|
431
|
+
} else if (hasProperty(opts, "userProps")) {
|
|
432
|
+
node.userProperties = opts.userProps;
|
|
433
|
+
}
|
|
420
434
|
|
|
421
435
|
function createLWT(topic, payload, qos, retain, v5opts, v5SubPropName) {
|
|
422
436
|
let message = undefined;
|
|
@@ -465,7 +479,7 @@ module.exports = function(RED) {
|
|
|
465
479
|
};
|
|
466
480
|
if(hasProperty(opts, "willTopic")) {
|
|
467
481
|
//will v5 properties must be set in the "properties" sub object
|
|
468
|
-
node.options.will = createLWT(opts.willTopic, opts.willPayload, opts.willQos, opts.willRetain, opts.willMsg, "
|
|
482
|
+
node.options.will = createLWT(opts.willTopic, opts.willPayload, opts.willQos, opts.willRetain, opts.willMsg, "properties");
|
|
469
483
|
};
|
|
470
484
|
} else {
|
|
471
485
|
//update options
|
|
@@ -525,7 +539,7 @@ module.exports = function(RED) {
|
|
|
525
539
|
// Only for ws or wss, check if proxy env var for additional configuration
|
|
526
540
|
if (node.brokerurl.indexOf("wss://") > -1 || node.brokerurl.indexOf("ws://") > -1) {
|
|
527
541
|
// check if proxy is set in env
|
|
528
|
-
let prox, noprox;
|
|
542
|
+
let prox, noprox, noproxy;
|
|
529
543
|
if (process.env.http_proxy) { prox = process.env.http_proxy; }
|
|
530
544
|
if (process.env.HTTP_PROXY) { prox = process.env.HTTP_PROXY; }
|
|
531
545
|
if (process.env.no_proxy) { noprox = process.env.no_proxy.split(","); }
|
|
@@ -637,24 +651,8 @@ module.exports = function(RED) {
|
|
|
637
651
|
|
|
638
652
|
node.deregister = function(mqttNode,done) {
|
|
639
653
|
delete node.users[mqttNode.id];
|
|
640
|
-
if (node.closing) {
|
|
641
|
-
|
|
642
|
-
}
|
|
643
|
-
if (Object.keys(node.users).length === 0) {
|
|
644
|
-
if (node.client && node.client.connected) {
|
|
645
|
-
// Send close message
|
|
646
|
-
if (node.closeMessage) {
|
|
647
|
-
node.publish(node.closeMessage,function(err) {
|
|
648
|
-
node.client.end(done);
|
|
649
|
-
});
|
|
650
|
-
} else {
|
|
651
|
-
node.client.end(done);
|
|
652
|
-
}
|
|
653
|
-
return;
|
|
654
|
-
} else {
|
|
655
|
-
if (node.client) { node.client.end(); }
|
|
656
|
-
return done();
|
|
657
|
-
}
|
|
654
|
+
if (!node.closing && node.connected && Object.keys(node.users).length === 0) {
|
|
655
|
+
node.disconnect();
|
|
658
656
|
}
|
|
659
657
|
done();
|
|
660
658
|
};
|
|
@@ -663,15 +661,22 @@ module.exports = function(RED) {
|
|
|
663
661
|
}
|
|
664
662
|
node.connect = function (callback) {
|
|
665
663
|
if (node.canConnect()) {
|
|
664
|
+
node.closing = false;
|
|
666
665
|
node.connecting = true;
|
|
667
666
|
setStatusConnecting(node, true);
|
|
668
667
|
try {
|
|
669
668
|
node.serverProperties = {};
|
|
669
|
+
if(node.client) {
|
|
670
|
+
//belt and braces to avoid left over clients
|
|
671
|
+
node.client.end(true);
|
|
672
|
+
node._clientRemoveListeners();
|
|
673
|
+
}
|
|
670
674
|
node.client = mqtt.connect(node.brokerurl, node.options);
|
|
671
675
|
node.client.setMaxListeners(0);
|
|
672
|
-
let callbackDone = false; //prevent re-connects causing node.
|
|
676
|
+
let callbackDone = false; //prevent re-connects causing node._clientOn('connect' firing callback multiple times
|
|
673
677
|
// Register successful connect or reconnect handler
|
|
674
|
-
node.
|
|
678
|
+
node._clientOn('connect', function (connack) {
|
|
679
|
+
node.closing = false;
|
|
675
680
|
node.connecting = false;
|
|
676
681
|
node.connected = true;
|
|
677
682
|
if(!callbackDone && typeof callback == "function") {
|
|
@@ -702,7 +707,7 @@ module.exports = function(RED) {
|
|
|
702
707
|
}
|
|
703
708
|
setStatusConnected(node, true);
|
|
704
709
|
// Remove any existing listeners before resubscribing to avoid duplicates in the event of a re-connection
|
|
705
|
-
node.
|
|
710
|
+
node._clientRemoveListeners('message');
|
|
706
711
|
|
|
707
712
|
// Re-subscribe to stored topics
|
|
708
713
|
for (var s in node.subscriptions) {
|
|
@@ -714,7 +719,7 @@ module.exports = function(RED) {
|
|
|
714
719
|
if (node.subscriptions[s].hasOwnProperty(r)) {
|
|
715
720
|
qos = Math.max(qos,node.subscriptions[s][r].qos);
|
|
716
721
|
_options = node.subscriptions[s][r].options;
|
|
717
|
-
node.
|
|
722
|
+
node._clientOn('message',node.subscriptions[s][r].handler);
|
|
718
723
|
}
|
|
719
724
|
}
|
|
720
725
|
_options.qos = _options.qos || qos;
|
|
@@ -727,11 +732,11 @@ module.exports = function(RED) {
|
|
|
727
732
|
node.publish(node.birthMessage);
|
|
728
733
|
}
|
|
729
734
|
});
|
|
730
|
-
node.
|
|
735
|
+
node._clientOn("reconnect", function() {
|
|
731
736
|
setStatusConnecting(node, true);
|
|
732
737
|
});
|
|
733
738
|
//Broker Disconnect - V5 event
|
|
734
|
-
node.
|
|
739
|
+
node._clientOn("disconnect", function(packet) {
|
|
735
740
|
//Emitted after receiving disconnect packet from broker. MQTT 5.0 feature.
|
|
736
741
|
const rc = (packet && packet.properties && packet.reasonCode) || packet.reasonCode;
|
|
737
742
|
const rs = packet && packet.properties && packet.properties.reasonString || "";
|
|
@@ -740,11 +745,12 @@ module.exports = function(RED) {
|
|
|
740
745
|
reasonCode: rc,
|
|
741
746
|
reasonString: rs
|
|
742
747
|
}
|
|
748
|
+
node.connected = false;
|
|
743
749
|
node.log(RED._("mqtt.state.broker-disconnected", details));
|
|
744
750
|
setStatusDisconnected(node, true);
|
|
745
751
|
});
|
|
746
752
|
// Register disconnect handlers
|
|
747
|
-
node.
|
|
753
|
+
node._clientOn('close', function () {
|
|
748
754
|
if (node.connected) {
|
|
749
755
|
node.connected = false;
|
|
750
756
|
node.log(RED._("mqtt.state.disconnected",{broker:(node.clientid?node.clientid+"@":"")+node.brokerurl}));
|
|
@@ -756,33 +762,59 @@ module.exports = function(RED) {
|
|
|
756
762
|
|
|
757
763
|
// Register connect error handler
|
|
758
764
|
// The client's own reconnect logic will take care of errors
|
|
759
|
-
node.
|
|
765
|
+
node._clientOn('error', function (error) {
|
|
760
766
|
});
|
|
761
767
|
}catch(err) {
|
|
762
768
|
console.log(err);
|
|
763
769
|
}
|
|
764
770
|
}
|
|
765
771
|
};
|
|
772
|
+
|
|
766
773
|
node.disconnect = function (callback) {
|
|
767
774
|
const _callback = function () {
|
|
768
|
-
|
|
775
|
+
if(node.connected || node.connecting) {
|
|
776
|
+
setStatusDisconnected(node, true);
|
|
777
|
+
}
|
|
778
|
+
if(node.client) { node._clientRemoveListeners(); }
|
|
769
779
|
node.connecting = false;
|
|
770
780
|
node.connected = false;
|
|
771
781
|
callback && typeof callback == "function" && callback();
|
|
772
782
|
};
|
|
773
|
-
|
|
774
|
-
if(node.
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
783
|
+
if(!node.client) { return _callback(); }
|
|
784
|
+
if(node.closing) { return _callback(); }
|
|
785
|
+
|
|
786
|
+
let waitEnd = (client, ms) => {
|
|
787
|
+
return new Promise( (resolve, reject) => {
|
|
788
|
+
node.closing = true;
|
|
789
|
+
if(!client) {
|
|
790
|
+
resolve();
|
|
791
|
+
} else {
|
|
792
|
+
const t = setTimeout(() => {
|
|
793
|
+
//clean end() has exceeded WAIT_END, lets force end!
|
|
794
|
+
client && client.end(true);
|
|
795
|
+
reject();
|
|
796
|
+
}, ms);
|
|
797
|
+
client.end(() => {
|
|
798
|
+
clearTimeout(t);
|
|
799
|
+
resolve()
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
};
|
|
804
|
+
if(node.connected && node.closeMessage) {
|
|
805
|
+
node.publish(node.closeMessage, function (err) {
|
|
806
|
+
waitEnd(node.client, 2000).then(() => {
|
|
807
|
+
_callback();
|
|
808
|
+
}).catch((e) => {
|
|
809
|
+
_callback();
|
|
810
|
+
})
|
|
811
|
+
});
|
|
784
812
|
} else {
|
|
785
|
-
|
|
813
|
+
waitEnd(node.client, 2000).then(() => {
|
|
814
|
+
_callback();
|
|
815
|
+
}).catch((e) => {
|
|
816
|
+
_callback();
|
|
817
|
+
})
|
|
786
818
|
}
|
|
787
819
|
}
|
|
788
820
|
node.subscriptionIds = {};
|
|
@@ -819,7 +851,7 @@ module.exports = function(RED) {
|
|
|
819
851
|
};
|
|
820
852
|
node.subscriptions[topic][ref] = sub;
|
|
821
853
|
if (node.connected) {
|
|
822
|
-
node.
|
|
854
|
+
node._clientOn('message',sub.handler);
|
|
823
855
|
node.client.subscribe(topic, options);
|
|
824
856
|
}
|
|
825
857
|
};
|
|
@@ -830,7 +862,7 @@ module.exports = function(RED) {
|
|
|
830
862
|
if (sub) {
|
|
831
863
|
if (sub[ref]) {
|
|
832
864
|
if(node.client) {
|
|
833
|
-
node.
|
|
865
|
+
node._clientRemoveListeners('message',sub[ref].handler);
|
|
834
866
|
}
|
|
835
867
|
delete sub[ref];
|
|
836
868
|
}
|
|
@@ -864,8 +896,18 @@ module.exports = function(RED) {
|
|
|
864
896
|
qos: msg.qos || 0,
|
|
865
897
|
retain: msg.retain || false
|
|
866
898
|
};
|
|
899
|
+
let topicOK = hasProperty(msg, "topic") && (typeof msg.topic === "string") && (isValidPublishTopic(msg.topic));
|
|
867
900
|
//https://github.com/mqttjs/MQTT.js/blob/master/README.md#mqttclientpublishtopic-message-options-callback
|
|
868
901
|
if(node.options.protocolVersion == 5) {
|
|
902
|
+
const bsp = node.serverProperties || {};
|
|
903
|
+
if (msg.userProperties && typeof msg.userProperties !== "object") {
|
|
904
|
+
delete msg.userProperties;
|
|
905
|
+
}
|
|
906
|
+
if (hasProperty(msg, "topicAlias") && !isNaN(Number(msg.topicAlias))) {
|
|
907
|
+
msg.topicAlias = parseInt(msg.topicAlias);
|
|
908
|
+
} else {
|
|
909
|
+
delete msg.topicAlias;
|
|
910
|
+
}
|
|
869
911
|
options.properties = options.properties || {};
|
|
870
912
|
setStrProp(msg, options.properties, "responseTopic");
|
|
871
913
|
setBufferProp(msg, options.properties, "correlationData");
|
|
@@ -875,31 +917,75 @@ module.exports = function(RED) {
|
|
|
875
917
|
setIntProp(msg, options.properties, "topicAlias", 1, node.serverProperties.topicAliasMaximum || 0);
|
|
876
918
|
setBoolProp(msg, options.properties, "payloadFormatIndicator");
|
|
877
919
|
//FUTURE setIntProp(msg, options.properties, "subscriptionIdentifier", 1, 268435455);
|
|
878
|
-
|
|
879
|
-
|
|
920
|
+
|
|
921
|
+
//check & sanitise topic
|
|
922
|
+
if (topicOK && options.properties.topicAlias) {
|
|
923
|
+
let aliasValid = (bsp.topicAliasMaximum && bsp.topicAliasMaximum >= options.properties.topicAlias);
|
|
924
|
+
if (!aliasValid) {
|
|
880
925
|
done("Invalid topicAlias");
|
|
881
926
|
return
|
|
882
927
|
}
|
|
883
928
|
if (node.topicAliases[options.properties.topicAlias] === msg.topic) {
|
|
884
|
-
msg.topic = ""
|
|
929
|
+
msg.topic = "";
|
|
885
930
|
} else {
|
|
886
|
-
node.topicAliases[options.properties.topicAlias] = msg.topic
|
|
931
|
+
node.topicAliases[options.properties.topicAlias] = msg.topic;
|
|
887
932
|
}
|
|
933
|
+
} else if (!msg.topic && options.properties.responseTopic) {
|
|
934
|
+
msg.topic = msg.responseTopic;
|
|
935
|
+
topicOK = isValidPublishTopic(msg.topic);
|
|
936
|
+
delete msg.responseTopic; //prevent responseTopic being resent?
|
|
888
937
|
}
|
|
889
938
|
}
|
|
890
939
|
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
940
|
+
if (topicOK) {
|
|
941
|
+
node.client.publish(msg.topic, msg.payload, options, function(err) {
|
|
942
|
+
done && done(err);
|
|
943
|
+
return
|
|
944
|
+
});
|
|
945
|
+
} else {
|
|
946
|
+
const error = new Error(RED._("mqtt.errors.invalid-topic"));
|
|
947
|
+
error.warn = true;
|
|
948
|
+
done(error);
|
|
949
|
+
}
|
|
895
950
|
}
|
|
896
951
|
};
|
|
897
952
|
|
|
898
953
|
node.on('close', function(done) {
|
|
899
|
-
node.
|
|
900
|
-
|
|
954
|
+
node.disconnect(function() {
|
|
955
|
+
done();
|
|
956
|
+
});
|
|
901
957
|
});
|
|
902
958
|
|
|
959
|
+
/**
|
|
960
|
+
* Add event handlers to the MQTT.js client and track them so that
|
|
961
|
+
* we do not remove any handlers that the MQTT client uses internally.
|
|
962
|
+
* Use {@link node._clientRemoveListeners `node._clientRemoveListeners`} to remove handlers
|
|
963
|
+
* @param {string} event The name of the event
|
|
964
|
+
* @param {function} handler The handler for this event
|
|
965
|
+
*/
|
|
966
|
+
node._clientOn = function(event, handler) {
|
|
967
|
+
node.clientListeners.push({event, handler})
|
|
968
|
+
node.client.on(event, handler)
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
/**
|
|
972
|
+
* Remove event handlers from the MQTT.js client & only the events
|
|
973
|
+
* that we attached in {@link node._clientOn `node._clientOn`}.
|
|
974
|
+
* * If `event` is omitted, then all events matching `handler` are removed
|
|
975
|
+
* * If `handler` is omitted, then all events named `event` are removed
|
|
976
|
+
* * If both parameters are omitted, then all events are removed
|
|
977
|
+
* @param {string} [event] The name of the event (optional)
|
|
978
|
+
* @param {function} [handler] The handler for this event (optional)
|
|
979
|
+
*/
|
|
980
|
+
node._clientRemoveListeners = function(event, handler) {
|
|
981
|
+
node.clientListeners = node.clientListeners.filter((l) => {
|
|
982
|
+
if (event && event !== l.event) { return true; }
|
|
983
|
+
if (handler && handler !== l.handler) { return true; }
|
|
984
|
+
node.client.removeListener(l.event, l.handler)
|
|
985
|
+
return false; //found and removed, filter out this one
|
|
986
|
+
})
|
|
987
|
+
}
|
|
988
|
+
|
|
903
989
|
}
|
|
904
990
|
|
|
905
991
|
RED.nodes.registerType("mqtt-broker",MQTTBrokerNode,{
|
|
@@ -1074,6 +1160,9 @@ module.exports = function(RED) {
|
|
|
1074
1160
|
node.brokerConn.unsubscribe(node.topic,node.id, removed);
|
|
1075
1161
|
}
|
|
1076
1162
|
node.brokerConn.deregister(node, done);
|
|
1163
|
+
node.brokerConn = null;
|
|
1164
|
+
} else {
|
|
1165
|
+
done();
|
|
1077
1166
|
}
|
|
1078
1167
|
});
|
|
1079
1168
|
} else {
|
|
@@ -1134,7 +1223,12 @@ module.exports = function(RED) {
|
|
|
1134
1223
|
}
|
|
1135
1224
|
node.brokerConn.register(node);
|
|
1136
1225
|
node.on('close', function(done) {
|
|
1137
|
-
node.brokerConn
|
|
1226
|
+
if (node.brokerConn) {
|
|
1227
|
+
node.brokerConn.deregister(node,done);
|
|
1228
|
+
node.brokerConn = null;
|
|
1229
|
+
} else {
|
|
1230
|
+
done();
|
|
1231
|
+
}
|
|
1138
1232
|
});
|
|
1139
1233
|
} else {
|
|
1140
1234
|
node.error(RED._("mqtt.errors.missing-config"));
|
|
@@ -91,6 +91,11 @@
|
|
|
91
91
|
<label for="node-input-senderr" style="width: auto" data-i18n="httpin.senderr"></label>
|
|
92
92
|
</div>
|
|
93
93
|
|
|
94
|
+
<div class="form-row">
|
|
95
|
+
<input type="checkbox" id="node-input-insecureHTTPParser" style="display: inline-block; width: auto; vertical-align: top;">
|
|
96
|
+
<label for="node-input-insecureHTTPParser", style="width: auto;" data-i18n="httpin.insecureHTTPParser"></label>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
94
99
|
|
|
95
100
|
<div class="form-row">
|
|
96
101
|
<label for="node-input-ret"><i class="fa fa-arrow-left"></i> <span data-i18n="httpin.label.return"></span></label>
|
|
@@ -120,6 +125,7 @@
|
|
|
120
125
|
tls: {type:"tls-config",required: false},
|
|
121
126
|
persist: {value:false},
|
|
122
127
|
proxy: {type:"http proxy",required: false},
|
|
128
|
+
insecureHTTPParser: {value: false},
|
|
123
129
|
authType: {value: ""},
|
|
124
130
|
senderr: {value: false}
|
|
125
131
|
},
|
|
@@ -224,6 +230,12 @@
|
|
|
224
230
|
} else {
|
|
225
231
|
$("#node-input-useProxy").prop("checked", false);
|
|
226
232
|
}
|
|
233
|
+
|
|
234
|
+
if (node.insecureHTTPParser) {
|
|
235
|
+
$("node-intput-insecureHTTPParser").prop("checked", true)
|
|
236
|
+
} else {
|
|
237
|
+
$("node-intput-insecureHTTPParser").prop("checked", false)
|
|
238
|
+
}
|
|
227
239
|
updateProxyOptions();
|
|
228
240
|
$("#node-input-useProxy").on("click", function() {
|
|
229
241
|
updateProxyOptions();
|
|
@@ -35,8 +35,6 @@ module.exports = function(RED) {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
var listenerNodes = {};
|
|
38
|
-
var activeListenerNodes = 0;
|
|
39
|
-
|
|
40
38
|
|
|
41
39
|
// A node red node that sets up a local websocket server
|
|
42
40
|
function WebSocketListenerNode(n) {
|
|
@@ -166,7 +164,6 @@ module.exports = function(RED) {
|
|
|
166
164
|
}
|
|
167
165
|
|
|
168
166
|
if (node.isServer) {
|
|
169
|
-
activeListenerNodes++;
|
|
170
167
|
if (!serverUpgradeAdded) {
|
|
171
168
|
RED.server.on('upgrade', handleServerUpgrade);
|
|
172
169
|
serverUpgradeAdded = true
|
|
@@ -210,7 +207,7 @@ module.exports = function(RED) {
|
|
|
210
207
|
startconn(); // start outbound connection
|
|
211
208
|
}
|
|
212
209
|
|
|
213
|
-
node.on("close", function() {
|
|
210
|
+
node.on("close", function(done) {
|
|
214
211
|
if (node.heartbeatInterval) {
|
|
215
212
|
clearInterval(node.heartbeatInterval);
|
|
216
213
|
}
|
|
@@ -218,19 +215,25 @@ module.exports = function(RED) {
|
|
|
218
215
|
delete listenerNodes[node.fullPath];
|
|
219
216
|
node.server.close();
|
|
220
217
|
node._inputNodes = [];
|
|
221
|
-
activeListenerNodes--;
|
|
222
|
-
// if (activeListenerNodes === 0 && serverUpgradeAdded) {
|
|
223
|
-
// RED.server.removeListener('upgrade', handleServerUpgrade);
|
|
224
|
-
// serverUpgradeAdded = false;
|
|
225
|
-
// }
|
|
226
218
|
}
|
|
227
219
|
else {
|
|
228
220
|
node.closing = true;
|
|
229
221
|
node.server.close();
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
222
|
+
//wait 20*50 (1000ms max) for ws to close.
|
|
223
|
+
//call done when readyState === ws.CLOSED (or 1000ms, whichever comes fist)
|
|
224
|
+
const closeMonitorInterval = 20;
|
|
225
|
+
let closeMonitorCount = 50;
|
|
226
|
+
let si = setInterval(() => {
|
|
227
|
+
if(node.server.readyState === ws.CLOSED || closeMonitorCount <= 0) {
|
|
228
|
+
if (node.tout) {
|
|
229
|
+
clearTimeout(node.tout);
|
|
230
|
+
node.tout = null;
|
|
231
|
+
}
|
|
232
|
+
clearInterval(si);
|
|
233
|
+
return done();
|
|
234
|
+
}
|
|
235
|
+
closeMonitorCount--;
|
|
236
|
+
}, closeMonitorInterval);
|
|
234
237
|
}
|
|
235
238
|
});
|
|
236
239
|
}
|
package/core/network/31-tcpin.js
CHANGED
|
@@ -135,7 +135,7 @@ module.exports = function(RED) {
|
|
|
135
135
|
buffer = buffer+data;
|
|
136
136
|
var parts = buffer.split(node.newline);
|
|
137
137
|
for (var i = 0; i<parts.length-1; i+=1) {
|
|
138
|
-
msg = {topic:node.topic, payload:parts[i]
|
|
138
|
+
msg = {topic:node.topic, payload:parts[i]};
|
|
139
139
|
msg._session = {type:"tcp",id:id};
|
|
140
140
|
node.send(msg);
|
|
141
141
|
}
|
|
@@ -229,7 +229,7 @@ module.exports = function(RED) {
|
|
|
229
229
|
buffer = buffer+data;
|
|
230
230
|
var parts = buffer.split(node.newline);
|
|
231
231
|
for (var i = 0; i<parts.length-1; i+=1) {
|
|
232
|
-
msg = {topic:node.topic, payload:parts[i]
|
|
232
|
+
msg = {topic:node.topic, payload:parts[i], ip:socket.remoteAddress, port:socket.remotePort};
|
|
233
233
|
msg._session = {type:"tcp",id:id};
|
|
234
234
|
node.send(msg);
|
|
235
235
|
}
|
|
@@ -432,7 +432,7 @@ module.exports = function(RED) {
|
|
|
432
432
|
});
|
|
433
433
|
}
|
|
434
434
|
else {
|
|
435
|
-
|
|
435
|
+
const connectedSockets = new Set();
|
|
436
436
|
node.status({text:RED._("tcpin.status.connections",{count:0})});
|
|
437
437
|
let srv = net;
|
|
438
438
|
let connOpts;
|
|
@@ -453,16 +453,16 @@ module.exports = function(RED) {
|
|
|
453
453
|
});
|
|
454
454
|
socket.on('close',function() {
|
|
455
455
|
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.
|
|
456
|
+
connectedSockets.delete(socket);
|
|
457
|
+
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.size})});
|
|
458
458
|
});
|
|
459
459
|
socket.on('error',function() {
|
|
460
460
|
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.
|
|
461
|
+
connectedSockets.delete(socket);
|
|
462
|
+
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.size})});
|
|
463
463
|
});
|
|
464
|
-
connectedSockets.
|
|
465
|
-
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.
|
|
464
|
+
connectedSockets.add(socket);
|
|
465
|
+
node.status({text:RED._("tcpin.status.connections",{count:connectedSockets.size})});
|
|
466
466
|
});
|
|
467
467
|
|
|
468
468
|
node.on("input", function(msg, nodeSend, nodeDone) {
|
|
@@ -475,10 +475,10 @@ module.exports = function(RED) {
|
|
|
475
475
|
} else {
|
|
476
476
|
buffer = Buffer.from(""+msg.payload);
|
|
477
477
|
}
|
|
478
|
-
|
|
479
|
-
if (node.doend === true) {
|
|
480
|
-
else {
|
|
481
|
-
}
|
|
478
|
+
connectedSockets.forEach(soc => {
|
|
479
|
+
if (node.doend === true) { soc.end(buffer); }
|
|
480
|
+
else { soc.write(buffer); }
|
|
481
|
+
})
|
|
482
482
|
}
|
|
483
483
|
nodeDone();
|
|
484
484
|
});
|
|
@@ -495,12 +495,10 @@ module.exports = function(RED) {
|
|
|
495
495
|
} else {
|
|
496
496
|
node.log(RED._("tcpin.status.listening-port",{port:node.port}));
|
|
497
497
|
node.on('close', function() {
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
}
|
|
503
|
-
}
|
|
498
|
+
connectedSockets.forEach(soc => {
|
|
499
|
+
soc.end();
|
|
500
|
+
soc.unref();
|
|
501
|
+
})
|
|
504
502
|
server.close();
|
|
505
503
|
node.log(RED._("tcpin.status.stopped-listening",{port:node.port}));
|
|
506
504
|
});
|
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
|
|
@@ -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
|
|
|
@@ -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 {
|
|
@@ -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">
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "48d660b3a4109400",
|
|
4
|
+
"type": "inject",
|
|
5
|
+
"z": "9e5f48c16729e4f0",
|
|
6
|
+
"name": "inject",
|
|
7
|
+
"props": [
|
|
8
|
+
{
|
|
9
|
+
"p": "payload"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
"repeat": "",
|
|
13
|
+
"crontab": "",
|
|
14
|
+
"once": false,
|
|
15
|
+
"onceDelay": 0.1,
|
|
16
|
+
"topic": "",
|
|
17
|
+
"payload": "",
|
|
18
|
+
"payloadType": "date",
|
|
19
|
+
"x": 185,
|
|
20
|
+
"y": 795,
|
|
21
|
+
"wires": [
|
|
22
|
+
[
|
|
23
|
+
"e0f9e206681f3504"
|
|
24
|
+
]
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "e0f9e206681f3504",
|
|
29
|
+
"type": "delay",
|
|
30
|
+
"z": "9e5f48c16729e4f0",
|
|
31
|
+
"name": "",
|
|
32
|
+
"pauseType": "rate",
|
|
33
|
+
"timeout": "5",
|
|
34
|
+
"timeoutUnits": "seconds",
|
|
35
|
+
"rate": "1",
|
|
36
|
+
"nbRateUnits": "30",
|
|
37
|
+
"rateUnits": "second",
|
|
38
|
+
"randomFirst": "1",
|
|
39
|
+
"randomLast": "5",
|
|
40
|
+
"randomUnits": "seconds",
|
|
41
|
+
"drop": false,
|
|
42
|
+
"allowrate": false,
|
|
43
|
+
"outputs": 1,
|
|
44
|
+
"x": 430,
|
|
45
|
+
"y": 795,
|
|
46
|
+
"wires": [
|
|
47
|
+
[
|
|
48
|
+
"e470f1d794e1bef9",
|
|
49
|
+
"af7cea1dfb797a75"
|
|
50
|
+
]
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": "943543cf7a1958e4",
|
|
55
|
+
"type": "change",
|
|
56
|
+
"z": "9e5f48c16729e4f0",
|
|
57
|
+
"name": "set flush to 1",
|
|
58
|
+
"rules": [
|
|
59
|
+
{
|
|
60
|
+
"t": "set",
|
|
61
|
+
"p": "flush",
|
|
62
|
+
"pt": "msg",
|
|
63
|
+
"to": "1",
|
|
64
|
+
"tot": "num"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"t": "delete",
|
|
68
|
+
"p": "payload",
|
|
69
|
+
"pt": "msg"
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
"action": "",
|
|
73
|
+
"property": "",
|
|
74
|
+
"from": "",
|
|
75
|
+
"to": "",
|
|
76
|
+
"reg": false,
|
|
77
|
+
"x": 510,
|
|
78
|
+
"y": 915,
|
|
79
|
+
"wires": [
|
|
80
|
+
[
|
|
81
|
+
"e0f9e206681f3504"
|
|
82
|
+
]
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"id": "e470f1d794e1bef9",
|
|
87
|
+
"type": "function",
|
|
88
|
+
"z": "9e5f48c16729e4f0",
|
|
89
|
+
"name": "Do something that takes a few seconds",
|
|
90
|
+
"func": "\n//send on the message between 3 and 6 seconds later\nsetTimeout(\n function() { \n node.send(msg) \n }, \n Math.random() * 3000 + 3000\n);\nreturn null;",
|
|
91
|
+
"outputs": 1,
|
|
92
|
+
"noerr": 0,
|
|
93
|
+
"initialize": "",
|
|
94
|
+
"finalize": "",
|
|
95
|
+
"libs": [],
|
|
96
|
+
"x": 760,
|
|
97
|
+
"y": 795,
|
|
98
|
+
"wires": [
|
|
99
|
+
[
|
|
100
|
+
"943543cf7a1958e4",
|
|
101
|
+
"859258551b8389b7"
|
|
102
|
+
]
|
|
103
|
+
]
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"id": "af7cea1dfb797a75",
|
|
107
|
+
"type": "debug",
|
|
108
|
+
"z": "9e5f48c16729e4f0",
|
|
109
|
+
"name": "IN",
|
|
110
|
+
"active": true,
|
|
111
|
+
"tosidebar": true,
|
|
112
|
+
"console": false,
|
|
113
|
+
"tostatus": false,
|
|
114
|
+
"complete": "payload",
|
|
115
|
+
"targetType": "msg",
|
|
116
|
+
"statusVal": "",
|
|
117
|
+
"statusType": "auto",
|
|
118
|
+
"x": 710,
|
|
119
|
+
"y": 735,
|
|
120
|
+
"wires": []
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"id": "859258551b8389b7",
|
|
124
|
+
"type": "debug",
|
|
125
|
+
"z": "9e5f48c16729e4f0",
|
|
126
|
+
"name": "OUT",
|
|
127
|
+
"active": true,
|
|
128
|
+
"tosidebar": true,
|
|
129
|
+
"console": false,
|
|
130
|
+
"tostatus": false,
|
|
131
|
+
"complete": "payload",
|
|
132
|
+
"targetType": "msg",
|
|
133
|
+
"statusVal": "",
|
|
134
|
+
"statusType": "auto",
|
|
135
|
+
"x": 895,
|
|
136
|
+
"y": 735,
|
|
137
|
+
"wires": []
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"id": "ecaaf26326da10ee",
|
|
141
|
+
"type": "comment",
|
|
142
|
+
"z": "9e5f48c16729e4f0",
|
|
143
|
+
"name": "Simple Queue with release",
|
|
144
|
+
"info": "This example shows how to use a delay node set to rate limit mode as a simple queue to feed a\nprocess that may take some time to complete. Once that process completes the feedback is then\nset to flush out the next message - thus running the \"loop\" as fast as possible with no overlaps.\n\n**Note**: only the `msg.flush` property msut be set - otherwise the other properties that are fed \nback will be added as another new message to the queue.",
|
|
145
|
+
"x": 235,
|
|
146
|
+
"y": 915,
|
|
147
|
+
"wires": []
|
|
148
|
+
}
|
|
149
|
+
]
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
<p>返却/sendの対象は次のとおりです:</p>
|
|
29
29
|
<ul>
|
|
30
30
|
<li>単一メッセージオブジェクト - 最初の出力に接続されたノードに渡されます</li>
|
|
31
|
-
<li>メッセージオブジェクトの配列 - 対応する出力に接続されたノードに渡されます</li>
|
|
31
|
+
<li>メッセージオブジェクトの配列 - 対応する出力に接続されたノードに渡されます</li>
|
|
32
32
|
</ul>
|
|
33
33
|
<p>注: 初期化処理の実行はノードの初期化中に行われます。そのため、初期化処理タブにsendを記述した場合に後続ノードでメッセージを受け取れないことがあります。</p>
|
|
34
34
|
<p>配列要素が配列の場合には、複数のメッセージを対応する出力に送出します。</p>
|
package/locales/ja/messages.json
CHANGED
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
<dt class="optional">userProperties <span class="property-type">オブジェクト</span></dt>
|
|
90
90
|
<dd><b>MQTTv5</b>: メッセージのユーザプロパティ</dd>
|
|
91
91
|
<dt class="optional">messageExpiryInterval <span class="property-type">数値</span></dt>
|
|
92
|
-
<dd><b>MQTTv5</b>: 秒単位のメッセージの有効期限</dd>
|
|
92
|
+
<dd><b>MQTTv5</b>: 秒単位のメッセージの有効期限</dd>
|
|
93
93
|
<dt class="optional">topicAlias <span class="property-type">数値</span></dt>
|
|
94
94
|
<dd><b>MQTTv5</b>: 使用するMQTTトピックエイリアス</dd>
|
|
95
95
|
</dl>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node-red/nodes",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.3",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"acorn": "8.7.0",
|
|
19
19
|
"acorn-walk": "8.2.0",
|
|
20
|
-
"ajv": "8.
|
|
20
|
+
"ajv": "8.10.0",
|
|
21
21
|
"body-parser": "1.19.1",
|
|
22
22
|
"cheerio": "1.0.0-rc.10",
|
|
23
23
|
"content-type": "1.0.4",
|
|
24
24
|
"cookie-parser": "1.4.6",
|
|
25
|
-
"cookie": "0.4.
|
|
25
|
+
"cookie": "0.4.2",
|
|
26
26
|
"cors": "2.8.5",
|
|
27
27
|
"cronosjs": "1.7.1",
|
|
28
28
|
"denque": "2.0.1",
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"is-utf8": "0.2.1",
|
|
37
37
|
"js-yaml": "3.14.1",
|
|
38
38
|
"media-typer": "1.1.0",
|
|
39
|
-
"mqtt": "4.3.
|
|
39
|
+
"mqtt": "4.3.5",
|
|
40
40
|
"multer": "1.4.4",
|
|
41
41
|
"mustache": "4.2.0",
|
|
42
42
|
"on-headers": "1.0.2",
|
|
43
|
-
"raw-body": "2.4.
|
|
43
|
+
"raw-body": "2.4.3",
|
|
44
44
|
"tough-cookie": "4.0.0",
|
|
45
45
|
"uuid": "8.3.2",
|
|
46
46
|
"ws": "7.5.6",
|