From 255d708fb6e26916493fd144bc9bf37832765ac9 Mon Sep 17 00:00:00 2001 From: dceejay Date: Tue, 31 Mar 2015 09:21:11 +0100 Subject: [PATCH] updates to serial, watch, websocket, udp, twitter, email to handle no payload. --- nodes/core/io/22-websocket.js | 24 +++--- nodes/core/io/23-watch.js | 15 ++-- nodes/core/io/25-serial.js | 32 +++---- nodes/core/io/32-udp.js | 2 +- nodes/core/social/27-twitter.js | 71 ++++++++-------- nodes/core/social/61-email.js | 63 +++++++------- test/nodes/core/io/22-websocket_spec.js | 107 +++++++++++++++++++++++- 7 files changed, 214 insertions(+), 100 deletions(-) diff --git a/nodes/core/io/22-websocket.js b/nodes/core/io/22-websocket.js index 805682c7a..b7f291ded 100644 --- a/nodes/core/io/22-websocket.js +++ b/nodes/core/io/22-websocket.js @@ -1,5 +1,5 @@ /** - * Copyright 2013 IBM Corp. + * Copyright 2013,2015 IBM Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -133,7 +133,7 @@ module.exports = function(RED) { if(this.isServer) { for (var i = 0; i < this.server.clients.length; i++) { this.server.clients[i].send(data); - } + } } else { this.server.send(data); @@ -181,7 +181,7 @@ module.exports = function(RED) { if (this.serverConfig.wholemsg) { delete msg._session; payload = JSON.stringify(msg); - } else { + } else if (msg.hasOwnProperty("payload")) { if (!Buffer.isBuffer(msg.payload)) { // if it's not a buffer make sure it's a string. payload = RED.util.ensureString(msg.payload); } @@ -189,14 +189,16 @@ module.exports = function(RED) { payload = msg.payload; } } - if (msg._session && msg._session.type == "websocket") { - node.serverConfig.reply(msg._session.id,payload); - } else { - node.serverConfig.broadcast(payload,function(error){ - if (!!error) { - node.warn("An error occurred while sending:" + inspect(error)); - } - }); + if (payload) { + if (msg._session && msg._session.type == "websocket") { + node.serverConfig.reply(msg._session.id,payload); + } else { + node.serverConfig.broadcast(payload,function(error){ + if (!!error) { + node.warn("An error occurred while sending:" + inspect(error)); + } + }); + } } }); } diff --git a/nodes/core/io/23-watch.js b/nodes/core/io/23-watch.js index 6434b42c1..59cd57069 100644 --- a/nodes/core/io/23-watch.js +++ b/nodes/core/io/23-watch.js @@ -23,11 +23,11 @@ module.exports = function(RED) { function WatchNode(n) { RED.nodes.createNode(this,n); - this.files = n.files.split(","); + this.files = (n.files || "").split(","); for (var f=0; f < this.files.length; f++) { this.files[f] = this.files[f].trim(); } - this.p = (this.files.length == 1) ? this.files[0] : JSON.stringify(this.files); + this.p = (this.files.length === 1) ? this.files[0] : JSON.stringify(this.files); var node = this; var notifications = new Notify(node.files); @@ -39,11 +39,12 @@ module.exports = function(RED) { } catch(e) { } var type = "other"; if (stat.isFile()) { type = "file"; } - if (stat.isDirectory()) { type = "directory"; } - if (stat.isBlockDevice()) { type = "blockdevice"; } - if (stat.isCharacterDevice()) { type = "characterdevice"; } - if (stat.isSocket()) { type = "socket"; } - if (stat.isFIFO()) { type = "fifo"; } + else if (stat.isDirectory()) { type = "directory"; } + else if (stat.isBlockDevice()) { type = "blockdevice"; } + else if (stat.isCharacterDevice()) { type = "characterdevice"; } + else if (stat.isSocket()) { type = "socket"; } + else if (stat.isFIFO()) { type = "fifo"; } + else { type = "n/a"; } var msg = { payload:path, topic:node.p, file:file, type:type, size:stat.size }; node.send(msg); }); diff --git a/nodes/core/io/25-serial.js b/nodes/core/io/25-serial.js index aa8b1d3a5..ef122e8a3 100644 --- a/nodes/core/io/25-serial.js +++ b/nodes/core/io/25-serial.js @@ -55,23 +55,25 @@ module.exports = function(RED) { node.addCh = this.serialConfig.newline.replace("\\n","\n").replace("\\r","\r").replace("\\t","\t").replace("\\e","\e").replace("\\f","\f").replace("\\0","\0"); } node.on("input",function(msg) { - var payload = msg.payload; - if (!Buffer.isBuffer(payload)) { - if (typeof payload === "object") { - payload = JSON.stringify(payload); - } else { - payload = payload.toString(); + if (msg.hasOwnProperty("payload")) { + var payload = msg.payload; + if (!Buffer.isBuffer(payload)) { + if (typeof payload === "object") { + payload = JSON.stringify(payload); + } else { + payload = payload.toString(); + } + payload += node.addCh; + } else if (node.addCh !== "") { + payload = Buffer.concat([payload,new Buffer(node.addCh)]); } - payload += node.addCh; - } else if (node.addCh !== "") { - payload = Buffer.concat([payload,new Buffer(node.addCh)]); + node.port.write(payload,function(err,res) { + if (err) { + var errmsg = err.toString().replace("Serialport","Serialport "+node.port.serial.path); + node.error(errmsg,msg); + } + }); } - node.port.write(payload,function(err,res) { - if (err) { - var errmsg = err.toString().replace("Serialport","Serialport "+node.port.serial.path); - node.error(errmsg,msg); - } - }); }); node.port.on('ready', function() { node.status({fill:"green",shape:"dot",text:"connected"}); diff --git a/nodes/core/io/32-udp.js b/nodes/core/io/32-udp.js index 284bd9bff..f2310b8b3 100644 --- a/nodes/core/io/32-udp.js +++ b/nodes/core/io/32-udp.js @@ -134,7 +134,7 @@ module.exports = function(RED) { } node.on("input", function(msg) { - if (msg.payload != null) { + if (msg.hasOwnProperty("payload")) { var add = node.addr || msg.ip || ""; var por = node.port || msg.port || 0; if (add == "") { diff --git a/nodes/core/social/27-twitter.js b/nodes/core/social/27-twitter.js index 7c2aa4269..c0a20d528 100644 --- a/nodes/core/social/27-twitter.js +++ b/nodes/core/social/27-twitter.js @@ -280,48 +280,51 @@ module.exports = function(RED) { access_token_secret: credentials.access_token_secret }); node.on("input", function(msg) { - node.status({fill:"blue",shape:"dot",text:"tweeting"}); + if (msg.hasOwnProperty("payload")) { + node.status({fill:"blue",shape:"dot",text:"tweeting"}); - if (msg.payload.length > 140) { - msg.payload = msg.payload.slice(0,139); - node.warn("Tweet greater than 140 : truncated"); - } + if (msg.payload.length > 140) { + msg.payload = msg.payload.slice(0,139); + node.warn("Tweet greater than 140 : truncated"); + } - if (msg.media && Buffer.isBuffer(msg.media)) { - var apiUrl = "https://api.twitter.com/1.1/statuses/update_with_media.json"; - var signedUrl = oa.signUrl(apiUrl, - credentials.access_token, - credentials.access_token_secret, - "POST"); + if (msg.media && Buffer.isBuffer(msg.media)) { + var apiUrl = "https://api.twitter.com/1.1/statuses/update_with_media.json"; + var signedUrl = oa.signUrl(apiUrl, + credentials.access_token, + credentials.access_token_secret, + "POST"); - var r = request.post(signedUrl,function(err,httpResponse,body) { - if (err) { - node.error(err,msg); - node.status({fill:"red",shape:"ring",text:"failed"}); - } else { - var response = JSON.parse(body); - if (response.errors) { - var errorList = response.errors.map(function(er) { return er.code+": "+er.message }).join(", "); - node.error("Send tweet failed: "+errorList,msg); + var r = request.post(signedUrl,function(err,httpResponse,body) { + if (err) { + node.error(err,msg); node.status({fill:"red",shape:"ring",text:"failed"}); } else { - node.status({}); + var response = JSON.parse(body); + if (response.errors) { + var errorList = response.errors.map(function(er) { return er.code+": "+er.message }).join(", "); + node.error("Send tweet failed: "+errorList,msg); + node.status({fill:"red",shape:"ring",text:"failed"}); + } else { + node.status({}); + } } - } - }); - var form = r.form(); - form.append("status",msg.payload); - form.append("media[]",msg.media,{filename:"image"}); + }); + var form = r.form(); + form.append("status",msg.payload); + form.append("media[]",msg.media,{filename:"image"}); - } else { - twit.updateStatus(msg.payload, function (err, data) { - if (err) { - node.status({fill:"red",shape:"ring",text:"failed"}); - node.error(err,msg); - } - node.status({}); - }); + } else { + twit.updateStatus(msg.payload, function (err, data) { + if (err) { + node.status({fill:"red",shape:"ring",text:"failed"}); + node.error(err,msg); + } + node.status({}); + }); + } } + else { node.warn("No payload to tweet"); } }); } } diff --git a/nodes/core/social/61-email.js b/nodes/core/social/61-email.js index 75defb5a6..b60ac60f7 100644 --- a/nodes/core/social/61-email.js +++ b/nodes/core/social/61-email.js @@ -69,39 +69,42 @@ module.exports = function(RED) { }); this.on("input", function(msg) { - if (smtpTransport) { - node.status({fill:"blue",shape:"dot",text:"sending"}); - if (msg.to && node.name && (msg.to !== node.name)) { - node.warn("Warning: msg properties can no longer override set node properties. See bit.ly/nr-override-msg-props"); - } - var sendopts = { from: node.userid }; // sender address - sendopts.to = node.name || msg.to; // comma separated list of addressees - sendopts.subject = msg.topic || msg.title || "Message from Node-RED"; // subject line - if (Buffer.isBuffer(msg.payload)) { // if it's a buffer in the payload then auto create an attachment instead - sendopts.attachments = [ { content: msg.payload, filename:(msg.filename.replace(/^.*[\\\/]/, '') || "file.bin") } ]; - if (msg.hasOwnProperty("headers") && msg.headers.hasOwnProperty("content-type")) { - sendopts.attachments[0].contentType = msg.headers["content-type"]; + if (msg.hasOwnProperty("payload")) { + if (smtpTransport) { + node.status({fill:"blue",shape:"dot",text:"sending"}); + if (msg.to && node.name && (msg.to !== node.name)) { + node.warn("Warning: msg properties can no longer override set node properties. See bit.ly/nr-override-msg-props"); } - // Create some body text.. - sendopts.text = "Your file from Node-RED is attached : "+(msg.filename.replace(/^.*[\\\/]/, '') || "file.bin")+ (msg.hasOwnProperty("description") ? "\n\n"+msg.description : ""); - } - else { - var payload = RED.util.ensureString(msg.payload); - sendopts.text = payload; // plaintext body - if (/<[a-z][\s\S]*>/i.test(payload)) { sendopts.html = payload; } // html body - if (msg.attachments) { sendopts.attachments = msg.attachments; } // add attachments - } - smtpTransport.sendMail(sendopts, function(error, info) { - if (error) { - node.error(error,msg); - node.status({fill:"red",shape:"ring",text:"send failed"}); - } else { - node.log("Message sent: " + info.response); - node.status({}); + var sendopts = { from: node.userid }; // sender address + sendopts.to = node.name || msg.to; // comma separated list of addressees + sendopts.subject = msg.topic || msg.title || "Message from Node-RED"; // subject line + if (Buffer.isBuffer(msg.payload)) { // if it's a buffer in the payload then auto create an attachment instead + sendopts.attachments = [ { content: msg.payload, filename:(msg.filename.replace(/^.*[\\\/]/, '') || "file.bin") } ]; + if (msg.hasOwnProperty("headers") && msg.headers.hasOwnProperty("content-type")) { + sendopts.attachments[0].contentType = msg.headers["content-type"]; + } + // Create some body text.. + sendopts.text = "Your file from Node-RED is attached : "+(msg.filename.replace(/^.*[\\\/]/, '') || "file.bin")+ (msg.hasOwnProperty("description") ? "\n\n"+msg.description : ""); } - }); + else { + var payload = RED.util.ensureString(msg.payload); + sendopts.text = payload; // plaintext body + if (/<[a-z][\s\S]*>/i.test(payload)) { sendopts.html = payload; } // html body + if (msg.attachments) { sendopts.attachments = msg.attachments; } // add attachments + } + smtpTransport.sendMail(sendopts, function(error, info) { + if (error) { + node.error(error,msg); + node.status({fill:"red",shape:"ring",text:"send failed"}); + } else { + node.log("Message sent: " + info.response); + node.status({}); + } + }); + } + else { node.warn("No Email credentials found. See info panel."); } } - else { node.warn("No Email credentials found. See info panel."); } + else { node.warn("No payload to send"); }); } RED.nodes.registerType("e-mail",EmailNode,{ diff --git a/test/nodes/core/io/22-websocket_spec.js b/test/nodes/core/io/22-websocket_spec.js index d6643a7a6..5d14628d7 100644 --- a/test/nodes/core/io/22-websocket_spec.js +++ b/test/nodes/core/io/22-websocket_spec.js @@ -55,7 +55,7 @@ function getSocket(listenerid) { return node.server; } -describe('websocket node', function() { +describe('websocket Node', function() { before(function(done) { helper.startServer(done); @@ -149,6 +149,22 @@ describe('websocket node', function() { }); }); + it('should receive wholemsg when data not JSON', function(done) { + var flow = [ + { id: "n1", type: "websocket-listener", path: "/ws", wholemsg: "true" }, + { id: "n2", type: "websocket in", server: "n1", wires: [["n3"]] }, + { id: "n3", type: "helper" }]; + helper.load(websocketNode, flow, function() { + createClient("n1").then(function(sock) { + sock.send('hello'); + helper.getNode("n3").on("input", function(msg) { + msg.should.have.property("payload", "hello"); + done(); + }); + }); + }); + }); + it('should send', function(done) { var flow = [ { id: "n1", type: "websocket-listener", path: "/ws" }, @@ -185,6 +201,25 @@ describe('websocket node', function() { }); }); + it('should do nothing if no payload', function(done) { + var flow = [ + { id: "n1", type: "websocket-listener", path: "/ws" }, + { id: "n2", type: "helper", wires: [["n3"]] }, + { id: "n3", type: "websocket out", server: "n1" }]; + helper.load(websocketNode, flow, function() { + createClient("n1").then(function(sock) { + setTimeout(function() { + var logEvents = helper.log().args.filter(function(evt) { + return evt[0].type == "file"; + }); + logEvents.should.have.length(0); + done(); + },100); + helper.getNode("n2").send({topic: "hello"}); + }); + }); + }); + it('should echo', function(done) { var flow = [ { id: "n1", type: "websocket-listener", path: "/ws" }, @@ -333,7 +368,6 @@ describe('websocket node', function() { getSocket('server').on('connection', function(sock) { sock.send('{"text":"hello"}'); }); - helper.getNode("n3").on("input", function(msg) { msg.should.have.property("text", "hello"); done(); @@ -341,6 +375,23 @@ describe('websocket node', function() { }); }); + it('should receive wholemsg when data not JSON', function(done) { + var flow = [ + { id: "server", type: "websocket-listener", path: "/ws" }, + { id: "n1", type: "websocket-client", path: getWsUrl("/ws"), wholemsg: "true" }, + { id: "n2", type: "websocket in", client: "n1", wires: [["n3"]] }, + { id: "n3", type: "helper" }]; + helper.load(websocketNode, flow, function() { + getSocket('server').on('connection', function(sock) { + sock.send('hello'); + }); + helper.getNode("n3").on("input", function(msg) { + msg.should.have.property("payload", "hello"); + done(); + }); + }); + }); + it('should send', function(done) { var flow = [ { id: "server", type: "websocket-listener", path: "/ws" }, @@ -362,6 +413,27 @@ describe('websocket node', function() { }); }); + it('should send buffer', function(done) { + var flow = [ + { id: "server", type: "websocket-listener", path: "/ws" }, + { id: "n1", type: "websocket-client", path: getWsUrl("/ws") }, + { id: "n2", type: "websocket out", client: "n1" }, + { id: "n3", type: "helper", wires: [["n2"]] }]; + helper.load(websocketNode, flow, function() { + getSocket('server').on('connection', function(sock) { + sock.on('message', function(msg) { + msg.should.have.length(5).and.be.a.buffer; + done(); + }); + }); + getSocket("n1").on("open", function() { + helper.getNode("n3").send({ + payload: new Buffer("hello") + }); + }); + }); + }); + it('should send wholemsg', function(done) { var flow = [ { id: "server", type: "websocket-listener", path: "/ws" }, @@ -407,4 +479,35 @@ describe('websocket node', function() { }); }); }); + + describe('websocket in node', function() { + it('should report error if no server config', function(done) { + var flow = [{ id: "n1", type: "websocket in", mode: "server" }]; + helper.load(websocketNode, flow, function() { + var logEvents = helper.log().args.filter(function(evt) { + return evt[0].type == "websocket in"; + }); + logEvents.should.have.length(1); + logEvents[0][0].should.have.a.property('msg'); + logEvents[0][0].msg.toString().should.startWith("Missing server configuration"); + done(); + }); + }); + }); + + describe('websocket out node', function() { + it('should report error if no server config', function(done) { + var flow = [{ id: "n1", type: "websocket out", mode: "server" }]; + helper.load(websocketNode, flow, function() { + var logEvents = helper.log().args.filter(function(evt) { + return evt[0].type == "websocket out"; + }); + //console.log(logEvents); + logEvents.should.have.length(1); + logEvents[0][0].should.have.a.property('msg'); + logEvents[0][0].msg.toString().should.startWith("Missing server configuration"); + done(); + }); + }); + }); });