Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Ben Hardill 2014-02-18 10:25:21 +00:00
commit 560d106ba2
19 changed files with 310 additions and 114 deletions

View File

@ -83,7 +83,7 @@ InjectNode.prototype.close = function() {
} }
} }
RED.app.post("/inject/:id", function(req,res) { RED.httpAdmin.post("/inject/:id", function(req,res) {
var node = RED.nodes.getNode(req.params.id); var node = RED.nodes.getNode(req.params.id);
if (node != null) { if (node != null) {
try { try {

View File

@ -80,7 +80,7 @@ DebugNode.send = function(msg) {
DebugNode.activeConnections = []; DebugNode.activeConnections = [];
var path = RED.settings.httpRoot || "/"; var path = RED.settings.httpAdminRoot || "/";
path = path + (path.slice(-1) == "/" ? "":"/") + "debug/ws"; path = path + (path.slice(-1) == "/" ? "":"/") + "debug/ws";
DebugNode.wsServer = new ws.Server({server:RED.server,path:path}); DebugNode.wsServer = new ws.Server({server:RED.server,path:path});
@ -104,7 +104,7 @@ DebugNode.logHandler.on("log",function(msg) {
}); });
RED.nodes.addLogHandler(DebugNode.logHandler); RED.nodes.addLogHandler(DebugNode.logHandler);
RED.app.post("/debug/:id/:state", function(req,res) { RED.httpAdmin.post("/debug/:id/:state", function(req,res) {
var node = RED.nodes.getNode(req.params.id); var node = RED.nodes.getNode(req.params.id);
var state = req.params.state; var state = req.params.state;
if (node != null) { if (node != null) {

View File

@ -132,7 +132,7 @@
}, },
label: function() { label: function() {
return this.broker+":"+this.port; return (this.clientid?this.clientid+"@":"")+this.broker+":"+this.port;
}, },
oneditprepare: function() { oneditprepare: function() {
$.getJSON('mqtt-broker/'+this.id,function(data) { $.getJSON('mqtt-broker/'+this.id,function(data) {

View File

@ -33,7 +33,7 @@ RED.nodes.registerType("mqtt-broker",MQTTBrokerNode);
var querystring = require('querystring'); var querystring = require('querystring');
RED.app.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!="")}));
@ -42,12 +42,12 @@ RED.app.get('/mqtt-broker/:id',function(req,res) {
} }
}); });
RED.app.delete('/mqtt-broker/:id',function(req,res) { RED.httpAdmin.delete('/mqtt-broker/:id',function(req,res) {
RED.nodes.deleteCredentials(req.params.id); RED.nodes.deleteCredentials(req.params.id);
res.send(200); res.send(200);
}); });
RED.app.post('/mqtt-broker/:id',function(req,res) { RED.httpAdmin.post('/mqtt-broker/:id',function(req,res) {
var body = ""; var body = "";
req.on('data', function(chunk) { req.on('data', function(chunk) {
body+=chunk; body+=chunk;

View File

@ -80,7 +80,7 @@
if (this.name) { if (this.name) {
return this.name; return this.name;
} else if (this.url) { } else if (this.url) {
var root = document.location.pathname.slice(0,-1); var root = RED.settings.httpNodeRoot.slice(0,-1);
root += this.url; root += this.url;
return "["+this.method+"] "+root; return "["+this.method+"] "+root;
} else { } else {

View File

@ -21,6 +21,7 @@ var https = require("follow-redirects").https;
var urllib = require("url"); var urllib = require("url");
var express = require("express"); var express = require("express");
var getBody = require('raw-body'); var getBody = require('raw-body');
var cors = require('cors');
var jsonParser = express.json(); var jsonParser = express.json();
var urlencParser = express.urlencoded(); var urlencParser = express.urlencoded();
@ -53,28 +54,49 @@ function HTTPIn(n) {
}; };
this.callback = function(req,res) { this.callback = function(req,res) {
if (node.method == "post") { node.send({req:req,res:res,payload:req.body}); } if (node.method == "post") {
else if (node.method == "get") { node.send({req:req,res:res,payload:req.query}); } node.send({req:req,res:res,payload:req.body});
else node.send({req:req,res:res}); } else if (node.method == "get") {
node.send({req:req,res:res,payload:req.query});
} else {
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") { if (this.method == "get") {
RED.app.get(this.url,this.callback,errorHandler); RED.httpNode.get(this.url,corsHandler,this.callback,this.errorHandler);
} else if (this.method == "post") { } else if (this.method == "post") {
RED.app.post(this.url,jsonParser,urlencParser,rawBodyParser,this.callback,this.errorHandler); RED.httpNode.post(this.url,corsHandler,jsonParser,urlencParser,rawBodyParser,this.callback,this.errorHandler);
} else if (this.method == "put") { } else if (this.method == "put") {
RED.app.put(this.url,jsonParser,urlencParser,rawBodyParser,this.callback,this.errorHandler); RED.httpNode.put(this.url,corsHandler,jsonParser,urlencParser,rawBodyParser,this.callback,this.errorHandler);
} else if (this.method == "delete") { } else if (this.method == "delete") {
RED.app.delete(this.url,this.callback,errorHandler); RED.httpNode.delete(this.url,corsHandler,this.callback,errorHandler);
} }
this.on("close",function() { this.on("close",function() {
var routes = RED.app.routes[this.method]; var routes = RED.httpNode.routes[this.method];
for (var i in routes) { for (var i = 0; i<routes.length; i++) {
if (routes[i].path == this.url) {
routes.splice(i,1);
//break;
}
}
if (RED.settings.httpNodeCors) {
var routes = RED.httpNode.routes['options'];
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;
} }
} }
}
}); });
} }
@ -106,14 +128,14 @@ RED.nodes.registerType("http response",HTTPOut);
function HTTPRequest(n) { function HTTPRequest(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
var nodeUrl = n.url; var nodeUrl = n.url;
var method = n.method || "GET"; var nodeMethod = n.method || "GET";
var node = this; var node = this;
this.on("input",function(msg) { this.on("input",function(msg) {
var url = msg.url||nodeUrl; var url = msg.url||nodeUrl;
var method = (msg.method||nodeMethod).toUpperCase();
var opts = urllib.parse(url); var opts = urllib.parse(url);
opts.method = (msg.method||method).toUpperCase(); opts.method = method;
if (msg.headers) { if (msg.headers) {
opts.headers = msg.headers; opts.headers = msg.headers;
} }

View File

@ -135,12 +135,12 @@
inputs:0, inputs:0,
outputs:0, outputs:0,
label: function() { label: function() {
var root = document.location.pathname.slice(0,-1); var root = RED.settings.httpNodeRoot.slice(0,-1);
root += this.path; root += this.path;
return root; return root;
}, },
oneditprepare: function() { oneditprepare: function() {
var root = document.location.pathname.slice(0,-1); var root = RED.settings.httpNodeRoot.slice(0,-1);
if (root == "") { if (root == "") {
$("#node-config-ws-tip").hide(); $("#node-config-ws-tip").hide();
} else { } else {

View File

@ -32,7 +32,7 @@ function WebSocketListenerNode(n) {
node._inputNodes = []; // collection of nodes that want to receive events node._inputNodes = []; // collection of nodes that want to receive events
var path = RED.settings.httpRoot || "/"; var path = RED.settings.httpNodeRoot || "/";
path = path + (path.slice(-1) == "/" ? "":"/") + (node.path.charAt(0) == "/" ? node.path.substring(1) : node.path); path = path + (path.slice(-1) == "/" ? "":"/") + (node.path.charAt(0) == "/" ? node.path.substring(1) : node.path);
// Workaround https://github.com/einaros/ws/pull/253 // Workaround https://github.com/einaros/ws/pull/253

View File

@ -185,7 +185,7 @@ var serialPool = function() {
} }
}(); }();
RED.app.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));

View File

@ -263,7 +263,7 @@ var oa = new OAuth(
var credentials = {}; var credentials = {};
RED.app.get('/twitter/:id', function(req,res) { RED.httpAdmin.get('/twitter/: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({sn:credentials.screen_name})); res.send(JSON.stringify({sn:credentials.screen_name}));
@ -272,12 +272,12 @@ RED.app.get('/twitter/:id', function(req,res) {
} }
}); });
RED.app.delete('/twitter/:id', function(req,res) { RED.httpAdmin.delete('/twitter/:id', function(req,res) {
RED.nodes.deleteCredentials(req.params.id); RED.nodes.deleteCredentials(req.params.id);
res.send(200); res.send(200);
}); });
RED.app.get('/twitter/:id/auth', function(req, res){ RED.httpAdmin.get('/twitter/:id/auth', function(req, res){
var credentials = {}; var credentials = {};
oa.getOAuthRequestToken({ oa.getOAuthRequestToken({
oauth_callback: req.query.callback oauth_callback: req.query.callback
@ -297,7 +297,7 @@ RED.app.get('/twitter/:id/auth', function(req, res){
}); });
}); });
RED.app.get('/twitter/:id/auth/callback', function(req, res, next){ RED.httpAdmin.get('/twitter/:id/auth/callback', function(req, res, next){
var credentials = RED.nodes.getCredentials(req.params.id); var credentials = RED.nodes.getCredentials(req.params.id);
credentials.oauth_verifier = req.query.oauth_verifier; credentials.oauth_verifier = req.query.oauth_verifier;

View File

@ -29,6 +29,14 @@
<label for="node-config-input-name"><i class="icon-tag"></i> Name</label> <label for="node-config-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-config-input-name" placeholder="Name"> <input type="text" id="node-config-input-name" placeholder="Name">
</div> </div>
<div class="form-row">
<label for="node-config-input-user"><i class="icon-user"></i> Username</label>
<input type="text" id="node-config-input-user">
</div>
<div class="form-row">
<label for="node-config-input-pass"><i class="icon-lock"></i> Password</label>
<input type="password" id="node-config-input-pass">
</div>
</script> </script>
<script type="text/javascript"> <script type="text/javascript">
@ -39,10 +47,47 @@
hostname: { value:"127.0.0.1",required:true}, hostname: { value:"127.0.0.1",required:true},
port: { value: 27017,required:true}, port: { value: 27017,required:true},
db: { value:"",required:true}, db: { value:"",required:true},
name: { value:"" } name: { value:"" },
//user -> credentials
//pass -> credentials
}, },
label: function() { label: function() {
return this.name||this.hostname+":"+this.port+"//"+this.db; return this.name||this.hostname+":"+this.port+"/"+this.db;
},
oneditprepare: function() {
$.getJSON('mongodb/'+this.id,function(data) {
if (data.user) {
$('#node-config-input-user').val(data.user);
}
if (data.hasPassword) {
$('#node-config-input-pass').val('__PWRD__');
} else {
$('#node-config-input-pass').val('');
}
});
},
oneditsave: function() {
var newUser = $('#node-config-input-user').val();
var newPass = $('#node-config-input-pass').val();
var credentials = {};
credentials.user = newUser;
if (newPass != '__PWRD__') {
credentials.password = newPass;
}
$.ajax({
url: 'mongodb/'+this.id,
type: 'POST',
data: credentials,
success:function(result){}
});
},
ondelete: function() {
$.ajax({
url: 'mongodb/'+this.id,
type: 'DELETE',
success: function(result) {}
});
} }
}); });
</script> </script>
@ -110,7 +155,7 @@
align: "right", align: "right",
label: function() { label: function() {
var mongoNode = RED.nodes.node(this.mongodb); var mongoNode = RED.nodes.node(this.mongodb);
return this.name||(mongoNode?mongoNode.label()+"//"+this.collection:"mongodb"); return this.name||(mongoNode?mongoNode.label()+" "+this.collection:"mongodb");
}, },
labelStyle: function() { labelStyle: function() {
return this.name?"node_label_italic":""; return this.name?"node_label_italic":"";
@ -154,7 +199,7 @@
icon: "mongodb.png", icon: "mongodb.png",
label: function() { label: function() {
var mongoNode = RED.nodes.node(this.mongodb); var mongoNode = RED.nodes.node(this.mongodb);
return this.name||(mongoNode?mongoNode.label()+"//"+this.collection:"mongodb"); return this.name||(mongoNode?mongoNode.label()+" "+this.collection:"mongodb");
}, },
labelStyle: function() { labelStyle: function() {
return this.name?"node_label_italic":""; return this.name?"node_label_italic":"";

View File

@ -16,6 +16,7 @@
var RED = require(process.env.NODE_RED_HOME+"/red/red"); var RED = require(process.env.NODE_RED_HOME+"/red/red");
var mongo = require('mongodb'); var mongo = require('mongodb');
var MongoClient = mongo.MongoClient;
function MongoNode(n) { function MongoNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
@ -23,9 +24,62 @@ function MongoNode(n) {
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);
if (credentials) {
this.username = credentials.user;
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;
} }
RED.nodes.registerType("mongodb",MongoNode); RED.nodes.registerType("mongodb",MongoNode);
var querystring = require('querystring');
RED.httpAdmin.get('/mongodb/: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.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);
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);
});
});
function MongoOutNode(n) { function MongoOutNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
@ -37,34 +91,33 @@ function MongoOutNode(n) {
if (this.mongoConfig) { if (this.mongoConfig) {
var node = this; var node = this;
this.clientDb = new mongo.Db(node.mongoConfig.db, new mongo.Server(node.mongoConfig.hostname, node.mongoConfig.port, {}), {w: 1}); MongoClient.connect(this.mongoConfig.url, function(err,db) {
this.clientDb.open(function(err,cli) { if (err) {
if (err) { node.error(err); } node.error(err);
else { } else {
node.clientDb.collection(node.collection,function(err,coll) { node.clientDb = db;
if (err) { node.error(err); } var coll = db.collection(node.collection);
else { node.on("input",function(msg) {
node.on("input",function(msg) { if (node.operation == "store") {
if (node.operation == "store") { delete msg._topic;
delete msg._topic; if (node.payonly) {
if (node.payonly) { if (typeof msg.payload !== "object") { msg.payload = {"payload":msg.payload}; }
if (typeof msg.payload !== "object") { msg.payload = {"payload":msg.payload}; } coll.save(msg.payload,function(err,item){ if (err){node.error(err);} });
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 coll.save(msg,function(err,item){if (err){node.error(err);}}); }
} }
else if (node.operation == "insert") { else if (node.operation == "insert") {
delete msg._topic; delete msg._topic;
if (node.payonly) { if (node.payonly) {
if (typeof msg.payload !== "object") { msg.payload = {"payload":msg.payload}; } if (typeof msg.payload !== "object") { msg.payload = {"payload":msg.payload}; }
coll.insert(msg.payload,function(err,item){ if (err){node.error(err);} }); coll.insert(msg.payload,function(err,item){ if (err){node.error(err);} });
} } else {
else coll.insert(msg,function(err,item){if (err){node.error(err);}}); 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); }); if (node.operation == "delete") {
} coll.remove(msg.payload, {w:1}, function(err, items){ if (err) node.error(err); });
});
} }
}); });
} }
@ -90,25 +143,25 @@ function MongoInNode(n) {
if (this.mongoConfig) { if (this.mongoConfig) {
var node = this; var node = this;
this.clientDb = new mongo.Db(node.mongoConfig.db, new mongo.Server(node.mongoConfig.hostname, node.mongoConfig.port, {}), {w: 1}); MongoClient.connect(this.mongoConfig.url, function(err,db) {
this.clientDb.open(function(err,cli) { if (err) {
if (err) { node.error(err); } node.error(err);
else { } else {
node.clientDb.collection(node.collection,function(err,coll) { node.clientDb = db;
if (err) { node.error(err); } var coll = db.collection(node.collection);
else { node.on("input",function(msg) {
node.on("input",function(msg) { msg.projection = msg.projection || {};
msg.projection = msg.projection || {}; coll.find(msg.payload,msg.projection).sort(msg.sort).limit(msg.limit).toArray(function(err, items) {
coll.find(msg.payload,msg.projection).sort(msg.sort).limit(msg.limit).toArray(function(err, items) { if (err) {
if (err) { node.error(err); } node.error(err);
msg.payload = items; } else {
delete msg.projection; msg.payload = items;
delete msg.sort; delete msg.projection;
delete msg.limit; delete msg.sort;
node.send(msg); delete msg.limit;
}); node.send(msg);
}); }
} });
}); });
} }
}); });

View File

@ -36,6 +36,7 @@
"sentiment":"~0.2.1", "sentiment":"~0.2.1",
"irc":"~0.3.6", "irc":"~0.3.6",
"follow-redirects":"~0.0.3", "follow-redirects":"~0.0.3",
"cors":"~2.1.1",
"mkdirp":"~0.3.5" "mkdirp":"~0.3.5"
}, },
"devDependencies": { "devDependencies": {

View File

@ -122,6 +122,12 @@ var RED = function() {
] ]
}); });
function loadSettings() {
$.get('settings', function(data) {
RED.settings = data;
loadNodes();
});
}
function loadNodes() { function loadNodes() {
$.get('nodes', function(data) { $.get('nodes', function(data) {
$("body").append(data); $("body").append(data);
@ -157,7 +163,7 @@ var RED = function() {
$(function() { $(function() {
RED.keyboard.add(/* ? */ 191,{shift:true},function(){showHelp();d3.event.preventDefault();}); RED.keyboard.add(/* ? */ 191,{shift:true},function(){showHelp();d3.event.preventDefault();});
loadNodes(); loadSettings();
}); });
return { return {

56
red.js
View File

@ -48,31 +48,57 @@ if (settings.https) {
server = http.createServer(function(req,res){app(req,res);}); server = http.createServer(function(req,res){app(req,res);});
} }
function formatRoot(root) {
if (root[0] != "/") {
root = "/" + root;
}
if (root.slice(-1) != "/") {
root = root + "/";
}
return root;
}
settings.httpRoot = settings.httpRoot||"/"; settings.httpRoot = settings.httpRoot||"/";
if (settings.httpRoot[0] != "/") { settings.httpAdminRoot = formatRoot(settings.httpAdminRoot || settings.httpRoot || "/");
settings.httpRoot = "/"+settings.httpRoot; settings.httpAdminAuth = settings.httpAdminAuth || settings.httpAuth;
}
if (settings.httpRoot.slice(-1) != "/") { settings.httpNodeRoot = formatRoot(settings.httpNodeRoot || settings.httpRoot || "/");
settings.httpRoot = settings.httpRoot + "/"; settings.httpNodeAuth = settings.httpNodeAuth || settings.httpAuth;
}
settings.uiPort = settings.uiPort||1880; settings.uiPort = settings.uiPort||1880;
settings.uiHost = settings.uiHost||"0.0.0.0"; settings.uiHost = settings.uiHost||"0.0.0.0";
if (settings.httpAuth) { settings.flowFile = flowFile || settings.flowFile;
app.use(settings.httpRoot,
RED.init(server,settings);
if (settings.httpAdminAuth) {
app.use(settings.httpAdminRoot,
express.basicAuth(function(user, pass) { express.basicAuth(function(user, pass) {
return user === settings.httpAuth.user && crypto.createHash('md5').update(pass,'utf8').digest('hex') === settings.httpAuth.pass; return user === settings.httpAdminAuth.user && crypto.createHash('md5').update(pass,'utf8').digest('hex') === settings.httpAdminAuth.pass;
}) })
); );
} }
if (settings.httpNodeAuth) {
settings.flowFile = flowFile || settings.flowFile; app.use(settings.httpNodeRoot,
express.basicAuth(function(user, pass) {
var red = RED.init(server,settings); return user === settings.httpNodeAuth.user && crypto.createHash('md5').update(pass,'utf8').digest('hex') === settings.httpNodeAuth.pass;
app.use(settings.httpRoot,red); })
);
}
app.use(settings.httpAdminRoot,RED.httpAdmin);
app.use(settings.httpNodeRoot,RED.httpNode);
if (settings.httpStatic) { if (settings.httpStatic) {
settings.httpStaticAuth = settings.httpStaticAuth || settings.httpAuth;
if (settings.httpStaticAuth) {
app.use("/",
express.basicAuth(function(user, pass) {
return user === settings.httpStaticAuth.user && crypto.createHash('md5').update(pass,'utf8').digest('hex') === settings.httpStaticAuth.pass;
})
);
}
app.use("/",express.static(settings.httpStatic)); app.use("/",express.static(settings.httpStatic));
} }
@ -80,7 +106,7 @@ RED.start();
var listenPath = 'http'+(settings.https?'s':'')+'://'+ var listenPath = 'http'+(settings.https?'s':'')+'://'+
(settings.uiHost == '0.0.0.0'?'127.0.0.1':settings.uiHost)+ (settings.uiHost == '0.0.0.0'?'127.0.0.1':settings.uiHost)+
':'+settings.uiPort+settings.httpRoot; ':'+settings.uiPort+settings.httpAdminRoot;
server.listen(settings.uiPort,settings.uiHost,function() { server.listen(settings.uiPort,settings.uiHost,function() {
util.log('[red] Server now running at '+listenPath); util.log('[red] Server now running at '+listenPath);

View File

@ -42,7 +42,9 @@ var RED = {
events: events events: events
}; };
RED.__defineGetter__("app", function() { return server.app }); RED.__defineGetter__("app", function() { console.log("Deprecated use of RED.app - use RED.httpAdmin instead"); return server.app });
RED.__defineGetter__("httpAdmin", function() { return server.app });
RED.__defineGetter__("httpNode", function() { return server.nodeApp });
RED.__defineGetter__("server", function() { return server.server }); RED.__defineGetter__("server", function() { return server.server });
RED.__defineGetter__("settings", function() { return settings }); RED.__defineGetter__("settings", function() { return settings });

View File

@ -14,11 +14,13 @@
* limitations under the License. * limitations under the License.
**/ **/
var express = require('express');
var util = require('util'); var util = require('util');
var createUI = require("./ui"); var createUI = require("./ui");
var redNodes = require("./nodes"); var redNodes = require("./nodes");
var app = null; var app = null;
var nodeApp = null;
var server = null; var server = null;
var settings = null; var settings = null;
var storage = null; var storage = null;
@ -28,6 +30,7 @@ function createServer(_server,_settings) {
settings = _settings; settings = _settings;
storage = require("./storage"); storage = require("./storage");
app = createUI(settings); app = createUI(settings);
nodeApp = express();
flowfile = settings.flowFile || 'flows_'+require('os').hostname()+'.json'; flowfile = settings.flowFile || 'flows_'+require('os').hostname()+'.json';
@ -103,4 +106,5 @@ module.exports = {
} }
module.exports.__defineGetter__("app", function() { return app }); module.exports.__defineGetter__("app", function() { return app });
module.exports.__defineGetter__("nodeApp", function() { return nodeApp });
module.exports.__defineGetter__("server", function() { return server }); module.exports.__defineGetter__("server", function() { return server });

View File

@ -34,24 +34,30 @@ function setupUI(settings) {
// Need to ensure the url ends with a '/' so the static serving works // Need to ensure the url ends with a '/' so the static serving works
// with relative paths // with relative paths
app.get("/",function(req,res) { app.get("/",function(req,res) {
if (req.originalUrl.slice(-1) != "/") { if (req.originalUrl.slice(-1) != "/") {
res.redirect(req.originalUrl+"/"); res.redirect(req.originalUrl+"/");
} else { } else {
req.next(); req.next();
} }
}); });
app.get("/icons/:icon",function(req,res) { app.get("/icons/:icon",function(req,res) {
for (var p in icon_paths) { for (var p in icon_paths) {
if (fs.existsSync(icon_paths[p]+'/'+req.params.icon)) { if (fs.existsSync(icon_paths[p]+'/'+req.params.icon)) {
res.sendfile(icon_paths[p]+'/'+req.params.icon); res.sendfile(icon_paths[p]+'/'+req.params.icon);
return; return;
}
} }
//TODO: create a default icon }
res.sendfile(path.resolve(__dirname + '/../public/icons/arrow-in.png')); //TODO: create a default icon
res.sendfile(path.resolve(__dirname + '/../public/icons/arrow-in.png'));
}); });
app.get("/settings", function(req,res) {
var safeSettings = {
httpNodeRoot: settings.httpNodeRoot
};
res.json(safeSettings);
});
app.use("/",express.static(__dirname + '/../public')); app.use("/",express.static(__dirname + '/../public'));

View File

@ -49,19 +49,41 @@ module.exports = {
// The following property can be used to specify an additional directory to scan. // The following property can be used to specify an additional directory to scan.
//nodesDir: '/home/nol/.node-red/nodes', //nodesDir: '/home/nol/.node-red/nodes',
// You can protect the user interface with a userid and password by using the following property
// the password must be an md5 hash eg.. 5f4dcc3b5aa765d61d8327deb882cf99 ('password')
//httpAuth: {user:"user",pass:"5f4dcc3b5aa765d61d8327deb882cf99"},
// By default, the Node-RED UI is available at http://localhost:1880/ // By default, the Node-RED UI is available at http://localhost:1880/
// The following property can be used to specifiy a different root path. // The following property can be used to specifiy a different root path.
//httpRoot: '/admin', //httpAdminRoot: '/admin',
// When httpRoot is used to move the UI to a different root path, the // You can protect the user interface with a userid and password by using the following property.
// The password must be an md5 hash eg.. 5f4dcc3b5aa765d61d8327deb882cf99 ('password')
//httpAdminAuth: {user:"user",pass:"5f4dcc3b5aa765d61d8327deb882cf99"},
// Some nodes, such as HTTP In, can be used to listen for incoming http requests.
// By default, these are served relative to '/'. The following property
// can be used to specifiy a different root path.
//httpNodeRoot: '/nodes',
// To password protect the node-defined HTTP endpoints, the following property
// can be used.
// The password must be an md5 hash eg.. 5f4dcc3b5aa765d61d8327deb882cf99 ('password')
//httpNodeAuth: {user:"user",pass:"5f4dcc3b5aa765d61d8327deb882cf99"},
// When httpAdminRoot is used to move the UI to a different root path, the
// following property can be used to identify a directory of static content // following property can be used to identify a directory of static content
// that should be served at http://localhost:1880/. // that should be served at http://localhost:1880/.
//httpStatic: '/home/nol/node-red-dashboard/', //httpStatic: '/home/nol/node-red-dashboard/',
// To password protect the static content, the following property can be used.
// The password must be an md5 hash eg.. 5f4dcc3b5aa765d61d8327deb882cf99 ('password')
//httpStaticAuth: {user:"user",pass:"5f4dcc3b5aa765d61d8327deb882cf99"},
// The following property can be used in place of 'httpAdminRoot' and 'httpNodeRoot',
// to apply the same root to both parts.
//httpRoot: '/red',
// The following property can be used in place of 'httpAdminAuth' and 'httpNodeAuth',
// to apply the same authentication to both parts.
//httpAuth: {user:"user",pass:"5f4dcc3b5aa765d61d8327deb882cf99"},
// The following property can be used to enable HTTPS // The following property can be used to enable HTTPS
// See http://nodejs.org/api/https.html#https_https_createserver_options_requestlistener // See http://nodejs.org/api/https.html#https_https_createserver_options_requestlistener
// for details on its contents. // for details on its contents.
@ -70,6 +92,15 @@ module.exports = {
// cert: fs.readFileSync('certificate.pem') // cert: fs.readFileSync('certificate.pem')
//}, //},
// The following property can be used to configure cross-origin resource sharing
// in the HTTP nodes.
// See https://github.com/troygoode/node-cors#configuration-options for
// details on its contents. The following is a basic permissive set of options:
//httpNodeCors: {
// origin: "*",
// methods: "GET,PUT,POST,DELETE"
//},
// Anything in this hash is globally available to all functions. // Anything in this hash is globally available to all functions.
// It is accessed as context.global. // It is accessed as context.global.
// eg: // eg: