1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Migrate to new node function style

This commit is contained in:
Nick O'Leary 2014-05-03 23:32:04 +01:00
parent 5afc5857c4
commit ff49d2b217
37 changed files with 3194 additions and 3170 deletions

View File

@ -17,7 +17,7 @@
<!-- Sample html file that corresponds to the 99-sample.js file --> <!-- Sample html file that corresponds to the 99-sample.js file -->
<!-- This creates and configures the onscreen elements of the node --> <!-- This creates and configures the onscreen elements of the node -->
<!-- If you use this as a template, replace IBM Corp. with your own name. --> <!-- If you use this as a template, update the copyright with your own name. -->
<!-- First, the content of the edit dialog is defined. --> <!-- First, the content of the edit dialog is defined. -->

View File

@ -14,39 +14,41 @@
* limitations under the License. * limitations under the License.
**/ **/
// If you use this as a template, replace IBM Corp. with your own name. // If you use this as a template, update the copyright with your own name.
// Sample Node-RED node file // Sample Node-RED node file
// Require main module
var RED = require(process.env.NODE_RED_HOME+"/red/red");
// The main node definition - most things happen in here module.export = function(RED) {
function SampleNode(n) {
// Create a RED node
RED.nodes.createNode(this,n);
// Store local copies of the node configuration (as defined in the .html) // The main node definition - most things happen in here
this.topic = n.topic; function SampleNode(n) {
// Create a RED node
RED.nodes.createNode(this,n);
// Do whatever you need to do in here - declare callbacks etc // Store local copies of the node configuration (as defined in the .html)
// Note: this sample doesn't do anything much - it will only send this.topic = n.topic;
// this message once at startup...
// Look at other real nodes for some better ideas of what to do....
var msg = {};
msg.topic = this.topic;
msg.payload = "Hello world !"
// send out the message to the rest of the workspace. // Do whatever you need to do in here - declare callbacks etc
this.send(msg); // Note: this sample doesn't do anything much - it will only send
// this message once at startup...
// Look at other real nodes for some better ideas of what to do....
var msg = {};
msg.topic = this.topic;
msg.payload = "Hello world !"
// send out the message to the rest of the workspace.
this.send(msg);
this.on("close", function() {
// Called when the node is shutdown - eg on redeploy.
// Allows ports to be closed, connections dropped etc.
// eg: this.client.disconnect();
});
}
// Register the node by name. This must be called before overriding any of the
// Node functions.
RED.nodes.registerType("sample",SampleNode);
this.on("close", function() {
// Called when the node is shutdown - eg on redeploy.
// Allows ports to be closed, connections dropped etc.
// eg: this.client.disconnect();
});
} }
// Register the node by name. This must be called before overriding any of the
// Node functions.
RED.nodes.registerType("sample",SampleNode);

View File

@ -14,18 +14,19 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var sentiment = require('sentiment'); var sentiment = require('sentiment');
function SentimentNode(n) { function SentimentNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
var node = this; var node = this;
this.on("input", function(msg) { this.on("input", function(msg) {
sentiment(msg.payload, msg.overrides || null, function (err, result) { sentiment(msg.payload, msg.overrides || null, function (err, result) {
msg.sentiment = result; msg.sentiment = result;
node.send(msg); node.send(msg);
});
}); });
}); }
RED.nodes.registerType("sentiment",SentimentNode);
} }
RED.nodes.registerType("sentiment",SentimentNode);

View File

@ -14,31 +14,32 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var util = require("util"); var util = require("util");
var parseString = require('xml2js').parseString; var parseString = require('xml2js').parseString;
var useColors = true; var useColors = true;
//util.inspect.styles.boolean = "red"; //util.inspect.styles.boolean = "red";
function Xml2jsNode(n) { function Xml2jsNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.useEyes = n.useEyes||false; this.useEyes = n.useEyes||false;
var node = this; var node = this;
this.on("input", function(msg) { this.on("input", function(msg) {
try { try {
parseString(msg.payload, {strict:true,async:true}, function (err, result) { parseString(msg.payload, {strict:true,async:true}, function (err, result) {
//parseString(msg.payload, {strict:false,async:true}, function (err, result) { //parseString(msg.payload, {strict:false,async:true}, function (err, result) {
if (err) { node.error(err); } if (err) { node.error(err); }
else { else {
msg.payload = result; msg.payload = result;
node.send(msg); node.send(msg);
if (node.useEyes == true) { if (node.useEyes == true) {
node.log("\n"+util.inspect(msg, {colors:useColors, depth:10})); node.log("\n"+util.inspect(msg, {colors:useColors, depth:10}));
}
} }
} });
}); }
} catch(e) { util.log("[73-parsexml.js] "+e); }
catch(e) { util.log("[73-parsexml.js] "+e); } });
}); }
RED.nodes.registerType("xml2js",Xml2jsNode);
} }
RED.nodes.registerType("xml2js",Xml2jsNode);

View File

@ -14,23 +14,24 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var js2xmlparser = require("js2xmlparser"); var js2xmlparser = require("js2xmlparser");
function Js2XmlNode(n) { function Js2XmlNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.root = n.root; this.root = n.root;
var node = this; var node = this;
this.on("input", function(msg) { this.on("input", function(msg) {
try { try {
var root = node.root || typeof msg.payload; var root = node.root || typeof msg.payload;
if (typeof msg.payload !== "object") { msg.payload = '"'+msg.payload+'"'; } if (typeof msg.payload !== "object") { msg.payload = '"'+msg.payload+'"'; }
console.log(root, typeof msg.payload,msg.payload); console.log(root, typeof msg.payload,msg.payload);
msg.payload = js2xmlparser(root, msg.payload); msg.payload = js2xmlparser(root, msg.payload);
node.send(msg); node.send(msg);
} }
catch(e) { console.log(e); } catch(e) { console.log(e); }
}); });
}
RED.nodes.registerType("json2xml",Js2XmlNode);
} }
RED.nodes.registerType("json2xml",Js2XmlNode);

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2013 IBM Corp. * Copyright 2013, 2014 IBM Corp.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -14,87 +14,84 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
try {
var cron = require("cron"); var cron = require("cron");
} catch(err) {
require("util").log("[inject] Warning: cannot find module 'cron'");
}
function InjectNode(n) { function InjectNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.topic = n.topic; this.topic = n.topic;
this.payload = n.payload; this.payload = n.payload;
this.payloadType = n.payloadType; this.payloadType = n.payloadType;
this.repeat = n.repeat; this.repeat = n.repeat;
this.crontab = n.crontab; this.crontab = n.crontab;
this.once = n.once; this.once = n.once;
var node = this; var node = this;
this.interval_id = null; this.interval_id = null;
this.cronjob = null; this.cronjob = null;
if (this.repeat && !isNaN(this.repeat) && this.repeat > 0) { if (this.repeat && !isNaN(this.repeat) && this.repeat > 0) {
this.repeat = this.repeat * 1000; this.repeat = this.repeat * 1000;
this.log("repeat = "+this.repeat); this.log("repeat = "+this.repeat);
this.interval_id = setInterval( function() { this.interval_id = setInterval( function() {
node.emit("input",{}); node.emit("input",{});
}, this.repeat ); }, this.repeat );
} else if (this.crontab) { } else if (this.crontab) {
if (cron) { if (cron) {
this.log("crontab = "+this.crontab); this.log("crontab = "+this.crontab);
this.cronjob = new cron.CronJob(this.crontab, this.cronjob = new cron.CronJob(this.crontab,
function() { function() {
node.emit("input",{}); node.emit("input",{});
}, },
null,true); null,true);
} else { } else {
this.error("'cron' module not found"); this.error("'cron' module not found");
}
}
if (this.once) {
setTimeout( function(){ node.emit("input",{}); }, 100);
}
this.on("input",function(msg) {
var msg = {topic:this.topic};
if ( (this.payloadType == null && this.payload == "") || this.payloadType == "date") {
msg.payload = Date.now();
} else if (this.payloadType == null || this.payloadType == "string") {
msg.payload = this.payload;
} else {
msg.payload = "";
}
this.send(msg);
msg = null;
});
}
RED.nodes.registerType("inject",InjectNode);
InjectNode.prototype.close = function() {
if (this.interval_id != null) {
clearInterval(this.interval_id);
this.log("inject: repeat stopped");
} else if (this.cronjob != null) {
this.cronjob.stop();
this.log("inject: cronjob stopped");
delete this.cronjob;
} }
} }
if (this.once) { RED.httpAdmin.post("/inject/:id", function(req,res) {
setTimeout( function(){ node.emit("input",{}); }, 100); var node = RED.nodes.getNode(req.params.id);
} if (node != null) {
try {
this.on("input",function(msg) { node.receive();
var msg = {topic:this.topic}; res.send(200);
if ( (this.payloadType == null && this.payload == "") || this.payloadType == "date") { } catch(err) {
msg.payload = Date.now(); res.send(500);
} else if (this.payloadType == null || this.payloadType == "string") { node.error("Inject failed:"+err);
msg.payload = this.payload; console.log(err.stack);
} else { }
msg.payload = ""; } else {
} res.send(404);
this.send(msg); }
msg = null;
}); });
} }
RED.nodes.registerType("inject",InjectNode);
InjectNode.prototype.close = function() {
if (this.interval_id != null) {
clearInterval(this.interval_id);
this.log("inject: repeat stopped");
} else if (this.cronjob != null) {
this.cronjob.stop();
this.log("inject: cronjob stopped");
delete this.cronjob;
}
}
RED.httpAdmin.post("/inject/:id", function(req,res) {
var node = RED.nodes.getNode(req.params.id);
if (node != null) {
try {
node.receive();
res.send(200);
} catch(err) {
res.send(500);
node.error("Inject failed:"+err);
console.log(err.stack);
}
} else {
res.send(404);
}
});

View File

@ -14,157 +14,158 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var util = require("util"); var util = require("util");
var ws = require("ws"); var ws = require("ws");
var events = require("events"); var events = require("events");
var debuglength = RED.settings.debugMaxLength||1000; var debuglength = RED.settings.debugMaxLength||1000;
var useColors = false; var useColors = false;
// util.inspect.styles.boolean = "red"; // util.inspect.styles.boolean = "red";
function DebugNode(n) { function DebugNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.name = n.name; this.name = n.name;
this.complete = n.complete; this.complete = n.complete;
this.console = n.console; this.console = n.console;
this.active = (n.active == null)||n.active; this.active = (n.active == null)||n.active;
var node = this; var node = this;
this.on("input",function(msg) { this.on("input",function(msg) {
if (this.complete == "true") { // debug complete msg object if (this.complete == "true") { // debug complete msg object
if (this.console == "true") { if (this.console == "true") {
node.log("\n"+util.inspect(msg, {colors:useColors, depth:10})); node.log("\n"+util.inspect(msg, {colors:useColors, depth:10}));
} }
if (msg.payload instanceof Buffer) { msg.payload = "(Buffer) "+msg.payload.toString('hex'); } if (msg.payload instanceof Buffer) { msg.payload = "(Buffer) "+msg.payload.toString('hex'); }
if (this.active) { if (this.active) {
DebugNode.send({id:this.id,name:this.name,topic:msg.topic,msg:msg,_path:msg._path}); DebugNode.send({id:this.id,name:this.name,topic:msg.topic,msg:msg,_path:msg._path});
} }
} else { // debug just the msg.payload } else { // debug just the msg.payload
if (this.console == "true") { if (this.console == "true") {
if (typeof msg.payload === "string") { if (typeof msg.payload === "string") {
if (msg.payload.indexOf("\n") != -1) { msg.payload = "\n"+msg.payload; } if (msg.payload.indexOf("\n") != -1) { msg.payload = "\n"+msg.payload; }
node.log(msg.payload); node.log(msg.payload);
}
else if (typeof msg.payload === "object") { node.log("\n"+util.inspect(msg.payload, {colors:useColors, depth:10})); }
else { node.log(util.inspect(msg.payload, {colors:useColors})); }
}
if (typeof msg.payload == "undefined") { msg.payload = "(undefined)"; }
if (msg.payload instanceof Buffer) { msg.payload = "(Buffer) "+msg.payload.toString('hex'); }
if (this.active) {
DebugNode.send({id:this.id,name:this.name,topic:msg.topic,msg:msg.payload,_path:msg._path});
} }
else if (typeof msg.payload === "object") { node.log("\n"+util.inspect(msg.payload, {colors:useColors, depth:10})); }
else { node.log(util.inspect(msg.payload, {colors:useColors})); }
} }
if (typeof msg.payload == "undefined") { msg.payload = "(undefined)"; } });
if (msg.payload instanceof Buffer) { msg.payload = "(Buffer) "+msg.payload.toString('hex'); } }
if (this.active) {
DebugNode.send({id:this.id,name:this.name,topic:msg.topic,msg:msg.payload,_path:msg._path}); var lastSentTime = (new Date()).getTime();
setInterval(function() {
var now = (new Date()).getTime();
if (now-lastSentTime > 15000) {
lastSentTime = now;
for (var i in DebugNode.activeConnections) {
var ws = DebugNode.activeConnections[i];
try {
var p = JSON.stringify({heartbeat:lastSentTime});
ws.send(p);
} catch(err) {
util.log("[debug] ws heartbeat error : "+err);
}
} }
} }
}); }, 15000);
}
var lastSentTime = (new Date()).getTime();
setInterval(function() {
var now = (new Date()).getTime(); RED.nodes.registerType("debug",DebugNode);
if (now-lastSentTime > 15000) {
lastSentTime = now; DebugNode.send = function(msg) {
if (msg.msg instanceof Error) {
msg.msg = msg.msg.toString();
} else if (typeof msg.msg === 'object') {
var seen = [];
var ty = "(Object) ";
if (util.isArray(msg.msg)) { ty = "(Array) "; }
msg.msg = ty + JSON.stringify(msg.msg, function(key, value) {
if (typeof value === 'object' && value !== null) {
if (seen.indexOf(value) !== -1) { return "[circular]"; }
seen.push(value);
}
return value;
}," ");
seen = null;
} else if (typeof msg.msg === "boolean") {
msg.msg = "(boolean) "+msg.msg.toString();
} else if (msg.msg === 0) {
msg.msg = "0";
} else if (msg.msg == null) {
msg.msg = "[undefined]";
}
if (msg.msg.length > debuglength) {
msg.msg = msg.msg.substr(0,debuglength) +" ....";
}
for (var i in DebugNode.activeConnections) { for (var i in DebugNode.activeConnections) {
var ws = DebugNode.activeConnections[i]; var ws = DebugNode.activeConnections[i];
try { try {
var p = JSON.stringify({heartbeat:lastSentTime}); var p = JSON.stringify(msg);
ws.send(p); ws.send(p);
} catch(err) { } catch(err) {
util.log("[debug] ws heartbeat error : "+err); util.log("[debug] ws error : "+err);
} }
} }
lastSentTime = (new Date()).getTime();
} }
}, 15000);
DebugNode.activeConnections = [];
var path = RED.settings.httpAdminRoot || "/";
path = path + (path.slice(-1) == "/" ? "":"/") + "debug/ws";
RED.nodes.registerType("debug",DebugNode); DebugNode.wsServer = new ws.Server({server:RED.server,path:path});
DebugNode.wsServer.on('connection',function(ws) {
DebugNode.send = function(msg) { DebugNode.activeConnections.push(ws);
if (msg.msg instanceof Error) { ws.on('close',function() {
msg.msg = msg.msg.toString(); for (var i in DebugNode.activeConnections) {
} else if (typeof msg.msg === 'object') { if (DebugNode.activeConnections[i] === ws) {
var seen = []; DebugNode.activeConnections.splice(i,1);
var ty = "(Object) "; break;
if (util.isArray(msg.msg)) { ty = "(Array) "; } }
msg.msg = ty + JSON.stringify(msg.msg, function(key, value) {
if (typeof value === 'object' && value !== null) {
if (seen.indexOf(value) !== -1) { return "[circular]"; }
seen.push(value);
} }
return value; });
}," "); ws.on('error', function(err) {
seen = null;
} else if (typeof msg.msg === "boolean") {
msg.msg = "(boolean) "+msg.msg.toString();
} else if (msg.msg === 0) {
msg.msg = "0";
} else if (msg.msg == null) {
msg.msg = "[undefined]";
}
if (msg.msg.length > debuglength) {
msg.msg = msg.msg.substr(0,debuglength) +" ....";
}
for (var i in DebugNode.activeConnections) {
var ws = DebugNode.activeConnections[i];
try {
var p = JSON.stringify(msg);
ws.send(p);
} catch(err) {
util.log("[debug] ws error : "+err); util.log("[debug] ws error : "+err);
});
});
DebugNode.wsServer.on('error', function(err) {
util.log("[debug] ws server error : "+err);
});
DebugNode.logHandler = new events.EventEmitter();
DebugNode.logHandler.on("log",function(msg) {
if (msg.level == "warn" || msg.level == "error") {
DebugNode.send(msg);
} }
} });
lastSentTime = (new Date()).getTime(); RED.log.addHandler(DebugNode.logHandler);
}
DebugNode.activeConnections = []; RED.httpAdmin.post("/debug/:id/:state", function(req,res) {
var node = RED.nodes.getNode(req.params.id);
var path = RED.settings.httpAdminRoot || "/"; var state = req.params.state;
path = path + (path.slice(-1) == "/" ? "":"/") + "debug/ws"; if (node != null) {
if (state === "enable") {
DebugNode.wsServer = new ws.Server({server:RED.server,path:path}); node.active = true;
DebugNode.wsServer.on('connection',function(ws) { res.send(200);
DebugNode.activeConnections.push(ws); } else if (state === "disable") {
ws.on('close',function() { node.active = false;
for (var i in DebugNode.activeConnections) { res.send(201);
if (DebugNode.activeConnections[i] === ws) { } else {
DebugNode.activeConnections.splice(i,1); res.send(404);
break;
} }
}
});
ws.on('error', function(err) {
util.log("[debug] ws error : "+err);
});
});
DebugNode.wsServer.on('error', function(err) {
util.log("[debug] ws server error : "+err);
});
DebugNode.logHandler = new events.EventEmitter();
DebugNode.logHandler.on("log",function(msg) {
if (msg.level == "warn" || msg.level == "error") {
DebugNode.send(msg);
}
});
RED.log.addHandler(DebugNode.logHandler);
RED.httpAdmin.post("/debug/:id/:state", function(req,res) {
var node = RED.nodes.getNode(req.params.id);
var state = req.params.state;
if (node != null) {
if (state === "enable") {
node.active = true;
res.send(200);
} else if (state === "disable") {
node.active = false;
res.send(201);
} else { } else {
res.send(404); res.send(404);
} }
} else { });
res.send(404); }
}
});

View File

@ -14,68 +14,68 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var spawn = require('child_process').spawn;
var exec = require('child_process').exec;
var spawn = require('child_process').spawn; function ExecNode(n) {
var exec = require('child_process').exec; RED.nodes.createNode(this,n);
this.cmd = n.command.trim();
this.append = n.append.trim() || "";
this.useSpawn = n.useSpawn;
function ExecNode(n) { var node = this;
RED.nodes.createNode(this,n); this.on("input", function(msg) {
this.cmd = n.command.trim(); if (msg != null) {
this.append = n.append.trim() || "";
this.useSpawn = n.useSpawn;
var node = this; if (this.useSpawn == true) {
this.on("input", function(msg) { // make the extra args into an array
if (msg != null) { // then prepend with the msg.payload
if (typeof(msg.payload !== "string")) { msg.payload = msg.payload.toString(); }
var arg = [];
if (node.append.length > 0) { arg = node.append.split(","); }
if (msg.payload.trim() != "") { arg.unshift(msg.payload); }
node.log(node.cmd+" ["+arg+"]");
if (node.cmd.indexOf(" ") == -1) {
var ex = spawn(node.cmd,arg);
ex.stdout.on('data', function (data) {
//console.log('[exec] stdout: ' + data);
msg.payload = data.toString();
node.send([msg,null,null]);
});
ex.stderr.on('data', function (data) {
//console.log('[exec] stderr: ' + data);
msg.payload = data.toString();
node.send([null,msg,null]);
});
ex.on('close', function (code) {
//console.log('[exec] result: ' + code);
msg.payload = code;
node.send([null,null,msg]);
});
}
else { node.error("Spawn command must be just the command - no spaces or extra parameters"); }
}
if (this.useSpawn == true) { else {
// make the extra args into an array var cl = node.cmd+" "+msg.payload+" "+node.append;
// then prepend with the msg.payload node.log(cl);
if (typeof(msg.payload !== "string")) { msg.payload = msg.payload.toString(); } var child = exec(cl, function (error, stdout, stderr) {
var arg = []; msg.payload = stdout;
if (node.append.length > 0) { arg = node.append.split(","); } var msg2 = {payload:stderr};
if (msg.payload.trim() != "") { arg.unshift(msg.payload); } //console.log('[exec] stdout: ' + stdout);
node.log(node.cmd+" ["+arg+"]"); //console.log('[exec] stderr: ' + stderr);
if (node.cmd.indexOf(" ") == -1) { if (error !== null) {
var ex = spawn(node.cmd,arg); var msg3 = {payload:error};
ex.stdout.on('data', function (data) { //console.log('[exec] error: ' + error);
//console.log('[exec] stdout: ' + data); }
msg.payload = data.toString(); node.send([msg,msg2,msg3]);
node.send([msg,null,null]);
});
ex.stderr.on('data', function (data) {
//console.log('[exec] stderr: ' + data);
msg.payload = data.toString();
node.send([null,msg,null]);
});
ex.on('close', function (code) {
//console.log('[exec] result: ' + code);
msg.payload = code;
node.send([null,null,msg]);
}); });
} }
else { node.error("Spawn command must be just the command - no spaces or extra parameters"); }
} }
else { });
var cl = node.cmd+" "+msg.payload+" "+node.append; }
node.log(cl);
var child = exec(cl, function (error, stdout, stderr) {
msg.payload = stdout;
var msg2 = {payload:stderr};
//console.log('[exec] stdout: ' + stdout);
//console.log('[exec] stderr: ' + stderr);
if (error !== null) {
var msg3 = {payload:error};
//console.log('[exec] error: ' + error);
}
node.send([msg,msg2,msg3]);
});
}
}
}); RED.nodes.registerType("exec",ExecNode);
} }
RED.nodes.registerType("exec",ExecNode);

View File

@ -14,58 +14,58 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var util = require("util");
var vm = require("vm");
var fs = require('fs');
var fspath = require('path');
var util = require("util"); function FunctionNode(n) {
var vm = require("vm"); RED.nodes.createNode(this,n);
var fs = require('fs'); this.name = n.name;
var fspath = require('path'); this.func = n.func;
var functionText = "var results = (function(msg){"+this.func+"\n})(msg);";
this.topic = n.topic;
this.context = {global:RED.settings.functionGlobalContext || {}};
try {
this.script = vm.createScript(functionText);
this.on("input", function(msg) {
if (msg != null) {
var sandbox = {msg:msg,console:console,util:util,Buffer:Buffer,context:this.context};
try {
this.script.runInNewContext(sandbox);
var results = sandbox.results;
function FunctionNode(n) { if (results == null) {
RED.nodes.createNode(this,n); results = [];
this.name = n.name; } else if (results.length == null) {
this.func = n.func; results = [results];
var functionText = "var results = (function(msg){"+this.func+"\n})(msg);"; }
this.topic = n.topic; if (msg._topic) {
this.context = {global:RED.settings.functionGlobalContext || {}}; for (var m in results) {
try { if (results[m]) {
this.script = vm.createScript(functionText); if (util.isArray(results[m])) {
this.on("input", function(msg) { for (var n in results[m]) {
if (msg != null) { results[m][n]._topic = msg._topic;
var sandbox = {msg:msg,console:console,util:util,Buffer:Buffer,context:this.context}; }
try { } else {
this.script.runInNewContext(sandbox); results[m]._topic = msg._topic;
var results = sandbox.results;
if (results == null) {
results = [];
} else if (results.length == null) {
results = [results];
}
if (msg._topic) {
for (var m in results) {
if (results[m]) {
if (util.isArray(results[m])) {
for (var n in results[m]) {
results[m][n]._topic = msg._topic;
} }
} else {
results[m]._topic = msg._topic;
} }
} }
} }
this.send(results);
} catch(err) {
this.error(err);
} }
this.send(results);
} catch(err) {
this.error(err);
} }
} });
}); } catch(err) {
} catch(err) { this.error(err);
this.error(err); }
} }
}
RED.nodes.registerType("function",FunctionNode); RED.nodes.registerType("function",FunctionNode);
RED.library.register("functions"); RED.library.register("functions");
}

View File

@ -14,28 +14,28 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var mustache = require("mustache");
var util = require("util");
var fs = require('fs');
var mustache = require("mustache"); function TemplateNode(n) {
var util = require("util"); RED.nodes.createNode(this,n);
var fs = require('fs'); this.name = n.name;
this.template = n.template;
function TemplateNode(n) { this.on("input", function(msg) {
RED.nodes.createNode(this,n); if (msg != null) {
this.name = n.name; try {
this.template = n.template; msg.payload = mustache.render(this.template,msg)
this.on("input", function(msg) { this.send(msg);
if (msg != null) { } catch(err) {
try { this.error(err.message);
msg.payload = mustache.render(this.template,msg) }
this.send(msg);
} catch(err) {
this.error(err.message);
} }
} });
}); }
RED.nodes.registerType("template",TemplateNode);
RED.library.register("templates");
} }
RED.nodes.registerType("template",TemplateNode);
RED.library.register("templates");

View File

@ -15,140 +15,140 @@
**/ **/
//Simple node to introduce a pause into a flow //Simple node to introduce a pause into a flow
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
function random(n) {
function random(n) { var wait = n.randomFirst + (n.diff * Math.random());
var wait = n.randomFirst + (n.diff * Math.random()); if (n.buffer.length > 0) {
if (n.buffer.length > 0) { n.send(n.buffer.pop());
n.send(n.buffer.pop()); n.randomID = setTimeout(function() {random(n);},wait);
n.randomID = setTimeout(function() {random(n);},wait); } else {
} else { n.randomID = -1;
n.randomID = -1; }
}
}
function DelayNode(n) {
RED.nodes.createNode(this,n);
this.pauseType = n.pauseType;
this.timeoutUnits = n.timeoutUnits;
this.randomUnits = n.randomUnits;
this.rateUnits = n.rateUnits;
if (n.timeoutUnits === "milliseconds") {
this.timeout = n.timeout;
} else if (n.timeoutUnits === "seconds") {
this.timeout = n.timeout * 1000;
} else if (n.timeoutUnits === "minutes") {
this.timeout = n.timeout * (60 * 1000);
} else if (n.timeoutUnits === "hours") {
this.timeout = n.timeout * (60 * 60 * 1000);
} else if (n.timeoutUnits === "days") {
this.timeout = n.timeout * (24 * 60 * 60 * 1000);
} }
if (n.rateUnits === "second") { function DelayNode(n) {
this.rate = 1000/n.rate; RED.nodes.createNode(this,n);
} else if (n.rateUnits === "minute") {
this.rate = (60 * 1000)/n.rate;
} else if (n.rateUnits === "hour") {
this.rate = (60 * 60 * 1000)/n.rate;
} else if (n.rateUnits === "day") {
this.rate = (24 * 60 * 60 * 1000)/n.rate;
}
if (n.randomUnits === "milliseconds") { this.pauseType = n.pauseType;
this.randomFirst = n.randomFirst; this.timeoutUnits = n.timeoutUnits;
this.randomLast = n.randomLast; this.randomUnits = n.randomUnits;
} else if (n.randomUnits === "seconds") { this.rateUnits = n.rateUnits;
this.randomFirst = n.randomFirst * 1000;
this.randomLast = n.randomLast * 1000;
} else if (n.randomUnits === "minutes") {
this.randomFirst = n.randomFirst * (60 * 1000);
this.randomLast = n.randomLast * (60 * 1000);
} else if (n.randomUnits === "hours") {
this.randomFirst = n.randomFirst * (60 * 60 * 1000);
this.randomLast = n.randomLast * (60 * 60 * 1000);
} else if (n.randomUnits === "days") {
this.randomFirst = n.randomFirst * (24 * 60 * 60 * 1000);
this.randomLast = n.randomLast * (24 * 60 * 60 * 1000);
}
this.diff = this.randomLast - this.randomFirst; if (n.timeoutUnits === "milliseconds") {
this.name = n.name; this.timeout = n.timeout;
this.idList = []; } else if (n.timeoutUnits === "seconds") {
this.buffer = []; this.timeout = n.timeout * 1000;
this.intervalID = -1; } else if (n.timeoutUnits === "minutes") {
this.randomID = -1; this.timeout = n.timeout * (60 * 1000);
this.lastSent = Date.now(); } else if (n.timeoutUnits === "hours") {
var node = this; this.timeout = n.timeout * (60 * 60 * 1000);
} else if (n.timeoutUnits === "days") {
this.timeout = n.timeout * (24 * 60 * 60 * 1000);
}
if (this.pauseType === "delay") { if (n.rateUnits === "second") {
this.on("input", function(msg) { this.rate = 1000/n.rate;
var id; } else if (n.rateUnits === "minute") {
id = setTimeout(function(){ this.rate = (60 * 1000)/n.rate;
node.idList.splice(node.idList.indexOf(id),1); } else if (n.rateUnits === "hour") {
node.send(msg); this.rate = (60 * 60 * 1000)/n.rate;
}, node.timeout); } else if (n.rateUnits === "day") {
this.idList.push(id); this.rate = (24 * 60 * 60 * 1000)/n.rate;
}); }
this.on("close", function() { if (n.randomUnits === "milliseconds") {
for (var i=0; i<this.idList.length; i++ ) { this.randomFirst = n.randomFirst;
clearTimeout(this.idList[i]); this.randomLast = n.randomLast;
} } else if (n.randomUnits === "seconds") {
this.idList = []; this.randomFirst = n.randomFirst * 1000;
}); this.randomLast = n.randomLast * 1000;
} else if (n.randomUnits === "minutes") {
this.randomFirst = n.randomFirst * (60 * 1000);
this.randomLast = n.randomLast * (60 * 1000);
} else if (n.randomUnits === "hours") {
this.randomFirst = n.randomFirst * (60 * 60 * 1000);
this.randomLast = n.randomLast * (60 * 60 * 1000);
} else if (n.randomUnits === "days") {
this.randomFirst = n.randomFirst * (24 * 60 * 60 * 1000);
this.randomLast = n.randomLast * (24 * 60 * 60 * 1000);
}
} else if (this.pauseType === "rate") { this.diff = this.randomLast - this.randomFirst;
this.on("input", function(msg) { this.name = n.name;
if (node.drop) { this.idList = [];
if ( node.intervalID !== -1) { this.buffer = [];
node.buffer.push(msg); this.intervalID = -1;
if (node.buffer.length > 1000) { this.randomID = -1;
node.warn(this.name + " buffer exceeded 1000 messages"); this.lastSent = Date.now();
var node = this;
if (this.pauseType === "delay") {
this.on("input", function(msg) {
var id;
id = setTimeout(function(){
node.idList.splice(node.idList.indexOf(id),1);
node.send(msg);
}, node.timeout);
this.idList.push(id);
});
this.on("close", function() {
for (var i=0; i<this.idList.length; i++ ) {
clearTimeout(this.idList[i]);
}
this.idList = [];
});
} else if (this.pauseType === "rate") {
this.on("input", function(msg) {
if (node.drop) {
if ( node.intervalID !== -1) {
node.buffer.push(msg);
if (node.buffer.length > 1000) {
node.warn(this.name + " buffer exceeded 1000 messages");
}
} else {
node.send(msg);
node.intervalID = setInterval(function() {
if (node.buffer.length === 0) {
clearInterval(node.intervalID);
node.intervalID = -1;
}
if (node.buffer.length > 0) {
node.send(node.buffer.shift());
}
},node.rate);
} }
} else { } else {
node.send(msg); var now = Date.now();
node.intervalID = setInterval(function() { if (now-node.lastSent > node.rate) {
if (node.buffer.length === 0) { node.lastSent = now;
clearInterval(node.intervalID); node.send(msg);
node.intervalID = -1; }
}
if (node.buffer.length > 0) {
node.send(node.buffer.shift());
}
},node.rate);
} }
} else { });
var now = Date.now();
if (now-node.lastSent > node.rate) { this.on("close", function() {
node.lastSent = now; clearInterval(this.intervalID);
node.send(msg); this.buffer = [];
});
} else if (this.pauseType === "random") {
this.on("input",function(msg){
node.buffer.push(msg);
if (node.randomID === -1) {
var wait = node.randomFirst + (node.diff * Math.random());
node.randomID = setTimeout(function() {random(node);},wait);
} }
} });
});
this.on("close", function() { this.on("close", function (){
clearInterval(this.intervalID); if (this.randomID !== -1) {
this.buffer = []; clearTimeout(this.randomID);
}); }
});
} else if (this.pauseType === "random") { }
this.on("input",function(msg){
node.buffer.push(msg);
if (node.randomID === -1) {
var wait = node.randomFirst + (node.diff * Math.random());
node.randomID = setTimeout(function() {random(node);},wait);
}
});
this.on("close", function (){
if (this.randomID !== -1) {
clearTimeout(this.randomID);
}
});
} }
RED.nodes.registerType("delay",DelayNode);
} }
RED.nodes.registerType("delay",DelayNode);

View File

@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
function CommentNode(n) {
RED.nodes.createNode(this,n);
}
function CommentNode(n) { RED.nodes.registerType("comment",CommentNode);
RED.nodes.createNode(this,n);
} }
RED.nodes.registerType("comment",CommentNode);

View File

@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
function UnknownNode(n) {
function UnknownNode(n) { RED.nodes.createNode(this,n);
RED.nodes.createNode(this,n); }
RED.nodes.registerType("unknown",UnknownNode);
} }
RED.nodes.registerType("unknown",UnknownNode);

View File

@ -14,174 +14,176 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var util = require("util");
var firmata = require("firmata");
var arduinoReady = false;
var thisboard = null;
// The Board Definition - this opens (and closes) the connection var util = require("util");
function ArduinoNode(n) { var firmata = require("firmata");
RED.nodes.createNode(this,n); var arduinoReady = false;
this.device = n.device; var thisboard = null;
this.repeat = n.repeat||25;
util.log("[firmata] Opening "+this.device);
var node = this;
node.toun = setInterval(function() { // The Board Definition - this opens (and closes) the connection
if (!arduinoReady) { function ArduinoNode(n) {
if (thisboard == null) { RED.nodes.createNode(this,n);
node.board = new firmata.Board(node.device, function(err) { this.device = n.device;
if (err) { this.repeat = n.repeat||25;
util.log("[firmata] error: "+err); util.log("[firmata] Opening "+this.device);
return;
}
arduinoReady = true;
thisboard = node.board;
clearInterval(node.toun);
util.log('[firmata] Arduino connected');
});
}
else {
node.board = thisboard;
node.board.removeAllListeners();
arduinoReady = true;
clearInterval(node.toun);
node.toun = false;
util.log("[firmata] Arduino already connected");
}
} else { util.log("[firmata] Waiting for Firmata"); }
}, 10000); // wait for firmata to connect to arduino
this.on('close', function() {
//this.board.sp.close(function() { console.log("[firmata] Serial port closed"); arduinoReady = false; });
arduinoReady = false;
if (node.toun) {
clearInterval(node.toun);
util.log("[firmata] arduino wait loop stopped");
}
util.log("[firmata] Stopped");
});
}
RED.nodes.registerType("arduino-board",ArduinoNode);
// The Input Node
function DuinoNodeIn(n) {
RED.nodes.createNode(this,n);
this.buttonState = -1;
this.pin = n.pin;
this.state = n.state;
this.arduino = n.arduino;
this.serverConfig = RED.nodes.getNode(this.arduino);
if (typeof this.serverConfig === "object") {
this.board = this.serverConfig.board;
this.repeat = this.serverConfig.repeat;
var node = this; var node = this;
node.toui = setInterval(function() { node.toun = setInterval(function() {
if (thisboard != null) { if (!arduinoReady) {
node.board = thisboard; if (thisboard == null) {
clearInterval(node.toui); node.board = new firmata.Board(node.device, function(err) {
node.toui = false; if (err) {
//console.log("i",node.state,node.pin,node.board.MODES[node.state]); util.log("[firmata] error: "+err);
node.board.pinMode(node.pin, node.board.MODES[node.state]); return;
node.board.setSamplingInterval(node.repeat);
var oldrdg = "";
if (node.state == "ANALOG") {
node.board.analogRead(node.pin, function(data) {
var msg = {payload:data, topic:"A"+node.pin};
if (data != oldrdg) {
node.send(msg);
oldrdg = data;
} }
arduinoReady = true;
thisboard = node.board;
clearInterval(node.toun);
util.log('[firmata] Arduino connected');
}); });
} }
else { else {
node.board.digitalRead(node.pin, function(data) { node.board = thisboard;
var msg = {payload:data, topic:node.pin}; node.board.removeAllListeners();
node.send(msg); arduinoReady = true;
}); clearInterval(node.toun);
node.toun = false;
util.log("[firmata] Arduino already connected");
} }
} } else { util.log("[firmata] Waiting for Firmata"); }
else { node.log("Waiting for Arduino"); } }, 10000); // wait for firmata to connect to arduino
}, 5000); // loop to wait for firmata to connect to arduino
this.on('close', function() { this.on('close', function() {
if (node.toui) { //this.board.sp.close(function() { console.log("[firmata] Serial port closed"); arduinoReady = false; });
clearInterval(node.toui); arduinoReady = false;
util.log("[firmata] input wait loop stopped"); if (node.toun) {
clearInterval(node.toun);
util.log("[firmata] arduino wait loop stopped");
} }
util.log("[firmata] Stopped");
}); });
} }
else { RED.nodes.registerType("arduino-board",ArduinoNode);
util.log("[firmata] Serial Port not Configured");
// The Input Node
function DuinoNodeIn(n) {
RED.nodes.createNode(this,n);
this.buttonState = -1;
this.pin = n.pin;
this.state = n.state;
this.arduino = n.arduino;
this.serverConfig = RED.nodes.getNode(this.arduino);
if (typeof this.serverConfig === "object") {
this.board = this.serverConfig.board;
this.repeat = this.serverConfig.repeat;
var node = this;
node.toui = setInterval(function() {
if (thisboard != null) {
node.board = thisboard;
clearInterval(node.toui);
node.toui = false;
//console.log("i",node.state,node.pin,node.board.MODES[node.state]);
node.board.pinMode(node.pin, node.board.MODES[node.state]);
node.board.setSamplingInterval(node.repeat);
var oldrdg = "";
if (node.state == "ANALOG") {
node.board.analogRead(node.pin, function(data) {
var msg = {payload:data, topic:"A"+node.pin};
if (data != oldrdg) {
node.send(msg);
oldrdg = data;
}
});
}
else {
node.board.digitalRead(node.pin, function(data) {
var msg = {payload:data, topic:node.pin};
node.send(msg);
});
}
}
else { node.log("Waiting for Arduino"); }
}, 5000); // loop to wait for firmata to connect to arduino
this.on('close', function() {
if (node.toui) {
clearInterval(node.toui);
util.log("[firmata] input wait loop stopped");
}
});
}
else {
util.log("[firmata] Serial Port not Configured");
}
} }
RED.nodes.registerType("arduino in",DuinoNodeIn);
// The Output Node
function DuinoNodeOut(n) {
RED.nodes.createNode(this,n);
this.buttonState = -1;
this.pin = n.pin;
this.state = n.state;
this.arduino = n.arduino;
this.serverConfig = RED.nodes.getNode(this.arduino);
if (typeof this.serverConfig === "object") {
this.board = this.serverConfig.board;
var node = this;
this.on("input", function(msg) {
//console.log(msg);
if (node.board != null) {
if (node.state == "OUTPUT") {
if ((msg.payload == true)||(msg.payload == 1)||(msg.payload.toString().toLowerCase() == "on")) {
node.board.digitalWrite(node.pin, node.board.HIGH);
}
if ((msg.payload == false)||(msg.payload == 0)||(msg.payload.toString().toLowerCase() == "off")) {
node.board.digitalWrite(node.pin, node.board.LOW);
}
}
if (node.state == "PWM") {
msg.payload = msg.payload * 1;
if ((msg.payload >= 0) && (msg.payload <= 255)) {
//console.log(msg.payload, node.pin);
node.board.servoWrite(node.pin, msg.payload);
}
}
if (node.state == "SERVO") {
msg.payload = msg.payload * 1;
if ((msg.payload >= 0) && (msg.payload <= 180)) {
//console.log(msg.payload, node.pin);
node.board.servoWrite(node.pin, msg.payload);
}
}
}
//else { console.log("Arduino not ready"); }
});
node.touo = setInterval(function() {
if (thisboard != null) {
clearInterval(node.touo);
node.touo = false;
node.board = thisboard;
//console.log("o",node.state,node.pin,node.board.MODES[node.state]);
node.board.pinMode(node.pin, node.board.MODES[node.state]);
}
else { util.log("[firmata] waiting for arduino to connect"); }
}, 5000); // loop to wait for firmata to connect to arduino
this.on('close', function() {
if (node.touo) {
clearInterval(node.touo);
util.log("[firmata] output wait loop stopped");
}
});
}
else {
util.log("[firmata] Serial Port not Configured");
}
}
RED.nodes.registerType("arduino out",DuinoNodeOut);
} }
RED.nodes.registerType("arduino in",DuinoNodeIn);
// The Output Node
function DuinoNodeOut(n) {
RED.nodes.createNode(this,n);
this.buttonState = -1;
this.pin = n.pin;
this.state = n.state;
this.arduino = n.arduino;
this.serverConfig = RED.nodes.getNode(this.arduino);
if (typeof this.serverConfig === "object") {
this.board = this.serverConfig.board;
var node = this;
this.on("input", function(msg) {
//console.log(msg);
if (node.board != null) {
if (node.state == "OUTPUT") {
if ((msg.payload == true)||(msg.payload == 1)||(msg.payload.toString().toLowerCase() == "on")) {
node.board.digitalWrite(node.pin, node.board.HIGH);
}
if ((msg.payload == false)||(msg.payload == 0)||(msg.payload.toString().toLowerCase() == "off")) {
node.board.digitalWrite(node.pin, node.board.LOW);
}
}
if (node.state == "PWM") {
msg.payload = msg.payload * 1;
if ((msg.payload >= 0) && (msg.payload <= 255)) {
//console.log(msg.payload, node.pin);
node.board.servoWrite(node.pin, msg.payload);
}
}
if (node.state == "SERVO") {
msg.payload = msg.payload * 1;
if ((msg.payload >= 0) && (msg.payload <= 180)) {
//console.log(msg.payload, node.pin);
node.board.servoWrite(node.pin, msg.payload);
}
}
}
//else { console.log("Arduino not ready"); }
});
node.touo = setInterval(function() {
if (thisboard != null) {
clearInterval(node.touo);
node.touo = false;
node.board = thisboard;
//console.log("o",node.state,node.pin,node.board.MODES[node.state]);
node.board.pinMode(node.pin, node.board.MODES[node.state]);
}
else { util.log("[firmata] waiting for arduino to connect"); }
}, 5000); // loop to wait for firmata to connect to arduino
this.on('close', function() {
if (node.touo) {
clearInterval(node.touo);
util.log("[firmata] output wait loop stopped");
}
});
}
else {
util.log("[firmata] Serial Port not Configured");
}
}
RED.nodes.registerType("arduino out",DuinoNodeOut);

View File

@ -14,145 +14,146 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var util = require("util"); var util = require("util");
var exec = require('child_process').exec; var exec = require('child_process').exec;
var fs = require('fs'); var fs = require('fs');
if (!fs.existsSync("/dev/ttyAMA0")) { // unlikely if not on a Pi if (!fs.existsSync("/dev/ttyAMA0")) { // unlikely if not on a Pi
throw "Info : Ignoring Raspberry Pi specific node."; throw "Info : Ignoring Raspberry Pi specific node.";
}
if (!fs.existsSync("/usr/local/bin/gpio")) { // gpio command not installed
throw "Info : Can't find Raspberry Pi wiringPi gpio command.";
}
// Map physical P1 pins to Gordon's Wiring-Pi Pins (as they should be V1/V2 tolerant)
var pintable = {
// Physical : WiringPi
"11":"0",
"12":"1",
"13":"2",
"15":"3",
"16":"4",
"18":"5",
"22":"6",
"7":"7",
"3":"8",
"5":"9",
"24":"10",
"26":"11",
"19":"12",
"21":"13",
"23":"14",
"8":"15",
"10":"16"
}
var tablepin = {
// WiringPi : Physical
"0":"11",
"1":"12",
"2":"13",
"3":"15",
"4":"16",
"5":"18",
"6":"22",
"7":"7",
"8":"3",
"9":"5",
"10":"24",
"11":"26",
"12":"19",
"13":"21",
"14":"23",
"15":"8",
"16":"10"
}
function GPIOInNode(n) {
RED.nodes.createNode(this,n);
this.buttonState = -1;
this.pin = pintable[n.pin];
this.intype = n.intype;
var node = this;
if (this.pin) {
exec("gpio mode "+node.pin+" "+node.intype, function(err,stdout,stderr) {
if (err) node.error(err);
else {
node._interval = setInterval( function() {
exec("gpio read "+node.pin, function(err,stdout,stderr) {
if (err) node.error(err);
else {
if (node.buttonState !== Number(stdout)) {
var previousState = node.buttonState;
node.buttonState = Number(stdout);
if (previousState !== -1) {
var msg = {topic:"pi/"+tablepin[node.pin], payload:node.buttonState};
node.send(msg);
}
}
}
});
}, 250);
}
});
}
else {
this.error("Invalid GPIO pin: "+this.pin);
} }
this.on("close", function() { if (!fs.existsSync("/usr/local/bin/gpio")) { // gpio command not installed
clearInterval(this._interval); throw "Info : Can't find Raspberry Pi wiringPi gpio command.";
}); }
}
function GPIOOutNode(n) { // Map physical P1 pins to Gordon's Wiring-Pi Pins (as they should be V1/V2 tolerant)
RED.nodes.createNode(this,n); var pintable = {
this.pin = pintable[n.pin]; // Physical : WiringPi
var node = this; "11":"0",
"12":"1",
"13":"2",
"15":"3",
"16":"4",
"18":"5",
"22":"6",
"7":"7",
"3":"8",
"5":"9",
"24":"10",
"26":"11",
"19":"12",
"21":"13",
"23":"14",
"8":"15",
"10":"16"
}
var tablepin = {
// WiringPi : Physical
"0":"11",
"1":"12",
"2":"13",
"3":"15",
"4":"16",
"5":"18",
"6":"22",
"7":"7",
"8":"3",
"9":"5",
"10":"24",
"11":"26",
"12":"19",
"13":"21",
"14":"23",
"15":"8",
"16":"10"
}
if (this.pin) { function GPIOInNode(n) {
process.nextTick(function() { RED.nodes.createNode(this,n);
exec("gpio mode "+node.pin+" out", function(err,stdout,stderr) { this.buttonState = -1;
this.pin = pintable[n.pin];
this.intype = n.intype;
var node = this;
if (this.pin) {
exec("gpio mode "+node.pin+" "+node.intype, function(err,stdout,stderr) {
if (err) node.error(err); if (err) node.error(err);
else { else {
node.on("input", function(msg) { node._interval = setInterval( function() {
if (msg.payload === "true") msg.payload = true; exec("gpio read "+node.pin, function(err,stdout,stderr) {
if (msg.payload === "false") msg.payload = false; if (err) node.error(err);
var out = Number(msg.payload); else {
if ((out == 0)|(out == 1)) { if (node.buttonState !== Number(stdout)) {
exec("gpio write "+node.pin+" "+out, function(err,stdout,stderr) { var previousState = node.buttonState;
if (err) node.error(err); node.buttonState = Number(stdout);
}); if (previousState !== -1) {
} var msg = {topic:"pi/"+tablepin[node.pin], payload:node.buttonState};
else node.warn("Invalid input - not 0 or 1"); node.send(msg);
}); }
}
}
});
}, 250);
} }
}); });
}
else {
this.error("Invalid GPIO pin: "+this.pin);
}
this.on("close", function() {
clearInterval(this._interval);
}); });
} }
else {
this.error("Invalid GPIO pin: "+this.pin); function GPIOOutNode(n) {
RED.nodes.createNode(this,n);
this.pin = pintable[n.pin];
var node = this;
if (this.pin) {
process.nextTick(function() {
exec("gpio mode "+node.pin+" out", function(err,stdout,stderr) {
if (err) node.error(err);
else {
node.on("input", function(msg) {
if (msg.payload === "true") msg.payload = true;
if (msg.payload === "false") msg.payload = false;
var out = Number(msg.payload);
if ((out == 0)|(out == 1)) {
exec("gpio write "+node.pin+" "+out, function(err,stdout,stderr) {
if (err) node.error(err);
});
}
else node.warn("Invalid input - not 0 or 1");
});
}
});
});
}
else {
this.error("Invalid GPIO pin: "+this.pin);
}
this.on("close", function() {
exec("gpio mode "+this.pin+" in");
});
} }
this.on("close", function() { exec("gpio mode 0 in",function(err,stdout,stderr) {
exec("gpio mode "+this.pin+" in"); if (err) {
util.log('[36-rpi-gpio.js] Error: "gpio" command failed for some reason.');
}
exec("gpio mode 1 in");
exec("gpio mode 2 in");
exec("gpio mode 3 in");
exec("gpio mode 4 in");
exec("gpio mode 5 in");
exec("gpio mode 6 in");
exec("gpio mode 7 in");
}); });
RED.nodes.registerType("rpi-gpio in",GPIOInNode);
RED.nodes.registerType("rpi-gpio out",GPIOOutNode);
} }
exec("gpio mode 0 in",function(err,stdout,stderr) {
if (err) {
util.log('[36-rpi-gpio.js] Error: "gpio" command failed for some reason.');
}
exec("gpio mode 1 in");
exec("gpio mode 2 in");
exec("gpio mode 3 in");
exec("gpio mode 4 in");
exec("gpio mode 5 in");
exec("gpio mode 6 in");
exec("gpio mode 7 in");
});
RED.nodes.registerType("rpi-gpio in",GPIOInNode);
RED.nodes.registerType("rpi-gpio out",GPIOOutNode);

View File

@ -14,122 +14,124 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var connectionPool = require("./lib/mqttConnectionPool");
var util = require("util");
function MQTTBrokerNode(n) { var connectionPool = require("./lib/mqttConnectionPool");
RED.nodes.createNode(this,n); var util = require("util");
this.broker = n.broker;
this.port = n.port; function MQTTBrokerNode(n) {
this.clientid = n.clientid; RED.nodes.createNode(this,n);
var credentials = RED.nodes.getCredentials(n.id); this.broker = n.broker;
if (credentials) { this.port = n.port;
this.username = credentials.user; this.clientid = n.clientid;
this.password = credentials.password; var credentials = RED.nodes.getCredentials(n.id);
if (credentials) {
this.username = credentials.user;
this.password = credentials.password;
}
} }
} RED.nodes.registerType("mqtt-broker",MQTTBrokerNode);
RED.nodes.registerType("mqtt-broker",MQTTBrokerNode);
var querystring = require('querystring'); var querystring = require('querystring');
RED.httpAdmin.get('/mqtt-broker/:id',function(req,res) { RED.httpAdmin.get('/mqtt-broker/:id',function(req,res) {
var credentials = RED.nodes.getCredentials(req.params.id); var credentials = RED.nodes.getCredentials(req.params.id);
if (credentials) { if (credentials) {
res.send(JSON.stringify({user:credentials.user,hasPassword:(credentials.password&&credentials.password!="")})); res.send(JSON.stringify({user:credentials.user,hasPassword:(credentials.password&&credentials.password!="")}));
} else { } else {
res.send(JSON.stringify({})); res.send(JSON.stringify({}));
} }
});
RED.httpAdmin.delete('/mqtt-broker/:id',function(req,res) {
RED.nodes.deleteCredentials(req.params.id);
res.send(200);
});
RED.httpAdmin.post('/mqtt-broker/:id',function(req,res) {
var body = "";
req.on('data', function(chunk) {
body+=chunk;
}); });
req.on('end', function(){
var newCreds = querystring.parse(body); RED.httpAdmin.delete('/mqtt-broker/:id',function(req,res) {
var credentials = RED.nodes.getCredentials(req.params.id)||{}; RED.nodes.deleteCredentials(req.params.id);
if (newCreds.user == null || newCreds.user == "") {
delete credentials.user;
} else {
credentials.user = newCreds.user;
}
if (newCreds.password == "") {
delete credentials.password;
} else {
credentials.password = newCreds.password||credentials.password;
}
RED.nodes.addCredentials(req.params.id,credentials);
res.send(200); res.send(200);
}); });
});
RED.httpAdmin.post('/mqtt-broker/:id',function(req,res) {
function MQTTInNode(n) { var body = "";
RED.nodes.createNode(this,n); req.on('data', function(chunk) {
this.topic = n.topic; body+=chunk;
this.broker = n.broker;
this.brokerConfig = RED.nodes.getNode(this.broker);
if (this.brokerConfig) {
this.client = connectionPool.get(this.brokerConfig.broker,this.brokerConfig.port,this.brokerConfig.clientid,this.brokerConfig.username,this.brokerConfig.password);
var node = this;
this.client.subscribe(this.topic,2,function(topic,payload,qos,retain) {
var msg = {topic:topic,payload:payload,qos:qos,retain:retain};
if ((node.brokerConfig.broker == "localhost")||(node.brokerConfig.broker == "127.0.0.1")) {
msg._topic = topic;
}
node.send(msg);
}); });
this.client.connect(); req.on('end', function(){
} else { var newCreds = querystring.parse(body);
this.error("missing broker configuration"); var credentials = RED.nodes.getCredentials(req.params.id)||{};
} if (newCreds.user == null || newCreds.user == "") {
} delete credentials.user;
} else {
RED.nodes.registerType("mqtt in",MQTTInNode); credentials.user = newCreds.user;
MQTTInNode.prototype.close = function() {
if (this.client) {
this.client.disconnect();
}
}
function MQTTOutNode(n) {
RED.nodes.createNode(this,n);
this.topic = n.topic;
this.broker = n.broker;
this.brokerConfig = RED.nodes.getNode(this.broker);
if (this.brokerConfig) {
this.client = connectionPool.get(this.brokerConfig.broker,this.brokerConfig.port,this.brokerConfig.clientid,this.brokerConfig.username,this.brokerConfig.password);
this.on("input",function(msg) {
if (msg != null) {
if (this.topic) {
msg.topic = this.topic;
}
this.client.publish(msg);
} }
if (newCreds.password == "") {
delete credentials.password;
} else {
credentials.password = newCreds.password||credentials.password;
}
RED.nodes.addCredentials(req.params.id,credentials);
res.send(200);
}); });
this.client.connect(); });
} else {
this.error("missing broker configuration");
} function MQTTInNode(n) {
} RED.nodes.createNode(this,n);
this.topic = n.topic;
RED.nodes.registerType("mqtt out",MQTTOutNode); this.broker = n.broker;
this.brokerConfig = RED.nodes.getNode(this.broker);
MQTTOutNode.prototype.close = function() { if (this.brokerConfig) {
if (this.client) { this.client = connectionPool.get(this.brokerConfig.broker,this.brokerConfig.port,this.brokerConfig.clientid,this.brokerConfig.username,this.brokerConfig.password);
this.client.disconnect(); var node = this;
this.client.subscribe(this.topic,2,function(topic,payload,qos,retain) {
var msg = {topic:topic,payload:payload,qos:qos,retain:retain};
if ((node.brokerConfig.broker == "localhost")||(node.brokerConfig.broker == "127.0.0.1")) {
msg._topic = topic;
}
node.send(msg);
});
this.client.connect();
} else {
this.error("missing broker configuration");
}
}
RED.nodes.registerType("mqtt in",MQTTInNode);
MQTTInNode.prototype.close = function() {
if (this.client) {
this.client.disconnect();
}
}
function MQTTOutNode(n) {
RED.nodes.createNode(this,n);
this.topic = n.topic;
this.broker = n.broker;
this.brokerConfig = RED.nodes.getNode(this.broker);
if (this.brokerConfig) {
this.client = connectionPool.get(this.brokerConfig.broker,this.brokerConfig.port,this.brokerConfig.clientid,this.brokerConfig.username,this.brokerConfig.password);
this.on("input",function(msg) {
if (msg != null) {
if (this.topic) {
msg.topic = this.topic;
}
this.client.publish(msg);
}
});
this.client.connect();
} else {
this.error("missing broker configuration");
}
}
RED.nodes.registerType("mqtt out",MQTTOutNode);
MQTTOutNode.prototype.close = function() {
if (this.client) {
this.client.disconnect();
}
} }
} }

View File

@ -14,232 +14,234 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var util = require("util");
var http = require("follow-redirects").http;
var https = require("follow-redirects").https;
var urllib = require("url");
var express = require("express");
var getBody = require('raw-body');
var mustache = require("mustache");
var querystring = require("querystring");
var cors = require('cors'); var util = require("util");
var jsonParser = express.json(); var http = require("follow-redirects").http;
var urlencParser = express.urlencoded(); var https = require("follow-redirects").https;
var urllib = require("url");
var express = require("express");
var getBody = require('raw-body');
var mustache = require("mustache");
var querystring = require("querystring");
function rawBodyParser(req, res, next) { var cors = require('cors');
if (req._body) return next(); var jsonParser = express.json();
req.body = ""; var urlencParser = express.urlencoded();
req._body = true;
getBody(req, { function rawBodyParser(req, res, next) {
limit: '1mb', if (req._body) return next();
length: req.headers['content-length'], req.body = "";
encoding: 'utf8' req._body = true;
}, function (err, buf) { getBody(req, {
if (err) return next(err); limit: '1mb',
req.body = buf; length: req.headers['content-length'],
next(); encoding: 'utf8'
}); }, function (err, buf) {
} if (err) return next(err);
req.body = buf;
next();
});
}
function HTTPIn(n) { function HTTPIn(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
if (RED.settings.httpNodeRoot !== false) { if (RED.settings.httpNodeRoot !== false) {
this.url = n.url; this.url = n.url;
this.method = n.method; this.method = n.method;
var node = this; var node = this;
this.errorHandler = function(err,req,res,next) { this.errorHandler = function(err,req,res,next) {
node.warn(err); node.warn(err);
res.send(500); res.send(500);
}; };
this.callback = function(req,res) { this.callback = function(req,res) {
if (node.method == "post") { if (node.method == "post") {
node.send({req:req,res:res,payload:req.body}); node.send({req:req,res:res,payload:req.body});
} else if (node.method == "get") { } else if (node.method == "get") {
node.send({req:req,res:res,payload:req.query}); node.send({req:req,res:res,payload:req.query});
} else { } else {
node.send({req:req,res:res}); node.send({req:req,res:res});
}
}
var corsHandler = function(req,res,next) { next(); }
if (RED.settings.httpNodeCors) {
corsHandler = cors(RED.settings.httpNodeCors);
RED.httpNode.options(this.url,corsHandler);
}
if (this.method == "get") {
RED.httpNode.get(this.url,corsHandler,this.callback,this.errorHandler);
} else if (this.method == "post") {
RED.httpNode.post(this.url,corsHandler,jsonParser,urlencParser,rawBodyParser,this.callback,this.errorHandler);
} else if (this.method == "put") {
RED.httpNode.put(this.url,corsHandler,jsonParser,urlencParser,rawBodyParser,this.callback,this.errorHandler);
} else if (this.method == "delete") {
RED.httpNode.delete(this.url,corsHandler,this.callback,errorHandler);
}
this.on("close",function() {
var routes = RED.httpNode.routes[this.method];
for (var i = 0; i<routes.length; i++) {
if (routes[i].path == this.url) {
routes.splice(i,1);
//break;
} }
} }
var corsHandler = function(req,res,next) { next(); }
if (RED.settings.httpNodeCors) { if (RED.settings.httpNodeCors) {
var routes = RED.httpNode.routes['options']; corsHandler = cors(RED.settings.httpNodeCors);
RED.httpNode.options(this.url,corsHandler);
}
if (this.method == "get") {
RED.httpNode.get(this.url,corsHandler,this.callback,this.errorHandler);
} else if (this.method == "post") {
RED.httpNode.post(this.url,corsHandler,jsonParser,urlencParser,rawBodyParser,this.callback,this.errorHandler);
} else if (this.method == "put") {
RED.httpNode.put(this.url,corsHandler,jsonParser,urlencParser,rawBodyParser,this.callback,this.errorHandler);
} else if (this.method == "delete") {
RED.httpNode.delete(this.url,corsHandler,this.callback,errorHandler);
}
this.on("close",function() {
var routes = RED.httpNode.routes[this.method];
for (var i = 0; i<routes.length; i++) { for (var i = 0; i<routes.length; i++) {
if (routes[i].path == this.url) { if (routes[i].path == this.url) {
routes.splice(i,1); routes.splice(i,1);
//break; //break;
} }
} }
} if (RED.settings.httpNodeCors) {
}); var routes = RED.httpNode.routes['options'];
} else { for (var i = 0; i<routes.length; i++) {
this.warn("Cannot create http-in node when httpNodeRoot set to false"); if (routes[i].path == this.url) {
} routes.splice(i,1);
} //break;
RED.nodes.registerType("http in",HTTPIn);
function HTTPOut(n) {
RED.nodes.createNode(this,n);
var node = this;
this.on("input",function(msg) {
if (msg.res) {
if (msg.headers) {
msg.res.set(msg.headers);
}
var statusCode = msg.statusCode || 200;
if (typeof msg.payload == "object" && !Buffer.isBuffer(msg.payload)) {
msg.res.jsonp(statusCode,msg.payload);
} else {
msg.res.send(statusCode,msg.payload);
}
} else {
node.warn("No response object");
}
});
}
RED.nodes.registerType("http response",HTTPOut);
function HTTPRequest(n) {
RED.nodes.createNode(this,n);
var nodeUrl = n.url;
var isTemplatedUrl = (nodeUrl||"").indexOf("{{") != -1;
var nodeMethod = n.method || "GET";
var node = this;
var credentials = RED.nodes.getCredentials(n.id);
this.on("input",function(msg) {
var url;
if (msg.url) {
url = msg.url;
} else if (isTemplatedUrl) {
url = mustache.render(nodeUrl,msg);
} else {
url = nodeUrl;
}
var method = (msg.method||nodeMethod).toUpperCase();
var opts = urllib.parse(url);
opts.method = method;
opts.headers = {};
if (msg.headers) {
for (var v in msg.headers) {
opts.headers[v.toLowerCase()] = msg.headers[v];
}
}
if (credentials) {
opts.auth = credentials.user+":"+(credentials.password||"");
}
var payload = null;
if (msg.payload && (method == "POST" || method == "PUT") ) {
if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) {
payload = msg.payload;
} else if (typeof msg.payload == "number") {
payload = msg.payload+"";
} else {
if (opts.headers['content-type'] == 'application/x-www-form-urlencoded') {
payload = querystring.stringify(msg.payload);
} else {
payload = JSON.stringify(msg.payload);
if (opts.headers['content-type'] == null) {
opts.headers['content-type'] = "application/json";
} }
} }
} }
if (opts.headers['content-length'] == null) { });
opts.headers['content-length'] = Buffer.byteLength(payload); } else {
} this.warn("Cannot create http-in node when httpNodeRoot set to false");
} }
}
RED.nodes.registerType("http in",HTTPIn);
var req = ((/^https/.test(url))?https:http).request(opts,function(res) {
res.setEncoding('utf8'); function HTTPOut(n) {
msg.statusCode = res.statusCode; RED.nodes.createNode(this,n);
msg.headers = res.headers; var node = this;
msg.payload = ""; this.on("input",function(msg) {
res.on('data',function(chunk) { if (msg.res) {
msg.payload += chunk; if (msg.headers) {
msg.res.set(msg.headers);
}
var statusCode = msg.statusCode || 200;
if (typeof msg.payload == "object" && !Buffer.isBuffer(msg.payload)) {
msg.res.jsonp(statusCode,msg.payload);
} else {
msg.res.send(statusCode,msg.payload);
}
} else {
node.warn("No response object");
}
});
}
RED.nodes.registerType("http response",HTTPOut);
function HTTPRequest(n) {
RED.nodes.createNode(this,n);
var nodeUrl = n.url;
var isTemplatedUrl = (nodeUrl||"").indexOf("{{") != -1;
var nodeMethod = n.method || "GET";
var node = this;
var credentials = RED.nodes.getCredentials(n.id);
this.on("input",function(msg) {
var url;
if (msg.url) {
url = msg.url;
} else if (isTemplatedUrl) {
url = mustache.render(nodeUrl,msg);
} else {
url = nodeUrl;
}
var method = (msg.method||nodeMethod).toUpperCase();
var opts = urllib.parse(url);
opts.method = method;
opts.headers = {};
if (msg.headers) {
for (var v in msg.headers) {
opts.headers[v.toLowerCase()] = msg.headers[v];
}
}
if (credentials) {
opts.auth = credentials.user+":"+(credentials.password||"");
}
var payload = null;
if (msg.payload && (method == "POST" || method == "PUT") ) {
if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) {
payload = msg.payload;
} else if (typeof msg.payload == "number") {
payload = msg.payload+"";
} else {
if (opts.headers['content-type'] == 'application/x-www-form-urlencoded') {
payload = querystring.stringify(msg.payload);
} else {
payload = JSON.stringify(msg.payload);
if (opts.headers['content-type'] == null) {
opts.headers['content-type'] = "application/json";
}
}
}
if (opts.headers['content-length'] == null) {
opts.headers['content-length'] = Buffer.byteLength(payload);
}
}
var req = ((/^https/.test(url))?https:http).request(opts,function(res) {
res.setEncoding('utf8');
msg.statusCode = res.statusCode;
msg.headers = res.headers;
msg.payload = "";
res.on('data',function(chunk) {
msg.payload += chunk;
});
res.on('end',function() {
node.send(msg);
});
}); });
res.on('end',function() { req.on('error',function(err) {
msg.payload = err.toString();
msg.statusCode = err.code;
node.send(msg); node.send(msg);
}); });
}); if (payload) {
req.on('error',function(err) { req.write(payload);
msg.payload = err.toString(); }
msg.statusCode = err.code; req.end();
node.send(msg); });
});
if (payload) {
req.write(payload);
}
req.end();
});
}
RED.nodes.registerType("http request",HTTPRequest);
RED.httpAdmin.get('/http-request/:id',function(req,res) {
var credentials = RED.nodes.getCredentials(req.params.id);
if (credentials) {
res.send(JSON.stringify({user:credentials.user,hasPassword:(credentials.password&&credentials.password!="")}));
} else {
res.send(JSON.stringify({}));
} }
}); RED.nodes.registerType("http request",HTTPRequest);
RED.httpAdmin.delete('/http-request/:id',function(req,res) { RED.httpAdmin.get('/http-request/:id',function(req,res) {
RED.nodes.deleteCredentials(req.params.id); var credentials = RED.nodes.getCredentials(req.params.id);
res.send(200); if (credentials) {
}); res.send(JSON.stringify({user:credentials.user,hasPassword:(credentials.password&&credentials.password!="")}));
} else {
RED.httpAdmin.post('/http-request/:id',function(req,res) { res.send(JSON.stringify({}));
var body = ""; }
req.on('data', function(chunk) {
body+=chunk;
}); });
req.on('end', function(){
var newCreds = querystring.parse(body); RED.httpAdmin.delete('/http-request/:id',function(req,res) {
var credentials = RED.nodes.getCredentials(req.params.id)||{}; RED.nodes.deleteCredentials(req.params.id);
if (newCreds.user == null || newCreds.user == "") {
delete credentials.user;
} else {
credentials.user = newCreds.user;
}
if (newCreds.password == "") {
delete credentials.password;
} else {
credentials.password = newCreds.password||credentials.password;
}
RED.nodes.addCredentials(req.params.id,credentials);
res.send(200); res.send(200);
}); });
});
RED.httpAdmin.post('/http-request/:id',function(req,res) {
var body = "";
req.on('data', function(chunk) {
body+=chunk;
});
req.on('end', function(){
var newCreds = querystring.parse(body);
var credentials = RED.nodes.getCredentials(req.params.id)||{};
if (newCreds.user == null || newCreds.user == "") {
delete credentials.user;
} else {
credentials.user = newCreds.user;
}
if (newCreds.password == "") {
delete credentials.password;
} else {
credentials.password = newCreds.password||credentials.password;
}
RED.nodes.addCredentials(req.params.id,credentials);
res.send(200);
});
});
}

View File

@ -14,159 +14,160 @@
* limitations under the License. * limitations under the License.
**/ **/
// Require main module module.exports = function(RED) {
var RED = require(process.env.NODE_RED_HOME+"/red/red"),
ws = require("ws"),
inspect = require("sys").inspect;
// A node red node that sets up a local websocket server var ws = require("ws"),
function WebSocketListenerNode(n) { inspect = require("sys").inspect;
// Create a RED node
RED.nodes.createNode(this,n);
var node = this; // A node red node that sets up a local websocket server
function WebSocketListenerNode(n) {
// Create a RED node
RED.nodes.createNode(this,n);
// Store local copies of the node configuration (as defined in the .html) var node = this;
node.path = n.path;
node.wholemsg = (n.wholemsg === "true");
node._inputNodes = []; // collection of nodes that want to receive events // Store local copies of the node configuration (as defined in the .html)
node.path = n.path;
node.wholemsg = (n.wholemsg === "true");
var path = RED.settings.httpNodeRoot || "/"; node._inputNodes = []; // collection of nodes that want to receive events
path = path + (path.slice(-1) == "/" ? "":"/") + (node.path.charAt(0) == "/" ? node.path.substring(1) : node.path);
// Workaround https://github.com/einaros/ws/pull/253 var path = RED.settings.httpNodeRoot || "/";
// Listen for 'newListener' events from RED.server path = path + (path.slice(-1) == "/" ? "":"/") + (node.path.charAt(0) == "/" ? node.path.substring(1) : node.path);
node._serverListeners = {};
var storeListener = function(/*String*/event,/*function*/listener){
if(event == "error" || event == "upgrade" || event == "listening"){
node._serverListeners[event] = listener;
}
}
node._clients = {};
RED.server.addListener('newListener',storeListener);
// Create a WebSocket Server
node.server = new ws.Server({server:RED.server,path:path});
// Workaround https://github.com/einaros/ws/pull/253
// Stop listening for new listener events
RED.server.removeListener('newListener',storeListener);
node.server.on('connection', function(socket){
var id = (1+Math.random()*4294967295).toString(16);
node._clients[id] = socket;
socket.on('close',function() {
delete node._clients[id];
});
socket.on('message',function(data,flags){
node.handleEvent(id,socket,'message',data,flags);
});
socket.on('error', function(err) {
node.warn("An error occured on the ws connection: "+inspect(err));
});
});
node.on("close", function() {
// Workaround https://github.com/einaros/ws/pull/253 // Workaround https://github.com/einaros/ws/pull/253
// Remove listeners from RED.server // Listen for 'newListener' events from RED.server
var listener = null;
for(var event in node._serverListeners){
listener = node._serverListeners[event];
if(typeof listener === "function"){
RED.server.removeListener(event,listener);
}
}
node._serverListeners = {}; node._serverListeners = {};
node.server.close(); var storeListener = function(/*String*/event,/*function*/listener){
node._inputNodes = []; if(event == "error" || event == "upgrade" || event == "listening"){
}); node._serverListeners[event] = listener;
}
RED.nodes.registerType("websocket-listener",WebSocketListenerNode);
WebSocketListenerNode.prototype.registerInputNode = function(/*Node*/handler){
this._inputNodes.push(handler);
}
WebSocketListenerNode.prototype.handleEvent = function(id,/*socket*/socket,/*String*/event,/*Object*/data,/*Object*/flags){
var msg;
if (this.wholemsg) {
msg = JSON.parse(data);
} else {
msg = {
payload:data
};
}
msg._session = {type:"websocket",id:id};
for (var i = 0; i < this._inputNodes.length; i++) {
this._inputNodes[i].send(msg);
};
}
WebSocketListenerNode.prototype.broadcast = function(data){
for(var i in this.server.clients){
this.server.clients[i].send(data);
};
}
WebSocketListenerNode.prototype.send = function(id,data){
var session = this._clients[id];
if (session) {
session.send(data);
}
}
function WebSocketInNode(n) {
RED.nodes.createNode(this,n);
this.server = n.server;
var node = this;
this.serverConfig = RED.nodes.getNode(this.server);
if (this.serverConfig) {
this.serverConfig.registerInputNode(this);
} else {
this.error("Missing server configuration");
}
}
RED.nodes.registerType("websocket in",WebSocketInNode);
function WebSocketOutNode(n) {
RED.nodes.createNode(this,n);
var node = this;
this.server = n.server;
this.serverConfig = RED.nodes.getNode(this.server);
if (!this.serverConfig) {
this.error("Missing server configuration");
}
this.on("input", function(msg) {
var payload;
if (this.serverConfig.wholemsg) {
delete msg._session;
payload = JSON.stringify(msg);
} else {
payload = msg.payload;
if (Buffer.isBuffer(payload)) {
payload = payload.toString();
} else if (typeof payload === "object") {
payload = JSON.stringify(payload);
} else if (typeof payload !== "string") {
payload = ""+payload;
} }
} }
if (msg._session && msg._session.type == "websocket") {
node.serverConfig.send(msg._session.id,payload); node._clients = {};
} else {
node.serverConfig.broadcast(payload,function(error){ RED.server.addListener('newListener',storeListener);
if(!!error){
node.warn("An error occurred while sending:" + inspect(error)); // Create a WebSocket Server
} node.server = new ws.Server({server:RED.server,path:path});
// Workaround https://github.com/einaros/ws/pull/253
// Stop listening for new listener events
RED.server.removeListener('newListener',storeListener);
node.server.on('connection', function(socket){
var id = (1+Math.random()*4294967295).toString(16);
node._clients[id] = socket;
socket.on('close',function() {
delete node._clients[id];
}); });
socket.on('message',function(data,flags){
node.handleEvent(id,socket,'message',data,flags);
});
socket.on('error', function(err) {
node.warn("An error occured on the ws connection: "+inspect(err));
});
});
node.on("close", function() {
// Workaround https://github.com/einaros/ws/pull/253
// Remove listeners from RED.server
var listener = null;
for(var event in node._serverListeners){
listener = node._serverListeners[event];
if(typeof listener === "function"){
RED.server.removeListener(event,listener);
}
}
node._serverListeners = {};
node.server.close();
node._inputNodes = [];
});
}
RED.nodes.registerType("websocket-listener",WebSocketListenerNode);
WebSocketListenerNode.prototype.registerInputNode = function(/*Node*/handler){
this._inputNodes.push(handler);
}
WebSocketListenerNode.prototype.handleEvent = function(id,/*socket*/socket,/*String*/event,/*Object*/data,/*Object*/flags){
var msg;
if (this.wholemsg) {
msg = JSON.parse(data);
} else {
msg = {
payload:data
};
} }
}); msg._session = {type:"websocket",id:id};
for (var i = 0; i < this._inputNodes.length; i++) {
this._inputNodes[i].send(msg);
};
}
WebSocketListenerNode.prototype.broadcast = function(data){
for(var i in this.server.clients){
this.server.clients[i].send(data);
};
}
WebSocketListenerNode.prototype.send = function(id,data){
var session = this._clients[id];
if (session) {
session.send(data);
}
}
function WebSocketInNode(n) {
RED.nodes.createNode(this,n);
this.server = n.server;
var node = this;
this.serverConfig = RED.nodes.getNode(this.server);
if (this.serverConfig) {
this.serverConfig.registerInputNode(this);
} else {
this.error("Missing server configuration");
}
}
RED.nodes.registerType("websocket in",WebSocketInNode);
function WebSocketOutNode(n) {
RED.nodes.createNode(this,n);
var node = this;
this.server = n.server;
this.serverConfig = RED.nodes.getNode(this.server);
if (!this.serverConfig) {
this.error("Missing server configuration");
}
this.on("input", function(msg) {
var payload;
if (this.serverConfig.wholemsg) {
delete msg._session;
payload = JSON.stringify(msg);
} else {
payload = msg.payload;
if (Buffer.isBuffer(payload)) {
payload = payload.toString();
} else if (typeof payload === "object") {
payload = JSON.stringify(payload);
} else if (typeof payload !== "string") {
payload = ""+payload;
}
}
if (msg._session && msg._session.type == "websocket") {
node.serverConfig.send(msg._session.id,payload);
} else {
node.serverConfig.broadcast(payload,function(error){
if(!!error){
node.warn("An error occurred while sending:" + inspect(error));
}
});
}
});
}
RED.nodes.registerType("websocket out",WebSocketOutNode);
} }
RED.nodes.registerType("websocket out",WebSocketOutNode);

View File

@ -14,29 +14,30 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var notify = require("fs.notify"); var notify = require("fs.notify");
var fs = require("fs"); var fs = require("fs");
var sep = require("path").sep; var sep = require("path").sep;
function WatchNode(n) { function WatchNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.files = n.files.split(","); this.files = n.files.split(",");
for (var f in this.files) { for (var f in this.files) {
this.files[f] = this.files[f].trim(); 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 node = this;
var notifications = new notify(node.files); var notifications = new notify(node.files);
notifications.on('change', function (file, event, path) { notifications.on('change', function (file, event, path) {
if (fs.statSync(path).isDirectory()) { path = path + sep + file; } if (fs.statSync(path).isDirectory()) { path = path + sep + file; }
var msg = { payload: path, topic: node.p, file: file}; var msg = { payload: path, topic: node.p, file: file};
node.send(msg); node.send(msg);
}); });
this.close = function() { this.close = function() {
notifications.close(); notifications.close();
}
} }
RED.nodes.registerType("watch",WatchNode);
} }
RED.nodes.registerType("watch",WatchNode);

View File

@ -14,199 +14,200 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var settings = RED.settings; var settings = RED.settings;
var events = require("events"); var events = require("events");
var util = require("util"); var util = require("util");
var serialp = require("serialport"); var serialp = require("serialport");
// TODO: 'serialPool' should be encapsulated in SerialPortNode // TODO: 'serialPool' should be encapsulated in SerialPortNode
function SerialPortNode(n) { function SerialPortNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.serialport = n.serialport; this.serialport = n.serialport;
this.newline = n.newline; this.newline = n.newline;
this.addchar = n.addchar || "false"; this.addchar = n.addchar || "false";
this.serialbaud = parseInt(n.serialbaud) || 57600; this.serialbaud = parseInt(n.serialbaud) || 57600;
this.databits = parseInt(n.databits) || 8; this.databits = parseInt(n.databits) || 8;
this.parity = n.parity || "none"; this.parity = n.parity || "none";
this.stopbits = parseInt(n.stopbits) || 1; this.stopbits = parseInt(n.stopbits) || 1;
}
RED.nodes.registerType("serial-port",SerialPortNode);
function SerialOutNode(n) {
RED.nodes.createNode(this,n);
this.serial = n.serial;
this.serialConfig = RED.nodes.getNode(this.serial);
if (this.serialConfig) {
var node = this;
node.port = serialPool.get(this.serialConfig.serialport,
this.serialConfig.serialbaud,
this.serialConfig.databits,
this.serialConfig.parity,
this.serialConfig.stopbits,
this.serialConfig.newline);
node.addCh = "";
if (node.serialConfig.addchar == "true") {
node.addCh = this.serialConfig.newline.replace("\\n","\n").replace("\\r","\r");
}
node.on("input",function(msg) {
var payload = msg.payload;
if (!Buffer.isBuffer(payload)) {
if (typeof payload === "object") {
payload = JSON.stringify(payload);
} else {
payload = new String(payload);
}
payload += node.addCh;
} else if (node.addCh !== "") {
payload = Buffer.concat([payload,new Buffer(node.addCh)]);
}
node.port.write(payload,function(err,res) {
if (err) {
node.error(err);
}
});
});
} else {
this.error("missing serial config");
} }
RED.nodes.registerType("serial-port",SerialPortNode);
function SerialOutNode(n) {
RED.nodes.createNode(this,n);
this.serial = n.serial;
this.serialConfig = RED.nodes.getNode(this.serial);
this.on("close", function() {
if (this.serialConfig) { if (this.serialConfig) {
serialPool.close(this.serialConfig.serialport); var node = this;
} node.port = serialPool.get(this.serialConfig.serialport,
}); this.serialConfig.serialbaud,
} this.serialConfig.databits,
RED.nodes.registerType("serial out",SerialOutNode); this.serialConfig.parity,
this.serialConfig.stopbits,
function SerialInNode(n) { this.serialConfig.newline);
RED.nodes.createNode(this,n); node.addCh = "";
this.serial = n.serial; if (node.serialConfig.addchar == "true") {
this.serialConfig = RED.nodes.getNode(this.serial); node.addCh = this.serialConfig.newline.replace("\\n","\n").replace("\\r","\r");
if (this.serialConfig) {
var node = this;
node.port = serialPool.get(this.serialConfig.serialport,
this.serialConfig.serialbaud,
this.serialConfig.databits,
this.serialConfig.parity,
this.serialConfig.stopbits,
this.serialConfig.newline);
this.port.on('data', function(msg) {
node.send({ "payload": msg });
});
} else {
this.error("missing serial config");
}
this.on("close", function() {
if (this.serialConfig) {
try {
serialPool.close(this.serialConfig.serialport);
} catch(err) {
} }
} node.on("input",function(msg) {
}); var payload = msg.payload;
} if (!Buffer.isBuffer(payload)) {
RED.nodes.registerType("serial in",SerialInNode); if (typeof payload === "object") {
payload = JSON.stringify(payload);
} else {
var serialPool = function() { payload = new String(payload);
var connections = {};
return {
get:function(port,baud,databits,parity,stopbits,newline,callback) {
var id = port;
if (!connections[id]) {
connections[id] = function() {
var obj = {
_emitter: new events.EventEmitter(),
serial: null,
_closing: false,
tout: null,
on: function(a,b) { this._emitter.on(a,b); },
close: function(cb) { this.serial.close(cb); },
write: function(m,cb) { this.serial.write(m,cb); },
} }
newline = newline.replace("\\n","\n").replace("\\r","\r"); payload += node.addCh;
var setupSerial = function() { } else if (node.addCh !== "") {
if (newline == "") { payload = Buffer.concat([payload,new Buffer(node.addCh)]);
obj.serial = new serialp.SerialPort(port,{ }
baudrate: baud, node.port.write(payload,function(err,res) {
databits: databits, if (err) {
parity: parity, node.error(err);
stopbits: stopbits, }
parser: serialp.parsers.raw });
},true, function(err, results) { if (err) obj.serial.emit('error',err); }); });
} else {
this.error("missing serial config");
}
this.on("close", function() {
if (this.serialConfig) {
serialPool.close(this.serialConfig.serialport);
}
});
}
RED.nodes.registerType("serial out",SerialOutNode);
function SerialInNode(n) {
RED.nodes.createNode(this,n);
this.serial = n.serial;
this.serialConfig = RED.nodes.getNode(this.serial);
if (this.serialConfig) {
var node = this;
node.port = serialPool.get(this.serialConfig.serialport,
this.serialConfig.serialbaud,
this.serialConfig.databits,
this.serialConfig.parity,
this.serialConfig.stopbits,
this.serialConfig.newline);
this.port.on('data', function(msg) {
node.send({ "payload": msg });
});
} else {
this.error("missing serial config");
}
this.on("close", function() {
if (this.serialConfig) {
try {
serialPool.close(this.serialConfig.serialport);
} catch(err) {
}
}
});
}
RED.nodes.registerType("serial in",SerialInNode);
var serialPool = function() {
var connections = {};
return {
get:function(port,baud,databits,parity,stopbits,newline,callback) {
var id = port;
if (!connections[id]) {
connections[id] = function() {
var obj = {
_emitter: new events.EventEmitter(),
serial: null,
_closing: false,
tout: null,
on: function(a,b) { this._emitter.on(a,b); },
close: function(cb) { this.serial.close(cb); },
write: function(m,cb) { this.serial.write(m,cb); },
} }
else { newline = newline.replace("\\n","\n").replace("\\r","\r");
obj.serial = new serialp.SerialPort(port,{ var setupSerial = function() {
baudrate: baud, if (newline == "") {
databits: databits, obj.serial = new serialp.SerialPort(port,{
parity: parity, baudrate: baud,
stopbits: stopbits, databits: databits,
parser: serialp.parsers.readline(newline) parity: parity,
},true, function(err, results) { if (err) obj.serial.emit('error',err); }); stopbits: stopbits,
} parser: serialp.parsers.raw
obj.serial.on('error', function(err) { },true, function(err, results) { if (err) obj.serial.emit('error',err); });
util.log("[serial] serial port "+port+" error "+err); }
obj.tout = setTimeout(function() { else {
setupSerial(); obj.serial = new serialp.SerialPort(port,{
}, settings.serialReconnectTime); baudrate: baud,
}); databits: databits,
obj.serial.on('close', function() { parity: parity,
if (!obj._closing) { stopbits: stopbits,
util.log("[serial] serial port "+port+" closed unexpectedly"); parser: serialp.parsers.readline(newline)
},true, function(err, results) { if (err) obj.serial.emit('error',err); });
}
obj.serial.on('error', function(err) {
util.log("[serial] serial port "+port+" error "+err);
obj.tout = setTimeout(function() { obj.tout = setTimeout(function() {
setupSerial(); setupSerial();
}, settings.serialReconnectTime); }, settings.serialReconnectTime);
} });
}); obj.serial.on('close', function() {
obj.serial.on('open',function() { if (!obj._closing) {
util.log("[serial] serial port "+port+" opened at "+baud+" baud "+databits+""+parity.charAt(0).toUpperCase()+stopbits); util.log("[serial] serial port "+port+" closed unexpectedly");
if (obj.tout) { clearTimeout(obj.tout); } obj.tout = setTimeout(function() {
//obj.serial.flush(); setupSerial();
obj._emitter.emit('ready'); }, settings.serialReconnectTime);
});
obj.serial.on('data',function(d) {
if (typeof d !== "string") {
d = d.toString();
for (i=0; i<d.length; i++) {
obj._emitter.emit('data',d.charAt(i));
} }
} });
else { obj.serial.on('open',function() {
obj._emitter.emit('data',d); util.log("[serial] serial port "+port+" opened at "+baud+" baud "+databits+""+parity.charAt(0).toUpperCase()+stopbits);
} if (obj.tout) { clearTimeout(obj.tout); }
//obj.serial.flush();
obj._emitter.emit('ready');
});
obj.serial.on('data',function(d) {
if (typeof d !== "string") {
d = d.toString();
for (i=0; i<d.length; i++) {
obj._emitter.emit('data',d.charAt(i));
}
}
else {
obj._emitter.emit('data',d);
}
});
}
setupSerial();
return obj;
}();
}
return connections[id];
},
close: function(port) {
if (connections[port]) {
if (connections[port].tout != null) clearTimeout(connections[port].tout);
connections[port]._closing = true;
try {
connections[port].close(function() {
util.log("[serial] serial port closed");
}); });
} } catch(err) { };
setupSerial(); }
return obj; delete connections[port];
}();
} }
return connections[id];
},
close: function(port) {
if (connections[port]) {
if (connections[port].tout != null) clearTimeout(connections[port].tout);
connections[port]._closing = true;
try {
connections[port].close(function() {
util.log("[serial] serial port closed");
});
} catch(err) { };
}
delete connections[port];
} }
} }();
}();
RED.httpAdmin.get("/serialports",function(req,res) { RED.httpAdmin.get("/serialports",function(req,res) {
serialp.list(function (err, ports) { serialp.list(function (err, ports) {
res.writeHead(200, {'Content-Type': 'text/plain'}); res.writeHead(200, {'Content-Type': 'text/plain'});
res.write(JSON.stringify(ports)); res.write(JSON.stringify(ports));
res.end(); res.end();
});
}); });
}); }

View File

@ -14,229 +14,208 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var reconnectTime = RED.settings.socketReconnectTime||10000; var reconnectTime = RED.settings.socketReconnectTime||10000;
var socketTimeout = RED.settings.socketTimeout||null; var socketTimeout = RED.settings.socketTimeout||null;
var net = require('net'); var net = require('net');
var connectionPool = {}; var connectionPool = {};
function TcpIn(n) { function TcpIn(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.host = n.host; this.host = n.host;
this.port = n.port * 1; this.port = n.port * 1;
this.topic = n.topic; this.topic = n.topic;
this.stream = (!n.datamode||n.datamode=='stream'); /* stream,single*/ this.stream = (!n.datamode||n.datamode=='stream'); /* stream,single*/
this.datatype = n.datatype||'buffer'; /* buffer,utf8,base64 */ this.datatype = n.datatype||'buffer'; /* buffer,utf8,base64 */
this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r"); this.newline = (n.newline||"").replace("\\n","\n").replace("\\r","\r");
this.base64 = n.base64; this.base64 = n.base64;
this.server = (typeof n.server == 'boolean')?n.server:(n.server == "server"); this.server = (typeof n.server == 'boolean')?n.server:(n.server == "server");
this.closing = false; this.closing = false;
var node = this; var node = this;
if (!node.server) { if (!node.server) {
var buffer = null; var buffer = null;
var client; var client;
var reconnectTimeout; var reconnectTimeout;
function setupTcpClient() { function setupTcpClient() {
node.log("connecting to "+node.host+":"+node.port); node.log("connecting to "+node.host+":"+node.port);
var id = (1+Math.random()*4294967295).toString(16); var id = (1+Math.random()*4294967295).toString(16);
client = net.connect(node.port, node.host, function() { client = net.connect(node.port, node.host, function() {
buffer = (node.datatype == 'buffer')? new Buffer(0):""; buffer = (node.datatype == 'buffer')? new Buffer(0):"";
node.log("connected to "+node.host+":"+node.port); node.log("connected to "+node.host+":"+node.port);
}); });
connectionPool[id] = client; connectionPool[id] = client;
client.on('data', function (data) { client.on('data', function (data) {
if (node.datatype != 'buffer') { if (node.datatype != 'buffer') {
data = data.toString(node.datatype); data = data.toString(node.datatype);
} }
if (node.stream) { if (node.stream) {
if ((node.datatype) === "utf8" && node.newline != "") { if ((node.datatype) === "utf8" && node.newline != "") {
buffer = buffer+data; buffer = buffer+data;
var parts = buffer.split(node.newline); var parts = buffer.split(node.newline);
for (var i = 0;i<parts.length-1;i+=1) { for (var i = 0;i<parts.length-1;i+=1) {
var msg = {topic:node.topic, payload:parts[i]}; var msg = {topic:node.topic, payload:parts[i]};
msg._session = {type:"tcp",id:id};
node.send(msg);
}
buffer = parts[parts.length-1];
} else {
var msg = {topic:node.topic, payload:data};
msg._session = {type:"tcp",id:id}; msg._session = {type:"tcp",id:id};
node.send(msg); node.send(msg);
} }
buffer = parts[parts.length-1];
} else { } else {
var msg = {topic:node.topic, payload:data}; if ((typeof data) === "string") {
msg._session = {type:"tcp",id:id}; buffer = buffer+data;
node.send(msg); } else {
} buffer = Buffer.concat([buffer,data],buffer.length+data.length);
} else {
if ((typeof data) === "string") {
buffer = buffer+data;
} else {
buffer = Buffer.concat([buffer,data],buffer.length+data.length);
}
}
});
client.on('end', function() {
if (!node.stream || (node.datatype == "utf8" && node.newline != "" && buffer.length > 0)) {
var msg = {topic:node.topic,payload:buffer};
msg._session = {type:"tcp",id:id};
node.send(msg);
buffer = null;
}
});
client.on('close', function() {
delete connectionPool[id];
node.log("connection lost to "+node.host+":"+node.port);
if (!node.closing) {
reconnectTimeout = setTimeout(setupTcpClient, reconnectTime);
}
});
client.on('error', function(err) {
node.log(err);
});
}
setupTcpClient();
this.on('close', function() {
this.closing = true;
client.end();
clearTimeout(reconnectTimeout);
});
} else {
var server = net.createServer(function (socket) {
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
var id = (1+Math.random()*4294967295).toString(16);
connectionPool[id] = socket;
var buffer = (node.datatype == 'buffer')? new Buffer(0):"";
socket.on('data', function (data) {
if (node.datatype != 'buffer') {
data = data.toString(node.datatype);
}
if (node.stream) {
if ((typeof data) === "string" && node.newline != "") {
buffer = buffer+data;
var parts = buffer.split(node.newline);
for (var i = 0;i<parts.length-1;i+=1) {
var msg = {topic:node.topic, payload:parts[i],ip:socket.remoteAddress,port:socket.remotePort};
msg._session = {type:"tcp",id:id};
node.send(msg);
} }
buffer = parts[parts.length-1]; }
} else { });
var msg = {topic:node.topic, payload:data}; client.on('end', function() {
if (!node.stream || (node.datatype == "utf8" && node.newline != "" && buffer.length > 0)) {
var msg = {topic:node.topic,payload:buffer};
msg._session = {type:"tcp",id:id}; msg._session = {type:"tcp",id:id};
node.send(msg); node.send(msg);
buffer = null;
} }
} else { });
if ((typeof data) === "string") { client.on('close', function() {
buffer = buffer+data; delete connectionPool[id];
} else { node.log("connection lost to "+node.host+":"+node.port);
buffer = Buffer.concat([buffer,data],buffer.length+data.length); if (!node.closing) {
reconnectTimeout = setTimeout(setupTcpClient, reconnectTime);
} }
} });
}); client.on('error', function(err) {
socket.on('end', function() { node.log(err);
if (!node.stream || (node.datatype == "utf8" && node.newline != "" && buffer.length > 0)) {
var msg = {topic:node.topic,payload:buffer};
msg._session = {type:"tcp",id:id};
node.send(msg);
buffer = null;
}
});
socket.on('timeout', function() {
node.log('timeout closed socket port '+node.port);
socket.end();
});
socket.on('close', function() {
delete connectionPool[id];
});
socket.on('error',function(err) {
node.log(err);
});
});
server.on('error', function(err) {
if (err) {
node.error('unable to listen on port '+node.port+' : '+err);
}
});
server.listen(node.port, function(err) {
if (err) {
node.error('unable to listen on port '+node.port+' : '+err);
} else {
node.log('listening on port '+node.port);
node.on('close', function() {
node.closing = true;
server.close();
node.log('stopped listening on port '+node.port);
}); });
} }
}); setupTcpClient();
}
} this.on('close', function() {
RED.nodes.registerType("tcp in",TcpIn); this.closing = true;
client.end();
function TcpOut(n) { clearTimeout(reconnectTimeout);
RED.nodes.createNode(this,n);
this.host = n.host;
this.port = n.port * 1;
this.base64 = n.base64;
this.beserver = n.beserver;
this.name = n.name;
this.closing = false;
var node = this;
if (!node.beserver||node.beserver=="client") {
var reconnectTimeout;
var client = null;
var connected = false;
function setupTcpClient() {
node.log("connecting to "+node.host+":"+node.port);
client = net.connect(node.port, node.host, function() {
connected = true;
node.log("connected to "+node.host+":"+node.port);
}); });
client.on('error', function (err) { } else {
node.log('error : '+err); var server = net.createServer(function (socket) {
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
var id = (1+Math.random()*4294967295).toString(16);
connectionPool[id] = socket;
var buffer = (node.datatype == 'buffer')? new Buffer(0):"";
socket.on('data', function (data) {
if (node.datatype != 'buffer') {
data = data.toString(node.datatype);
}
if (node.stream) {
if ((typeof data) === "string" && node.newline != "") {
buffer = buffer+data;
var parts = buffer.split(node.newline);
for (var i = 0;i<parts.length-1;i+=1) {
var msg = {topic:node.topic, payload:parts[i],ip:socket.remoteAddress,port:socket.remotePort};
msg._session = {type:"tcp",id:id};
node.send(msg);
}
buffer = parts[parts.length-1];
} else {
var msg = {topic:node.topic, payload:data};
msg._session = {type:"tcp",id:id};
node.send(msg);
}
} else {
if ((typeof data) === "string") {
buffer = buffer+data;
} else {
buffer = Buffer.concat([buffer,data],buffer.length+data.length);
}
}
});
socket.on('end', function() {
if (!node.stream || (node.datatype == "utf8" && node.newline != "" && buffer.length > 0)) {
var msg = {topic:node.topic,payload:buffer};
msg._session = {type:"tcp",id:id};
node.send(msg);
buffer = null;
}
});
socket.on('timeout', function() {
node.log('timeout closed socket port '+node.port);
socket.end();
});
socket.on('close', function() {
delete connectionPool[id];
});
socket.on('error',function(err) {
node.log(err);
});
}); });
client.on('end', function (err) { server.on('error', function(err) {
if (err) {
node.error('unable to listen on port '+node.port+' : '+err);
}
}); });
client.on('close', function() { server.listen(node.port, function(err) {
node.log("connection lost to "+node.host+":"+node.port); if (err) {
connected = false; node.error('unable to listen on port '+node.port+' : '+err);
client.destroy(); } else {
if (!node.closing) { node.log('listening on port '+node.port);
reconnectTimeout = setTimeout(setupTcpClient,reconnectTime);
node.on('close', function() {
node.closing = true;
server.close();
node.log('stopped listening on port '+node.port);
});
} }
}); });
} }
setupTcpClient();
node.on("input", function(msg) { }
if (connected && msg.payload != null) { RED.nodes.registerType("tcp in",TcpIn);
if (Buffer.isBuffer(msg.payload)) {
client.write(msg.payload); function TcpOut(n) {
} else if (typeof msg.payload === "string" && node.base64) { RED.nodes.createNode(this,n);
client.write(new Buffer(msg.payload,'base64')); this.host = n.host;
} else { this.port = n.port * 1;
client.write(new Buffer(""+msg.payload)); this.base64 = n.base64;
} this.beserver = n.beserver;
this.name = n.name;
this.closing = false;
var node = this;
if (!node.beserver||node.beserver=="client") {
var reconnectTimeout;
var client = null;
var connected = false;
function setupTcpClient() {
node.log("connecting to "+node.host+":"+node.port);
client = net.connect(node.port, node.host, function() {
connected = true;
node.log("connected to "+node.host+":"+node.port);
});
client.on('error', function (err) {
node.log('error : '+err);
});
client.on('end', function (err) {
});
client.on('close', function() {
node.log("connection lost to "+node.host+":"+node.port);
connected = false;
client.destroy();
if (!node.closing) {
reconnectTimeout = setTimeout(setupTcpClient,reconnectTime);
}
});
} }
}); setupTcpClient();
node.on("close", function() { node.on("input", function(msg) {
this.closing = true; if (connected && msg.payload != null) {
client.end();
clearTimeout(reconnectTimeout);
});
} else if (node.beserver == "reply") {
node.on("input",function(msg) {
if (msg._session && msg._session.type == "tcp") {
var client = connectionPool[msg._session.id];
if (client) {
if (Buffer.isBuffer(msg.payload)) { if (Buffer.isBuffer(msg.payload)) {
client.write(msg.payload); client.write(msg.payload);
} else if (typeof msg.payload === "string" && node.base64) { } else if (typeof msg.payload === "string" && node.base64) {
@ -245,62 +224,84 @@ function TcpOut(n) {
client.write(new Buffer(""+msg.payload)); client.write(new Buffer(""+msg.payload));
} }
} }
}
});
} else {
var connectedSockets = [];
var server = net.createServer(function (socket) {
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
var remoteDetails = socket.remoteAddress+":"+socket.remotePort;
node.log("connection from "+remoteDetails);
connectedSockets.push(socket);
socket.on('timeout', function() {
node.log('timeout closed socket port '+node.port);
socket.end();
}); });
socket.on('close',function() {
node.log("connection closed from "+remoteDetails);
connectedSockets.splice(connectedSockets.indexOf(socket),1);
});
socket.on('error',function() {
node.log("socket error from "+remoteDetails);
connectedSockets.splice(connectedSockets.indexOf(socket),1);
});
});
node.on("input", function(msg) {
if (msg.payload != null) {
var buffer;
if (Buffer.isBuffer(msg.payload)) {
buffer = msg.payload;
} else if (typeof msg.payload === "string" && node.base64) {
buffer = new Buffer(msg.payload,'base64');
} else {
buffer = new Buffer(""+msg.payload);
}
for (var i = 0; i<connectedSockets.length;i+=1) {
connectedSockets[i].write(buffer);
}
}
});
server.on('error', function(err) { node.on("close", function() {
if (err) { this.closing = true;
node.error('unable to listen on port '+node.port+' : '+err); client.end();
} clearTimeout(reconnectTimeout);
}); });
server.listen(node.port, function(err) { } else if (node.beserver == "reply") {
if (err) { node.on("input",function(msg) {
node.error('unable to listen on port '+node.port+' : '+err); if (msg._session && msg._session.type == "tcp") {
} else { var client = connectionPool[msg._session.id];
node.log('listening on port '+node.port); if (client) {
node.on('close', function() { if (Buffer.isBuffer(msg.payload)) {
server.close(); client.write(msg.payload);
node.log('stopped listening on port '+node.port); } else if (typeof msg.payload === "string" && node.base64) {
client.write(new Buffer(msg.payload,'base64'));
} else {
client.write(new Buffer(""+msg.payload));
}
}
}
});
} else {
var connectedSockets = [];
var server = net.createServer(function (socket) {
if (socketTimeout !== null) { socket.setTimeout(socketTimeout); }
var remoteDetails = socket.remoteAddress+":"+socket.remotePort;
node.log("connection from "+remoteDetails);
connectedSockets.push(socket);
socket.on('timeout', function() {
node.log('timeout closed socket port '+node.port);
socket.end();
}); });
} socket.on('close',function() {
}); node.log("connection closed from "+remoteDetails);
} connectedSockets.splice(connectedSockets.indexOf(socket),1);
} });
socket.on('error',function() {
node.log("socket error from "+remoteDetails);
connectedSockets.splice(connectedSockets.indexOf(socket),1);
});
});
node.on("input", function(msg) {
if (msg.payload != null) {
var buffer;
if (Buffer.isBuffer(msg.payload)) {
buffer = msg.payload;
} else if (typeof msg.payload === "string" && node.base64) {
buffer = new Buffer(msg.payload,'base64');
} else {
buffer = new Buffer(""+msg.payload);
}
for (var i = 0; i<connectedSockets.length;i+=1) {
connectedSockets[i].write(buffer);
}
}
});
RED.nodes.registerType("tcp out",TcpOut); server.on('error', function(err) {
if (err) {
node.error('unable to listen on port '+node.port+' : '+err);
}
});
server.listen(node.port, function(err) {
if (err) {
node.error('unable to listen on port '+node.port+' : '+err);
} else {
node.log('listening on port '+node.port);
node.on('close', function() {
server.close();
node.log('stopped listening on port '+node.port);
});
}
});
}
}
RED.nodes.registerType("tcp out",TcpOut);
}

View File

@ -14,100 +14,51 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var dgram = require('dgram'); var dgram = require('dgram');
// The Input Node // The Input Node
function UDPin(n) { function UDPin(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.group = n.group; this.group = n.group;
this.port = n.port; this.port = n.port;
this.datatype = n.datatype; this.datatype = n.datatype;
this.iface = n.iface || null; this.iface = n.iface || null;
this.multicast = n.multicast; this.multicast = n.multicast;
var node = this; var node = this;
var server = dgram.createSocket('udp4'); var server = dgram.createSocket('udp4');
server.on("error", function (err) { server.on("error", function (err) {
if ((err.code == "EACCES") && (node.port < 1024)) { if ((err.code == "EACCES") && (node.port < 1024)) {
node.error("UDP access error, you may need root access for ports below 1024"); node.error("UDP access error, you may need root access for ports below 1024");
} else { } else {
node.error("UDP error : "+err.code); node.error("UDP error : "+err.code);
}
server.close();
});
server.on('message', function (message, remote) {
var msg;
if (node.datatype =="base64") {
msg = { payload:message.toString('base64'), fromip:remote.address+':'+remote.port };
} else if (node.datatype =="utf8") {
msg = { payload:message.toString('utf8'), fromip:remote.address+':'+remote.port };
} else {
msg = { payload:message, fromip:remote.address+':'+remote.port, ip:remote.address, port:remote.port };
}
node.send(msg);
});
server.on('listening', function () {
var address = server.address();
node.log('udp listener at ' + address.address + ":" + address.port);
if (node.multicast == "true") {
server.setBroadcast(true);
try {
server.setMulticastTTL(128);
server.addMembership(node.group,node.iface);
node.log("udp multicast group "+node.group);
} catch (e) {
if (e.errno == "EINVAL") {
node.error("Bad Multicast Address");
} else if (e.errno == "ENODEV") {
node.error("Must be ip address of the required interface");
} else {
node.error("Error :"+e.errno);
}
} }
}
});
node.on("close", function() {
try {
server.close(); server.close();
node.log('udp listener stopped'); });
} catch (err) {
node.error(err);
}
});
server.bind(node.port,node.iface); server.on('message', function (message, remote) {
} var msg;
RED.nodes.registerType("udp in",UDPin); if (node.datatype =="base64") {
msg = { payload:message.toString('base64'), fromip:remote.address+':'+remote.port };
} else if (node.datatype =="utf8") {
msg = { payload:message.toString('utf8'), fromip:remote.address+':'+remote.port };
} else {
msg = { payload:message, fromip:remote.address+':'+remote.port, ip:remote.address, port:remote.port };
}
node.send(msg);
});
server.on('listening', function () {
// The Output Node var address = server.address();
function UDPout(n) { node.log('udp listener at ' + address.address + ":" + address.port);
RED.nodes.createNode(this,n); if (node.multicast == "true") {
//this.group = n.group; server.setBroadcast(true);
this.port = n.port;
this.outport = n.outport||"";
this.base64 = n.base64;
this.addr = n.addr;
this.iface = n.iface || null;
this.multicast = n.multicast;
var node = this;
var sock = dgram.createSocket('udp4'); // only use ipv4 for now
if (node.multicast != "false") {
if (node.outport == "") { node.outport = node.port; }
sock.bind(node.outport, function() { // have to bind before you can enable broadcast...
sock.setBroadcast(true); // turn on broadcast
if (node.multicast == "multi") {
try { try {
sock.setMulticastTTL(128); server.setMulticastTTL(128);
sock.addMembership(node.addr,node.iface); // Add to the multicast group server.addMembership(node.group,node.iface);
node.log('udp multicast ready : '+node.outport+' -> '+node.addr+":"+node.port); node.log("udp multicast group "+node.group);
} catch (e) { } catch (e) {
if (e.errno == "EINVAL") { if (e.errno == "EINVAL") {
node.error("Bad Multicast Address"); node.error("Bad Multicast Address");
@ -117,52 +68,102 @@ function UDPout(n) {
node.error("Error :"+e.errno); node.error("Error :"+e.errno);
} }
} }
} else {
node.log('udp broadcast ready : '+node.outport+' -> '+node.addr+":"+node.port);
} }
}); });
} else if (node.outport != "") {
sock.bind(node.outport);
node.log('udp ready : '+node.outport+' -> '+node.addr+":"+node.port);
} else {
node.log('udp ready : '+node.addr+":"+node.port);
}
node.on("input", function(msg) { node.on("close", function() {
if (msg.payload != null) { try {
var add = node.addr || msg.ip || ""; server.close();
var por = node.port || msg.port || 0; node.log('udp listener stopped');
if (add == "") { } catch (err) {
node.warn("udp: ip address not set"); node.error(err);
} else if (por == 0) {
node.warn("udp: port not set");
} else if (isNaN(por) || (por < 1) || (por > 65535)) {
node.warn("udp: port number not valid");
} else {
var message;
if (node.base64) {
message = new Buffer(b64string, 'base64');
} else if (msg.payload instanceof Buffer) {
message = msg.payload;
} else {
message = new Buffer(""+msg.payload);
}
sock.send(message, 0, message.length, por, add, function(err, bytes) {
if (err) {
node.error("udp : "+err);
}
});
} }
} });
});
node.on("close", function() { server.bind(node.port,node.iface);
try { }
sock.close(); RED.nodes.registerType("udp in",UDPin);
node.log('udp output stopped');
} catch (err) {
node.error(err); // The Output Node
function UDPout(n) {
RED.nodes.createNode(this,n);
//this.group = n.group;
this.port = n.port;
this.outport = n.outport||"";
this.base64 = n.base64;
this.addr = n.addr;
this.iface = n.iface || null;
this.multicast = n.multicast;
var node = this;
var sock = dgram.createSocket('udp4'); // only use ipv4 for now
if (node.multicast != "false") {
if (node.outport == "") { node.outport = node.port; }
sock.bind(node.outport, function() { // have to bind before you can enable broadcast...
sock.setBroadcast(true); // turn on broadcast
if (node.multicast == "multi") {
try {
sock.setMulticastTTL(128);
sock.addMembership(node.addr,node.iface); // Add to the multicast group
node.log('udp multicast ready : '+node.outport+' -> '+node.addr+":"+node.port);
} catch (e) {
if (e.errno == "EINVAL") {
node.error("Bad Multicast Address");
} else if (e.errno == "ENODEV") {
node.error("Must be ip address of the required interface");
} else {
node.error("Error :"+e.errno);
}
}
} else {
node.log('udp broadcast ready : '+node.outport+' -> '+node.addr+":"+node.port);
}
});
} else if (node.outport != "") {
sock.bind(node.outport);
node.log('udp ready : '+node.outport+' -> '+node.addr+":"+node.port);
} else {
node.log('udp ready : '+node.addr+":"+node.port);
} }
});
node.on("input", function(msg) {
if (msg.payload != null) {
var add = node.addr || msg.ip || "";
var por = node.port || msg.port || 0;
if (add == "") {
node.warn("udp: ip address not set");
} else if (por == 0) {
node.warn("udp: port not set");
} else if (isNaN(por) || (por < 1) || (por > 65535)) {
node.warn("udp: port number not valid");
} else {
var message;
if (node.base64) {
message = new Buffer(b64string, 'base64');
} else if (msg.payload instanceof Buffer) {
message = msg.payload;
} else {
message = new Buffer(""+msg.payload);
}
sock.send(message, 0, message.length, por, add, function(err, bytes) {
if (err) {
node.error("udp : "+err);
}
});
}
}
});
node.on("close", function() {
try {
sock.close();
node.log('udp output stopped');
} catch (err) {
node.error(err);
}
});
}
RED.nodes.registerType("udp out",UDPout);
} }
RED.nodes.registerType("udp out",UDPout);

View File

@ -14,60 +14,60 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME + "/red/red"); module.exports = function(RED) {
var operators = {
'eq': function(a, b) { return a == b; },
'neq': function(a, b) { return a != b; },
'lt': function(a, b) { return a < b; },
'lte': function(a, b) { return a <= b; },
'gt': function(a, b) { return a > b; },
'gte': function(a, b) { return a >= b; },
'btwn': function(a, b, c) { return a >= b && a <= c; },
'cont': function(a, b) { return (a + "").indexOf(b) != -1; },
'regex': function(a, b) { return (a + "").match(new RegExp(b)); },
'true': function(a) { return a === true; },
'false': function(a) { return a === false; },
'null': function(a) { return typeof a == "undefined"; },
'nnull': function(a) { return typeof a != "undefined"; },
'else': function(a) { return a === true; }
};
var operators = { function SwitchNode(n) {
'eq': function(a, b) { return a == b; }, RED.nodes.createNode(this, n);
'neq': function(a, b) { return a != b; }, this.rules = n.rules;
'lt': function(a, b) { return a < b; }, this.property = n.property;
'lte': function(a, b) { return a <= b; }, this.checkall = n.checkall || "true";
'gt': function(a, b) { return a > b; }, var propertyParts = n.property.split("."),
'gte': function(a, b) { return a >= b; }, node = this;
'btwn': function(a, b, c) { return a >= b && a <= c; },
'cont': function(a, b) { return (a + "").indexOf(b) != -1; },
'regex': function(a, b) { return (a + "").match(new RegExp(b)); },
'true': function(a) { return a === true; },
'false': function(a) { return a === false; },
'null': function(a) { return typeof a == "undefined"; },
'nnull': function(a) { return typeof a != "undefined"; },
'else': function(a) { return a === true; }
};
function SwitchNode(n) { for (var i=0; i<this.rules.length; i+=1) {
RED.nodes.createNode(this, n); var rule = this.rules[i];
this.rules = n.rules; if (!isNaN(Number(rule.v))) {
this.property = n.property; rule.v = Number(rule.v);
this.checkall = n.checkall || "true"; rule.v2 = Number(rule.v2);
var propertyParts = n.property.split("."),
node = this;
for (var i=0; i<this.rules.length; i+=1) {
var rule = this.rules[i];
if (!isNaN(Number(rule.v))) {
rule.v = Number(rule.v);
rule.v2 = Number(rule.v2);
}
}
this.on('input', function (msg) {
var onward = [];
var prop = propertyParts.reduce(function (obj, i) {
return obj[i]
}, msg);
var elseflag = true;
for (var i=0; i<node.rules.length; i+=1) {
var rule = node.rules[i];
var test = prop;
if (rule.t == "else") { test = elseflag; elseflag = true; }
if (operators[rule.t](test,rule.v, rule.v2)) {
onward.push(msg);
elseflag = false;
if (node.checkall == "false") { break; }
} else {
onward.push(null);
} }
} }
this.send(onward);
}); this.on('input', function (msg) {
var onward = [];
var prop = propertyParts.reduce(function (obj, i) {
return obj[i]
}, msg);
var elseflag = true;
for (var i=0; i<node.rules.length; i+=1) {
var rule = node.rules[i];
var test = prop;
if (rule.t == "else") { test = elseflag; elseflag = true; }
if (operators[rule.t](test,rule.v, rule.v2)) {
onward.push(msg);
elseflag = false;
if (node.checkall == "false") { break; }
} else {
onward.push(null);
}
}
this.send(onward);
});
}
RED.nodes.registerType("switch", SwitchNode);
} }
RED.nodes.registerType("switch", SwitchNode);

View File

@ -14,60 +14,60 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME + "/red/red"); module.exports = function(RED) {
function ChangeNode(n) {
RED.nodes.createNode(this, n);
this.action = n.action;
this.property = n.property || "";
this.from = n.from || " ";
this.to = n.to || " ";
this.reg = (n.reg === null || n.reg);
var node = this;
if (node.reg === false) {
this.from = this.from.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
}
var makeNew = function( stem, path, value ) {
var lastPart = (arguments.length === 3) ? path.pop() : false;
for (var i = 0; i < path.length; i++) {
stem = stem[path[i]] = stem[path[i]] || {};
}
if (lastPart) { stem = stem[lastPart] = value; }
return stem;
};
function ChangeNode(n) { this.on('input', function (msg) {
RED.nodes.createNode(this, n); if (node.action == "change") {
this.action = n.action; try {
this.property = n.property || ""; node.re = new RegExp(this.from, "g");
this.from = n.from || " "; } catch (e) {
this.to = n.to || " "; node.error(e.message);
this.reg = (n.reg === null || n.reg); }
var node = this; if (typeof msg[node.property] === "string") {
if (node.reg === false) { msg[node.property] = (msg[node.property]).replace(node.re, node.to);
this.from = this.from.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); }
}
//else if (node.action == "replace") {
//if (node.to.indexOf("msg.") == 0) {
//msg[node.property] = eval(node.to);
//}
//else {
//msg[node.property] = node.to;
//}
//}
else if (node.action == "replace") {
if (node.to.indexOf("msg.") == 0) {
makeNew( msg, node.property.split("."), eval(node.to) );
}
else {
makeNew( msg, node.property.split("."), node.to );
}
//makeNew( msg, node.property.split("."), node.to );
}
else if (node.action == "delete") {
delete(msg[node.property]);
}
node.send(msg);
});
} }
var makeNew = function( stem, path, value ) { RED.nodes.registerType("change", ChangeNode);
var lastPart = (arguments.length === 3) ? path.pop() : false;
for (var i = 0; i < path.length; i++) {
stem = stem[path[i]] = stem[path[i]] || {};
}
if (lastPart) { stem = stem[lastPart] = value; }
return stem;
};
this.on('input', function (msg) {
if (node.action == "change") {
try {
node.re = new RegExp(this.from, "g");
} catch (e) {
node.error(e.message);
}
if (typeof msg[node.property] === "string") {
msg[node.property] = (msg[node.property]).replace(node.re, node.to);
}
}
//else if (node.action == "replace") {
//if (node.to.indexOf("msg.") == 0) {
//msg[node.property] = eval(node.to);
//}
//else {
//msg[node.property] = node.to;
//}
//}
else if (node.action == "replace") {
if (node.to.indexOf("msg.") == 0) {
makeNew( msg, node.property.split("."), eval(node.to) );
}
else {
makeNew( msg, node.property.split("."), node.to );
}
//makeNew( msg, node.property.split("."), node.to );
}
else if (node.action == "delete") {
delete(msg[node.property]);
}
node.send(msg);
});
} }
RED.nodes.registerType("change", ChangeNode);

View File

@ -14,34 +14,34 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME + "/red/red"); module.exports = function(RED) {
function RangeNode(n) {
RED.nodes.createNode(this, n);
this.action = n.action;
this.round = n.round || false;
this.minin = Number(n.minin);
this.maxin = Number(n.maxin);
this.minout = Number(n.minout);
this.maxout = Number(n.maxout);
var node = this;
function RangeNode(n) { this.on('input', function (msg) {
RED.nodes.createNode(this, n); var n = Number(msg.payload);
this.action = n.action; if (!isNaN(n)) {
this.round = n.round || false; if (node.action == "clamp") {
this.minin = Number(n.minin); if (n < node.minin) { n = node.minin; }
this.maxin = Number(n.maxin); if (n > node.maxin) { n = node.maxin; }
this.minout = Number(n.minout); }
this.maxout = Number(n.maxout); if (node.action == "roll") {
var node = this; if (n >= node.maxin) { n = (n - node.minin) % (node.maxin - node.minin) + node.minin; }
if (n < node.minin) { n = (n - node.minin) % (node.maxin - node.minin) + node.maxin; }
this.on('input', function (msg) { }
var n = Number(msg.payload); msg.payload = ((n - node.minin) / (node.maxin - node.minin) * (node.maxout - node.minout)) + node.minout;
if (!isNaN(n)) { if (node.round) { msg.payload = Math.round(msg.payload); }
if (node.action == "clamp") { node.send(msg);
if (n < node.minin) { n = node.minin; }
if (n > node.maxin) { n = node.maxin; }
} }
if (node.action == "roll") { else { node.log("Not a number: "+msg.payload); }
if (n >= node.maxin) { n = (n - node.minin) % (node.maxin - node.minin) + node.minin; } });
if (n < node.minin) { n = (n - node.minin) % (node.maxin - node.minin) + node.maxin; } }
} RED.nodes.registerType("range", RangeNode);
msg.payload = ((n - node.minin) / (node.maxin - node.minin) * (node.maxout - node.minout)) + node.minout;
if (node.round) { msg.payload = Math.round(msg.payload); }
node.send(msg);
}
else { node.log("Not a number: "+msg.payload); }
});
} }
RED.nodes.registerType("range", RangeNode);

View File

@ -14,65 +14,65 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
function CSVNode(n) {
function CSVNode(n) { RED.nodes.createNode(this,n);
RED.nodes.createNode(this,n); this.template = n.temp.split(",");
this.template = n.temp.split(","); this.sep = n.sep || ',';
this.sep = n.sep || ','; this.sep = this.sep.replace("\\n","\n").replace("\\r","\r").replace("\\t","\t");
this.sep = this.sep.replace("\\n","\n").replace("\\r","\r").replace("\\t","\t"); this.quo = '"';
this.quo = '"'; var node = this;
var node = this; this.on("input", function(msg) {
this.on("input", function(msg) { if (msg.hasOwnProperty("payload")) {
if (msg.hasOwnProperty("payload")) { if (typeof msg.payload == "object") { // convert to csv
if (typeof msg.payload == "object") { // convert to csv try {
try { var o = "";
var o = ""; for (var i in node.template) {
for (var i in node.template) { if (msg.payload.hasOwnProperty(node.template[i])) {
if (msg.payload.hasOwnProperty(node.template[i])) { if (msg.payload[node.template[i]].indexOf(node.sep) != -1) {
if (msg.payload[node.template[i]].indexOf(node.sep) != -1) { o += node.quo + msg.payload[node.template[i]] + node.quo + node.sep;
o += node.quo + msg.payload[node.template[i]] + node.quo + node.sep; }
else if (msg.payload[node.template[i]].indexOf(node.quo) != -1) {
msg.payload[node.template[i]] = msg.payload[node.template[i]].replace(/"/g, '""');
o += node.quo + msg.payload[node.template[i]] + node.quo + node.sep;
}
else { o += msg.payload[node.template[i]] + node.sep; }
} }
else if (msg.payload[node.template[i]].indexOf(node.quo) != -1) { }
msg.payload[node.template[i]] = msg.payload[node.template[i]].replace(/"/g, '""'); msg.payload = o.slice(0,-1);
o += node.quo + msg.payload[node.template[i]] + node.quo + node.sep; node.send(msg);
}
catch(e) { node.log(e); }
}
else if (typeof msg.payload == "string") { // convert to object
try {
var f = true;
var j = 0;
var k = [""];
var o = {};
for (var i = 0; i < msg.payload.length; i++) {
if (msg.payload[i] === node.quo) {
f = !f;
if (msg.payload[i-1] === node.quo) { k[j] += '\"'; }
}
else if ((msg.payload[i] === node.sep) && f) {
if ( node.template[j] && (node.template[j] != "") ) { o[node.template[j]] = k[j]; }
j += 1;
k[j] = "";
}
else {
k[j] += msg.payload[i];
} }
else { o += msg.payload[node.template[i]] + node.sep; }
} }
if ( node.template[j] && (node.template[j] != "") ) { o[node.template[j]] = k[j]; }
msg.payload = o;
node.send(msg);
} }
msg.payload = o.slice(0,-1); catch(e) { node.log(e); }
node.send(msg);
} }
catch(e) { node.log(e); } else { node.log("This node only handles csv strings or js objects."); }
} }
else if (typeof msg.payload == "string") { // convert to object });
try { }
var f = true; RED.nodes.registerType("csv",CSVNode);
var j = 0;
var k = [""];
var o = {};
for (var i = 0; i < msg.payload.length; i++) {
if (msg.payload[i] === node.quo) {
f = !f;
if (msg.payload[i-1] === node.quo) { k[j] += '\"'; }
}
else if ((msg.payload[i] === node.sep) && f) {
if ( node.template[j] && (node.template[j] != "") ) { o[node.template[j]] = k[j]; }
j += 1;
k[j] = "";
}
else {
k[j] += msg.payload[i];
}
}
if ( node.template[j] && (node.template[j] != "") ) { o[node.template[j]] = k[j]; }
msg.payload = o;
node.send(msg);
}
catch(e) { node.log(e); }
}
else { node.log("This node only handles csv strings or js objects."); }
}
});
} }
RED.nodes.registerType("csv",CSVNode);

View File

@ -14,31 +14,32 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var util = require("util"); var util = require("util");
function JSONNode(n) { function JSONNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
var node = this; var node = this;
this.on("input", function(msg) { this.on("input", function(msg) {
if (msg.hasOwnProperty("payload")) { if (msg.hasOwnProperty("payload")) {
if (typeof msg.payload === "string") { if (typeof msg.payload === "string") {
try { try {
msg.payload = JSON.parse(msg.payload); msg.payload = JSON.parse(msg.payload);
node.send(msg);
}
catch(e) { node.log(e+ "\n"+msg.payload); }
}
else if (typeof msg.payload === "object") {
if (!Buffer.isBuffer(msg.payload) ) {
if (!util.isArray(msg.payload)) {
msg.payload = JSON.stringify(msg.payload);
node.send(msg); node.send(msg);
} }
catch(e) { node.log(e+ "\n"+msg.payload); }
} }
else if (typeof msg.payload === "object") {
if (!Buffer.isBuffer(msg.payload) ) {
if (!util.isArray(msg.payload)) {
msg.payload = JSON.stringify(msg.payload);
node.send(msg);
}
}
}
else { node.log("dropped: "+msg.payload); }
} }
else { node.log("dropped: "+msg.payload); } });
} }
}); RED.nodes.registerType("json",JSONNode);
} }
RED.nodes.registerType("json",JSONNode);

View File

@ -14,37 +14,38 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var xml2js = require('xml2js'); var xml2js = require('xml2js');
var parseString = xml2js.parseString; var parseString = xml2js.parseString;
var builder = new xml2js.Builder({renderOpts:{pretty:false}}); var builder = new xml2js.Builder({renderOpts:{pretty:false}});
function XMLNode(n) { function XMLNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
var node = this; var node = this;
this.on("input", function(msg) { this.on("input", function(msg) {
if (msg.hasOwnProperty("payload")) { if (msg.hasOwnProperty("payload")) {
if (typeof msg.payload == "object") { if (typeof msg.payload == "object") {
try { try {
msg.payload = builder.buildObject(msg.payload); msg.payload = builder.buildObject(msg.payload);
node.send(msg); node.send(msg);
}
catch(e) { node.log(e); }
} }
catch(e) { node.log(e); } else if (typeof msg.payload == "string") {
} try {
else if (typeof msg.payload == "string") { parseString(msg.payload, {strict:true,async:true}, function (err, result) {
try { if (err) { node.error(err); }
parseString(msg.payload, {strict:true,async:true}, function (err, result) { else {
if (err) { node.error(err); } msg.payload = result;
else { node.send(msg);
msg.payload = result; }
node.send(msg); });
} }
}); catch(e) { node.log(e); }
} }
catch(e) { node.log(e); } else { node.log("This node only handles xml strings or js objects."); }
} }
else { node.log("This node only handles xml strings or js objects."); } });
} }
}); RED.nodes.registerType("xml",XMLNode);
} }
RED.nodes.registerType("xml",XMLNode);

View File

@ -14,82 +14,122 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var ntwitter = require('twitter-ng'); var ntwitter = require('twitter-ng');
var OAuth= require('oauth').OAuth; var OAuth= require('oauth').OAuth;
function TwitterNode(n) { function TwitterNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.screen_name = n.screen_name; this.screen_name = n.screen_name;
} }
RED.nodes.registerType("twitter-credentials",TwitterNode); RED.nodes.registerType("twitter-credentials",TwitterNode);
function TwitterInNode(n) { function TwitterInNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.active = true; this.active = true;
this.user = n.user; this.user = n.user;
//this.tags = n.tags.replace(/ /g,''); //this.tags = n.tags.replace(/ /g,'');
this.tags = n.tags; this.tags = n.tags;
this.twitter = n.twitter; this.twitter = n.twitter;
this.topic = n.topic||"tweets"; this.topic = n.topic||"tweets";
this.twitterConfig = RED.nodes.getNode(this.twitter); this.twitterConfig = RED.nodes.getNode(this.twitter);
var credentials = RED.nodes.getCredentials(this.twitter); var credentials = RED.nodes.getCredentials(this.twitter);
if (credentials && credentials.screen_name == this.twitterConfig.screen_name) { if (credentials && credentials.screen_name == this.twitterConfig.screen_name) {
var twit = new ntwitter({ var twit = new ntwitter({
consumer_key: "OKjYEd1ef2bfFolV25G5nQ", consumer_key: "OKjYEd1ef2bfFolV25G5nQ",
consumer_secret: "meRsltCktVMUI8gmggpXett7WBLd1k0qidYazoML6g", consumer_secret: "meRsltCktVMUI8gmggpXett7WBLd1k0qidYazoML6g",
access_token_key: credentials.access_token, access_token_key: credentials.access_token,
access_token_secret: credentials.access_token_secret access_token_secret: credentials.access_token_secret
}); });
//setInterval(function() { //setInterval(function() {
// twit.get("/application/rate_limit_status.json",null,function(err,cb) { // twit.get("/application/rate_limit_status.json",null,function(err,cb) {
// console.log("direct_messages:",cb["resources"]["direct_messages"]); // console.log("direct_messages:",cb["resources"]["direct_messages"]);
// }); // });
// //
//},10000); //},10000);
var node = this; var node = this;
if (this.user === "user") { if (this.user === "user") {
node.poll_ids = []; node.poll_ids = [];
node.since_ids = {}; node.since_ids = {};
var users = node.tags.split(","); var users = node.tags.split(",");
for (var i=0;i<users.length;i++) { for (var i=0;i<users.length;i++) {
var user = users[i].replace(" ",""); var user = users[i].replace(" ","");
twit.getUserTimeline({ twit.getUserTimeline({
screen_name:user, screen_name:user,
trim_user:0,
count:1
},function() {
var u = user+"";
return function(err,cb) {
if (err) {
node.error(err);
return;
}
if (cb[0]) {
node.since_ids[u] = cb[0].id_str;
} else {
node.since_ids[u] = '0';
}
node.poll_ids.push(setInterval(function() {
twit.getUserTimeline({
screen_name:u,
trim_user:0,
since_id:node.since_ids[u]
},function(err,cb) {
if (cb) {
for (var t=cb.length-1;t>=0;t-=1) {
var tweet = cb[t];
var where = tweet.user.location||"";
var la = tweet.lang || tweet.user.lang;
//console.log(tweet.user.location,"=>",tweet.user.screen_name,"=>",pay);
var msg = { topic:node.topic+"/"+tweet.user.screen_name, payload:tweet.text, location:where, lang:la, tweet:tweet };
node.send(msg);
if (t == 0) {
node.since_ids[u] = tweet.id_str;
}
}
}
if (err) {
node.error(err);
}
});
},60000));
}
}());
}
} else if (this.user === "dm") {
node.poll_ids = [];
twit.getDirectMessages({
screen_name:node.twitterConfig.screen_name,
trim_user:0, trim_user:0,
count:1 count:1
},function() { },function(err,cb) {
var u = user+""; if (err) {
return function(err,cb) { node.error(err);
if (err) { return;
node.error(err); }
return; if (cb[0]) {
} node.since_id = cb[0].id_str;
if (cb[0]) { } else {
node.since_ids[u] = cb[0].id_str; node.since_id = '0';
} else { }
node.since_ids[u] = '0'; node.poll_ids.push(setInterval(function() {
} twit.getDirectMessages({
node.poll_ids.push(setInterval(function() { screen_name:node.twitterConfig.screen_name,
twit.getUserTimeline({
screen_name:u,
trim_user:0, trim_user:0,
since_id:node.since_ids[u] since_id:node.since_id
},function(err,cb) { },function(err,cb) {
if (cb) { if (cb) {
for (var t=cb.length-1;t>=0;t-=1) { for (var t=cb.length-1;t>=0;t-=1) {
var tweet = cb[t]; var tweet = cb[t];
var where = tweet.user.location||""; var msg = { topic:node.topic+"/"+tweet.sender.screen_name, payload:tweet.text, tweet:tweet };
var la = tweet.lang || tweet.user.lang;
//console.log(tweet.user.location,"=>",tweet.user.screen_name,"=>",pay);
var msg = { topic:node.topic+"/"+tweet.user.screen_name, payload:tweet.text, location:where, lang:la, tweet:tweet };
node.send(msg); node.send(msg);
if (t == 0) { if (t == 0) {
node.since_ids[u] = tweet.id_str; node.since_id = tweet.id_str;
} }
} }
} }
@ -97,226 +137,187 @@ function TwitterInNode(n) {
node.error(err); node.error(err);
} }
}); });
},60000)); },120000));
});
} else if (this.tags !== "") {
try {
var thing = 'statuses/filter';
if (this.user === "true") { thing = 'user'; }
var st = { track: [node.tags] };
var bits = node.tags.split(",");
if ((bits.length > 0) && (bits.length % 4 == 0)) {
if ((Number(bits[0]) < Number(bits[2])) && (Number(bits[1]) < Number(bits[3]))) {
st = { locations: node.tags };
}
else {
node.warn("twitter: possible bad geo area format. Should be lower-left lon,lat, upper-right lon,lat");
}
} }
}());
} function setupStream() {
} else if (this.user === "dm") { if (node.active) {
node.poll_ids = []; twit.stream(thing, st, function(stream) {
twit.getDirectMessages({ //console.log(st);
screen_name:node.twitterConfig.screen_name, //twit.stream('user', { track: [node.tags] }, function(stream) {
trim_user:0, //twit.stream('site', { track: [node.tags] }, function(stream) {
count:1 //twit.stream('statuses/filter', { track: [node.tags] }, function(stream) {
},function(err,cb) { node.stream = stream;
if (err) { stream.on('data', function(tweet) {
node.error(err); //console.log(tweet.user);
return; if (tweet.user !== undefined) {
} var where = tweet.user.location||"";
if (cb[0]) { var la = tweet.lang || tweet.user.lang;
node.since_id = cb[0].id_str; //console.log(tweet.user.location,"=>",tweet.user.screen_name,"=>",pay);
} else { var msg = { topic:node.topic+"/"+tweet.user.screen_name, payload:tweet.text, location:where, lang:la, tweet:tweet };
node.since_id = '0'; node.send(msg);
}
node.poll_ids.push(setInterval(function() {
twit.getDirectMessages({
screen_name:node.twitterConfig.screen_name,
trim_user:0,
since_id:node.since_id
},function(err,cb) {
if (cb) {
for (var t=cb.length-1;t>=0;t-=1) {
var tweet = cb[t];
var msg = { topic:node.topic+"/"+tweet.sender.screen_name, payload:tweet.text, tweet:tweet };
node.send(msg);
if (t == 0) {
node.since_id = tweet.id_str;
} }
} });
} stream.on('limit', function(tweet) {
if (err) { node.log("tweet rate limit hit");
node.error(err); });
} stream.on('error', function(tweet,rc) {
}); node.warn(tweet);
},120000));
});
} else if (this.tags !== "") {
try {
var thing = 'statuses/filter';
if (this.user === "true") { thing = 'user'; }
var st = { track: [node.tags] };
var bits = node.tags.split(",");
if ((bits.length > 0) && (bits.length % 4 == 0)) {
if ((Number(bits[0]) < Number(bits[2])) && (Number(bits[1]) < Number(bits[3]))) {
st = { locations: node.tags };
}
else {
node.warn("twitter: possible bad geo area format. Should be lower-left lon,lat, upper-right lon,lat");
}
}
function setupStream() {
if (node.active) {
twit.stream(thing, st, function(stream) {
//console.log(st);
//twit.stream('user', { track: [node.tags] }, function(stream) {
//twit.stream('site', { track: [node.tags] }, function(stream) {
//twit.stream('statuses/filter', { track: [node.tags] }, function(stream) {
node.stream = stream;
stream.on('data', function(tweet) {
//console.log(tweet.user);
if (tweet.user !== undefined) {
var where = tweet.user.location||"";
var la = tweet.lang || tweet.user.lang;
//console.log(tweet.user.location,"=>",tweet.user.screen_name,"=>",pay);
var msg = { topic:node.topic+"/"+tweet.user.screen_name, payload:tweet.text, location:where, lang:la, tweet:tweet };
node.send(msg);
}
});
stream.on('limit', function(tweet) {
node.log("tweet rate limit hit");
});
stream.on('error', function(tweet,rc) {
node.warn(tweet);
setTimeout(setupStream,10000);
});
stream.on('destroy', function (response) {
if (this.active) {
node.warn("twitter ended unexpectedly");
setTimeout(setupStream,10000); setTimeout(setupStream,10000);
} });
stream.on('destroy', function (response) {
if (this.active) {
node.warn("twitter ended unexpectedly");
setTimeout(setupStream,10000);
}
});
}); });
}); }
} }
setupStream();
} }
setupStream(); catch (err) {
} node.error(err);
catch (err) { }
node.error(err); } else {
this.error("Invalid tag property");
} }
} else { } else {
this.error("Invalid tag property"); this.error("missing twitter credentials");
} }
} else {
this.error("missing twitter credentials");
}
this.on('close', function() { this.on('close', function() {
if (this.stream) { if (this.stream) {
this.active = false; this.active = false;
this.stream.destroy(); this.stream.destroy();
}
if (this.poll_ids) {
for (var i=0;i<this.poll_ids.length;i++) {
clearInterval(this.poll_ids[i]);
} }
} if (this.poll_ids) {
}); for (var i=0;i<this.poll_ids.length;i++) {
} clearInterval(this.poll_ids[i]);
RED.nodes.registerType("twitter in",TwitterInNode); }
function TwitterOutNode(n) {
RED.nodes.createNode(this,n);
this.topic = n.topic;
this.twitter = n.twitter;
this.twitterConfig = RED.nodes.getNode(this.twitter);
var credentials = RED.nodes.getCredentials(this.twitter);
var node = this;
if (credentials && credentials.screen_name == this.twitterConfig.screen_name) {
var twit = new ntwitter({
consumer_key: "OKjYEd1ef2bfFolV25G5nQ",
consumer_secret: "meRsltCktVMUI8gmggpXett7WBLd1k0qidYazoML6g",
access_token_key: credentials.access_token,
access_token_secret: credentials.access_token_secret
}).verifyCredentials(function (err, data) {
if (err) {
node.error("Error verifying credentials: " + err);
} else {
node.on("input", function(msg) {
if (msg != null) {
if (msg.payload.length > 140) {
msg.payload = msg.payload.slice(0,139);
node.warn("Tweet greater than 140 : truncated");
}
twit.updateStatus(msg.payload, function (err, data) {
if (err) node.error(err);
});
}
});
} }
}); });
} }
} RED.nodes.registerType("twitter in",TwitterInNode);
RED.nodes.registerType("twitter out",TwitterOutNode);
var oa = new OAuth(
"https://api.twitter.com/oauth/request_token",
"https://api.twitter.com/oauth/access_token",
"OKjYEd1ef2bfFolV25G5nQ",
"meRsltCktVMUI8gmggpXett7WBLd1k0qidYazoML6g",
"1.0",
null,
"HMAC-SHA1"
);
var credentials = {}; function TwitterOutNode(n) {
RED.nodes.createNode(this,n);
this.topic = n.topic;
this.twitter = n.twitter;
this.twitterConfig = RED.nodes.getNode(this.twitter);
var credentials = RED.nodes.getCredentials(this.twitter);
var node = this;
RED.httpAdmin.get('/twitter/:id', function(req,res) { if (credentials && credentials.screen_name == this.twitterConfig.screen_name) {
var credentials = RED.nodes.getCredentials(req.params.id); var twit = new ntwitter({
if (credentials) { consumer_key: "OKjYEd1ef2bfFolV25G5nQ",
res.send(JSON.stringify({sn:credentials.screen_name})); consumer_secret: "meRsltCktVMUI8gmggpXett7WBLd1k0qidYazoML6g",
} else { access_token_key: credentials.access_token,
res.send(JSON.stringify({})); access_token_secret: credentials.access_token_secret
}).verifyCredentials(function (err, data) {
if (err) {
node.error("Error verifying credentials: " + err);
} else {
node.on("input", function(msg) {
if (msg != null) {
if (msg.payload.length > 140) {
msg.payload = msg.payload.slice(0,139);
node.warn("Tweet greater than 140 : truncated");
}
twit.updateStatus(msg.payload, function (err, data) {
if (err) node.error(err);
});
}
});
}
});
}
} }
}); RED.nodes.registerType("twitter out",TwitterOutNode);
RED.httpAdmin.delete('/twitter/:id', function(req,res) { var oa = new OAuth(
RED.nodes.deleteCredentials(req.params.id); "https://api.twitter.com/oauth/request_token",
res.send(200); "https://api.twitter.com/oauth/access_token",
}); "OKjYEd1ef2bfFolV25G5nQ",
"meRsltCktVMUI8gmggpXett7WBLd1k0qidYazoML6g",
"1.0",
null,
"HMAC-SHA1"
);
RED.httpAdmin.get('/twitter/:id/auth', function(req, res){
var credentials = {}; var credentials = {};
oa.getOAuthRequestToken({
oauth_callback: req.query.callback RED.httpAdmin.get('/twitter/:id', function(req,res) {
},function(error, oauth_token, oauth_token_secret, results){ var credentials = RED.nodes.getCredentials(req.params.id);
if (error) { if (credentials) {
var resp = '<h2>Oh no!</h2>'+ res.send(JSON.stringify({sn:credentials.screen_name}));
'<p>Something went wrong with the authentication process. The following error was returned:<p>'+
'<p><b>'+error.statusCode+'</b>: '+error.data+'</p>'+
'<p>One known cause of this type of failure is if the clock is wrong on system running Node-RED.';
res.send(resp)
} else { } else {
credentials.oauth_token = oauth_token; res.send(JSON.stringify({}));
credentials.oauth_token_secret = oauth_token_secret;
res.redirect('https://twitter.com/oauth/authorize?oauth_token='+oauth_token)
RED.nodes.addCredentials(req.params.id,credentials);
} }
}); });
});
RED.httpAdmin.get('/twitter/:id/auth/callback', function(req, res, next){ RED.httpAdmin.delete('/twitter/:id', function(req,res) {
var credentials = RED.nodes.getCredentials(req.params.id); RED.nodes.deleteCredentials(req.params.id);
credentials.oauth_verifier = req.query.oauth_verifier; res.send(200);
});
oa.getOAuthAccessToken( RED.httpAdmin.get('/twitter/:id/auth', function(req, res){
credentials.oauth_token, var credentials = {};
credentials.token_secret, oa.getOAuthRequestToken({
credentials.oauth_verifier, oauth_callback: req.query.callback
function(error, oauth_access_token, oauth_access_token_secret, results){ },function(error, oauth_token, oauth_token_secret, results){
if (error){ if (error) {
console.log(error); var resp = '<h2>Oh no!</h2>'+
res.send("yeah something broke."); '<p>Something went wrong with the authentication process. The following error was returned:<p>'+
'<p><b>'+error.statusCode+'</b>: '+error.data+'</p>'+
'<p>One known cause of this type of failure is if the clock is wrong on system running Node-RED.';
res.send(resp)
} else { } else {
credentials = {}; credentials.oauth_token = oauth_token;
credentials.access_token = oauth_access_token; credentials.oauth_token_secret = oauth_token_secret;
credentials.access_token_secret = oauth_access_token_secret; res.redirect('https://twitter.com/oauth/authorize?oauth_token='+oauth_token)
credentials.screen_name = "@"+results.screen_name;
RED.nodes.addCredentials(req.params.id,credentials); RED.nodes.addCredentials(req.params.id,credentials);
res.send("<html><head></head><body>Authorised - you can close this window and return to Node-RED</body></html>");
} }
} });
); });
});
RED.httpAdmin.get('/twitter/:id/auth/callback', function(req, res, next){
var credentials = RED.nodes.getCredentials(req.params.id);
credentials.oauth_verifier = req.query.oauth_verifier;
oa.getOAuthAccessToken(
credentials.oauth_token,
credentials.token_secret,
credentials.oauth_verifier,
function(error, oauth_access_token, oauth_access_token_secret, results){
if (error){
console.log(error);
res.send("yeah something broke.");
} else {
credentials = {};
credentials.access_token = oauth_access_token;
credentials.access_token_secret = oauth_access_token_secret;
credentials.screen_name = "@"+results.screen_name;
RED.nodes.addCredentials(req.params.id,credentials);
res.send("<html><head></head><body>Authorised - you can close this window and return to Node-RED</body></html>");
}
}
);
});
}

View File

@ -14,58 +14,58 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var FeedParser = require("feedparser"); var FeedParser = require("feedparser");
var request = require("request"); var request = require("request");
function FeedParseNode(n) { function FeedParseNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.url = n.url; this.url = n.url;
this.interval = (parseInt(n.interval)||15)*60000; this.interval = (parseInt(n.interval)||15)*60000;
var node = this; var node = this;
this.interval_id = null; this.interval_id = null;
this.seen = {}; this.seen = {};
if (this.url !== "") { if (this.url !== "") {
var getFeed = function() { var getFeed = function() {
request(node.url,function(err) { request(node.url,function(err) {
if (err) node.error(err); if (err) node.error(err);
})
.pipe(new FeedParser({feedurl:node.url}))
.on('error', function(error) {
node.error(error);
}) })
.on('meta', function (meta) {}) .pipe(new FeedParser({feedurl:node.url}))
.on('readable', function () { .on('error', function(error) {
var stream = this, article; node.error(error);
while (article = stream.read()) { })
if (!(article.guid in node.seen) || ( node.seen[article.guid] != 0 && node.seen[article.guid] != article.date.getTime())) { .on('meta', function (meta) {})
node.seen[article.guid] = article.date?article.date.getTime():0; .on('readable', function () {
var msg = { var stream = this, article;
topic:article.origlink||article.link, while (article = stream.read()) {
payload: article.description, if (!(article.guid in node.seen) || ( node.seen[article.guid] != 0 && node.seen[article.guid] != article.date.getTime())) {
article: article node.seen[article.guid] = article.date?article.date.getTime():0;
}; var msg = {
node.send(msg); topic:article.origlink||article.link,
payload: article.description,
article: article
};
node.send(msg);
}
} }
} })
}) .on('end', function () {
.on('end', function () { });
}); };
}; this.interval_id = setInterval(getFeed,node.interval);
this.interval_id = setInterval(getFeed,node.interval); getFeed();
getFeed();
} else { } else {
this.error("Invalid url"); this.error("Invalid url");
} }
} }
RED.nodes.registerType("feedparse",FeedParseNode); RED.nodes.registerType("feedparse",FeedParseNode);
FeedParseNode.prototype.close = function() { FeedParseNode.prototype.close = function() {
if (this.interval_id != null) { if (this.interval_id != null) {
clearInterval(this.interval_id); clearInterval(this.interval_id);
}
} }
} }

View File

@ -14,247 +14,248 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var util = require('util'); var util = require('util');
var nodemailer = require("nodemailer"); var nodemailer = require("nodemailer");
var Imap = null; var Imap = null;
try { try {
Imap = require('imap'); Imap = require('imap');
} catch (e) { } catch (e) {
util.log("[61-email.js] - imap npm not installed - no inbound email available"); util.log("[61-email.js] - imap npm not installed - no inbound email available");
}
//console.log(nodemailer.Transport.transports.SMTP.wellKnownHosts);
// module.exports = { service: "Gmail", user: "blahblah@gmail.com", pass: "password", server: "imap.gmail.com", port: "993" }
try { var globalkeys = RED.settings.email || require(process.env.NODE_RED_HOME+"/../emailkeys.js"); }
catch(err) { }
function EmailNode(n) {
RED.nodes.createNode(this,n);
this.topic = n.topic;
this.name = n.name;
this.outserver = n.server;
this.outport = n.port;
var flag = false;
var credentials = RED.nodes.getCredentials(n.id);
if ((credentials) && (credentials.hasOwnProperty("userid"))) { this.userid = credentials.userid; }
else {
if (globalkeys) { this.userid = globalkeys.user; flag = true; }
else { this.error("No e-mail userid set"); }
} }
if ((credentials) && (credentials.hasOwnProperty("password"))) { this.password = credentials.password; }
else {
if (globalkeys) { this.password = globalkeys.pass; flag = true; }
else { this.error("No e-mail password set"); }
}
if (flag) { RED.nodes.addCredentials(n.id,{userid:this.userid, password:this.password, global:true}); }
var node = this;
var smtpTransport = nodemailer.createTransport("SMTP",{ //console.log(nodemailer.Transport.transports.SMTP.wellKnownHosts);
//service: emailkey.service,
// { // module.exports = { service: "Gmail", user: "blahblah@gmail.com", pass: "password", server: "imap.gmail.com", port: "993" }
//transport: 'SMTP', try { var globalkeys = RED.settings.email || require(process.env.NODE_RED_HOME+"/../emailkeys.js"); }
host: node.outserver, catch(err) { }
port: node.outport,
requiresAuth: true, function EmailNode(n) {
secureConnection: true, RED.nodes.createNode(this,n);
//domains: [ 'gmail.com', 'googlemail.com' ], this.topic = n.topic;
//}, this.name = n.name;
auth: { this.outserver = n.server;
user: node.userid, this.outport = n.port;
pass: node.password var flag = false;
var credentials = RED.nodes.getCredentials(n.id);
if ((credentials) && (credentials.hasOwnProperty("userid"))) { this.userid = credentials.userid; }
else {
if (globalkeys) { this.userid = globalkeys.user; flag = true; }
else { this.error("No e-mail userid set"); }
} }
}); if ((credentials) && (credentials.hasOwnProperty("password"))) { this.password = credentials.password; }
else {
if (globalkeys) { this.password = globalkeys.pass; flag = true; }
else { this.error("No e-mail password set"); }
}
if (flag) { RED.nodes.addCredentials(n.id,{userid:this.userid, password:this.password, global:true}); }
var node = this;
this.on("input", function(msg) { var smtpTransport = nodemailer.createTransport("SMTP",{
//node.log("email :",this.id,this.topic," received",msg.payload); //service: emailkey.service,
if (msg != null) { // {
if (smtpTransport) { //transport: 'SMTP',
smtpTransport.sendMail({ host: node.outserver,
from: node.userid, // sender address port: node.outport,
to: node.name, // comma separated list of receivers requiresAuth: true,
subject: msg.topic, // subject line secureConnection: true,
text: msg.payload // plaintext body //domains: [ 'gmail.com', 'googlemail.com' ],
}, function(error, response) { //},
if (error) { auth: {
node.error(error); user: node.userid,
} else { pass: node.password
node.log("Message sent: " + response.message); }
});
this.on("input", function(msg) {
//node.log("email :",this.id,this.topic," received",msg.payload);
if (msg != null) {
if (smtpTransport) {
smtpTransport.sendMail({
from: node.userid, // sender address
to: node.name, // comma separated list of receivers
subject: msg.topic, // subject line
text: msg.payload // plaintext body
}, function(error, response) {
if (error) {
node.error(error);
} else {
node.log("Message sent: " + response.message);
}
});
}
else { node.warn("No Email credentials found. See info panel."); }
}
});
}
RED.nodes.registerType("e-mail",EmailNode);
function EmailInNode(n) {
RED.nodes.createNode(this,n);
this.name = n.name;
this.repeat = n.repeat * 1000 || 300000;
this.inserver = n.server || emailkey.server || "imap.gmail.com";
this.inport = n.port || emailkey.port || "993";
var flag = false;
var credentials = RED.nodes.getCredentials(n.id);
if ((credentials) && (credentials.hasOwnProperty("userid"))) { this.userid = credentials.userid; }
else {
if (globalkeys) { this.userid = globalkeys.user; flag = true; }
else { this.error("No e-mail userid set"); }
}
if ((credentials) && (credentials.hasOwnProperty("password"))) { this.password = credentials.password; }
else {
if (globalkeys) { this.password = globalkeys.pass; flag = true; }
else { this.error("No e-mail password set"); }
}
if (flag) { RED.nodes.addCredentials(n.id,{userid:this.userid, password:this.password, global:true}); }
var node = this;
this.interval_id = null;
var oldmail = {};
var imap = new Imap({
user: node.userid,
password: node.password,
host: node.inserver,
port: node.inport,
tls: true,
tlsOptions: { rejectUnauthorized: false },
connTimeout: node.repeat,
authTimeout: node.repeat
});
if (!isNaN(this.repeat) && this.repeat > 0) {
node.log("repeat = "+this.repeat);
this.interval_id = setInterval( function() {
node.emit("input",{});
}, this.repeat );
}
this.on("input", function(msg) {
imap.once('ready', function() {
var pay = {};
imap.openBox('INBOX', true, function(err, box) {
if (box.messages.total > 0) {
var f = imap.seq.fetch(box.messages.total + ':*', { bodies: ['HEADER.FIELDS (FROM SUBJECT DATE)','TEXT'] });
f.on('message', function(msg, seqno) {
node.log('message: #'+ seqno);
var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) {
var buffer = '';
stream.on('data', function(chunk) {
buffer += chunk.toString('utf8');
});
stream.on('end', function() {
if (info.which !== 'TEXT') {
pay.from = Imap.parseHeader(buffer).from[0];
pay.topic = Imap.parseHeader(buffer).subject[0];
pay.date = Imap.parseHeader(buffer).date[0];
} else {
var parts = buffer.split("Content-Type");
for (var p in parts) {
if (parts[p].indexOf("text/plain") >= 0) {
pay.payload = parts[p].split("\n").slice(1,-2).join("\n").trim();
}
if (parts[p].indexOf("text/html") >= 0) {
pay.html = parts[p].split("\n").slice(1,-2).join("\n").trim();
}
}
//pay.body = buffer;
}
});
});
msg.on('end', function() {
//node.log('Finished: '+prefix);
});
});
f.on('error', function(err) {
node.warn('fetch error: ' + err);
});
f.on('end', function() {
if (JSON.stringify(pay) !== oldmail) {
node.send(pay);
oldmail = JSON.stringify(pay);
node.log('received new email: '+pay.topic);
}
else { node.log('duplicate not sent: '+pay.topic); }
imap.end();
});
}
else {
node.log("you have achieved inbox zero");
imap.end();
} }
}); });
}
else { node.warn("No Email credentials found. See info panel."); }
}
});
}
RED.nodes.registerType("e-mail",EmailNode);
function EmailInNode(n) {
RED.nodes.createNode(this,n);
this.name = n.name;
this.repeat = n.repeat * 1000 || 300000;
this.inserver = n.server || emailkey.server || "imap.gmail.com";
this.inport = n.port || emailkey.port || "993";
var flag = false;
var credentials = RED.nodes.getCredentials(n.id);
if ((credentials) && (credentials.hasOwnProperty("userid"))) { this.userid = credentials.userid; }
else {
if (globalkeys) { this.userid = globalkeys.user; flag = true; }
else { this.error("No e-mail userid set"); }
}
if ((credentials) && (credentials.hasOwnProperty("password"))) { this.password = credentials.password; }
else {
if (globalkeys) { this.password = globalkeys.pass; flag = true; }
else { this.error("No e-mail password set"); }
}
if (flag) { RED.nodes.addCredentials(n.id,{userid:this.userid, password:this.password, global:true}); }
var node = this;
this.interval_id = null;
var oldmail = {};
var imap = new Imap({
user: node.userid,
password: node.password,
host: node.inserver,
port: node.inport,
tls: true,
tlsOptions: { rejectUnauthorized: false },
connTimeout: node.repeat,
authTimeout: node.repeat
});
if (!isNaN(this.repeat) && this.repeat > 0) {
node.log("repeat = "+this.repeat);
this.interval_id = setInterval( function() {
node.emit("input",{});
}, this.repeat );
}
this.on("input", function(msg) {
imap.once('ready', function() {
var pay = {};
imap.openBox('INBOX', true, function(err, box) {
if (box.messages.total > 0) {
var f = imap.seq.fetch(box.messages.total + ':*', { bodies: ['HEADER.FIELDS (FROM SUBJECT DATE)','TEXT'] });
f.on('message', function(msg, seqno) {
node.log('message: #'+ seqno);
var prefix = '(#' + seqno + ') ';
msg.on('body', function(stream, info) {
var buffer = '';
stream.on('data', function(chunk) {
buffer += chunk.toString('utf8');
});
stream.on('end', function() {
if (info.which !== 'TEXT') {
pay.from = Imap.parseHeader(buffer).from[0];
pay.topic = Imap.parseHeader(buffer).subject[0];
pay.date = Imap.parseHeader(buffer).date[0];
} else {
var parts = buffer.split("Content-Type");
for (var p in parts) {
if (parts[p].indexOf("text/plain") >= 0) {
pay.payload = parts[p].split("\n").slice(1,-2).join("\n").trim();
}
if (parts[p].indexOf("text/html") >= 0) {
pay.html = parts[p].split("\n").slice(1,-2).join("\n").trim();
}
}
//pay.body = buffer;
}
});
});
msg.on('end', function() {
//node.log('Finished: '+prefix);
});
});
f.on('error', function(err) {
node.warn('fetch error: ' + err);
});
f.on('end', function() {
if (JSON.stringify(pay) !== oldmail) {
node.send(pay);
oldmail = JSON.stringify(pay);
node.log('received new email: '+pay.topic);
}
else { node.log('duplicate not sent: '+pay.topic); }
imap.end();
});
}
else {
node.log("you have achieved inbox zero");
imap.end();
}
}); });
imap.on('error', function(err) {
node.log(err);
});
imap.connect();
}); });
imap.on('error', function(err) {
node.log(err); this.on("error", function(err) {
node.log("error: ",err);
}); });
imap.connect();
});
this.on("error", function(err) { this.on("close", function() {
node.log("error: ",err); if (this.interval_id != null) {
}); clearInterval(this.interval_id);
}
if (imap) { imap.destroy(); }
});
this.on("close", function() { node.emit("input",{});
if (this.interval_id != null) {
clearInterval(this.interval_id);
}
if (imap) { imap.destroy(); }
});
node.emit("input",{});
}
if (Imap != null) {
RED.nodes.registerType("e-mail in",EmailInNode);
}
var querystring = require('querystring');
RED.httpAdmin.get('/email/global',function(req,res) {
res.send(JSON.stringify({hasToken:!(globalkeys && globalkeys.userid && globalkeys.password)}));
});
RED.httpAdmin.get('/email/:id',function(req,res) {
var credentials = RED.nodes.getCredentials(req.params.id);
if (credentials) {
res.send(JSON.stringify({userid:credentials.userid,hasPassword:(credentials.password&&credentials.password!="")}));
} }
else if (globalkeys && globalkeys.user && globalkeys.pass) { if (Imap != null) {
RED.nodes.addCredentials(req.params.id,{userid:globalkeys.user, password:globalkeys.pass, global:true}); RED.nodes.registerType("e-mail in",EmailInNode);
credentials = RED.nodes.getCredentials(req.params.id);
res.send(JSON.stringify({userid:credentials.userid,global:credentials.global,hasPassword:(credentials.password&&credentials.password!="")}));
} }
else {
res.send(JSON.stringify({}));
}
});
RED.httpAdmin.delete('/email/:id',function(req,res) { var querystring = require('querystring');
RED.nodes.deleteCredentials(req.params.id);
res.send(200);
});
RED.httpAdmin.post('/email/:id',function(req,res) { RED.httpAdmin.get('/email/global',function(req,res) {
var body = ""; res.send(JSON.stringify({hasToken:!(globalkeys && globalkeys.userid && globalkeys.password)}));
req.on('data', function(chunk) {
body+=chunk;
}); });
req.on('end', function(){
var newCreds = querystring.parse(body); RED.httpAdmin.get('/email/:id',function(req,res) {
var credentials = RED.nodes.getCredentials(req.params.id)||{}; var credentials = RED.nodes.getCredentials(req.params.id);
if (newCreds.userid == null || newCreds.userid == "") { if (credentials) {
delete credentials.userid; res.send(JSON.stringify({userid:credentials.userid,hasPassword:(credentials.password&&credentials.password!="")}));
} else {
credentials.userid = newCreds.userid;
} }
if (newCreds.password == "") { else if (globalkeys && globalkeys.user && globalkeys.pass) {
delete credentials.password; RED.nodes.addCredentials(req.params.id,{userid:globalkeys.user, password:globalkeys.pass, global:true});
} else { credentials = RED.nodes.getCredentials(req.params.id);
credentials.password = newCreds.password||credentials.password; res.send(JSON.stringify({userid:credentials.userid,global:credentials.global,hasPassword:(credentials.password&&credentials.password!="")}));
} }
RED.nodes.addCredentials(req.params.id,credentials); else {
res.send(JSON.stringify({}));
}
});
RED.httpAdmin.delete('/email/:id',function(req,res) {
RED.nodes.deleteCredentials(req.params.id);
res.send(200); res.send(200);
}); });
});
RED.httpAdmin.post('/email/:id',function(req,res) {
var body = "";
req.on('data', function(chunk) {
body+=chunk;
});
req.on('end', function(){
var newCreds = querystring.parse(body);
var credentials = RED.nodes.getCredentials(req.params.id)||{};
if (newCreds.userid == null || newCreds.userid == "") {
delete credentials.userid;
} else {
credentials.userid = newCreds.userid;
}
if (newCreds.password == "") {
delete credentials.password;
} else {
credentials.password = newCreds.password||credentials.password;
}
RED.nodes.addCredentials(req.params.id,credentials);
res.send(200);
});
});
}

View File

@ -14,127 +14,128 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var irc = require("irc"); var irc = require("irc");
var util = require("util"); var util = require("util");
// The Server Definition - this opens (and closes) the connection // The Server Definition - this opens (and closes) the connection
function IRCServerNode(n) { function IRCServerNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.server = n.server; this.server = n.server;
this.channel = n.channel; this.channel = n.channel;
this.nickname = n.nickname; this.nickname = n.nickname;
this.ircclient = null; this.ircclient = null;
this.on("close", function() { this.on("close", function() {
if (this.ircclient != null) { if (this.ircclient != null) {
this.ircclient.disconnect(); this.ircclient.disconnect();
}
});
}
RED.nodes.registerType("irc-server",IRCServerNode);
// The Input Node
function IrcInNode(n) {
RED.nodes.createNode(this,n);
this.ircserver = n.ircserver;
this.serverConfig = RED.nodes.getNode(this.ircserver);
this.channel = n.channel || this.serverConfig.channel;
if (this.serverConfig.ircclient == null) {
this.serverConfig.ircclient = new irc.Client(this.serverConfig.server, this.serverConfig.nickname, {
channels: [this.channel]
});
this.serverConfig.ircclient.addListener('error', function(message) {
util.log('[irc] '+ JSON.stringify(message));
});
}
this.ircclient = this.serverConfig.ircclient;
var node = this;
this.ircclient.addListener('message', function (from, to, message) {
//util.log(from + ' => ' + to + ': ' + message);
var msg = { "topic":from, "from":from, "to":to, "payload":message };
node.send([msg,null]);
});
this.ircclient.addListener('pm', function(from, message) {
var msg = { "topic":from, "from":from, "to":"PRIV", "payload":message };
node.send([msg,null]);
});
this.ircclient.addListener('join', function(channel, who) {
var msg = { "payload": { "type":"join", "who":who, "channel":channel } };
node.send([null,msg]);
node.log(who+' has joined '+channel);
});
this.ircclient.addListener('invite', function(channel, from, message) {
var msg = { "payload": { "type":"invite", "who":from, "channel":channel, "message":message } };
node.send([null,msg]);
node.log(from+' sent invite to '+channel+': '+message);
});
this.ircclient.addListener('part', function(channel, who, reason) {
var msg = { "payload": { "type":"part", "who":who, "channel":channel, "reason":reason } };
node.send([null,msg]);
node.log(who+'has left '+channel+': '+reason);
});
this.ircclient.addListener('quit', function(nick, reason, channels, message) {
var msg = { "payload": { "type":"quit", "who":nick, "channel":channels, "reason":reason } };
node.send([null,msg]);
node.log(nick+'has quit '+channels+': '+reason);
});
this.ircclient.addListener('kick', function(channel, who, by, reason) {
var msg = { "payload": { "type":"kick", "who":who, "channel":channel, "by":by, "reason":reason } };
node.send([null,msg]);
node.log(who+' was kicked from '+channel+' by '+by+': '+reason);
});
}
RED.nodes.registerType("irc in",IrcInNode);
// The Output Node
function IrcOutNode(n) {
RED.nodes.createNode(this,n);
this.sendAll = n.sendObject;
this.ircserver = n.ircserver;
this.serverConfig = RED.nodes.getNode(this.ircserver);
this.channel = n.channel || this.serverConfig.channel;
if (this.serverConfig.ircclient == null) {
this.serverConfig.ircclient = new irc.Client(this.serverConfig.server, this.serverConfig.nickname, {
channels: [this.channel]
});
this.serverConfig.ircclient.addListener('error', function(message) {
util.log('[irc] '+ JSON.stringify(message));
});
}
this.ircclient = this.serverConfig.ircclient;
var node = this;
this.on("input", function(msg) {
if (Object.prototype.toString.call( msg.raw ) === '[object Array]') {
var m = msg.raw;
for (var i = 0; i < 10; i++) {
if (typeof m[i] !== "string") { m[i] = ""; }
m[i] = m[i].replace(/"/g, "");
} }
util.log("[irc] RAW command:"+m); });
node.ircclient.send(m[0],m[1],m[2],m[3],m[4],m[5],m[6],m[7],m[8],m[9]); }
RED.nodes.registerType("irc-server",IRCServerNode);
// The Input Node
function IrcInNode(n) {
RED.nodes.createNode(this,n);
this.ircserver = n.ircserver;
this.serverConfig = RED.nodes.getNode(this.ircserver);
this.channel = n.channel || this.serverConfig.channel;
if (this.serverConfig.ircclient == null) {
this.serverConfig.ircclient = new irc.Client(this.serverConfig.server, this.serverConfig.nickname, {
channels: [this.channel]
});
this.serverConfig.ircclient.addListener('error', function(message) {
util.log('[irc] '+ JSON.stringify(message));
});
} }
else { this.ircclient = this.serverConfig.ircclient;
if (msg._topic) { delete msg._topic; } var node = this;
if (node.sendAll == "false") {
node.ircclient.say(node.channel, JSON.stringify(msg)); this.ircclient.addListener('message', function (from, to, message) {
//util.log(from + ' => ' + to + ': ' + message);
var msg = { "topic":from, "from":from, "to":to, "payload":message };
node.send([msg,null]);
});
this.ircclient.addListener('pm', function(from, message) {
var msg = { "topic":from, "from":from, "to":"PRIV", "payload":message };
node.send([msg,null]);
});
this.ircclient.addListener('join', function(channel, who) {
var msg = { "payload": { "type":"join", "who":who, "channel":channel } };
node.send([null,msg]);
node.log(who+' has joined '+channel);
});
this.ircclient.addListener('invite', function(channel, from, message) {
var msg = { "payload": { "type":"invite", "who":from, "channel":channel, "message":message } };
node.send([null,msg]);
node.log(from+' sent invite to '+channel+': '+message);
});
this.ircclient.addListener('part', function(channel, who, reason) {
var msg = { "payload": { "type":"part", "who":who, "channel":channel, "reason":reason } };
node.send([null,msg]);
node.log(who+'has left '+channel+': '+reason);
});
this.ircclient.addListener('quit', function(nick, reason, channels, message) {
var msg = { "payload": { "type":"quit", "who":nick, "channel":channels, "reason":reason } };
node.send([null,msg]);
node.log(nick+'has quit '+channels+': '+reason);
});
this.ircclient.addListener('kick', function(channel, who, by, reason) {
var msg = { "payload": { "type":"kick", "who":who, "channel":channel, "by":by, "reason":reason } };
node.send([null,msg]);
node.log(who+' was kicked from '+channel+' by '+by+': '+reason);
});
}
RED.nodes.registerType("irc in",IrcInNode);
// The Output Node
function IrcOutNode(n) {
RED.nodes.createNode(this,n);
this.sendAll = n.sendObject;
this.ircserver = n.ircserver;
this.serverConfig = RED.nodes.getNode(this.ircserver);
this.channel = n.channel || this.serverConfig.channel;
if (this.serverConfig.ircclient == null) {
this.serverConfig.ircclient = new irc.Client(this.serverConfig.server, this.serverConfig.nickname, {
channels: [this.channel]
});
this.serverConfig.ircclient.addListener('error', function(message) {
util.log('[irc] '+ JSON.stringify(message));
});
}
this.ircclient = this.serverConfig.ircclient;
var node = this;
this.on("input", function(msg) {
if (Object.prototype.toString.call( msg.raw ) === '[object Array]') {
var m = msg.raw;
for (var i = 0; i < 10; i++) {
if (typeof m[i] !== "string") { m[i] = ""; }
m[i] = m[i].replace(/"/g, "");
}
util.log("[irc] RAW command:"+m);
node.ircclient.send(m[0],m[1],m[2],m[3],m[4],m[5],m[6],m[7],m[8],m[9]);
} }
else { else {
if (typeof msg.payload === "object") { msg.payload = JSON.stringify(msg.payload); } if (msg._topic) { delete msg._topic; }
if (node.sendAll == "pay") { if (node.sendAll == "false") {
node.ircclient.say(node.channel, msg.payload); node.ircclient.say(node.channel, JSON.stringify(msg));
} }
else { else {
var to = msg.topic || node.channel; if (typeof msg.payload === "object") { msg.payload = JSON.stringify(msg.payload); }
node.ircclient.say(to, msg.payload); if (node.sendAll == "pay") {
node.ircclient.say(node.channel, msg.payload);
}
else {
var to = msg.topic || node.channel;
node.ircclient.say(to, msg.payload);
}
} }
} }
} });
}); }
RED.nodes.registerType("irc out",IrcOutNode);
} }
RED.nodes.registerType("irc out",IrcOutNode);

View File

@ -14,43 +14,44 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var fs = require("fs"); var fs = require("fs");
var spawn = require('child_process').spawn; var spawn = require('child_process').spawn;
function TailNode(n) { function TailNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.filename = n.filename; this.filename = n.filename;
this.split = n.split; this.split = n.split;
var node = this; var node = this;
var err = ""; var err = "";
var tail = spawn("tail", ["-f", this.filename]); var tail = spawn("tail", ["-f", this.filename]);
tail.stdout.on("data", function (data) { tail.stdout.on("data", function (data) {
var msg = {topic:node.filename}; var msg = {topic:node.filename};
if (node.split) { if (node.split) {
var strings = data.toString().split("\n"); var strings = data.toString().split("\n");
for (s in strings) { for (s in strings) {
if (strings[s] != "") { if (strings[s] != "") {
msg.payload = strings[s]; msg.payload = strings[s];
node.send(msg); node.send(msg);
}
} }
} }
} else {
else { msg.payload = data.toString();
msg.payload = data.toString(); node.send(msg);
node.send(msg); }
} });
});
tail.stderr.on("data", function(data) { tail.stderr.on("data", function(data) {
node.warn(data.toString()); node.warn(data.toString());
}); });
this.on("close", function() { this.on("close", function() {
if (tail) tail.kill(); if (tail) tail.kill();
}); });
}
RED.nodes.registerType("tail",TailNode);
} }
RED.nodes.registerType("tail",TailNode);

View File

@ -14,77 +14,78 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var fs = require("fs"); var fs = require("fs");
function FileNode(n) { function FileNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.filename = n.filename; this.filename = n.filename;
this.appendNewline = n.appendNewline; this.appendNewline = n.appendNewline;
this.overwriteFile = n.overwriteFile; this.overwriteFile = n.overwriteFile;
var node = this; var node = this;
this.on("input",function(msg) { this.on("input",function(msg) {
var filename = msg.filename || this.filename; var filename = msg.filename || this.filename;
if (filename == "") { if (filename == "") {
node.warn('No filename specified'); node.warn('No filename specified');
} else if (typeof msg.payload != "undefined") { } else if (typeof msg.payload != "undefined") {
var data = msg.payload; var data = msg.payload;
if (typeof data == "object") { data = JSON.stringify(data); } if (typeof data == "object") { data = JSON.stringify(data); }
if (typeof data == "boolean") { data = data.toString(); } if (typeof data == "boolean") { data = data.toString(); }
if (this.appendNewline) { if (this.appendNewline) {
data += "\n"; data += "\n";
} }
if (msg.hasOwnProperty('delete')) { if (msg.hasOwnProperty('delete')) {
fs.unlink(filename, function (err) { fs.unlink(filename, function (err) {
if (err) node.warn('Failed to delete file : '+err); if (err) node.warn('Failed to delete file : '+err);
//console.log('Deleted file",filename); //console.log('Deleted file",filename);
});
}
else {
if (this.overwriteFile) {
fs.writeFile(filename, data, function (err) {
if (err) node.warn('Failed to write to file : '+err);
//console.log('Message written to file',filename);
}); });
} }
else { else {
fs.appendFile(filename, data, function (err) { if (this.overwriteFile) {
if (err) node.warn('Failed to append to file : '+err); fs.writeFile(filename, data, function (err) {
//console.log('Message appended to file',filename); if (err) node.warn('Failed to write to file : '+err);
}); //console.log('Message written to file',filename);
});
}
else {
fs.appendFile(filename, data, function (err) {
if (err) node.warn('Failed to append to file : '+err);
//console.log('Message appended to file',filename);
});
}
} }
} }
} });
});
}
RED.nodes.registerType("file",FileNode);
function FileInNode(n) {
RED.nodes.createNode(this,n);
this.filename = n.filename;
this.format = n.format;
var node = this;
var options = {};
if (this.format) {
options['encoding'] = this.format;
} }
this.on("input",function(msg) { RED.nodes.registerType("file",FileNode);
var filename = msg.filename || this.filename;
if (filename == "") { function FileInNode(n) {
node.warn('No filename specified'); RED.nodes.createNode(this,n);
} else {
fs.readFile(filename,options,function(err,data) { this.filename = n.filename;
if (err) { this.format = n.format;
node.warn(err); var node = this;
} else { var options = {};
node.send({payload:data}); if (this.format) {
} options['encoding'] = this.format;
});
} }
}); this.on("input",function(msg) {
var filename = msg.filename || this.filename;
if (filename == "") {
node.warn('No filename specified');
} else {
fs.readFile(filename,options,function(err,data) {
if (err) {
node.warn(err);
} else {
node.send({payload:data});
}
});
}
});
}
RED.nodes.registerType("file in",FileInNode);
} }
RED.nodes.registerType("file in",FileInNode);

View File

@ -14,83 +14,84 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var util = require("util"); var util = require("util");
var redis = require("redis"); var redis = require("redis");
var hashFieldRE = /^([^=]+)=(.*)$/; var hashFieldRE = /^([^=]+)=(.*)$/;
var redisConnectionPool = function() { var redisConnectionPool = function() {
var connections = {}; var connections = {};
var obj = { var obj = {
get: function(host,port) { get: function(host,port) {
var id = host+":"+port; var id = host+":"+port;
if (!connections[id]) { if (!connections[id]) {
connections[id] = redis.createClient(port,host); connections[id] = redis.createClient(port,host);
connections[id].on("error",function(err) { connections[id].on("error",function(err) {
util.log("[redis] "+err); util.log("[redis] "+err);
}); });
connections[id].on("connect",function() { connections[id].on("connect",function() {
util.log("[redis] connected to "+host+":"+port); util.log("[redis] connected to "+host+":"+port);
}); });
connections[id]._id = id; connections[id]._id = id;
connections[id]._nodeCount = 0; connections[id]._nodeCount = 0;
}
connections[id]._nodeCount += 1;
return connections[id];
},
close: function(connection) {
connection._nodeCount -= 1;
if (connection._nodeCount == 0) {
if (connection) {
clearTimeout(connection.retry_timer);
connection.end();
} }
delete connections[connection._id]; connections[id]._nodeCount += 1;
} return connections[id];
} },
}; close: function(connection) {
return obj; connection._nodeCount -= 1;
}(); if (connection._nodeCount == 0) {
if (connection) {
clearTimeout(connection.retry_timer);
function RedisOutNode(n) { connection.end();
RED.nodes.createNode(this,n);
this.port = n.port||"6379";
this.hostname = n.hostname||"127.0.0.1";
this.key = n.key;
this.structtype = n.structtype;
this.client = redisConnectionPool.get(this.hostname,this.port);
this.on("input", function(msg) {
if (msg != null) {
var k = this.key || msg.topic;
if (k) {
if (this.structtype == "string") {
this.client.set(k,msg.payload);
} else if (this.structtype == "hash") {
var r = hashFieldRE.exec(msg.payload);
if (r) {
this.client.hset(k,r[1],r[2]);
} else {
this.warn("Invalid payload for redis hash");
}
} else if (this.structtype == "set") {
this.client.sadd(k,msg.payload);
} else if (this.structtype == "list") {
this.client.rpush(k,msg.payload);
} }
} else { delete connections[connection._id];
this.warn("No key or topic set");
} }
} }
}); };
} return obj;
}();
RED.nodes.registerType("redis out",RedisOutNode);
RedisOutNode.prototype.close = function() { function RedisOutNode(n) {
redisConnectionPool.close(this.client); RED.nodes.createNode(this,n);
this.port = n.port||"6379";
this.hostname = n.hostname||"127.0.0.1";
this.key = n.key;
this.structtype = n.structtype;
this.client = redisConnectionPool.get(this.hostname,this.port);
this.on("input", function(msg) {
if (msg != null) {
var k = this.key || msg.topic;
if (k) {
if (this.structtype == "string") {
this.client.set(k,msg.payload);
} else if (this.structtype == "hash") {
var r = hashFieldRE.exec(msg.payload);
if (r) {
this.client.hset(k,r[1],r[2]);
} else {
this.warn("Invalid payload for redis hash");
}
} else if (this.structtype == "set") {
this.client.sadd(k,msg.payload);
} else if (this.structtype == "list") {
this.client.rpush(k,msg.payload);
}
} else {
this.warn("No key or topic set");
}
}
});
}
RED.nodes.registerType("redis out",RedisOutNode);
RedisOutNode.prototype.close = function() {
redisConnectionPool.close(this.client);
}
} }

View File

@ -14,165 +14,166 @@
* limitations under the License. * limitations under the License.
**/ **/
var RED = require(process.env.NODE_RED_HOME+"/red/red"); module.exports = function(RED) {
var mongo = require('mongodb'); var mongo = require('mongodb');
var MongoClient = mongo.MongoClient; var MongoClient = mongo.MongoClient;
function MongoNode(n) { function MongoNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.hostname = n.hostname; this.hostname = n.hostname;
this.port = n.port; this.port = n.port;
this.db = n.db; this.db = n.db;
this.name = n.name; this.name = n.name;
var credentials = RED.nodes.getCredentials(n.id); var credentials = RED.nodes.getCredentials(n.id);
if (credentials) { if (credentials) {
this.username = credentials.user; this.username = credentials.user;
this.password = credentials.password; this.password = credentials.password;
}
var url = "mongodb://";
if (this.username && this.password) {
url += this.username+":"+this.password+"@";
}
url += this.hostname+":"+this.port+"/"+this.db;
this.url = url;
} }
var url = "mongodb://"; RED.nodes.registerType("mongodb",MongoNode);
if (this.username && this.password) {
url += this.username+":"+this.password+"@";
}
url += this.hostname+":"+this.port+"/"+this.db;
this.url = url; var querystring = require('querystring');
}
RED.nodes.registerType("mongodb",MongoNode); RED.httpAdmin.get('/mongodb/:id',function(req,res) {
var credentials = RED.nodes.getCredentials(req.params.id);
var querystring = require('querystring'); if (credentials) {
res.send(JSON.stringify({user:credentials.user,hasPassword:(credentials.password&&credentials.password!="")}));
RED.httpAdmin.get('/mongodb/:id',function(req,res) { } else {
var credentials = RED.nodes.getCredentials(req.params.id); res.send(JSON.stringify({}));
if (credentials) { }
res.send(JSON.stringify({user:credentials.user,hasPassword:(credentials.password&&credentials.password!="")}));
} else {
res.send(JSON.stringify({}));
}
});
RED.httpAdmin.delete('/mongodb/:id',function(req,res) {
RED.nodes.deleteCredentials(req.params.id);
res.send(200);
});
RED.httpAdmin.post('/mongodb/:id',function(req,res) {
var body = "";
req.on('data', function(chunk) {
body+=chunk;
}); });
req.on('end', function(){
var newCreds = querystring.parse(body); RED.httpAdmin.delete('/mongodb/:id',function(req,res) {
var credentials = RED.nodes.getCredentials(req.params.id)||{}; RED.nodes.deleteCredentials(req.params.id);
if (newCreds.user == null || newCreds.user == "") {
delete credentials.user;
} else {
credentials.user = newCreds.user;
}
if (newCreds.password == "") {
delete credentials.password;
} else {
credentials.password = newCreds.password||credentials.password;
}
RED.nodes.addCredentials(req.params.id,credentials);
res.send(200); res.send(200);
}); });
});
RED.httpAdmin.post('/mongodb/:id',function(req,res) {
function MongoOutNode(n) { var body = "";
RED.nodes.createNode(this,n); req.on('data', function(chunk) {
this.collection = n.collection; body+=chunk;
this.mongodb = n.mongodb;
this.payonly = n.payonly || false;
this.operation = n.operation;
this.mongoConfig = RED.nodes.getNode(this.mongodb);
if (this.mongoConfig) {
var node = this;
MongoClient.connect(this.mongoConfig.url, function(err,db) {
if (err) {
node.error(err);
} else {
node.clientDb = db;
var coll = db.collection(node.collection);
node.on("input",function(msg) {
if (node.operation == "store") {
delete msg._topic;
if (node.payonly) {
if (typeof msg.payload !== "object") { msg.payload = {"payload":msg.payload}; }
coll.save(msg.payload,function(err,item){ if (err){node.error(err);} });
} else {
coll.save(msg,function(err,item){if (err){node.error(err);}});
}
}
else if (node.operation == "insert") {
delete msg._topic;
if (node.payonly) {
if (typeof msg.payload !== "object") { msg.payload = {"payload":msg.payload}; }
coll.insert(msg.payload,function(err,item){ if (err){node.error(err);} });
} else {
coll.insert(msg,function(err,item){if (err){node.error(err);}});
}
}
if (node.operation == "delete") {
coll.remove(msg.payload, {w:1}, function(err, items){ if (err) node.error(err); });
}
});
}
}); });
} else { req.on('end', function(){
this.error("missing mongodb configuration"); var newCreds = querystring.parse(body);
} var credentials = RED.nodes.getCredentials(req.params.id)||{};
if (newCreds.user == null || newCreds.user == "") {
this.on("close", function() { delete credentials.user;
if (this.clientDb) {
this.clientDb.close();
}
});
}
RED.nodes.registerType("mongodb out",MongoOutNode);
function MongoInNode(n) {
RED.nodes.createNode(this,n);
this.collection = n.collection;
this.mongodb = n.mongodb;
this.mongoConfig = RED.nodes.getNode(this.mongodb);
if (this.mongoConfig) {
var node = this;
MongoClient.connect(this.mongoConfig.url, function(err,db) {
if (err) {
node.error(err);
} else { } else {
node.clientDb = db; credentials.user = newCreds.user;
var coll = db.collection(node.collection); }
node.on("input",function(msg) { if (newCreds.password == "") {
msg.projection = msg.projection || {}; delete credentials.password;
coll.find(msg.payload,msg.projection).sort(msg.sort).limit(msg.limit).toArray(function(err, items) { } else {
if (err) { credentials.password = newCreds.password||credentials.password;
node.error(err); }
} else { RED.nodes.addCredentials(req.params.id,credentials);
msg.payload = items; res.send(200);
delete msg.projection; });
delete msg.sort; });
delete msg.limit;
node.send(msg);
function MongoOutNode(n) {
RED.nodes.createNode(this,n);
this.collection = n.collection;
this.mongodb = n.mongodb;
this.payonly = n.payonly || false;
this.operation = n.operation;
this.mongoConfig = RED.nodes.getNode(this.mongodb);
if (this.mongoConfig) {
var node = this;
MongoClient.connect(this.mongoConfig.url, function(err,db) {
if (err) {
node.error(err);
} else {
node.clientDb = db;
var coll = db.collection(node.collection);
node.on("input",function(msg) {
if (node.operation == "store") {
delete msg._topic;
if (node.payonly) {
if (typeof msg.payload !== "object") { msg.payload = {"payload":msg.payload}; }
coll.save(msg.payload,function(err,item){ if (err){node.error(err);} });
} else {
coll.save(msg,function(err,item){if (err){node.error(err);}});
}
}
else if (node.operation == "insert") {
delete msg._topic;
if (node.payonly) {
if (typeof msg.payload !== "object") { msg.payload = {"payload":msg.payload}; }
coll.insert(msg.payload,function(err,item){ if (err){node.error(err);} });
} else {
coll.insert(msg,function(err,item){if (err){node.error(err);}});
}
}
if (node.operation == "delete") {
coll.remove(msg.payload, {w:1}, function(err, items){ if (err) node.error(err); });
} }
}); });
}); }
});
} else {
this.error("missing mongodb configuration");
}
this.on("close", function() {
if (this.clientDb) {
this.clientDb.close();
} }
}); });
} else {
this.error("missing mongodb configuration");
} }
RED.nodes.registerType("mongodb out",MongoOutNode);
this.on("close", function() {
if (this.clientDb) { function MongoInNode(n) {
this.clientDb.close(); RED.nodes.createNode(this,n);
this.collection = n.collection;
this.mongodb = n.mongodb;
this.mongoConfig = RED.nodes.getNode(this.mongodb);
if (this.mongoConfig) {
var node = this;
MongoClient.connect(this.mongoConfig.url, function(err,db) {
if (err) {
node.error(err);
} else {
node.clientDb = db;
var coll = db.collection(node.collection);
node.on("input",function(msg) {
msg.projection = msg.projection || {};
coll.find(msg.payload,msg.projection).sort(msg.sort).limit(msg.limit).toArray(function(err, items) {
if (err) {
node.error(err);
} else {
msg.payload = items;
delete msg.projection;
delete msg.sort;
delete msg.limit;
node.send(msg);
}
});
});
}
});
} else {
this.error("missing mongodb configuration");
} }
});
this.on("close", function() {
if (this.clientDb) {
this.clientDb.close();
}
});
}
RED.nodes.registerType("mongodb in",MongoInNode);
} }
RED.nodes.registerType("mongodb in",MongoInNode);

View File

@ -54,7 +54,7 @@ function loadNode(nodeDir, nodeFn) {
var r = require(nodeFilename); var r = require(nodeFilename);
if (typeof r === "function") { if (typeof r === "function") {
try { try {
var promise = r(RED); var promise = r(require('../red'));
if (promise != null && typeof promise.then === "function") { if (promise != null && typeof promise.then === "function") {
promise.then(function() { promise.then(function() {
resolve(loadTemplate(templateFilename)); resolve(loadTemplate(templateFilename));