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

WIP: add flow api

This commit is contained in:
Nick O'Leary 2015-12-06 22:49:51 +00:00
parent d5f2255a68
commit fd2e47ed73
5 changed files with 203 additions and 6 deletions

32
red/api/flow.js Normal file
View File

@ -0,0 +1,32 @@
/**
* Copyright 2014, 2015 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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 log;
var redNodes;
var settings;
module.exports = {
init: function(runtime) {
settings = runtime.settings;
redNodes = runtime.nodes;
log = runtime.log;
},
get: function(req,res) {
var id = req.params.id;
log.audit({event: "flow.get"},req);
res.json(redNodes.getFlow(id));
}
}

View File

@ -24,6 +24,7 @@ var when = require('when');
var ui = require("./ui"); var ui = require("./ui");
var nodes = require("./nodes"); var nodes = require("./nodes");
var flows = require("./flows"); var flows = require("./flows");
var flow = require("./flow");
var library = require("./library"); var library = require("./library");
var info = require("./info"); var info = require("./info");
var theme = require("./theme"); var theme = require("./theme");
@ -64,6 +65,7 @@ function init(_server,runtime) {
auth.init(runtime); auth.init(runtime);
credentials.init(runtime); credentials.init(runtime);
flows.init(runtime); flows.init(runtime);
flow.init(runtime);
info.init(runtime); info.init(runtime);
library.init(adminApp,runtime); library.init(adminApp,runtime);
locales.init(runtime); locales.init(runtime);
@ -103,6 +105,8 @@ function init(_server,runtime) {
adminApp.get("/flows",needsPermission("flows.read"),flows.get); adminApp.get("/flows",needsPermission("flows.read"),flows.get);
adminApp.post("/flows",needsPermission("flows.write"),flows.post); adminApp.post("/flows",needsPermission("flows.write"),flows.post);
adminApp.get("/flow/:id",needsPermission("flows.read"),flow.get);
// Nodes // Nodes
adminApp.get("/nodes",needsPermission("nodes.read"),nodes.getAll); adminApp.get("/nodes",needsPermission("nodes.read"),nodes.getAll);
adminApp.post("/nodes",needsPermission("nodes.write"),nodes.post); adminApp.post("/nodes",needsPermission("nodes.write"),nodes.post);

View File

@ -352,6 +352,81 @@ function checkTypeInUse(id) {
} }
} }
function addFlow(flow) {
/*
{
id:'',
label:'',
nodes:[]
}
*/
// flow.id should not exist - it will be assigned by the runtime
// all flow.{subflows|configs|nodes}.z will be set to flow.id
// all nodes will have new ids assigned if there is a clash
// check all known types - fail if otherwise?
//
// resolves with generated flow id
return when.promise(function(resolve,reject) {
var i,id,node;
flow.id = redUtil.generateId();
for (i=0;i<flow.nodes.length;i++) {
node = flow.nodes[i];
if (activeFlowConfig.allNodes[node.id]) {
// TODO nls
return reject(new Error('duplicate id'));
}
node.z = flow.id;
}
var tabNode = {
type:'tab',
label:flow.label,
id:flow.id
}
var nodes = [tabNode].concat(flow.nodes);
var parsedConfig = flowUtil.parseConfig(clone(nodes));
// TODO: handle unknown type
for (id in parsedConfig.flows[flow.id]) {
if (parsedConfig.flows[flow.id].hasOwnProperty(id)) {
activeFlowConfig.allNodes[id] = parsedConfig.flows[flow.id][id];
}
}
activeFlowConfig.flows[flow.id] = parsedConfig.flows[flow.id];
activeConfig = activeConfig.concat(nodes);
// TODO: extract creds
// TODO: save config
start("flows",{added:flow.nodes.map(function(n) { return n.id})}).then(function() {
// console.log(activeFlowConfig);
resolve(flow.id);
})
})
}
function getFlow(id) {
var flow = activeFlowConfig.flows[id];
if (!flow) {
return null;
}
var result = {
id: id,
label: flow.label,
nodes: []
};
for (var i=0;i<activeConfig.length;i++) {
if (activeConfig[i].z === id && activeConfig[i].type != 'tab') {
result.nodes.push(activeConfig[i]);
}
}
return result;
}
module.exports = { module.exports = {
init: init, init: init,
@ -388,11 +463,19 @@ module.exports = {
*/ */
stopFlows: stop, stopFlows: stop,
started: function() { return started }, get started() { return started },
handleError: handleError, handleError: handleError,
handleStatus: handleStatus, handleStatus: handleStatus,
checkTypeInUse: checkTypeInUse checkTypeInUse: checkTypeInUse,
addFlow: addFlow,
getFlow: getFlow,
updateFlow:null,
removeFlow:null,
disableFlow:null,
enableFlow:null
}; };

View File

@ -120,11 +120,19 @@ module.exports = {
cleanModuleList: registry.cleanModuleList, cleanModuleList: registry.cleanModuleList,
// Flow handling // Flow handling
loadFlows: flows.load, loadFlows: flows.load,
startFlows: flows.startFlows, startFlows: flows.startFlows,
stopFlows: flows.stopFlows, stopFlows: flows.stopFlows,
setFlows: flows.setFlows, setFlows: flows.setFlows,
getFlows: flows.getFlows, getFlows: flows.getFlows,
addFlow: flows.addFlow,
getFlow: flows.getFlow,
updateFlow: flows.updateFlow,
removeFlow: flows.removeFlow,
disableFlow: flows.disableFlow,
enableFlow: flows.enableFlow,
// Credentials // Credentials
addCredentials: credentials.add, addCredentials: credentials.add,

View File

@ -497,4 +497,74 @@ describe('flows/index', function() {
}); });
}); });
}); });
describe('#addFlow', function() {
it("rejects duplicate node id",function(done) {
var originalConfig = [
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
{id:"t1",type:"tab"}
];
storage.getFlows = function() {
return when.resolve(originalConfig);
}
flows.init({},storage);
flows.load().then(function() {
flows.addFlow({
label:'new flow',
nodes:[
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]}
]
}).then(function() {
done(new Error('failed to reject duplicate node id'));
}).otherwise(function(err) {
done();
})
});
});
it("addFlow",function(done) {
var originalConfig = [
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
{id:"t1",type:"tab"}
];
storage.getFlows = function() {
return when.resolve(originalConfig);
}
flows.init({},storage);
flows.load().then(function() {
return flows.startFlows();
}).then(function() {
flows.addFlow({
label:'new flow',
nodes:[
{id:"t2-1",x:10,y:10,z:"t1",type:"test",wires:[]},
{id:"t2-2",x:10,y:10,z:"t1",type:"test",wires:[]},
{id:"t2-3",z:"t1",type:"test"}
]
}).then(function(id) {
flows.getFlows().should.have.lengthOf(6);
var createdFlows = Object.keys(flowCreate.flows);
createdFlows.should.have.lengthOf(3);
createdFlows[2].should.eql(id);
done();
}).otherwise(function(err) {
done(err);
})
});
});
})
describe('#updateFlow', function() {
it.skip("updateFlow");
})
describe('#removeFlow', function() {
it.skip("removeFlow");
})
describe('#disableFlow', function() {
it.skip("disableFlow");
})
describe('#enableFlow', function() {
it.skip("enableFlow");
})
}); });