Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Ben Hardill 2013-09-10 14:54:19 +01:00
commit 75d1adcb18
10 changed files with 283 additions and 49 deletions

View File

@ -0,0 +1,49 @@
<!--
Copyright 2013 IBM Corp.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-template-name="blinkstick">
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-tips">Expects a msg.payload with either hex #rrggbb or decimal red,green,blue.</div>
</script>
<script type="text/x-red" data-help-name="blinkstick">
<p>BlinkStick output node. Expects a <b>msg.payload</b> with either a hex string #rrggbb triple or red,green,blue as three 0-255 values.</p>
<p><b>NOTE:</b> currently only works with a single BlinkStick. (As it uses the findFirst() function to attach).</p>
<p>For more info see the <i><a href="http://blinkstick.com/" target="_new">BlinkStick website</a></i> or the <i><a href="https://github.com/arvydas/blinkstick-node" target="_new">node module</a></i> documentation.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('blinkstick',{
category: 'advanced-output',
color:"cornsilk",
defaults: {
name: {value:""}
},
inputs:1,
outputs:0,
icon: "arrow-in.png",
align: "right",
label: function() {
return this.name||"blinkstick";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>

View File

@ -0,0 +1,42 @@
/**
* Copyright 2013 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var RED = require("../../red/red");
var blinkstick = require("blinkstick");
function BlinkStick(n) {
RED.nodes.createNode(this,n);
var p1 = /^#.*/
var p2 = /[0-9]+,[0-9]+,[0-9]+/
this.led = new blinkstick.findFirst();
var node = this;
node.log("started");
this.on("input", function(msg) {
if (msg != null) {
if ((p1.test(msg.payload))|(p2.test(msg.payload))) {
node.led.setColor(msg.payload);
}
else {
node.error("Incorrect format: "+msg.payload);
}
}
});
}
RED.nodes.registerType("blinkstick",BlinkStick);

View File

@ -42,7 +42,8 @@
outputs:1,
icon: "serial.png",
label: function() {
return this.name||(this.serial)?RED.nodes.node(this.serial).label():"serial";
var serialNode = RED.nodes.node(this.serial);
return this.name||(serialNode?serialNode.label():"serial");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
@ -80,7 +81,8 @@
icon: "serial.png",
align: "right",
label: function() {
return this.name||((this.serial)?RED.nodes.node(this.serial).label():"serial");
var serialNode = RED.nodes.node(this.serial);
return this.name||(serialNode?serialNode.label():"serial");
},
labelStyle: function() {
return this.name?"node_label_italic":"";

View File

@ -24,17 +24,24 @@ function SocketIn(n) {
var node = this;
if (this.trans == "http") {
var http = require('http');
var serv = http.createServer(function (req, res) {
var server = http.createServer(function (req, res) {
//node.log("http "+req.url);
var msg = {topic:node.topic,payload:req.url.slice(1)};
node.send(msg);
res.writeHead(304, {'Content-Type': 'text/plain'});
res.end('\n');
}).listen(node.port);
server.on('error', function (e) {
if (e.code == 'EADDRINUSE') {
setTimeout(node.error('TCP port is already in use - please reconfigure socket.'),250);
}
else { console.log(e); }
server = null;
});
node.log('http listener at http://127.0.0.1:'+node.port+'/');
this._close = function() {
serv.close();
if (server) server.close();
node.log('http listener stopped');
}
}
@ -44,11 +51,11 @@ function SocketIn(n) {
var server = net.createServer(function (socket) {
var buffer = null;
socket.on('data', function (chunk) {
if (buffer == null) {
buffer = chunk;
} else {
buffer = Buffer.concat([buffer,chunk]);
}
if (buffer == null) {
buffer = chunk;
} else {
buffer = Buffer.concat([buffer,chunk]);
}
});
socket.on('end', function() {
var msg = {topic:node.topic, payload:buffer, fromip:socket.remoteAddress+':'+socket.remotePort};
@ -59,12 +66,14 @@ function SocketIn(n) {
if (e.code == 'EADDRINUSE') {
setTimeout(node.error('TCP port is already in use - please reconfigure socket.'),250);
}
else { console.log(e); }
server = null;
});
server.listen(node.port);
node.log('tcp listener on port :'+node.port);
this._close = function() {
server.close();
if (server) server.close();
node.log('tcp listener stopped');
}
}
@ -95,13 +104,14 @@ function SocketIn(n) {
client.on('error', function() {
node.log('tcpc socket error');
client = null;
to = setTimeout(setupTcpClient, 10000); //Try to reconnect
});
}
setupTcpClient();
this._close = function() {
client.end();
if (client) client.end();
//client.destroy();
clearTimeout(to);
node.log('tcpc stopped client');
@ -120,10 +130,14 @@ function SocketIn(n) {
var msg = {topic:node.topic,payload:message,fromip:remote.address+':'+remote.port};
node.send(msg);
});
server.on('error', function (e) {
console.log(e);
server = null;
});
server.bind(node.port);
this._close = function() {
server.close();
if (server) server.close();
node.log('udp listener stopped');
}
}

View File

@ -42,7 +42,8 @@
outputs:1,
icon: "hash.png",
label: function() {
return this.name||(this.ircserver)?RED.nodes.node(this.ircserver).label():"irc";
var ircNode = RED.nodes.node(this.ircserver);
return this.name||(ircNode?ircNode.label():"irc");
},
labelStyle: function() {
return this.name?"node_label_italic":"";

View File

@ -27,10 +27,6 @@
</div>
</script>
<script type="text/x-red" data-help-name="mongodb out">
<p>A MongoDB output node.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('mongodb',{
category: 'config',
@ -47,11 +43,60 @@
</script>
<script type="text/x-red" data-template-name="mongodb out">
<div class="form-row">
<label for="node-input-mongodb"><i class="icon-tag"></i> Server</label>
<input type="text" id="node-input-mongodb">
</div>
<div class="form-row">
<label for="node-input-collection"><i class="icon-briefcase"></i> Collection</label>
<input type="text" id="node-input-collection" placeholder="collection">
</div>
<div class="form-row">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-payonly" placeholder="Only" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-payonly" style="width: 70%;">Only store msg.payload object ?</label>
</div>
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/x-red" data-help-name="mongodb out">
<p>A simple MongoDB output node. Stores the <b>msg</b> object in a chosen collection.</p>
<p>By default MongoDB creates an <i>_id</i> property as the primary key - so repeated injections of the same <b>msg</b> will result in many database entries.</p>
<p>If this is NOT the desired behaviour - ie you want repeated entries to overwrite, then you must set the <b>msg._id</b> property to be a constant by the use of a previous function node.</p>
<p>This could be a unique constant or you could create one based on some other msg property.</p>
<p>Currently we do not limit or cap the collection size at all... this may well change.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('mongodb out',{
category: 'storage-output',
color:"rgb(218, 196, 180)",
defaults: {
mongodb: { type:"mongodb",required:true},
name: {value:""},
collection: {value:"",required:true},
payonly: {value:false}
},
inputs:1,
outputs:0,
icon: "mongodb.png",
align: "right",
label: function() {
var mongoNode = RED.nodes.node(this.mongodb);
return this.name||this.collection||(mongoNode?mongoNode.label():"mongodb");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>
<script type="text/x-red" data-template-name="mongodb in">
<div class="form-row">
<label for="node-input-mongodb"><i class="icon-tag"></i> Server</label>
<input type="text" id="node-input-mongodb">
@ -64,16 +109,17 @@
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/x-red" data-help-name="mongodb out">
<p>A MongoDB output node.</p>
<script type="text/x-red" data-help-name="mongodb in">
<p>Queries a MongoDB collection by using the <b>msg.payload</b> to be a MongoDB query statement as per the .find() function.</p>
<p>You may also (via a function) set a <b>msg.projection</b> object to constrain the returned fields, a <b>msg.sort</b> object and a <b>msg.limit</b> object.</p>
<p>All are optional - see the <a href="http://docs.mongodb.org/manual/reference/method/db.collection.find/" target="new"><i>MongoDB find docs</i></a> for examples.
</script>
<script type="text/javascript">
RED.nodes.registerType('mongodb out',{
category: 'storage-output',
RED.nodes.registerType('mongodb in',{
category: 'storage-input',
color:"rgb(218, 196, 180)",
defaults: {
mongodb: { type:"mongodb",required:true},
@ -81,11 +127,14 @@
collection: {value:"",required:true},
},
inputs:1,
outputs:0,
outputs:1,
icon: "mongodb.png",
align: "right",
label: function() {
return this.name||this.collection||((this.mongodb)?RED.nodes.node(this.mongodb).label():"mongodb");
var mongoNode = RED.nodes.node(this.mongodb);
return this.name||(mongoNode?mongoNode.label()+"//"+this.collection:"mongodb");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>

View File

@ -30,25 +30,26 @@ function MongoOutNode(n) {
RED.nodes.createNode(this,n);
this.collection = n.collection;
this.mongodb = n.mongodb;
this.payonly = n.payonly || false;
this.mongoConfig = RED.nodes.getNode(this.mongodb);
if (this.mongoConfig) {
var node = this;
this.clientDb = new mongo.Db(node.mongoConfig.db, new mongo.Server(node.mongoConfig.hostname, node.mongoConfig.port, {}), {w: 1});
this.clientDb.open(function(err,cli) {
if (err) { node.error(err); }
else {
node.clientDb.collection(node.collection,function(err,coll) {
if (err) { node.error(err); }
else {
node.on("input",function(msg) {
delete msg._topic;
coll.save(msg,function(err,item){if (err){node.error(err);}});
});
}
});
}
if (err) { node.error(err); }
else {
node.clientDb.collection(node.collection,function(err,coll) {
if (err) { node.error(err); }
else {
node.on("input",function(msg) {
delete msg._topic;
if (node.payonly) 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 {
this.error("missing mongodb configuration");
@ -63,4 +64,45 @@ MongoOutNode.prototype.close = function() {
}
}
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;
this.clientDb = new mongo.Db(node.mongoConfig.db, new mongo.Server(node.mongoConfig.hostname, node.mongoConfig.port, {}), {w: 1});
this.clientDb.open(function(err,cli) {
if (err) { node.error(err); }
else {
node.clientDb.collection(node.collection,function(err,coll) {
if (err) { node.error(err); }
else {
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); }
msg.payload = items;
delete msg.projection;
delete msg.sort;
delete msg.limit;
node.send(msg);
});
});
}
});
}
});
} else {
this.error("missing mongodb configuration");
}
}
RED.nodes.registerType("mongodb in",MongoInNode);
MongoInNode.prototype.close = function() {
if (this.clientDb) {
this.clientDb.close();
}
}

19
red/events.js Normal file
View File

@ -0,0 +1,19 @@
/**
* Copyright 2013 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var events = require("events");
module.exports = new events.EventEmitter();

View File

@ -14,9 +14,9 @@
* limitations under the License.
**/
var util = require("util");
var events = require("events");
var EventEmitter = require("events").EventEmitter;
var fs = require("fs");
var events = require("./events");
function getCallerFilename(type) {
//if (type == "summary") {
@ -59,9 +59,11 @@ var registry = (function() {
return nodes[i];
},
clear: function() {
events.emit("nodes-stopping");
for (var n in nodes) {
nodes[n].close();
}
events.emit("nodes-stopped");
nodes = {};
},
@ -72,7 +74,7 @@ var registry = (function() {
return obj;
})();
var ConsoleLogHandler = new events.EventEmitter();
var ConsoleLogHandler = new EventEmitter();
ConsoleLogHandler.on("log",function(msg) {
util.log("["+msg.level+"] ["+msg.type+":"+(msg.name||msg.id)+"] "+msg.msg);
});
@ -128,7 +130,7 @@ function Node(n) {
}
this.wires = n.wires||[];
}
util.inherits(Node,events.EventEmitter);
util.inherits(Node,EventEmitter);
Node.prototype.close = function() {
// called when a node is removed
@ -253,6 +255,8 @@ module.exports.load = function() {
}
loadNodes("nodes");
events.emit("nodes-loaded");
}
@ -261,7 +265,10 @@ module.exports.getNode = function(nid) {
return registry.get(nid);
}
module.exports.parseConfig = function(conf) {
registry.clear();
events.emit("nodes-starting");
for (var i in conf) {
var nn = null;
var nt = node_type_registry.get(conf[i].type);
@ -286,5 +293,7 @@ module.exports.parseConfig = function(conf) {
if (deletedCredentials) {
saveCredentialsFile();
}
events.emit("nodes-started");
}

View File

@ -14,15 +14,22 @@
* limitations under the License.
**/
var events = require("./events");
var server = require("./server");
var nodes = require("./nodes");
var library = require("./library");
var settings = require("../settings");
module.exports = {
var events = require("events");
var RED = {
nodes: nodes,
app: server.app,
server: server.server,
settings: settings,
library: library
}
library: library,
events: events
};
module.exports = RED;