diff --git a/red/api/flows.js b/red/api/flows.js new file mode 100644 index 000000000..a7ef22311 --- /dev/null +++ b/red/api/flows.js @@ -0,0 +1,37 @@ +/** + * Copyright 2014 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 express = require('express'); +var fs = require("fs"); +var events = require("../events"); +var path = require("path"); + +var redNodes = require("../nodes"); +var settings = require("../settings"); + +module.exports = { + get: function(req,res) { + res.json(redNodes.getFlows()); + }, + post: function(req,res) { + var flows = req.body; + redNodes.setFlows(flows).then(function() { + res.send(204); + }).otherwise(function(err) { + util.log("[red] Error saving flows : "+err); + res.send(500,err.message); + }); + } +} diff --git a/red/api/index.js b/red/api/index.js new file mode 100644 index 000000000..f56f6c40e --- /dev/null +++ b/red/api/index.js @@ -0,0 +1,68 @@ +/** + * Copyright 2014 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 express = require("express"); +var util = require('util'); + +var ui = require("./ui"); +var nodes = require("./nodes"); +var flows = require("./flows"); +var library = require("./library"); + +var settings = require("../settings"); + +var errorHandler = function(err,req,res,next) { + //TODO: standardize json response + res.send(400,err.toString()); +} + +function init(adminApp) { + + library.init(adminApp); + + adminApp.use(express.json()); + + // Editor + if (!settings.disableEditor) { + adminApp.get("/",ui.ensureSlash); + adminApp.get("/icons/:icon",ui.icon); + adminApp.get("/settings",ui.settings); + adminApp.use("/",ui.editor); + } + + // Flows + adminApp.get("/flows",flows.get); + adminApp.post("/flows",flows.post); + + // Nodes + adminApp.get("/nodes",nodes.getAll); + adminApp.post("/nodes",nodes.post); + + adminApp.get("/nodes/:id",nodes.get); + adminApp.put("/nodes/:id",nodes.put); + adminApp.delete("/nodes/:id",nodes.delete); + + // Library + adminApp.post(new RegExp("/library/flows\/(.*)"),library.post); + adminApp.get("/library/flows",library.getAll); + adminApp.get(new RegExp("/library/flows\/(.*)"),library.get); + + adminApp.use(errorHandler); +} + +module.exports = { + init: init +} diff --git a/red/api/library.js b/red/api/library.js new file mode 100644 index 000000000..9ad0d99ff --- /dev/null +++ b/red/api/library.js @@ -0,0 +1,111 @@ +/** + * Copyright 2013, 2014 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 util = require("util"); + +var redApp = null; +var storage = require("../storage"); + +function createLibrary(type) { + + redApp.get(new RegExp("/library/"+type+"($|\/(.*))"),function(req,res) { + var path = req.params[1]||""; + storage.getLibraryEntry(type,path).then(function(result) { + if (typeof result === "string") { + res.writeHead(200, {'Content-Type': 'text/plain'}); + res.write(result); + res.end(); + } else { + res.json(result); + } + }).otherwise(function(err) { + if (err) { + util.log("[red] Error loading library entry '"+path+"' : "+err); + if (err.message.indexOf('forbidden') === 0) { + res.send(403); + return; + } + } + res.send(404); + }); + }); + + redApp.post(new RegExp("/library/"+type+"\/(.*)"),function(req,res) { + var path = req.params[0]; + var fullBody = ''; + req.on('data', function(chunk) { + fullBody += chunk.toString(); + }); + req.on('end', function() { + storage.saveLibraryEntry(type,path,req.query,fullBody).then(function() { + res.send(204); + }).otherwise(function(err) { + util.log("[red] Error saving library entry '"+path+"' : "+err); + if (err.message.indexOf('forbidden') === 0) { + res.send(403); + return; + } + res.send(500); + }); + }); + }); +} +module.exports = { + init: function(app) { + redApp = app; + }, + register: createLibrary, + + getAll: function(req,res) { + storage.getAllFlows().then(function(flows) { + res.json(flows); + }); + }, + get: function(req,res) { + storage.getFlow(req.params[0]).then(function(data) { + res.set('Content-Type', 'application/json'); + res.send(data); + }).otherwise(function(err) { + if (err) { + util.log("[red] Error loading flow '"+req.params[0]+"' : "+err); + if (err.message.indexOf('forbidden') === 0) { + res.send(403); + return; + } + } + res.send(404); + }); + }, + post: function(req,res) { + //TODO: do content-type properly + var fullBody = ''; + req.on('data', function(chunk) { + fullBody += chunk.toString(); + }); + req.on('end', function() { + storage.saveFlow(req.params[0],fullBody).then(function() { + res.send(204); + }).otherwise(function(err) { + util.log("[red] Error loading flow '"+req.params[0]+"' : "+err); + if (err.message.indexOf('forbidden') === 0) { + res.send(403); + return; + } + res.send(500); + }); + }); + } +} diff --git a/red/api/nodes.js b/red/api/nodes.js new file mode 100644 index 000000000..793461771 --- /dev/null +++ b/red/api/nodes.js @@ -0,0 +1,156 @@ +/** + * Copyright 2014 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 express = require('express'); +var fs = require("fs"); +var path = require("path"); +var when = require('when'); +var util = require('util'); + +var events = require("../events"); +var redNodes = require("../nodes"); +var comms = require("../comms"); +var server = require("../server"); + +var settings = require("../settings"); + +module.exports = { + getAll: function(req,res) { + if (req.get("accept") == "application/json") { + res.json(redNodes.getNodeList()); + } else { + res.send(redNodes.getNodeConfigs()); + } + }, + post: function(req,res) { + if (!settings.available()) { + res.send(400,new Error("Settings unavailable").toString()); + return; + } + var node = req.body; + var promise; + if (node.file) { + promise = redNodes.addNode(node.file).then(server.reportAddedModules); + } else if (node.module) { + var module = redNodes.getNodeModuleInfo(node.module); + if (module) { + res.send(400,"Module already loaded"); + return; + } + promise = server.installModule(node.module); + } else { + res.send(400,"Invalid request"); + return; + } + promise.then(function(info) { + res.json(info); + }).otherwise(function(err) { + if (err.code === 404) { + res.send(404); + } else { + res.send(400,err.toString()); + } + }); + }, + + delete: function(req,res) { + if (!settings.available()) { + res.send(400,new Error("Settings unavailable").toString()); + return; + } + var id = req.params.id; + var removedNodes = []; + try { + var node = redNodes.getNodeInfo(id); + var promise = null; + if (!node) { + var module = redNodes.getNodeModuleInfo(id); + if (!module) { + res.send(404); + return; + } else { + promise = server.uninstallModule(id); + } + } else { + promise = when.resolve([redNodes.removeNode(id)]).then(server.reportRemovedModules); + } + + promise.then(function(removedNodes) { + res.json(removedNodes); + }).otherwise(function(err) { + console.log(err.stack); + res.send(400,err.toString()); + }); + } catch(err) { + res.send(400,err.toString()); + } + }, + + get: function(req,res) { + var id = req.params.id; + var result = null; + if (req.get("accept") == "application/json") { + result = redNodes.getNodeInfo(id); + } else { + result = redNodes.getNodeConfig(id); + } + if (result) { + res.send(result); + } else { + res.send(404); + } + }, + + put: function(req,res) { + if (!settings.available()) { + res.send(400,new Error("Settings unavailable").toString()); + return; + } + var body = req.body; + if (!body.hasOwnProperty("enabled")) { + res.send(400,"Invalid request"); + return; + } + try { + var info; + var id = req.params.id; + var node = redNodes.getNodeInfo(id); + if (!node) { + res.send(404); + } else if (!node.err && node.enabled === body.enabled) { + res.json(node); + } else { + if (body.enabled) { + info = redNodes.enableNode(id); + } else { + info = redNodes.disableNode(id); + } + if (info.enabled == body.enabled && !info.err) { + comms.publish("node/"+(body.enabled?"enabled":"disabled"),info,false); + util.log("[red] "+(body.enabled?"Enabled":"Disabled")+" node types:"); + for (var i=0;i 0) { + util.log("------------------------------------------"); + if (settings.verbose) { + for (i=0;i 0) { + util.log("[red] Missing node modules:"); + var missingModules = {}; + for (i=0;i 0) { @@ -292,72 +194,7 @@ function uninstallModule(module) { }); } -function start() { - var defer = when.defer(); - - storage.init(settings).then(function() { - settings.load(storage).then(function() { - console.log("\nWelcome to Node-RED\n===================\n"); - if (settings.version) { - util.log("[red] Version: "+settings.version); - } - util.log("[red] Loading palette nodes"); - redNodes.init(settings,storage); - redNodes.load().then(function() { - var i; - var nodes = redNodes.getNodeList(); - var nodeErrors = nodes.filter(function(n) { return n.err!=null;}); - var nodeMissing = nodes.filter(function(n) { return n.module && n.enabled && !n.loaded && !n.err;}); - if (nodeErrors.length > 0) { - util.log("------------------------------------------"); - if (settings.verbose) { - for (i=0;i 0) { - util.log("[red] Missing node modules:"); - var missingModules = {}; - for (i=0;i