From 52c0d360b2887def89788ca7bdef77c6d06e7355 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Tue, 27 Jun 2017 17:10:52 +0100 Subject: [PATCH] Add buffer joiner mode to Join node --- nodes/core/locales/en-US/messages.json | 3 +- nodes/core/logic/17-split.html | 44 ++++++++++++----- nodes/core/logic/17-split.js | 27 ++++++++-- test/nodes/core/logic/17-split_spec.js | 68 ++++++++++++++++++-------- 4 files changed, 103 insertions(+), 39 deletions(-) diff --git a/nodes/core/locales/en-US/messages.json b/nodes/core/locales/en-US/messages.json index df3b3d98a..e2c34c29b 100644 --- a/nodes/core/locales/en-US/messages.json +++ b/nodes/core/locales/en-US/messages.json @@ -812,10 +812,11 @@ "type":{ "string":"a String", "array":"an Array", + "buffer":"a Buffer", "object":"a key/value Object", "merged":"a merged Object" }, - "using":"using", + "using":"using the value of", "key":"as the key", "joinedUsing":"joined using", "send":"Send the message:", diff --git a/nodes/core/logic/17-split.html b/nodes/core/logic/17-split.html index 8aa53ea49..322ecf228 100644 --- a/nodes/core/logic/17-split.html +++ b/nodes/core/logic/17-split.html @@ -181,21 +181,23 @@
- +
- +
- + +
@@ -203,8 +205,8 @@
  • -
  • - +
  • +
  • @@ -249,14 +251,16 @@

    When configured to join in manual mode, the node is able to join sequences of messages in a variety of ways.

      -
    • a string - created by joining the selected property of each message with the specified join character.
    • -
    • an array.
    • +
    • a string or buffer - created by joining the selected property of each message with the specified join characters or buffer.
    • +
    • an array - created by adding each selected property, or entire message, to the output array.
    • a key/value object - created by using a property of each message to determine the key under which the required value is stored.
    • a merged object - created by merging the property of each message under a single object.

    The other properties of the output message are taken from the last message received before the result is sent.

    -

    A count can be set for how many messages should be received before generating the output message.

    +

    A count can be set for how many messages should be received before generating the output message. + For object outputs, once this count has been reached, the node can be configured to send a message for each subsequent message + received.

    A timeout can be set to trigger sending the new message using whatever has been received so far.

    If a message is received with the msg.complete property set, the output message is sent.

    @@ -273,8 +277,8 @@ propertyType: { value:"msg"}, key: {value:"topic"}, joiner: { value:"\\n"}, + joinerType: { value:"str"}, accumulate: { value:"false" }, - //topic: { value:""}, timeout: {value:""}, count: {value:""} }, @@ -300,15 +304,25 @@ $("#node-input-build").change(function(e) { var val = $(this).val(); $(".node-row-key").toggle(val==='object'); - $(".node-row-joiner").toggle(val==='string'); + $(".node-row-accumulate").toggle(val==='object' || val==='merged'); + $(".node-row-joiner").toggle(val==='string' || val==='buffer'); $(".node-row-trigger").toggle(val!=='auto'); - if (val === 'string') { + if (val === 'string' || val==='buffer') { $("#node-input-property").typedInput('types',['msg']); } else { $("#node-input-property").typedInput('types',['msg', {value:"full",label:"complete message",hasValue:false}]); } }); + $("#node-input-joiner").typedInput({ + default: 'str', + typeField: $("#node-input-joinerType"), + types:[ + 'str', + 'bin' + ] + }); + $("#node-input-property").typedInput({ typeField: $("#node-input-propertyType"), types:['msg', {value:"full", label:"complete message", hasValue:false}] @@ -320,6 +334,12 @@ $("#node-input-build").change(); $("#node-input-mode").change(); + }, + oneditsave: function() { + var build = $("#node-input-build").val(); + if (build !== 'object' && build !== 'merged') { + $("#node-input-accumulate").prop("checked",false); + } } }); diff --git a/nodes/core/logic/17-split.js b/nodes/core/logic/17-split.js index 1b96fd583..8fab1bcb5 100644 --- a/nodes/core/logic/17-split.js +++ b/nodes/core/logic/17-split.js @@ -66,7 +66,7 @@ module.exports = function(RED) { return; } node.c = 0; - node.buffer = new Buffer.from([]); + node.buffer = Buffer.from([]); this.on("input", function(msg) { if (msg.hasOwnProperty("payload")) { if (msg.hasOwnProperty("parts")) { msg.parts = { parts:msg.parts }; } // push existing parts to a stack @@ -182,7 +182,7 @@ module.exports = function(RED) { msg.payload = node.buffer; msg.parts.index = node.c++; node.send(RED.util.cloneMessage(msg)); - node.buffer = new Buffer.from([]); + node.buffer = Buffer.from([]); } } else { @@ -243,7 +243,20 @@ module.exports = function(RED) { this.key = n.key||"topic"; this.timer = (this.mode === "auto") ? 0 : Number(n.timeout || 0)*1000; this.count = Number(n.count || 0); - this.joiner = (n.joiner||"").replace(/\\n/g,"\n").replace(/\\r/g,"\r").replace(/\\t/g,"\t").replace(/\\e/g,"\e").replace(/\\f/g,"\f").replace(/\\0/g,"\0"); + this.joiner = n.joiner||""; + this.joinerType = n.joinerType||"str"; + + if (this.joinerType === "str") { + this.joiner = this.joiner.replace(/\\n/g,"\n").replace(/\\r/g,"\r").replace(/\\t/g,"\t").replace(/\\e/g,"\e").replace(/\\f/g,"\f").replace(/\\0/g,"\0"); + } else if (this.joinerType === "bin") { + var joinArray = JSON.parse(n.joiner) + if (Array.isArray(joinArray)) { + this.joiner = Buffer.from(joinArray); + } else { + throw new Error("not an array"); + } + } + this.build = n.build || "array"; this.accumulate = n.accumulate || "false"; //this.topic = n.topic; @@ -281,7 +294,11 @@ module.exports = function(RED) { } if (group.type === 'string') { - RED.util.setMessageProperty(group.msg,node.property,group.payload.join(group.joinChar)); + var groupJoinChar = group.joinChar; + if (typeof group.joinChar !== 'string') { + groupJoinChar = group.joinChar.toString(); + } + RED.util.setMessageProperty(group.msg,node.property,group.payload.join(groupJoinChar)); } else { RED.util.setMessageProperty(group.msg,node.property,group.payload); } @@ -378,7 +395,7 @@ module.exports = function(RED) { type:payloadType, msg:msg } - if (payloadType === 'string') { + if (payloadType === 'string' || payloadType === 'array' || payloadType === 'buffer') { inflight[partId].payload = []; } } diff --git a/test/nodes/core/logic/17-split_spec.js b/test/nodes/core/logic/17-split_spec.js index 289ded95e..bfbb4dae0 100644 --- a/test/nodes/core/logic/17-split_spec.js +++ b/test/nodes/core/logic/17-split_spec.js @@ -69,7 +69,7 @@ describe('SPLIT node', function() { msg.parts.should.have.property("count",2); msg.parts.should.have.property("type","array"); msg.parts.should.have.property("index"); - msg.payload.should.be.an.Array; + msg.payload.should.be.an.Array(); if (msg.parts.index === 0) { msg.payload.length.should.equal(3); } if (msg.parts.index === 1) { msg.payload.length.should.equal(1); done(); } }); @@ -213,16 +213,20 @@ describe('SPLIT node', function() { var sn1 = helper.getNode("sn1"); var sn2 = helper.getNode("sn2"); sn2.on("input", function(msg) { - //console.log(msg); - msg.should.have.property("parts"); - msg.payload.should.be.a.Buffer; - msg.parts.should.have.property("count",4); - msg.parts.should.have.property("index"); - msg.parts.should.have.property("type","buffer"); - if (msg.parts.index === 0) { msg.payload.toString().should.equal("12"); } - if (msg.parts.index === 1) { msg.payload.toString().should.equal("34"); } - if (msg.parts.index === 2) { msg.payload.toString().should.equal("56"); } - if (msg.parts.index === 3) { msg.payload.toString().should.equal("78"); done(); } + try { + //console.log(msg); + msg.should.have.property("parts"); + Buffer.isBuffer(msg.payload).should.be.true(); + msg.parts.should.have.property("count",4); + msg.parts.should.have.property("index"); + msg.parts.should.have.property("type","buffer"); + if (msg.parts.index === 0) { msg.payload.toString().should.equal("12"); } + if (msg.parts.index === 1) { msg.payload.toString().should.equal("34"); } + if (msg.parts.index === 2) { msg.payload.toString().should.equal("56"); } + if (msg.parts.index === 3) { msg.payload.toString().should.equal("78"); done(); } + } catch(err) { + done(err); + } }); var b = new Buffer.from("12345678"); sn1.receive({payload:b}); @@ -236,14 +240,17 @@ describe('SPLIT node', function() { var sn1 = helper.getNode("sn1"); var sn2 = helper.getNode("sn2"); sn2.on("input", function(msg) { - //console.log(msg); - msg.should.have.property("parts"); - msg.payload.should.be.a.Buffer; - msg.parts.should.have.property("index"); - msg.parts.should.have.property("type","buffer"); - if (msg.parts.index === 0) { msg.payload.toString().should.equal("123"); } - if (msg.parts.index === 1) { msg.payload.toString().should.equal("123"); } - if (msg.parts.index === 2) { msg.payload.toString().should.equal("123"); done(); } + try { + msg.should.have.property("parts"); + Buffer.isBuffer(msg.payload).should.be.true(); + msg.parts.should.have.property("index"); + msg.parts.should.have.property("type","buffer"); + if (msg.parts.index === 0) { msg.payload.toString().should.equal("123"); } + if (msg.parts.index === 1) { msg.payload.toString().should.equal("123"); } + if (msg.parts.index === 2) { msg.payload.toString().should.equal("123"); done(); } + } catch(err) { + done(err); + } }); var b1 = new Buffer.from("123412"); var b2 = new Buffer.from("341234"); @@ -296,7 +303,26 @@ describe('JOIN node', function() { n1.receive({payload:"D", parts:{id:1, type:"string", ch:",", index:3, count:4}}); }); }); - + it('should join bits of string back together automatically with a buffer joiner', function(done) { + var flow = [{id:"n1", type:"join", wires:[["n2"]], joiner:"[44]", joinerType:"bin", build:"string", mode:"auto"}, + {id:"n2", type:"helper"}]; + helper.load(joinNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + n2.on("input", function(msg) { + try { + msg.should.have.property("payload"); + msg.payload.should.equal("A,B,C,D"); + done(); + } + catch(e) {done(e);} + }); + n1.receive({payload:"A", parts:{id:1, type:"string", ch:",", index:0, count:4}}); + n1.receive({payload:"B", parts:{id:1, type:"string", ch:",", index:1, count:4}}); + n1.receive({payload:"C", parts:{id:1, type:"string", ch:",", index:2, count:4}}); + n1.receive({payload:"D", parts:{id:1, type:"string", ch:",", index:3, count:4}}); + }); + }); it('should join bits of buffer back together automatically', function(done) { var flow = [{id:"n1", type:"join", wires:[["n2"]], joiner:",", build:"buffer", mode:"auto"}, {id:"n2", type:"helper"}]; @@ -306,7 +332,7 @@ describe('JOIN node', function() { n2.on("input", function(msg) { try { msg.should.have.property("payload"); - msg.should.be.a.Buffer; + Buffer.isBuffer(msg.payload).should.be.true(); msg.payload.toString().should.equal("A-B-C-D"); done(); }