From d373105b32d7b04cca6115b891f042c2b21339c2 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Tue, 21 Aug 2018 13:42:51 +0100 Subject: [PATCH 1/4] Fix typo in template.html --- nodes/core/core/80-template.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nodes/core/core/80-template.html b/nodes/core/core/80-template.html index 31dfe97ca..2f2e27969 100644 --- a/nodes/core/core/80-template.html +++ b/nodes/core/core/80-template.html @@ -77,7 +77,9 @@ }

The resulting property will be:

Hello Fred. Today is Monday
-

It is possible to use a property from the flow context or global context. Just use {{flow.name}} or {{global.name}}, or for persistable store store use {{flow[store].name}} or {{flobal[store].name}}. +

It is possible to use a property from the flow context or global context. Just use {{flow.name}} or + {{global.name}}, or for persistable store store use {{flow[store].name}} or + {{global[store].name}}.

Note: By default, mustache will escape any HTML entities in the values it substitutes. To prevent this, use {{{triple}}} braces. From db1b0ccb79ee74d3e72ec3ea8fe16e11df77ca50 Mon Sep 17 00:00:00 2001 From: Christopher Hiller Date: Thu, 23 Aug 2018 00:50:51 -0700 Subject: [PATCH 2/4] fix lost messages / properties in TCPRequest Node; closes #1863 (#1864) - Added some more checks around this. - We're choosing to only use the latest message when sending, which is effectively what was happening before the queue implementation. --- nodes/core/io/31-tcpin.js | 13 +- test/nodes/core/io/31-tcprequest_spec.js | 163 ++++++++++++++++++++--- 2 files changed, 151 insertions(+), 25 deletions(-) diff --git a/nodes/core/io/31-tcpin.js b/nodes/core/io/31-tcpin.js index 63eb4a478..26593647a 100644 --- a/nodes/core/io/31-tcpin.js +++ b/nodes/core/io/31-tcpin.js @@ -467,6 +467,7 @@ module.exports = function(RED) { connecting: false }; enqueue(clients[connection_id].msgQueue, msg); + clients[connection_id].lastMsg = msg; if (!clients[connection_id].connecting && !clients[connection_id].connected) { var buf; @@ -507,8 +508,7 @@ module.exports = function(RED) { clients[connection_id].client.on('data', function(data) { if (node.out === "sit") { // if we are staying connected just send the buffer if (clients[connection_id]) { - let msg = dequeue(clients[connection_id].msgQueue) || {}; - clients[connection_id].msgQueue.unshift(msg); + const msg = clients[connection_id].lastMsg || {}; msg.payload = data; node.send(RED.util.cloneMessage(msg)); } @@ -530,8 +530,7 @@ module.exports = function(RED) { clients[connection_id].timeout = setTimeout(function () { if (clients[connection_id]) { clients[connection_id].timeout = null; - let msg = dequeue(clients[connection_id].msgQueue) || {}; - clients[connection_id].msgQueue.unshift(msg); + const msg = clients[connection_id].lastMsg || {}; msg.payload = Buffer.alloc(i+1); buf.copy(msg.payload,0,0,i+1); node.send(msg); @@ -553,8 +552,7 @@ module.exports = function(RED) { i += 1; if ( i >= node.splitc) { if (clients[connection_id]) { - let msg = dequeue(clients[connection_id].msgQueue) || {}; - clients[connection_id].msgQueue.unshift(msg); + const msg = clients[connection_id].lastMsg || {}; msg.payload = Buffer.alloc(i); buf.copy(msg.payload,0,0,i); node.send(msg); @@ -573,8 +571,7 @@ module.exports = function(RED) { i += 1; if (data[j] == node.splitc) { if (clients[connection_id]) { - let msg = dequeue(clients[connection_id].msgQueue) || {}; - clients[connection_id].msgQueue.unshift(msg); + const msg = clients[connection_id].lastMsg || {}; msg.payload = Buffer.alloc(i); buf.copy(msg.payload,0,0,i); node.send(msg); diff --git a/test/nodes/core/io/31-tcprequest_spec.js b/test/nodes/core/io/31-tcprequest_spec.js index 3cc0e1224..8aed61ef5 100644 --- a/test/nodes/core/io/31-tcprequest_spec.js +++ b/test/nodes/core/io/31-tcprequest_spec.js @@ -59,7 +59,11 @@ describe('TCP Request Node', function() { var n2 = helper.getNode("n2"); n2.on("input", function(msg) { try { - msg.should.have.property('payload', Buffer(val1)); + if (typeof val1 === 'object') { + msg.should.have.properties(Object.assign({}, val1, {payload: Buffer(val1.payload)})); + } else { + msg.should.have.property('payload', Buffer(val1)); + } done(); } catch(err) { done(err); @@ -79,7 +83,11 @@ describe('TCP Request Node', function() { const n2 = helper.getNode("n2"); n2.on("input", msg => { try { - msg.should.have.property('payload', Buffer(result)); + if (typeof result === 'object') { + msg.should.have.properties(Object.assign({}, result, {payload: Buffer(result.payload)})); + } else { + msg.should.have.property('payload', Buffer(result)); + } done(); } catch(err) { done(err); @@ -95,31 +103,75 @@ describe('TCP Request Node', function() { it('should send & recv data', function(done) { var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"time", splitc: "0", wires:[["n2"]] }, {id:"n2", type:"helper"}]; - testTCP(flow, "foo", "ACK:foo", done) + testTCP(flow, { + payload: 'foo', + topic: 'bar' + }, { + payload: 'ACK:foo', + topic: 'bar' + }, done); + }); + + it('should retain complete message', function(done) { + var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"time", splitc: "0", wires:[["n2"]] }, + {id:"n2", type:"helper"}]; + testTCP(flow, { + payload: 'foo', + topic: 'bar' + }, { + payload: 'ACK:foo', + topic: 'bar' + }, done); }); it('should send & recv data when specified character received', function(done) { var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"char", splitc: "0", wires:[["n2"]] }, {id:"n2", type:"helper"}]; - testTCP(flow, "foo0bar0", "ACK:foo0", done); + testTCP(flow, { + payload: 'foo0bar0', + topic: 'bar' + }, { + payload: 'ACK:foo0', + topic: 'bar' + }, done); }); it('should send & recv data after fixed number of chars received', function(done) { var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"count", splitc: "7", wires:[["n2"]] }, {id:"n2", type:"helper"}]; - testTCP(flow, "foo bar", "ACK:foo", done); + testTCP(flow, { + payload: 'foo bar', + topic: 'bar' + }, { + payload: 'ACK:foo', + topic: 'bar' + }, done); }); it('should send & receive, then keep connection', function(done) { var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"sit", splitc: "5", wires:[["n2"]] }, {id:"n2", type:"helper"}]; - testTCP(flow, "foo", "ACK:foo", done); + testTCP(flow, { + payload: 'foo', + topic: 'bar' + }, { + payload: 'ACK:foo', + topic: 'bar' + }, done); }); it('should send & recv data to/from server:port from msg', function(done) { var flow = [{id:"n1", type:"tcp request", server:"", port:"", out:"time", splitc: "0", wires:[["n2"]] }, {id:"n2", type:"helper"}]; - testTCP(flow, {payload:"foo", host:"localhost", port:port}, "ACK:foo", done) + testTCP(flow, { + payload: "foo", + host: "localhost", + port: port + }, { + payload: "ACK:foo", + host: 'localhost', + port: port + }, done); }); }); @@ -127,36 +179,95 @@ describe('TCP Request Node', function() { it('should send & recv data', function(done) { var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"time", splitc: "0", wires:[["n2"]] }, {id:"n2", type:"helper"}]; - - testTCPMany(flow, ['f', 'o', 'o'], 'ACK:foo', done); + testTCPMany(flow, [{ + payload: 'f', + topic: 'bar' + }, { + payload: 'o', + topic: 'bar' + }, { + payload: 'o', + topic: 'bar' + }], { + payload: 'ACK:foo', + topic: 'bar' + }, done); }); it('should send & recv data when specified character received', function(done) { var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"char", splitc: "0", wires:[["n2"]] }, {id:"n2", type:"helper"}]; - testTCPMany(flow, ["foo0","bar0"], "ACK:foo0", done); + testTCPMany(flow, [{ + payload: "foo0", + topic: 'bar' + }, { + payload: "bar0", + topic: 'bar' + }], { + payload: "ACK:foo0", + topic: 'bar' + }, done); }); it('should send & recv data after fixed number of chars received', function(done) { var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"count", splitc: "7", wires:[["n2"]] }, {id:"n2", type:"helper"}]; - testTCPMany(flow, ["fo", "ob", "ar"], "ACK:foo", done); + testTCPMany(flow, [{ + payload: "fo", + topic: 'bar' + }, { + payload: "ob", + topic: 'bar' + }, { + payload: "ar", + topic: 'bar' + }], { + payload: "ACK:foo", + topic: 'bar' + }, done); }); - it('should send & receive, then keep connection', function(done) { var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"sit", splitc: "5", wires:[["n2"]] }, {id:"n2", type:"helper"}]; - testTCPMany(flow, ["foo", "bar", "baz"], "ACK:foobarbaz", done); + testTCPMany(flow, [{ + payload: "foo", + topic: 'bar' + }, { + payload: "bar", + topic: 'bar' + }, { + payload: "baz", + topic: 'bar' + }], { + payload: "ACK:foobarbaz", + topic: 'bar' + }, done); }); it('should send & recv data to/from server:port from msg', function(done) { var flow = [{id:"n1", type:"tcp request", server:"", port:"", out:"time", splitc: "0", wires:[["n2"]] }, {id:"n2", type:"helper"}]; - testTCPMany(flow, [ - {payload:"f", host:"localhost", port:port}, - {payload:"o", host:"localhost", port:port}, - {payload:"o", host:"localhost", port:port}], "ACK:foo", done); + testTCPMany(flow, [{ + payload: "f", + host: "localhost", + port: port + }, + { + payload: "o", + host: "localhost", + port: port + }, + { + payload: "o", + host: "localhost", + port: port + } + ], { + payload: "ACK:foo", + host: 'localhost', + port: port + }, done); }); it('should limit the queue size', function (done) { @@ -168,5 +279,23 @@ describe('TCP Request Node', function() { const expected = msgs.slice(0, -1); testTCPMany(flow, msgs, "ACK:" + expected.join(''), done); }); + + it('should only retain the latest message', function(done) { + var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"time", splitc: "0", wires:[["n2"]] }, + {id:"n2", type:"helper"}]; + testTCPMany(flow, [{ + payload: 'f', + topic: 'bar' + }, { + payload: 'o', + topic: 'baz' + }, { + payload: 'o', + topic: 'quux' + }], { + payload: 'ACK:foo', + topic: 'quux' + }, done); + }); }); }); From c1a1a735990396d18168b1f3a2400103f2e2017b Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Fri, 24 Aug 2018 13:08:49 +0100 Subject: [PATCH 3/4] Ensure node default color is used if palette.theme has no match --- editor/js/ui/utils.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/editor/js/ui/utils.js b/editor/js/ui/utils.js index 13d27d5bd..8e6654a7a 100644 --- a/editor/js/ui/utils.js +++ b/editor/js/ui/utils.js @@ -800,8 +800,9 @@ RED.utils = (function() { var paletteTheme = RED.settings.theme('palette.theme') || []; if (paletteTheme.length > 0) { if (!nodeColorCache.hasOwnProperty(type)) { + nodeColorCache[type] = def.color; var l = paletteTheme.length; - for (var i=0;i Date: Fri, 24 Aug 2018 13:25:02 +0100 Subject: [PATCH 4/4] Bump for 0.19.2 --- CHANGELOG.md | 9 +++++++++ package.json | 14 +++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fe1454fe..075148316 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +#### 0.19.2: Maintenance Release + + - Ensure node default colour is used if palette.theme has no match + - fix lost messages / properties in TCPRequest Node; closes #1863 (#1864) + - Fix typo in template.html + - Improve error reporting from context plugin loading + - Prevent no-op edit of node marking as changed due to icon + - Change node must handle empty rule set + #### 0.19.1: Maintenance Release - Pull in latest twitter node diff --git a/package.json b/package.json index 09649f73e..870806d5b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node-red", - "version": "0.19.1", + "version": "0.19.2", "description": "A visual tool for wiring the Internet of Things", "homepage": "http://nodered.org", "license": "Apache-2.0", @@ -33,7 +33,7 @@ "flow" ], "dependencies": { - "ajv": "6.5.2", + "ajv": "6.5.3", "basic-auth": "2.0.0", "bcryptjs": "2.4.3", "body-parser": "1.18.3", @@ -56,7 +56,7 @@ "jsonata": "1.5.4", "media-typer": "0.3.0", "memorystore": "1.6.0", - "mqtt": "2.18.3", + "mqtt": "2.18.5", "multer": "1.3.1", "mustache": "2.3.1", "node-red-node-email": "0.1.*", @@ -71,9 +71,9 @@ "passport-oauth2-client-password": "0.1.2", "raw-body": "2.3.3", "request": "2.88.0", - "semver": "5.5.0", + "semver": "5.5.1", "sentiment": "2.1.0", - "uglify-js": "3.4.7", + "uglify-js": "3.4.8", "when": "3.7.8", "ws": "1.1.5", "xml2js": "0.4.19" @@ -103,6 +103,7 @@ "http-proxy": "^1.16.2", "istanbul": "0.4.5", "mocha": "^5.2.0", + "node-red-node-test-helper": "0.1.7", "should": "^8.4.0", "sinon": "1.17.7", "stoppable": "^1.0.6", @@ -110,8 +111,7 @@ "wdio-chromedriver-service": "^0.1.3", "wdio-mocha-framework": "^0.6.2", "wdio-spec-reporter": "^0.1.5", - "webdriverio": "^4.13.1", - "node-red-node-test-helper": "^0.1.7" + "webdriverio": "^4.13.1" }, "engines": { "node": ">=4"