mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Initial support of sequence rules for SWITCH node (#1545)
* new UI for parts support of SWITCH node * update UI of SWITCH node for parts support * add server side code of new SWITCH node * update info document of SWITCH node * add tests for new SWITCH node features * add test for too many pending messages & related fixes * fix handling when msg is undefined * tabs -> spaces * fixed meaning of "repair sequence" in SWITCH node docs * add a note on restricting internally kept messages * change label and position in menu of "pos. between" rule * fixed typos (again, sorry)
This commit is contained in:
parent
218794be77
commit
6310de0d20
@ -541,7 +541,8 @@
|
|||||||
"switch": {
|
"switch": {
|
||||||
"label": {
|
"label": {
|
||||||
"property": "Property",
|
"property": "Property",
|
||||||
"rule": "rule"
|
"rule": "rule",
|
||||||
|
"repair" : "repair sequence (reconstruct parts property of outgoing messages)"
|
||||||
},
|
},
|
||||||
"and": "and",
|
"and": "and",
|
||||||
"checkall": "checking all rules",
|
"checkall": "checking all rules",
|
||||||
@ -555,10 +556,15 @@
|
|||||||
"false":"is false",
|
"false":"is false",
|
||||||
"null":"is null",
|
"null":"is null",
|
||||||
"nnull":"is not null",
|
"nnull":"is not null",
|
||||||
|
"head":"head",
|
||||||
|
"tail":"tail",
|
||||||
|
"index":"is between",
|
||||||
|
"exp":"JSONata exp",
|
||||||
"else":"otherwise"
|
"else":"otherwise"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"invalid-expr": "Invalid JSONata expression: __error__"
|
"invalid-expr": "Invalid JSONata expression: __error__",
|
||||||
|
"too-many" : "too many pending messages in switch node"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"change": {
|
"change": {
|
||||||
|
@ -33,6 +33,10 @@
|
|||||||
<option value="false" data-i18n="switch.stopfirst"></option>
|
<option value="false" data-i18n="switch.stopfirst"></option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<input type="checkbox" id="node-input-repair" style="display: inline-block; width: auto; vertical-align: top;">
|
||||||
|
<label style="width: auto;" for="node-input-repair"><span data-i18n="switch.label.repair"></span></label></input>
|
||||||
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/x-red" data-help-name="switch">
|
<script type="text/x-red" data-help-name="switch">
|
||||||
@ -44,25 +48,138 @@
|
|||||||
that matches.</p>
|
that matches.</p>
|
||||||
<p>The rules can be evaluated against an individual message property, a flow or global
|
<p>The rules can be evaluated against an individual message property, a flow or global
|
||||||
context property or the result of a JSONata expression.</p>
|
context property or the result of a JSONata expression.</p>
|
||||||
|
<h3>Rules</h3>
|
||||||
|
<p>Routing rules are categorized into three:</p>
|
||||||
|
<dl>
|
||||||
|
<dt>value rules</dt>
|
||||||
|
<dd>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>operator</th>
|
||||||
|
<th>description</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>==</b></td>
|
||||||
|
<td>property value is equals to specified value</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>!=</b></td>
|
||||||
|
<td>property value is not equals to specified value</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b><</b></td>
|
||||||
|
<td>property value is less than specified value</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b><=</b></td>
|
||||||
|
<td>property value is less than or equals to specified value</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>></b></td>
|
||||||
|
<td>property value is greater than specified value</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>>=</b></td>
|
||||||
|
<td>property value is greater than or equals to specified value</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>is between</b></td>
|
||||||
|
<td>property value is between specified values</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>contains</b></td>
|
||||||
|
<td>property string value contains specified string value</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>matches regex</b></td>
|
||||||
|
<td>property string value matches specified regex</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>is true</b></td>
|
||||||
|
<td>property value is true</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>is false</b></td>
|
||||||
|
<td>property value is false</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>is null</b></td>
|
||||||
|
<td>property value is null</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>is not null</b></td>
|
||||||
|
<td>property value is not null</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</dd>
|
||||||
|
<dt>sequence rules</dt>
|
||||||
|
<dd>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>operator</th>
|
||||||
|
<th>description</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>head</b></td>
|
||||||
|
<td>message is included in the first specified number of messages in a sequence</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>tail</b></td>
|
||||||
|
<td>message is included in the last specified number of messages in a sequence</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>pos. between</b></td>
|
||||||
|
<td>message is included between specified positions in a sequence</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</dd>
|
||||||
|
<dt>other rules</dt>
|
||||||
|
<dd>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>operator</th>
|
||||||
|
<th>description</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>JSONata exp</b></td>
|
||||||
|
<td>specified JSONata expression evaluate to true. In JSONata expression, $I represents <code>msg.parts.index</code> and $N represents <code>msg.parts.count</code> respectively if exists.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>otherwise</b></td>
|
||||||
|
<td>no matching rule found</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h3>Repair Sequence</h3>
|
||||||
|
<p>If <b>repair sequence (reconstruct parts property of outgoing messages)</b> checkbox is selected, <code>msg.parts</code> property are reconstructed for each port to make forks of valid sequences. Otherwise, <code>msg.parts</code> property of incoming messages are passed through.</p>
|
||||||
|
|
||||||
|
<h3>Note:</h3>
|
||||||
|
<p>This node internally keeps messages for its operation if <b>repair sequence</b> checkbox is ON. In order to prevent unexpected memory usage, maximum number of messages kept can be specified by <code>switchMaxKeptMsgsCount</code> property in <b>settings.js</b>.</p>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
(function() {
|
(function() {
|
||||||
var operators = [
|
var operators = [
|
||||||
{v:"eq",t:"=="},
|
{v:"eq",t:"==",kind:'V'},
|
||||||
{v:"neq",t:"!="},
|
{v:"neq",t:"!=",kind:'V'},
|
||||||
{v:"lt",t:"<"},
|
{v:"lt",t:"<",kind:'V'},
|
||||||
{v:"lte",t:"<="},
|
{v:"lte",t:"<=",kind:'V'},
|
||||||
{v:"gt",t:">"},
|
{v:"gt",t:">",kind:'V'},
|
||||||
{v:"gte",t:">="},
|
{v:"gte",t:">=",kind:'V'},
|
||||||
{v:"btwn",t:"switch.rules.btwn"},
|
{v:"btwn",t:"switch.rules.btwn",kind:'V'},
|
||||||
{v:"cont",t:"switch.rules.cont"},
|
{v:"cont",t:"switch.rules.cont",kind:'V'},
|
||||||
{v:"regex",t:"switch.rules.regex"},
|
{v:"regex",t:"switch.rules.regex",kind:'V'},
|
||||||
{v:"true",t:"switch.rules.true"},
|
{v:"true",t:"switch.rules.true",kind:'V'},
|
||||||
{v:"false",t:"switch.rules.false"},
|
{v:"false",t:"switch.rules.false",kind:'V'},
|
||||||
{v:"null",t:"switch.rules.null"},
|
{v:"null",t:"switch.rules.null",kind:'V'},
|
||||||
{v:"nnull",t:"switch.rules.nnull"},
|
{v:"nnull",t:"switch.rules.nnull",kind:'V'},
|
||||||
{v:"else",t:"switch.rules.else"}
|
{v:"head",t:"switch.rules.head",kind:'S'},
|
||||||
|
{v:"index",t:"switch.rules.index",kind:'S'},
|
||||||
|
{v:"tail",t:"switch.rules.tail",kind:'S'},
|
||||||
|
{v:"jsonata_exp",t:"switch.rules.exp",kind:'O'},
|
||||||
|
{v:"else",t:"switch.rules.else",kind:'O'}
|
||||||
];
|
];
|
||||||
|
|
||||||
function clipValueLength(v) {
|
function clipValueLength(v) {
|
||||||
@ -88,6 +205,7 @@
|
|||||||
propertyType: { value:"msg" },
|
propertyType: { value:"msg" },
|
||||||
rules: {value:[{t:"eq", v:"", vt:"str"}]},
|
rules: {value:[{t:"eq", v:"", vt:"str"}]},
|
||||||
checkall: {value:"true", required:true},
|
checkall: {value:"true", required:true},
|
||||||
|
repair: {value:false},
|
||||||
outputs: {value:1}
|
outputs: {value:1}
|
||||||
},
|
},
|
||||||
inputs: 1,
|
inputs: 1,
|
||||||
@ -102,7 +220,8 @@
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rule.t === 'btwn') {
|
if ((rule.t === 'btwn') || (rule.t === 'index')) {
|
||||||
|
console.log(`; ${label}/${JSON.stringify(rule)}`);
|
||||||
label += " "+getValueLabel(rule.vt,rule.v)+" & "+getValueLabel(rule.v2t,rule.v2);
|
label += " "+getValueLabel(rule.vt,rule.v)+" & "+getValueLabel(rule.v2t,rule.v2);
|
||||||
} else if (rule.t !== 'true' && rule.t !== 'false' && rule.t !== 'null' && rule.t !== 'nnull' && rule.t !== 'else' ) {
|
} else if (rule.t !== 'true' && rule.t !== 'false' && rule.t !== 'null' && rule.t !== 'nnull' && rule.t !== 'else' ) {
|
||||||
label += " "+getValueLabel(rule.vt,rule.v);
|
label += " "+getValueLabel(rule.vt,rule.v);
|
||||||
@ -132,6 +251,8 @@
|
|||||||
var selectField = rule.find("select");
|
var selectField = rule.find("select");
|
||||||
var type = selectField.val()||"";
|
var type = selectField.val()||"";
|
||||||
var valueField = rule.find(".node-input-rule-value");
|
var valueField = rule.find(".node-input-rule-value");
|
||||||
|
var numField = rule.find(".node-input-rule-num-value");
|
||||||
|
var expField = rule.find(".node-input-rule-exp-value");
|
||||||
var btwnField1 = rule.find(".node-input-rule-btwn-value");
|
var btwnField1 = rule.find(".node-input-rule-btwn-value");
|
||||||
var btwnField2 = rule.find(".node-input-rule-btwn-value2");
|
var btwnField2 = rule.find(".node-input-rule-btwn-value2");
|
||||||
var selectWidth;
|
var selectWidth;
|
||||||
@ -143,9 +264,13 @@
|
|||||||
selectWidth = 120;
|
selectWidth = 120;
|
||||||
}
|
}
|
||||||
selectField.width(selectWidth);
|
selectField.width(selectWidth);
|
||||||
if (type === "btwn") {
|
if ((type === "btwn") || (type === "index")) {
|
||||||
btwnField1.typedInput("width",(newWidth-selectWidth-70));
|
btwnField1.typedInput("width",(newWidth-selectWidth-70));
|
||||||
btwnField2.typedInput("width",(newWidth-selectWidth-70));
|
btwnField2.typedInput("width",(newWidth-selectWidth-70));
|
||||||
|
} else if ((type === "head") || (type === "tail")) {
|
||||||
|
numField.typedInput("width",(newWidth-selectWidth-70));
|
||||||
|
} else if (type === "jsonata_exp") {
|
||||||
|
expField.typedInput("width",(newWidth-selectWidth-70));
|
||||||
} else {
|
} else {
|
||||||
if (type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else") {
|
if (type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else") {
|
||||||
// valueField.hide();
|
// valueField.hide();
|
||||||
@ -171,10 +296,26 @@
|
|||||||
var row2 = $('<div/>',{style:"padding-top: 5px; padding-left: 175px;"}).appendTo(container);
|
var row2 = $('<div/>',{style:"padding-top: 5px; padding-left: 175px;"}).appendTo(container);
|
||||||
var row3 = $('<div/>',{style:"padding-top: 5px; padding-left: 102px;"}).appendTo(container);
|
var row3 = $('<div/>',{style:"padding-top: 5px; padding-left: 102px;"}).appendTo(container);
|
||||||
var selectField = $('<select/>',{style:"width:120px; margin-left: 5px; text-align: center;"}).appendTo(row);
|
var selectField = $('<select/>',{style:"width:120px; margin-left: 5px; text-align: center;"}).appendTo(row);
|
||||||
|
var group0 = $('<optgroup/>', { label: "value rules" }).appendTo(selectField);
|
||||||
for (var d in operators) {
|
for (var d in operators) {
|
||||||
|
if(operators[d].kind === 'V') {
|
||||||
|
group0.append($("<option></option>").val(operators[d].v).text(/^switch/.test(operators[d].t)?node._(operators[d].t):operators[d].t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var group1 = $('<optgroup/>', { label: "sequence rules" }).appendTo(selectField);
|
||||||
|
for (var d in operators) {
|
||||||
|
if(operators[d].kind === 'S') {
|
||||||
|
group1.append($("<option></option>").val(operators[d].v).text(/^switch/.test(operators[d].t)?node._(operators[d].t):operators[d].t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var d in operators) {
|
||||||
|
if(operators[d].kind === 'O') {
|
||||||
selectField.append($("<option></option>").val(operators[d].v).text(/^switch/.test(operators[d].t)?node._(operators[d].t):operators[d].t));
|
selectField.append($("<option></option>").val(operators[d].v).text(/^switch/.test(operators[d].t)?node._(operators[d].t):operators[d].t));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
var valueField = $('<input/>',{class:"node-input-rule-value",type:"text",style:"margin-left: 5px;"}).appendTo(row).typedInput({default:'str',types:['msg','flow','global','str','num','jsonata',previousValueType]});
|
var valueField = $('<input/>',{class:"node-input-rule-value",type:"text",style:"margin-left: 5px;"}).appendTo(row).typedInput({default:'str',types:['msg','flow','global','str','num','jsonata',previousValueType]});
|
||||||
|
var numValueField = $('<input/>',{class:"node-input-rule-num-value",type:"text",style:"margin-left: 5px;"}).appendTo(row).typedInput({default:'num',types:['flow','global','num','jsonata']});
|
||||||
|
var expValueField = $('<input/>',{class:"node-input-rule-exp-value",type:"text",style:"margin-left: 5px;"}).appendTo(row).typedInput({default:'jsonata',types:['jsonata']});
|
||||||
var btwnValueField = $('<input/>',{class:"node-input-rule-btwn-value",type:"text",style:"margin-left: 5px;"}).appendTo(row).typedInput({default:'num',types:['msg','flow','global','str','num','jsonata',previousValueType]});
|
var btwnValueField = $('<input/>',{class:"node-input-rule-btwn-value",type:"text",style:"margin-left: 5px;"}).appendTo(row).typedInput({default:'num',types:['msg','flow','global','str','num','jsonata',previousValueType]});
|
||||||
var btwnAndLabel = $('<span/>',{class:"node-input-rule-btwn-label"}).text(" "+andLabel+" ").appendTo(row3);
|
var btwnAndLabel = $('<span/>',{class:"node-input-rule-btwn-label"}).text(" "+andLabel+" ").appendTo(row3);
|
||||||
var btwnValue2Field = $('<input/>',{class:"node-input-rule-btwn-value2",type:"text",style:"margin-left:2px;"}).appendTo(row3).typedInput({default:'num',types:['msg','flow','global','str','num','jsonata',previousValueType]});
|
var btwnValue2Field = $('<input/>',{class:"node-input-rule-btwn-value2",type:"text",style:"margin-left:2px;"}).appendTo(row3).typedInput({default:'num',types:['msg','flow','global','str','num','jsonata',previousValueType]});
|
||||||
@ -185,11 +326,27 @@
|
|||||||
selectField.change(function() {
|
selectField.change(function() {
|
||||||
resizeRule(container);
|
resizeRule(container);
|
||||||
var type = selectField.val();
|
var type = selectField.val();
|
||||||
if (type === "btwn") {
|
if ((type === "btwn") || (type === "index")) {
|
||||||
valueField.typedInput('hide');
|
valueField.typedInput('hide');
|
||||||
|
expValueField.typedInput('hide');
|
||||||
|
numValueField.typedInput('hide');
|
||||||
btwnValueField.typedInput('show');
|
btwnValueField.typedInput('show');
|
||||||
|
} else if ((type === "head") || (type === "tail")) {
|
||||||
|
btwnValueField.typedInput('hide');
|
||||||
|
btwnValue2Field.typedInput('hide');
|
||||||
|
expValueField.typedInput('hide');
|
||||||
|
numValueField.typedInput('show');
|
||||||
|
valueField.typedInput('hide');
|
||||||
|
} else if (type === "jsonata_exp") {
|
||||||
|
btwnValueField.typedInput('hide');
|
||||||
|
btwnValue2Field.typedInput('hide');
|
||||||
|
expValueField.typedInput('show');
|
||||||
|
numValueField.typedInput('hide');
|
||||||
|
valueField.typedInput('hide');
|
||||||
} else {
|
} else {
|
||||||
btwnValueField.typedInput('hide');
|
btwnValueField.typedInput('hide');
|
||||||
|
expValueField.typedInput('hide');
|
||||||
|
numValueField.typedInput('hide');
|
||||||
if (type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else") {
|
if (type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else") {
|
||||||
valueField.typedInput('hide');
|
valueField.typedInput('hide');
|
||||||
} else {
|
} else {
|
||||||
@ -199,7 +356,7 @@
|
|||||||
if (type === "regex") {
|
if (type === "regex") {
|
||||||
row2.show();
|
row2.show();
|
||||||
row3.hide();
|
row3.hide();
|
||||||
} else if (type === "btwn") {
|
} else if ((type === "btwn") || (type === "index")) {
|
||||||
row2.hide();
|
row2.hide();
|
||||||
row3.show();
|
row3.show();
|
||||||
btwnValue2Field.typedInput('show');
|
btwnValue2Field.typedInput('show');
|
||||||
@ -209,11 +366,17 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
selectField.val(rule.t);
|
selectField.val(rule.t);
|
||||||
if (rule.t == "btwn") {
|
if ((rule.t == "btwn") || (rule.t == "index")) {
|
||||||
btwnValueField.typedInput('value',rule.v);
|
btwnValueField.typedInput('value',rule.v);
|
||||||
btwnValueField.typedInput('type',rule.vt||'num');
|
btwnValueField.typedInput('type',rule.vt||'num');
|
||||||
btwnValue2Field.typedInput('value',rule.v2);
|
btwnValue2Field.typedInput('value',rule.v2);
|
||||||
btwnValue2Field.typedInput('type',rule.v2t||'num');
|
btwnValue2Field.typedInput('type',rule.v2t||'num');
|
||||||
|
} else if ((rule.t === "head") || (rule.t === "tail")) {
|
||||||
|
numValueField.typedInput('value',rule.v);
|
||||||
|
numValueField.typedInput('type',rule.vt||'num');
|
||||||
|
} else if (rule.t === "jsonata_exp") {
|
||||||
|
expValueField.typedInput('value',rule.v);
|
||||||
|
expValueField.typedInput('type',rule.vt||'jsonata');
|
||||||
} else if (typeof rule.v != "undefined") {
|
} else if (typeof rule.v != "undefined") {
|
||||||
valueField.typedInput('value',rule.v);
|
valueField.typedInput('value',rule.v);
|
||||||
valueField.typedInput('type',rule.vt||'str');
|
valueField.typedInput('type',rule.vt||'str');
|
||||||
@ -275,11 +438,17 @@
|
|||||||
var type = rule.find("select").val();
|
var type = rule.find("select").val();
|
||||||
var r = {t:type};
|
var r = {t:type};
|
||||||
if (!(type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else")) {
|
if (!(type === "true" || type === "false" || type === "null" || type === "nnull" || type === "else")) {
|
||||||
if (type === "btwn") {
|
if ((type === "btwn") || (type === "index")) {
|
||||||
r.v = rule.find(".node-input-rule-btwn-value").typedInput('value');
|
r.v = rule.find(".node-input-rule-btwn-value").typedInput('value');
|
||||||
r.vt = rule.find(".node-input-rule-btwn-value").typedInput('type');
|
r.vt = rule.find(".node-input-rule-btwn-value").typedInput('type');
|
||||||
r.v2 = rule.find(".node-input-rule-btwn-value2").typedInput('value');
|
r.v2 = rule.find(".node-input-rule-btwn-value2").typedInput('value');
|
||||||
r.v2t = rule.find(".node-input-rule-btwn-value2").typedInput('type');
|
r.v2t = rule.find(".node-input-rule-btwn-value2").typedInput('type');
|
||||||
|
} else if ((type === "head") || (type === "tail")) {
|
||||||
|
r.v = rule.find(".node-input-rule-num-value").typedInput('value');
|
||||||
|
r.vt = rule.find(".node-input-rule-num-value").typedInput('type');
|
||||||
|
} else if (type === "jsonata_exp") {
|
||||||
|
r.v = rule.find(".node-input-rule-exp-value").typedInput('value');
|
||||||
|
r.vt = rule.find(".node-input-rule-exp-value").typedInput('type');
|
||||||
} else {
|
} else {
|
||||||
r.v = rule.find(".node-input-rule-value").typedInput('value');
|
r.v = rule.find(".node-input-rule-value").typedInput('value');
|
||||||
r.vt = rule.find(".node-input-rule-value").typedInput('type');
|
r.vt = rule.find(".node-input-rule-value").typedInput('type');
|
||||||
|
@ -31,9 +31,39 @@ module.exports = function(RED) {
|
|||||||
'false': function(a) { return a === false; },
|
'false': function(a) { return a === false; },
|
||||||
'null': function(a) { return (typeof a == "undefined" || a === null); },
|
'null': function(a) { return (typeof a == "undefined" || a === null); },
|
||||||
'nnull': function(a) { return (typeof a != "undefined" && a !== null); },
|
'nnull': function(a) { return (typeof a != "undefined" && a !== null); },
|
||||||
|
'head': function(a, b, c, d, parts) {
|
||||||
|
var count = Number(b);
|
||||||
|
return (parts.index < count);
|
||||||
|
},
|
||||||
|
'tail': function(a, b, c, d, parts) {
|
||||||
|
var count = Number(b);
|
||||||
|
return (parts.count -count <= parts.index);
|
||||||
|
},
|
||||||
|
'index': function(a, b, c, d, parts) {
|
||||||
|
var min = Number(b);
|
||||||
|
var max = Number(c);
|
||||||
|
var index = parts.index;
|
||||||
|
return ((min <= index) && (index <= max));
|
||||||
|
},
|
||||||
|
'jsonata_exp': function(a, b) { return (b === true); },
|
||||||
'else': function(a) { return a === true; }
|
'else': function(a) { return a === true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var _max_kept_msgs_count = undefined;
|
||||||
|
|
||||||
|
function max_kept_msgs_count(node) {
|
||||||
|
if (_max_kept_msgs_count === undefined) {
|
||||||
|
var name = "switchMaxKeptMsgsCount";
|
||||||
|
if (RED.settings.hasOwnProperty(name)) {
|
||||||
|
_max_kept_msgs_count = RED.settings[name];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_max_kept_msgs_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _max_kept_msgs_count;
|
||||||
|
}
|
||||||
|
|
||||||
function SwitchNode(n) {
|
function SwitchNode(n) {
|
||||||
RED.nodes.createNode(this, n);
|
RED.nodes.createNode(this, n);
|
||||||
this.rules = n.rules || [];
|
this.rules = n.rules || [];
|
||||||
@ -53,8 +83,11 @@ module.exports = function(RED) {
|
|||||||
this.previousValue = null;
|
this.previousValue = null;
|
||||||
var node = this;
|
var node = this;
|
||||||
var valid = true;
|
var valid = true;
|
||||||
|
var needs_count = false;
|
||||||
|
var repair = n.repair;
|
||||||
for (var i=0; i<this.rules.length; i+=1) {
|
for (var i=0; i<this.rules.length; i+=1) {
|
||||||
var rule = this.rules[i];
|
var rule = this.rules[i];
|
||||||
|
needs_count = needs_count || ((rule.t === "tail") || (rule.t === "jsonata_exp"));
|
||||||
if (!rule.vt) {
|
if (!rule.vt) {
|
||||||
if (!isNaN(Number(rule.v))) {
|
if (!isNaN(Number(rule.v))) {
|
||||||
rule.vt = 'num';
|
rule.vt = 'num';
|
||||||
@ -99,7 +132,136 @@ module.exports = function(RED) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.on('input', function (msg) {
|
var pending_count = 0;
|
||||||
|
var pending_id = 0;
|
||||||
|
var pending_in = {};
|
||||||
|
var pending_out = {};
|
||||||
|
var received = {};
|
||||||
|
|
||||||
|
function add2group_in(id, msg, parts) {
|
||||||
|
if (!(id in pending_in)) {
|
||||||
|
pending_in[id] = {
|
||||||
|
count: undefined,
|
||||||
|
msgs: [],
|
||||||
|
seq_no: pending_id++
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var group = pending_in[id];
|
||||||
|
group.msgs.push(msg);
|
||||||
|
pending_count++;
|
||||||
|
var max_msgs = max_kept_msgs_count(node);
|
||||||
|
if ((max_msgs > 0) && (pending_count > max_msgs)) {
|
||||||
|
clear_pending();
|
||||||
|
node.error(RED._("switch.errors.too-many"), msg);
|
||||||
|
}
|
||||||
|
if (parts.hasOwnProperty("count")) {
|
||||||
|
group.count = parts.count;
|
||||||
|
}
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
function del_group_in(id, group) {
|
||||||
|
pending_count -= group.msgs.length;
|
||||||
|
delete pending_in[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
function add2pending_in(msg) {
|
||||||
|
var parts = msg.parts;
|
||||||
|
if (parts.hasOwnProperty("id") &&
|
||||||
|
parts.hasOwnProperty("index")) {
|
||||||
|
var group = add2group_in(parts.id, msg, parts);
|
||||||
|
var msgs = group.msgs;
|
||||||
|
var count = group.count;
|
||||||
|
if (count === msgs.length) {
|
||||||
|
for (var i = 0; i < msgs.length; i++) {
|
||||||
|
var msg = msgs[i];
|
||||||
|
msg.parts.count = count;
|
||||||
|
process_msg(msg, false);
|
||||||
|
}
|
||||||
|
del_group_in(parts.id, group);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_group(onwards, port_count) {
|
||||||
|
var counts = new Array(port_count).fill(0);
|
||||||
|
var ids = new Array(port_count);
|
||||||
|
for(var i = 0; i < onwards.length; i++) {
|
||||||
|
var onward = onwards[i];
|
||||||
|
for(var j = 0; j < port_count; j++) {
|
||||||
|
counts[j] += (onward[j] !== null) ? 1 : 0
|
||||||
|
}
|
||||||
|
ids[i] = RED.util.generateId();
|
||||||
|
}
|
||||||
|
var indexes = new Array(port_count).fill(0);
|
||||||
|
var ports = new Array(port_count);
|
||||||
|
for (var i = 0; i < onwards.length; i++) {
|
||||||
|
var onward = onwards[i];
|
||||||
|
for (var j = 0; j < port_count; j++) {
|
||||||
|
var msg = onward[j];
|
||||||
|
if (msg) {
|
||||||
|
var new_msg = RED.util.cloneMessage(msg);
|
||||||
|
var parts = new_msg.parts;
|
||||||
|
parts.id = ids[j];
|
||||||
|
parts.index = indexes[j];
|
||||||
|
parts.count = counts[j];
|
||||||
|
ports[j] = new_msg;
|
||||||
|
indexes[j]++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ports[j] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node.send(ports);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function send2ports(onward, msg) {
|
||||||
|
var parts = msg.parts;
|
||||||
|
var gid = parts.id;
|
||||||
|
received[gid] = ((gid in received) ? received[gid] : 0) +1;
|
||||||
|
var send_ok = (received[gid] === parts.count);
|
||||||
|
|
||||||
|
if (!(gid in pending_out)) {
|
||||||
|
pending_out[gid] = {
|
||||||
|
onwards: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var group = pending_out[gid];
|
||||||
|
var onwards = group.onwards;
|
||||||
|
onwards.push(onward);
|
||||||
|
pending_count++;
|
||||||
|
if (send_ok) {
|
||||||
|
send_group(onwards, onward.length, msg);
|
||||||
|
pending_count -= onward.length;
|
||||||
|
delete pending_out[gid];
|
||||||
|
delete received[gid];
|
||||||
|
}
|
||||||
|
var max_msgs = max_kept_msgs_count(node);
|
||||||
|
if ((max_msgs > 0) && (pending_count > max_msgs)) {
|
||||||
|
clear_pending();
|
||||||
|
node.error(RED._("switch.errors.too-many"), msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function msg_has_parts(msg) {
|
||||||
|
if (msg.hasOwnProperty("parts")) {
|
||||||
|
var parts = msg.parts;
|
||||||
|
return (parts.hasOwnProperty("id") &&
|
||||||
|
parts.hasOwnProperty("index") &&
|
||||||
|
parts.hasOwnProperty("count"));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function process_msg(msg, check_parts) {
|
||||||
|
var has_parts = msg_has_parts(msg);
|
||||||
|
if (needs_count && check_parts && has_parts &&
|
||||||
|
add2pending_in(msg)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var onward = [];
|
var onward = [];
|
||||||
try {
|
try {
|
||||||
var prop;
|
var prop;
|
||||||
@ -117,7 +279,14 @@ module.exports = function(RED) {
|
|||||||
v1 = node.previousValue;
|
v1 = node.previousValue;
|
||||||
} else if (rule.vt === 'jsonata') {
|
} else if (rule.vt === 'jsonata') {
|
||||||
try {
|
try {
|
||||||
v1 = RED.util.evaluateJSONataExpression(rule.v,msg);
|
var exp = rule.v;
|
||||||
|
if (rule.t === 'jsonata_exp') {
|
||||||
|
if (has_parts) {
|
||||||
|
exp.assign("I", msg.parts.index);
|
||||||
|
exp.assign("N", msg.parts.count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v1 = RED.util.evaluateJSONataExpression(exp,msg);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
node.error(RED._("switch.errors.invalid-expr",{error:err.message}));
|
node.error(RED._("switch.errors.invalid-expr",{error:err.message}));
|
||||||
return;
|
return;
|
||||||
@ -147,7 +316,7 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rule.t == "else") { test = elseflag; elseflag = true; }
|
if (rule.t == "else") { test = elseflag; elseflag = true; }
|
||||||
if (operators[rule.t](test,v1,v2,rule.case)) {
|
if (operators[rule.t](test,v1,v2,rule.case,msg.parts)) {
|
||||||
onward.push(msg);
|
onward.push(msg);
|
||||||
elseflag = false;
|
elseflag = false;
|
||||||
if (node.checkall == "false") { break; }
|
if (node.checkall == "false") { break; }
|
||||||
@ -156,11 +325,33 @@ module.exports = function(RED) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
node.previousValue = prop;
|
node.previousValue = prop;
|
||||||
this.send(onward);
|
if (repair || !has_parts) {
|
||||||
|
node.send(onward);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
send2ports(onward, msg);
|
||||||
|
}
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
node.warn(err);
|
node.warn(err);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear_pending() {
|
||||||
|
pending_count = 0;
|
||||||
|
pending_id = 0;
|
||||||
|
pending_in = {};
|
||||||
|
pending_out = {};
|
||||||
|
received = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
this.on('input', function(msg) {
|
||||||
|
process_msg(msg, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.on('close', function() {
|
||||||
|
clear_pending();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
RED.nodes.registerType("switch", SwitchNode);
|
RED.nodes.registerType("switch", SwitchNode);
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,7 @@ module.exports = {
|
|||||||
// The maximum number of messages kept internally in nodes.
|
// The maximum number of messages kept internally in nodes.
|
||||||
// Zero or undefined value means not restricting number of messages.
|
// Zero or undefined value means not restricting number of messages.
|
||||||
//sortMaxKeptMsgsCount: 0,
|
//sortMaxKeptMsgsCount: 0,
|
||||||
|
//switchMaxKeptMsgsCount: 0,
|
||||||
//joinMaxKeptMsgsCount: 0,
|
//joinMaxKeptMsgsCount: 0,
|
||||||
//batchMaxKeptMsgsCount: 0,
|
//batchMaxKeptMsgsCount: 0,
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ var should = require("should");
|
|||||||
|
|
||||||
var switchNode = require("../../../../nodes/core/logic/10-switch.js");
|
var switchNode = require("../../../../nodes/core/logic/10-switch.js");
|
||||||
var helper = require("../../helper.js");
|
var helper = require("../../helper.js");
|
||||||
|
var RED = require("../../../../red/red.js");
|
||||||
|
|
||||||
describe('switch Node', function() {
|
describe('switch Node', function() {
|
||||||
|
|
||||||
@ -28,6 +29,7 @@ describe('switch Node', function() {
|
|||||||
afterEach(function(done) {
|
afterEach(function(done) {
|
||||||
helper.unload();
|
helper.unload();
|
||||||
helper.stopServer(done);
|
helper.stopServer(done);
|
||||||
|
RED.settings.switchMaxKeptMsgsCount = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be loaded with some defaults', function(done) {
|
it('should be loaded with some defaults', function(done) {
|
||||||
@ -119,6 +121,44 @@ describe('switch Node', function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function customFlowSequenceSwitchTest(flow, seq_in, seq_out, done) {
|
||||||
|
helper.load(switchNode, flow, function() {
|
||||||
|
var switchNode1 = helper.getNode("switchNode1");
|
||||||
|
var helperNode1 = helper.getNode("helperNode1");
|
||||||
|
var sid = undefined;
|
||||||
|
var count = 0;
|
||||||
|
helperNode1.on("input", function(msg) {
|
||||||
|
try {
|
||||||
|
msg.should.have.property("payload", seq_out[count]);
|
||||||
|
msg.should.have.property("parts");
|
||||||
|
var parts = msg.parts;
|
||||||
|
parts.should.have.property("id");
|
||||||
|
var id = parts.id;
|
||||||
|
if (sid === undefined) {
|
||||||
|
sid = id;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
id.should.equal(sid);
|
||||||
|
}
|
||||||
|
parts.should.have.property("index", count);
|
||||||
|
parts.should.have.property("count", seq_out.length);
|
||||||
|
count++;
|
||||||
|
if (count === seq_out.length) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
done(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var len = seq_in.length;
|
||||||
|
for (var i = 0; i < len; i++) {
|
||||||
|
var parts = {index:i, count:len, id:222};
|
||||||
|
var msg = {payload:seq_in[i], parts:parts};
|
||||||
|
switchNode1.receive(msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
it('should check if payload equals given value', function(done) {
|
it('should check if payload equals given value', function(done) {
|
||||||
genericSwitchTest("eq", "Hello", true, true, "Hello", done);
|
genericSwitchTest("eq", "Hello", true, true, "Hello", done);
|
||||||
});
|
});
|
||||||
@ -498,4 +538,176 @@ describe('switch Node', function() {
|
|||||||
{id:"helperNode1", type:"helper", wires:[]}];
|
{id:"helperNode1", type:"helper", wires:[]}];
|
||||||
customFlowSwitchTest(flow, true, -5, done);
|
customFlowSwitchTest(flow, true, -5, done);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should take head of message sequence', function(done) {
|
||||||
|
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"head","v":3}],checkall:true,outputs:1,wires:[["helperNode1"]]},
|
||||||
|
{id:"helperNode1", type:"helper", wires:[]}];
|
||||||
|
customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [0, 1, 2], done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should take tail of message sequence', function(done) {
|
||||||
|
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"tail","v":3}],checkall:true,outputs:1,wires:[["helperNode1"]]},
|
||||||
|
{id:"helperNode1", type:"helper", wires:[]}];
|
||||||
|
customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [2, 3, 4], done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should take slice of message sequence', function(done) {
|
||||||
|
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"index","v":1,"v2":3}],checkall:true,outputs:1,wires:[["helperNode1"]]},
|
||||||
|
{id:"helperNode1", type:"helper", wires:[]}];
|
||||||
|
customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [1,2, 3], done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should check JSONata expression is true', function(done) {
|
||||||
|
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",
|
||||||
|
rules:[{"t":"jsonata_exp","v":"payload%2 = 1","vt":"jsonata"}],
|
||||||
|
checkall:true,outputs:1,wires:[["helperNode1"]]},
|
||||||
|
{id:"helperNode1", type:"helper", wires:[]}];
|
||||||
|
customFlowSwitchTest(flow, true, 9, done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should repair message sequence', function(done) {
|
||||||
|
var flow = [{id:"n1",type:"switch",name:"switchNode",property:"payload",
|
||||||
|
rules:[{"t":"gt","v":0},{"t":"lt","v":0},{"t":"else"}],
|
||||||
|
checkall:true,repair:true,
|
||||||
|
outputs:3,wires:[["n2"],["n3"],["n4"]]},
|
||||||
|
{id:"n2", type:"helper", wires:[]},
|
||||||
|
{id:"n3", type:"helper", wires:[]},
|
||||||
|
{id:"n4", type:"helper", wires:[]}
|
||||||
|
];
|
||||||
|
helper.load(switchNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
var n3 = helper.getNode("n3");
|
||||||
|
var n4 = helper.getNode("n4");
|
||||||
|
var data = { "0":1, "1":-2, "2":2, "3":0, "4":-1 };
|
||||||
|
var count = 0;
|
||||||
|
function check_msg(msg, vf) {
|
||||||
|
try {
|
||||||
|
msg.should.have.property("payload");
|
||||||
|
var payload = msg.payload;
|
||||||
|
msg.should.have.property("parts");
|
||||||
|
vf(payload).should.be.ok;
|
||||||
|
var parts = msg.parts;
|
||||||
|
parts.should.have.property("id", 222);
|
||||||
|
parts.should.have.property("count", 5);
|
||||||
|
parts.should.have.property("index");
|
||||||
|
var index = parts.index;
|
||||||
|
payload.should.equal(data[index]);
|
||||||
|
count++;
|
||||||
|
if (count == 5) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
done(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
check_msg(msg, function(x) { return(x < 0); });
|
||||||
|
});
|
||||||
|
n3.on("input", function(msg) {
|
||||||
|
check_msg(msg, function(x) { return(x === 0); });
|
||||||
|
});
|
||||||
|
n4.on("input", function(msg) {
|
||||||
|
check_msg(msg, function(x) { return(x > 0); });
|
||||||
|
});
|
||||||
|
for(var i in data) {
|
||||||
|
n1.receive({payload: data[i], parts:{index:i,count:5,id:222}});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create message sequence for each port', function(done) {
|
||||||
|
var flow = [{id:"n1",type:"switch",name:"switchNode",property:"payload",
|
||||||
|
rules:[{"t":"gt","v":0},{"t":"lt","v":0},{"t":"else"}],
|
||||||
|
checkall:true,repair:false,
|
||||||
|
outputs:3,wires:[["n2"],["n3"],["n4"]]},
|
||||||
|
{id:"n2", type:"helper", wires:[]}, // >0
|
||||||
|
{id:"n3", type:"helper", wires:[]}, // <0
|
||||||
|
{id:"n4", type:"helper", wires:[]} // ==0
|
||||||
|
];
|
||||||
|
helper.load(switchNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
var n2 = helper.getNode("n2");
|
||||||
|
var n3 = helper.getNode("n3");
|
||||||
|
var n4 = helper.getNode("n4");
|
||||||
|
var data = [ 1, -2, 2, 0, -1 ];
|
||||||
|
var vals = [[1, 2], [-2, -1], [0]];
|
||||||
|
var ids = [undefined, undefined, undefined];
|
||||||
|
var counts = [0, 0, 0];
|
||||||
|
var count = 0;
|
||||||
|
function check_msg(msg, ix, vf) {
|
||||||
|
try {
|
||||||
|
msg.should.have.property("payload");
|
||||||
|
var payload = msg.payload;
|
||||||
|
msg.should.have.property("parts");
|
||||||
|
vf(payload).should.be.ok;
|
||||||
|
var parts = msg.parts;
|
||||||
|
var evals = vals[ix];
|
||||||
|
parts.should.have.property("count", evals.length);
|
||||||
|
parts.should.have.property("id");
|
||||||
|
var id = parts.id;
|
||||||
|
if (ids[ix] === undefined) {
|
||||||
|
ids[ix] = id;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ids[ix].should.equal(id);
|
||||||
|
}
|
||||||
|
parts.should.have.property("index");
|
||||||
|
var index = parts.index;
|
||||||
|
var eindex = counts[ix];
|
||||||
|
var eval = evals[eindex];
|
||||||
|
payload.should.equal(eval);
|
||||||
|
counts[ix]++;
|
||||||
|
count++;
|
||||||
|
if (count == 5) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
done(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n2.on("input", function(msg) {
|
||||||
|
check_msg(msg, 0, function(x) { return(x > 0); });
|
||||||
|
});
|
||||||
|
n3.on("input", function(msg) {
|
||||||
|
check_msg(msg, 1, function(x) { return(x < 0); });
|
||||||
|
});
|
||||||
|
n4.on("input", function(msg) {
|
||||||
|
check_msg(msg, 2, function(x) { return(x === 0); });
|
||||||
|
});
|
||||||
|
for(var i in data) {
|
||||||
|
n1.receive({payload: data[i], parts:{index:i,count:5,id:222}});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle too many pending messages', function(done) {
|
||||||
|
var flow = [{id:"n1",type:"switch",name:"switchNode",property:"payload",
|
||||||
|
rules:[{"t":"tail","v":2}],
|
||||||
|
checkall:true,repair:false,
|
||||||
|
outputs:3,wires:[["n2"]]},
|
||||||
|
{id:"n2", type:"helper", wires:[]}
|
||||||
|
];
|
||||||
|
helper.load(switchNode, flow, function() {
|
||||||
|
var n1 = helper.getNode("n1");
|
||||||
|
RED.settings.switchMaxKeptMsgsCount = 2;
|
||||||
|
setTimeout(function() {
|
||||||
|
var logEvents = helper.log().args.filter(function (evt) {
|
||||||
|
return evt[0].type == "switch";
|
||||||
|
});
|
||||||
|
var evt = logEvents[0][0];
|
||||||
|
evt.should.have.property('id', "n1");
|
||||||
|
evt.should.have.property('type', "switch");
|
||||||
|
evt.should.have.property('msg', "switch.errors.too-many");
|
||||||
|
done();
|
||||||
|
}, 150);
|
||||||
|
n1.receive({payload:3, parts:{index:2, count:4, id:222}});
|
||||||
|
n1.receive({payload:2, parts:{index:1, count:4, id:222}});
|
||||||
|
n1.receive({payload:4, parts:{index:3, count:4, id:222}});
|
||||||
|
n1.receive({payload:1, parts:{index:0, count:4, id:222}});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user