WIP: create new runtime-api

This commit is contained in:
Nick O'Leary
2018-04-15 11:18:10 +01:00
parent e8a637498d
commit e8e8f70c27
22 changed files with 1422 additions and 611 deletions

View File

@@ -14,72 +14,56 @@
* limitations under the License.
**/
var log;
var redNodes;
var runtimeAPI;
var apiUtils = require("../util");
module.exports = {
init: function(runtime) {
redNodes = runtime.nodes;
log = runtime.log;
init: function(_runtimeAPI) {
runtimeAPI = _runtimeAPI;
},
get: function(req,res) {
var id = req.params.id;
var flow = redNodes.getFlow(id);
if (flow) {
log.audit({event: "flow.get",id:id},req);
res.json(flow);
} else {
log.audit({event: "flow.get",id:id,error:"not_found"},req);
res.status(404).end();
var opts = {
user: req.user,
id: req.params.id
}
runtimeAPI.flows.getFlow(opts).then(function(result) {
return res.json(result);
}).catch(function(err) {
apiUtils.rejectHandler(req,res,err);
})
},
post: function(req,res) {
var flow = req.body;
redNodes.addFlow(flow).then(function(id) {
log.audit({event: "flow.add",id:id},req);
res.json({id:id});
var opts = {
user: req.user,
flow: req.body
}
runtimeAPI.flows.addFlow(opts).then(function(id) {
return res.json({id:id});
}).catch(function(err) {
log.audit({event: "flow.add",error:err.code||"unexpected_error",message:err.toString()},req);
res.status(400).json({error:err.code||"unexpected_error", message:err.toString()});
apiUtils.rejectHandler(req,res,err);
})
},
put: function(req,res) {
var id = req.params.id;
var flow = req.body;
try {
redNodes.updateFlow(id,flow).then(function() {
log.audit({event: "flow.update",id:id},req);
res.json({id:id});
}).catch(function(err) {
log.audit({event: "flow.update",error:err.code||"unexpected_error",message:err.toString()},req);
res.status(400).json({error:err.code||"unexpected_error", message:err.toString()});
})
} catch(err) {
if (err.code === 404) {
log.audit({event: "flow.update",id:id,error:"not_found"},req);
res.status(404).end();
} else {
log.audit({event: "flow.update",error:err.code||"unexpected_error",message:err.toString()},req);
res.status(400).json({error:err.code||"unexpected_error", message:err.toString()});
}
var opts = {
user: req.user,
id: req.params.id,
flow: req.body
}
runtimeAPI.flows.updateFlow(opts).then(function(id) {
return res.json({id:id});
}).catch(function(err) {
apiUtils.rejectHandler(req,res,err);
})
},
delete: function(req,res) {
var id = req.params.id;
try {
redNodes.removeFlow(id).then(function() {
log.audit({event: "flow.remove",id:id},req);
res.status(204).end();
})
} catch(err) {
if (err.code === 404) {
log.audit({event: "flow.remove",id:id,error:"not_found"},req);
res.status(404).end();
} else {
log.audit({event: "flow.remove",id:id,error:err.code||"unexpected_error",message:err.toString()},req);
res.status(400).json({error:err.code||"unexpected_error", message:err.toString()});
}
var opts = {
user: req.user,
id: req.params.id
}
runtimeAPI.flows.deleteFlow(opts).then(function() {
res.status(204).end();
}).catch(function(err) {
apiUtils.rejectHandler(req,res,err);
})
}
}

View File

@@ -14,72 +14,56 @@
* limitations under the License.
**/
var log;
var redNodes;
var runtimeAPI;
module.exports = {
init: function(runtime) {
redNodes = runtime.nodes;
log = runtime.log;
init: function(_runtimeAPI) {
runtimeAPI = _runtimeAPI;
},
get: function(req,res) {
var version = req.get("Node-RED-API-Version")||"v1";
if (version === "v1") {
log.audit({event: "flows.get",version:"v1"},req);
res.json(redNodes.getFlows().flows);
} else if (version === "v2") {
log.audit({event: "flows.get",version:"v2"},req);
res.json(redNodes.getFlows());
} else {
log.audit({event: "flows.get",version:version,error:"invalid_api_version"},req);
res.status(400).json({code:"invalid_api_version", message:"Invalid API Version requested"});
if (!/^v[12]$/.test(version)) {
return res.status(500).json({code:"invalid_api_version", message:"Invalid API Version requested"});
}
var opts = {
user: req.user
}
runtimeAPI.flows.getFlows(opts).then(function(result) {
if (version === "v1") {
res.json(result.flows);
} else if (version === "v2") {
res.json(result);
}
}).catch(function(err) {
apiUtils.rejectHandler(req,res,err);
})
},
post: function(req,res) {
var version = req.get("Node-RED-API-Version")||"v1";
if (!/^v[12]$/.test(version)) {
log.audit({event: "flows.set",version:version,error:"invalid_api_version"},req);
res.status(400).json({code:"invalid_api_version", message:"Invalid API Version requested"});
return;
return res.status(500).json({code:"invalid_api_version", message:"Invalid API Version requested"});
}
var flows = req.body;
var deploymentType = req.get("Node-RED-Deployment-Type")||"full";
log.audit({event: "flows.set",type:deploymentType,version:version},req);
if (deploymentType === 'reload') {
redNodes.loadFlows().then(function(flowId) {
if (version === "v1") {
res.status(204).end();
} else {
res.json({rev:flowId});
}
}).catch(function(err) {
log.warn(log._("api.flows.error-reload",{message:err.message}));
log.warn(err.stack);
res.status(500).json({error:"unexpected_error", message:err.message});
});
} else {
var flowConfig = flows;
if (version === "v2") {
flowConfig = flows.flows;
if (flows.hasOwnProperty('rev')) {
var currentVersion = redNodes.getFlows().rev;
if (currentVersion !== flows.rev) {
//TODO: log warning
return res.status(409).json({code:"version_mismatch"});
}
}
var opts = {
user: req.user,
deploymentType: req.get("Node-RED-Deployment-Type")||"full"
}
if (opts.deploymentType !== 'reload') {
if (version === "v1") {
opts.flows = {flows: req.body}
} else {
opts.flows = req.body;
}
redNodes.setFlows(flowConfig,deploymentType).then(function(flowId) {
if (version === "v1") {
res.status(204).end();
} else if (version === "v2") {
res.json({rev:flowId});
}
}).catch(function(err) {
log.warn(log._("api.flows.error-save",{message:err.message}));
log.warn(err.stack);
res.status(500).json({error:err.code || "unexpected_error", message:err.message});
});
}
runtimeAPI.flows.setFlows(opts).then(function(result) {
if (version === "v1") {
res.status(204).end();
} else {
res.json(result);
}
}).catch(function(err) {
apiUtils.rejectHandler(req,res,err);
})
}
}

View File

@@ -24,10 +24,10 @@ var auth = require("../auth");
var apiUtil = require("../util");
module.exports = {
init: function(runtime) {
flows.init(runtime);
flow.init(runtime);
nodes.init(runtime);
init: function(runtimeAPI) {
flows.init(runtimeAPI);
flow.init(runtimeAPI);
nodes.init(runtimeAPI);
var needsPermission = auth.needsPermission;

View File

@@ -14,230 +14,133 @@
* limitations under the License.
**/
var when = require("when");
var apiUtils = require("../util");
var redNodes;
var log;
var settings;
var runtimeAPI;
module.exports = {
init: function(runtime) {
redNodes = runtime.nodes;
log = runtime.log;
settings = runtime.settings;
init: function(_runtimeAPI) {
runtimeAPI = _runtimeAPI;
},
getAll: function(req,res) {
var opts = {
user: req.user
}
if (req.get("accept") == "application/json") {
log.audit({event: "nodes.list.get"},req);
res.json(redNodes.getNodeList());
runtimeAPI.nodes.getNodeList(opts).then(function(list) {
res.json(list);
})
} else {
var lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages());
log.audit({event: "nodes.configs.get"},req);
res.send(redNodes.getNodeConfigs(lang));
opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages());
runtimeAPI.nodes.getNodeConfigs(opts).then(function(configs) {
res.send(configs);
})
}
},
post: function(req,res) {
if (!settings.available()) {
log.audit({event: "nodes.install",error:"settings_unavailable"},req);
res.status(400).json({error:"settings_unavailable", message:"Settings unavailable"});
return;
var opts = {
user: req.user,
module: req.body.module,
version: req.body.version
}
var node = req.body;
var promise;
var isUpgrade = false;
if (node.module) {
var module = redNodes.getModuleInfo(node.module);
if (module) {
if (!node.version || module.version === node.version) {
log.audit({event: "nodes.install",module:node.module, version:node.version, error:"module_already_loaded"},req);
res.status(400).json({error:"module_already_loaded", message:"Module already loaded"});
return;
}
if (!module.local) {
log.audit({event: "nodes.install",module:node.module, version:node.version, error:"module_not_local"},req);
res.status(400).json({error:"module_not_local", message:"Module not locally installed"});
return;
}
isUpgrade = true;
}
promise = redNodes.installModule(node.module,node.version);
} else {
log.audit({event: "nodes.install",module:node.module,error:"invalid_request"},req);
res.status(400).json({error:"invalid_request", message:"Invalid request"});
return;
}
promise.then(function(info) {
if (node.module) {
log.audit({event: "nodes.install",module:node.module,version:node.version},req);
res.json(info);
}
runtimeAPI.nodes.addModule(opts).then(function(info) {
res.json(info);
}).catch(function(err) {
if (err.code === 404) {
log.audit({event: "nodes.install",module:node.module,version:node.version,error:"not_found"},req);
res.status(404).end();
} else if (err.code) {
log.audit({event: "nodes.install",module:node.module,version:node.version,error:err.code},req);
res.status(400).json({error:err.code, message:err.message});
} else {
log.audit({event: "nodes.install",module:node.module,version:node.version,error:err.code||"unexpected_error",message:err.toString()},req);
res.status(400).json({error:err.code||"unexpected_error", message:err.toString()});
}
});
apiUtils.rejectHandler(req,res,err);
})
},
delete: function(req,res) {
if (!settings.available()) {
log.audit({event: "nodes.remove",error:"settings_unavailable"},req);
res.status(400).json({error:"settings_unavailable", message:"Settings unavailable"});
return;
}
var mod = req.params[0];
try {
var promise = null;
var module = redNodes.getModuleInfo(mod);
if (!module) {
log.audit({event: "nodes.remove",module:mod,error:"not_found"},req);
res.status(404).end();
return;
} else {
promise = redNodes.uninstallModule(mod);
}
promise.then(function(list) {
log.audit({event: "nodes.remove",module:mod},req);
res.status(204).end();
}).catch(function(err) {
log.audit({event: "nodes.remove",module:mod,error:err.code||"unexpected_error",message:err.toString()},req);
res.status(400).json({error:err.code||"unexpected_error", message:err.toString()});
});
} catch(err) {
log.audit({event: "nodes.remove",module:mod,error:err.code||"unexpected_error",message:err.toString()},req);
res.status(400).json({error:err.code||"unexpected_error", message:err.toString()});
var opts = {
user: req.user,
module: req.params[0]
}
runtimeAPI.nodes.removeModule(opts).then(function(info) {
res.status(204).end();
}).catch(function(err) {
apiUtils.rejectHandler(req,res,err);
})
},
getSet: function(req,res) {
var id = req.params[0] + "/" + req.params[2];
var result = null;
var opts = {
user: req.user,
id: req.params[0] + "/" + req.params[2]
}
if (req.get("accept") === "application/json") {
result = redNodes.getNodeInfo(id);
if (result) {
log.audit({event: "nodes.info.get",id:id},req);
delete result.loaded;
runtimeAPI.nodes.getNodeInfo(opts).then(function(result) {
res.send(result);
} else {
log.audit({event: "nodes.info.get",id:id,error:"not_found"},req);
res.status(404).end();
}
}).catch(function(err) {
apiUtils.rejectHandler(req,res,err);
})
} else {
var lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages());
result = redNodes.getNodeConfig(id,lang);
if (result) {
log.audit({event: "nodes.config.get",id:id},req);
res.send(result);
} else {
log.audit({event: "nodes.config.get",id:id,error:"not_found"},req);
res.status(404).end();
}
opts.lang = apiUtils.determineLangFromHeaders(req.acceptsLanguages());
runtimeAPI.nodes.getNodeConfig(opts).then(function(result) {
return res.json(result);
}).catch(function(err) {
apiUtils.rejectHandler(req,res,err);
})
}
},
getModule: function(req,res) {
var module = req.params[0];
var result = redNodes.getModuleInfo(module);
if (result) {
log.audit({event: "nodes.module.get",module:module},req);
res.json(result);
} else {
log.audit({event: "nodes.module.get",module:module,error:"not_found"},req);
res.status(404).end();
var opts = {
user: req.user,
module: req.params[0]
}
runtimeAPI.nodes.getModuleInfo(opts).then(function(result) {
res.send(result);
}).catch(function(err) {
apiUtils.rejectHandler(req,res,err);
})
},
putSet: function(req,res) {
if (!settings.available()) {
log.audit({event: "nodes.info.set",error:"settings_unavailable"},req);
res.status(400).json({error:"settings_unavailable", message:"Settings unavailable"});
return;
}
var body = req.body;
if (!body.hasOwnProperty("enabled")) {
log.audit({event: "nodes.info.set",error:"invalid_request"},req);
// log.audit({event: "nodes.module.set",error:"invalid_request"},req);
res.status(400).json({error:"invalid_request", message:"Invalid request"});
return;
}
var id = req.params[0] + "/" + req.params[2];
try {
var node = redNodes.getNodeInfo(id);
var info;
if (!node) {
log.audit({event: "nodes.info.set",id:id,error:"not_found"},req);
res.status(404).end();
} else {
delete node.loaded;
putNode(node, body.enabled).then(function(result) {
log.audit({event: "nodes.info.set",id:id,enabled:body.enabled},req);
res.json(result);
});
}
} catch(err) {
log.audit({event: "nodes.info.set",id:id,enabled:body.enabled,error:err.code||"unexpected_error",message:err.toString()},req);
res.status(400).json({error:err.code||"unexpected_error", message:err.toString()});
var opts = {
user: req.user,
id: req.params[0] + "/" + req.params[2],
enabled: body.enabled
}
runtimeAPI.nodes.setNodeSetState(opts).then(function(result) {
res.send(result);
}).catch(function(err) {
apiUtils.rejectHandler(req,res,err);
})
},
putModule: function(req,res) {
if (!settings.available()) {
log.audit({event: "nodes.module.set",error:"settings_unavailable"},req);
res.status(400).json({error:"settings_unavailable", message:"Settings unavailable"});
return;
}
var body = req.body;
if (!body.hasOwnProperty("enabled")) {
log.audit({event: "nodes.module.set",error:"invalid_request"},req);
// log.audit({event: "nodes.module.set",error:"invalid_request"},req);
res.status(400).json({error:"invalid_request", message:"Invalid request"});
return;
}
var mod = req.params[0];
try {
var module = redNodes.getModuleInfo(mod);
if (!module) {
log.audit({event: "nodes.module.set",module:mod,error:"not_found"},req);
return res.status(404).end();
}
var nodes = module.nodes;
var promises = [];
for (var i = 0; i < nodes.length; ++i) {
promises.push(putNode(nodes[i],body.enabled));
}
when.settle(promises).then(function() {
res.json(redNodes.getModuleInfo(mod));
});
} catch(err) {
log.audit({event: "nodes.module.set",module:mod,enabled:body.enabled,error:err.code||"unexpected_error",message:err.toString()},req);
res.status(400).json({error:err.code||"unexpected_error", message:err.toString()});
var opts = {
user: req.user,
module: req.params[0],
enabled: body.enabled
}
runtimeAPI.nodes.setModuleState(opts).then(function(result) {
res.send(result);
}).catch(function(err) {
apiUtils.rejectHandler(req,res,err);
})
},
getIcons: function(req,res) {
log.audit({event: "nodes.icons.get"},req);
res.json(redNodes.getNodeIcons());
var opts = {
user: req.user
}
runtimeAPI.nodes.getIconList(opts).then(function(list) {
res.json(list);
});
}
};
function putNode(node, enabled) {
var info;
var promise;
if (!node.err && node.enabled === enabled) {
promise = when.resolve(node);
} else {
if (enabled) {
promise = redNodes.enableNode(node.id);
} else {
promise = redNodes.disableNode(node.id);
}
}
return promise;
}