@node-red/runtime
Advanced tools
Comparing version 1.2.9 to 1.3.0-beta.1
@@ -36,2 +36,3 @@ /** | ||
const events = require("@node-red/util").events; | ||
@@ -92,10 +93,10 @@ function handleCommsEvent(event) { | ||
retained = {}; | ||
runtime.events.removeListener("node-status",handleStatusEvent); | ||
runtime.events.on("node-status",handleStatusEvent); | ||
runtime.events.removeListener("runtime-event",handleRuntimeEvent); | ||
runtime.events.on("runtime-event",handleRuntimeEvent); | ||
runtime.events.removeListener("comms",handleCommsEvent); | ||
runtime.events.on("comms",handleCommsEvent); | ||
runtime.events.removeListener("event-log",handleEventLog); | ||
runtime.events.on("event-log",handleEventLog); | ||
events.removeListener("node-status",handleStatusEvent); | ||
events.on("node-status",handleStatusEvent); | ||
events.removeListener("runtime-event",handleRuntimeEvent); | ||
events.on("runtime-event",handleRuntimeEvent); | ||
events.removeListener("comms",handleCommsEvent); | ||
events.on("comms",handleCommsEvent); | ||
events.removeListener("event-log",handleEventLog); | ||
events.on("event-log",handleEventLog); | ||
}, | ||
@@ -111,5 +112,4 @@ | ||
*/ | ||
addConnection: function(opts) { | ||
addConnection: async function(opts) { | ||
connections.push(opts.client); | ||
return Promise.resolve(); | ||
}, | ||
@@ -125,3 +125,3 @@ | ||
*/ | ||
removeConnection: function(opts) { | ||
removeConnection: async function(opts) { | ||
for (var i=0;i<connections.length;i++) { | ||
@@ -133,3 +133,2 @@ if (connections[i] === opts.client) { | ||
} | ||
return Promise.resolve(); | ||
}, | ||
@@ -148,3 +147,3 @@ | ||
*/ | ||
subscribe: function(opts) { | ||
subscribe: async function(opts) { | ||
var re = new RegExp("^"+opts.topic.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$"); | ||
@@ -156,3 +155,2 @@ for (var t in retained) { | ||
} | ||
return Promise.resolve(); | ||
}, | ||
@@ -169,3 +167,3 @@ | ||
*/ | ||
unsubscribe: function(opts) {} | ||
unsubscribe: async function(opts) {} | ||
}; |
@@ -74,3 +74,3 @@ /** | ||
*/ | ||
getValue: function(opts) { | ||
getValue: async function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
@@ -169,3 +169,3 @@ var scope = opts.scope; | ||
*/ | ||
delete: function(opts) { | ||
delete: async function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
@@ -172,0 +172,0 @@ var scope = opts.scope; |
@@ -31,2 +31,3 @@ /*! | ||
api.context.init(runtime); | ||
api.plugins.init(runtime); | ||
}, | ||
@@ -41,9 +42,10 @@ | ||
context: require("./context"), | ||
plugins: require("./plugins"), | ||
isStarted: function(opts) { | ||
return Promise.resolve(runtime.isStarted()); | ||
isStarted: async function(opts) { | ||
return runtime.isStarted(); | ||
}, | ||
version: function(opts) { | ||
return Promise.resolve(runtime.version()); | ||
version: async function(opts) { | ||
return runtime.version(); | ||
} | ||
} |
@@ -28,2 +28,23 @@ /** | ||
// /* * | ||
// * Gets the configuration of a library source. | ||
// * @param {Object} opts | ||
// * @param {User} opts.user - the user calling the api | ||
// * @param {String} opts.library - the library | ||
// * @param {Object} opts.req - the request to log (optional) | ||
// * @return {Promise<String|Object>} - resolves when complete | ||
// * @memberof @node-red/runtime_library | ||
// */ | ||
// getConfig: async function(opts) { | ||
// runtime.log.audit({event: "library.getConfig",library:opts.library}, opts.req); | ||
// try { | ||
// return runtime.library.getConfig(opts.library) | ||
// } catch(err) { | ||
// var error = new Error(); | ||
// error.code = "not_found"; | ||
// error.status = 404; | ||
// throw error; | ||
// } | ||
// }, | ||
/** | ||
@@ -40,28 +61,26 @@ * Gets an entry from the library. | ||
*/ | ||
getEntry: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
runtime.library.getEntry(opts.library,opts.type,opts.path).then(function(result) { | ||
runtime.log.audit({event: "library.get",library:opts.library,type:opts.type,path:opts.path}, opts.req); | ||
return resolve(result); | ||
}).catch(function(err) { | ||
if (err) { | ||
runtime.log.warn(runtime.log._("api.library.error-load-entry",{library:opts.library,type:opts.type,path:opts.path,message:err.toString()})); | ||
if (err.code === 'forbidden') { | ||
err.status = 403; | ||
return reject(err); | ||
} else if (err.code === "not_found") { | ||
err.status = 404; | ||
} else { | ||
err.status = 400; | ||
} | ||
runtime.log.audit({event: "library.get",library:opts.library,type:opts.type,path:opts.path,error:err.code}, opts.req); | ||
return reject(err); | ||
getEntry: async function(opts) { | ||
return runtime.library.getEntry(opts.library,opts.type,opts.path).then(function(result) { | ||
runtime.log.audit({event: "library.get",library:opts.library,type:opts.type,path:opts.path}, opts.req); | ||
return result; | ||
}).catch(function(err) { | ||
if (err) { | ||
runtime.log.warn(runtime.log._("api.library.error-load-entry",{library:opts.library,type:opts.type,path:opts.path,message:err.toString()})); | ||
if (err.code === 'forbidden') { | ||
err.status = 403; | ||
throw err; | ||
} else if (err.code === "not_found") { | ||
err.status = 404; | ||
} else { | ||
err.status = 400; | ||
} | ||
runtime.log.audit({event: "library.get",library:opts.library,type:opts.type,error:"not_found"}, opts.req); | ||
var error = new Error(); | ||
error.code = "not_found"; | ||
error.status = 404; | ||
return reject(error); | ||
}); | ||
}) | ||
runtime.log.audit({event: "library.get",library:opts.library,type:opts.type,path:opts.path,error:err.code}, opts.req); | ||
throw err; | ||
} | ||
runtime.log.audit({event: "library.get",library:opts.library,type:opts.type,error:"not_found"}, opts.req); | ||
var error = new Error(); | ||
error.code = "not_found"; | ||
error.status = 404; | ||
throw error; | ||
}); | ||
}, | ||
@@ -82,21 +101,18 @@ | ||
*/ | ||
saveEntry: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
runtime.library.saveEntry(opts.library,opts.type,opts.path,opts.meta,opts.body).then(function() { | ||
runtime.log.audit({event: "library.set",type:opts.type,path:opts.path}, opts.req); | ||
return resolve(); | ||
}).catch(function(err) { | ||
runtime.log.warn(runtime.log._("api.library.error-save-entry",{path:opts.path,message:err.toString()})); | ||
if (err.code === 'forbidden') { | ||
runtime.log.audit({event: "library.set",type:opts.type,path:opts.path,error:"forbidden"}, opts.req); | ||
err.status = 403; | ||
return reject(err); | ||
} | ||
runtime.log.audit({event: "library.set",type:opts.type,path:opts.path,error:"unexpected_error",message:err.toString()}, opts.req); | ||
var error = new Error(); | ||
error.status = 400; | ||
return reject(error); | ||
}); | ||
}) | ||
saveEntry: async function(opts) { | ||
return runtime.library.saveEntry(opts.library,opts.type,opts.path,opts.meta,opts.body).then(function() { | ||
runtime.log.audit({event: "library.set",type:opts.type,path:opts.path}, opts.req); | ||
}).catch(function(err) { | ||
runtime.log.warn(runtime.log._("api.library.error-save-entry",{path:opts.path,message:err.toString()})); | ||
if (err.code === 'forbidden') { | ||
runtime.log.audit({event: "library.set",type:opts.type,path:opts.path,error:"forbidden"}, opts.req); | ||
err.status = 403; | ||
throw err; | ||
} | ||
runtime.log.audit({event: "library.set",type:opts.type,path:opts.path,error:"unexpected_error",message:err.toString()}, opts.req); | ||
var error = new Error(); | ||
error.status = 400; | ||
throw error; | ||
}); | ||
} | ||
} |
@@ -21,3 +21,3 @@ /** | ||
var fs = require("fs"); | ||
var fs = require("fs-extra"); | ||
@@ -56,18 +56,16 @@ var runtime; | ||
*/ | ||
getNodeInfo: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
var id = opts.id; | ||
var result = runtime.nodes.getNodeInfo(id); | ||
if (result) { | ||
runtime.log.audit({event: "nodes.info.get",id:id}, opts.req); | ||
delete result.loaded; | ||
return resolve(result); | ||
} else { | ||
runtime.log.audit({event: "nodes.info.get",id:id,error:"not_found"}, opts.req); | ||
var err = new Error("Node not found"); | ||
err.code = "not_found"; | ||
err.status = 404; | ||
return reject(err); | ||
} | ||
}) | ||
getNodeInfo: async function(opts) { | ||
var id = opts.id; | ||
var result = runtime.nodes.getNodeInfo(id); | ||
if (result) { | ||
runtime.log.audit({event: "nodes.info.get",id:id}, opts.req); | ||
delete result.loaded; | ||
return result; | ||
} else { | ||
runtime.log.audit({event: "nodes.info.get",id:id,error:"not_found"}, opts.req); | ||
var err = new Error("Node not found"); | ||
err.code = "not_found"; | ||
err.status = 404; | ||
throw err; | ||
} | ||
}, | ||
@@ -83,7 +81,5 @@ | ||
*/ | ||
getNodeList: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
runtime.log.audit({event: "nodes.list.get"}, opts.req); | ||
return resolve(runtime.nodes.getNodeList()); | ||
}) | ||
getNodeList: async function(opts) { | ||
runtime.log.audit({event: "nodes.list.get"}, opts.req); | ||
return runtime.nodes.getNodeList(); | ||
}, | ||
@@ -101,22 +97,20 @@ | ||
*/ | ||
getNodeConfig: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
var id = opts.id; | ||
var lang = opts.lang; | ||
if (/[^0-9a-z=\-\*]/i.test(opts.lang)) { | ||
reject(new Error("Invalid language: "+opts.lang)); | ||
return | ||
} | ||
var result = runtime.nodes.getNodeConfig(id,lang); | ||
if (result) { | ||
runtime.log.audit({event: "nodes.config.get",id:id}, opts.req); | ||
return resolve(result); | ||
} else { | ||
runtime.log.audit({event: "nodes.config.get",id:id,error:"not_found"}, opts.req); | ||
var err = new Error("Node not found"); | ||
err.code = "not_found"; | ||
err.status = 404; | ||
return reject(err); | ||
} | ||
}); | ||
getNodeConfig: async function(opts) { | ||
var id = opts.id; | ||
var lang = opts.lang; | ||
if (/[^0-9a-z=\-\*]/i.test(opts.lang)) { | ||
reject(new Error("Invalid language: "+opts.lang)); | ||
return | ||
} | ||
var result = runtime.nodes.getNodeConfig(id,lang); | ||
if (result) { | ||
runtime.log.audit({event: "nodes.config.get",id:id}, opts.req); | ||
return result; | ||
} else { | ||
runtime.log.audit({event: "nodes.config.get",id:id,error:"not_found"}, opts.req); | ||
var err = new Error("Node not found"); | ||
err.code = "not_found"; | ||
err.status = 404; | ||
throw err; | ||
} | ||
}, | ||
@@ -132,11 +126,9 @@ /** | ||
*/ | ||
getNodeConfigs: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
runtime.log.audit({event: "nodes.configs.get"}, opts.req); | ||
if (/[^0-9a-z=\-\*]/i.test(opts.lang)) { | ||
reject(new Error("Invalid language: "+opts.lang)); | ||
return | ||
} | ||
return resolve(runtime.nodes.getNodeConfigs(opts.lang)); | ||
}); | ||
getNodeConfigs: async function(opts) { | ||
runtime.log.audit({event: "nodes.configs.get"}, opts.req); | ||
if (/[^0-9a-z=\-\*]/i.test(opts.lang)) { | ||
reject(new Error("Invalid language: "+opts.lang)); | ||
return | ||
} | ||
return runtime.nodes.getNodeConfigs(opts.lang); | ||
}, | ||
@@ -153,16 +145,14 @@ | ||
*/ | ||
getModuleInfo: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
var result = runtime.nodes.getModuleInfo(opts.module); | ||
if (result) { | ||
runtime.log.audit({event: "nodes.module.get",id:opts.module}, opts.req); | ||
return resolve(result); | ||
} else { | ||
runtime.log.audit({event: "nodes.module.get",id:opts.module,error:"not_found"}, opts.req); | ||
var err = new Error("Module not found"); | ||
err.code = "not_found"; | ||
err.status = 404; | ||
return reject(err); | ||
} | ||
}) | ||
getModuleInfo: async function(opts) { | ||
var result = runtime.nodes.getModuleInfo(opts.module); | ||
if (result) { | ||
runtime.log.audit({event: "nodes.module.get",id:opts.module}, opts.req); | ||
return result; | ||
} else { | ||
runtime.log.audit({event: "nodes.module.get",id:opts.module,error:"not_found"}, opts.req); | ||
var err = new Error("Module not found"); | ||
err.code = "not_found"; | ||
err.status = 404; | ||
throw err; | ||
} | ||
}, | ||
@@ -182,79 +172,74 @@ | ||
*/ | ||
addModule: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
if (!runtime.settings.available()) { | ||
runtime.log.audit({event: "nodes.install",error:"settings_unavailable"}, opts.req); | ||
var err = new Error("Settings unavailable"); | ||
err.code = "settings_unavailable"; | ||
addModule: async function(opts) { | ||
if (!runtime.settings.available()) { | ||
runtime.log.audit({event: "nodes.install",error:"settings_unavailable"}, opts.req); | ||
var err = new Error("Settings unavailable"); | ||
err.code = "settings_unavailable"; | ||
err.status = 400; | ||
throw err; | ||
} | ||
if (opts.tarball) { | ||
if (runtime.settings.externalModules && runtime.settings.externalModules.palette && runtime.settings.externalModules.palette.upload === false) { | ||
runtime.log.audit({event: "nodes.install",tarball:opts.tarball.file,error:"invalid_request"}, opts.req); | ||
var err = new Error("Invalid request"); | ||
err.code = "invalid_request"; | ||
err.status = 400; | ||
return reject(err); | ||
throw err; | ||
} | ||
if (opts.tarball) { | ||
if (runtime.settings.editorTheme && runtime.settings.editorTheme.palette && runtime.settings.editorTheme.palette.upload === false) { | ||
runtime.log.audit({event: "nodes.install",tarball:opts.tarball.file,error:"invalid_request"}, opts.req); | ||
var err = new Error("Invalid request"); | ||
err.code = "invalid_request"; | ||
if (opts.module || opts.version || opts.url) { | ||
runtime.log.audit({event: "nodes.install",tarball:opts.tarball.file,module:opts.module,error:"invalid_request"}, opts.req); | ||
var err = new Error("Invalid request"); | ||
err.code = "invalid_request"; | ||
err.status = 400; | ||
throw err; | ||
} | ||
return runtime.nodes.installModule(opts.tarball.buffer).then(function(info) { | ||
runtime.log.audit({event: "nodes.install",tarball:opts.tarball.file,module:info.id}, opts.req); | ||
return info; | ||
}).catch(function(err) { | ||
if (err.code) { | ||
err.status = 400; | ||
return reject(err); | ||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,url:opts.url,error:err.code}, opts.req); | ||
} else { | ||
err.status = 400; | ||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,url:opts.url,error:err.code||"unexpected_error",message:err.toString()}, opts.req); | ||
} | ||
if (opts.module || opts.version || opts.url) { | ||
runtime.log.audit({event: "nodes.install",tarball:opts.tarball.file,module:opts.module,error:"invalid_request"}, opts.req); | ||
var err = new Error("Invalid request"); | ||
err.code = "invalid_request"; | ||
throw err; | ||
}) | ||
} | ||
if (opts.module) { | ||
var existingModule = runtime.nodes.getModuleInfo(opts.module); | ||
if (existingModule && existingModule.user) { | ||
if (!opts.version || existingModule.version === opts.version) { | ||
runtime.log.audit({event: "nodes.install",module:opts.module, version:opts.version, error:"module_already_loaded"}, opts.req); | ||
var err = new Error("Module already loaded"); | ||
err.code = "module_already_loaded"; | ||
err.status = 400; | ||
return reject(err); | ||
throw err; | ||
} | ||
runtime.nodes.installModule(opts.tarball.buffer).then(function(info) { | ||
runtime.log.audit({event: "nodes.install",tarball:opts.tarball.file,module:info.id}, opts.req); | ||
return resolve(info); | ||
}).catch(function(err) { | ||
if (err.code) { | ||
err.status = 400; | ||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,url:opts.url,error:err.code}, opts.req); | ||
} else { | ||
err.status = 400; | ||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,url:opts.url,error:err.code||"unexpected_error",message:err.toString()}, opts.req); | ||
} | ||
return reject(err); | ||
}) | ||
return; | ||
} | ||
if (opts.module) { | ||
var existingModule = runtime.nodes.getModuleInfo(opts.module); | ||
if (existingModule) { | ||
if (!opts.version || existingModule.version === opts.version) { | ||
runtime.log.audit({event: "nodes.install",module:opts.module, version:opts.version, error:"module_already_loaded"}, opts.req); | ||
var err = new Error("Module already loaded"); | ||
err.code = "module_already_loaded"; | ||
err.status = 400; | ||
return reject(err); | ||
} | ||
return runtime.nodes.installModule(opts.module,opts.version,opts.url).then(function(info) { | ||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,url:opts.url}, opts.req); | ||
return info; | ||
}).catch(function(err) { | ||
if (err.code === 404) { | ||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,url:opts.url,error:"not_found"}, opts.req); | ||
// TODO: code/status | ||
err.status = 404; | ||
} else if (err.code) { | ||
err.status = 400; | ||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,url:opts.url,error:err.code}, opts.req); | ||
} else { | ||
err.status = 400; | ||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,url:opts.url,error:err.code||"unexpected_error",message:err.toString()}, opts.req); | ||
} | ||
runtime.nodes.installModule(opts.module,opts.version,opts.url).then(function(info) { | ||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,url:opts.url}, opts.req); | ||
return resolve(info); | ||
}).catch(function(err) { | ||
if (err.code === 404) { | ||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,url:opts.url,error:"not_found"}, opts.req); | ||
// TODO: code/status | ||
err.status = 404; | ||
} else if (err.code) { | ||
err.status = 400; | ||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,url:opts.url,error:err.code}, opts.req); | ||
} else { | ||
err.status = 400; | ||
runtime.log.audit({event: "nodes.install",module:opts.module,version:opts.version,url:opts.url,error:err.code||"unexpected_error",message:err.toString()}, opts.req); | ||
} | ||
return reject(err); | ||
}) | ||
} else { | ||
runtime.log.audit({event: "nodes.install",module:opts.module,error:"invalid_request"}, opts.req); | ||
var err = new Error("Invalid request"); | ||
err.code = "invalid_request"; | ||
err.status = 400; | ||
return reject(err); | ||
} | ||
}); | ||
throw err; | ||
}) | ||
} else { | ||
runtime.log.audit({event: "nodes.install",module:opts.module,error:"invalid_request"}, opts.req); | ||
var err = new Error("Invalid request"); | ||
err.code = "invalid_request"; | ||
err.status = 400; | ||
throw err; | ||
} | ||
}, | ||
@@ -270,34 +255,31 @@ /** | ||
*/ | ||
removeModule: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
if (!runtime.settings.available()) { | ||
runtime.log.audit({event: "nodes.install",error:"settings_unavailable"}, opts.req); | ||
var err = new Error("Settings unavailable"); | ||
err.code = "settings_unavailable"; | ||
removeModule: async function(opts) { | ||
if (!runtime.settings.available()) { | ||
runtime.log.audit({event: "nodes.install",error:"settings_unavailable"}, opts.req); | ||
var err = new Error("Settings unavailable"); | ||
err.code = "settings_unavailable"; | ||
err.status = 400; | ||
throw err; | ||
} | ||
var module = runtime.nodes.getModuleInfo(opts.module); | ||
if (!module) { | ||
runtime.log.audit({event: "nodes.remove",module:opts.module,error:"not_found"}, opts.req); | ||
var err = new Error("Module not found"); | ||
err.code = "not_found"; | ||
err.status = 404; | ||
throw err; | ||
} | ||
try { | ||
return runtime.nodes.uninstallModule(opts.module).then(function() { | ||
runtime.log.audit({event: "nodes.remove",module:opts.module}, opts.req); | ||
}).catch(function(err) { | ||
err.status = 400; | ||
return reject(err); | ||
} | ||
var module = runtime.nodes.getModuleInfo(opts.module); | ||
if (!module) { | ||
runtime.log.audit({event: "nodes.remove",module:opts.module,error:"not_found"}, opts.req); | ||
var err = new Error("Module not found"); | ||
err.code = "not_found"; | ||
err.status = 404; | ||
return reject(err); | ||
} | ||
try { | ||
runtime.nodes.uninstallModule(opts.module).then(function() { | ||
runtime.log.audit({event: "nodes.remove",module:opts.module}, opts.req); | ||
resolve(); | ||
}).catch(function(err) { | ||
err.status = 400; | ||
runtime.log.audit({event: "nodes.remove",module:opts.module,error:err.code||"unexpected_error",message:err.toString()}, opts.req); | ||
return reject(err); | ||
}) | ||
} catch(error) { | ||
runtime.log.audit({event: "nodes.remove",module:opts.module,error:error.code||"unexpected_error",message:error.toString()}, opts.req); | ||
error.status = 400; | ||
return reject(error); | ||
} | ||
}); | ||
runtime.log.audit({event: "nodes.remove",module:opts.module,error:err.code||"unexpected_error",message:err.toString()}, opts.req); | ||
throw err; | ||
}) | ||
} catch(error) { | ||
runtime.log.audit({event: "nodes.remove",module:opts.module,error:error.code||"unexpected_error",message:error.toString()}, opts.req); | ||
error.status = 400; | ||
throw err; | ||
} | ||
}, | ||
@@ -315,39 +297,37 @@ | ||
*/ | ||
setModuleState: function(opts) { | ||
setModuleState: async function(opts) { | ||
var mod = opts.module; | ||
return new Promise(function(resolve,reject) { | ||
if (!runtime.settings.available()) { | ||
runtime.log.audit({event: "nodes.module.set",error:"settings_unavailable"}, opts.req); | ||
var err = new Error("Settings unavailable"); | ||
err.code = "settings_unavailable"; | ||
err.status = 400; | ||
return reject(err); | ||
if (!runtime.settings.available()) { | ||
runtime.log.audit({event: "nodes.module.set",error:"settings_unavailable"}, opts.req); | ||
var err = new Error("Settings unavailable"); | ||
err.code = "settings_unavailable"; | ||
err.status = 400; | ||
throw err; | ||
} | ||
try { | ||
var module = runtime.nodes.getModuleInfo(mod); | ||
if (!module) { | ||
runtime.log.audit({event: "nodes.module.set",module:mod,error:"not_found"}, opts.req); | ||
var err = new Error("Module not found"); | ||
err.code = "not_found"; | ||
err.status = 404; | ||
throw err; | ||
} | ||
try { | ||
var module = runtime.nodes.getModuleInfo(mod); | ||
if (!module) { | ||
runtime.log.audit({event: "nodes.module.set",module:mod,error:"not_found"}, opts.req); | ||
var err = new Error("Module not found"); | ||
err.code = "not_found"; | ||
err.status = 404; | ||
return reject(err); | ||
} | ||
var nodes = module.nodes; | ||
var promises = []; | ||
for (var i = 0; i < nodes.length; ++i) { | ||
promises.push(putNode(nodes[i],opts.enabled)); | ||
} | ||
Promise.all(promises).then(function() { | ||
return resolve(runtime.nodes.getModuleInfo(mod)); | ||
}).catch(function(err) { | ||
err.status = 400; | ||
return reject(err); | ||
}); | ||
} catch(error) { | ||
runtime.log.audit({event: "nodes.module.set",module:mod,enabled:opts.enabled,error:error.code||"unexpected_error",message:error.toString()}, opts.req); | ||
error.status = 400; | ||
return reject(error); | ||
var nodes = module.nodes; | ||
var promises = []; | ||
for (var i = 0; i < nodes.length; ++i) { | ||
promises.push(putNode(nodes[i],opts.enabled)); | ||
} | ||
}); | ||
return Promise.all(promises).then(function() { | ||
return runtime.nodes.getModuleInfo(mod); | ||
}).catch(function(err) { | ||
err.status = 400; | ||
throw err; | ||
}); | ||
} catch(error) { | ||
runtime.log.audit({event: "nodes.module.set",module:mod,enabled:opts.enabled,error:error.code||"unexpected_error",message:error.toString()}, opts.req); | ||
error.status = 400; | ||
throw err; | ||
} | ||
}, | ||
@@ -365,39 +345,37 @@ | ||
*/ | ||
setNodeSetState: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
if (!runtime.settings.available()) { | ||
runtime.log.audit({event: "nodes.info.set",error:"settings_unavailable"}, opts.req); | ||
var err = new Error("Settings unavailable"); | ||
err.code = "settings_unavailable"; | ||
err.status = 400; | ||
return reject(err); | ||
} | ||
setNodeSetState: async function(opts) { | ||
if (!runtime.settings.available()) { | ||
runtime.log.audit({event: "nodes.info.set",error:"settings_unavailable"}, opts.req); | ||
var err = new Error("Settings unavailable"); | ||
err.code = "settings_unavailable"; | ||
err.status = 400; | ||
throw err; | ||
} | ||
var id = opts.id; | ||
var enabled = opts.enabled; | ||
try { | ||
var node = runtime.nodes.getNodeInfo(id); | ||
if (!node) { | ||
runtime.log.audit({event: "nodes.info.set",id:id,error:"not_found"}, opts.req); | ||
var err = new Error("Node not found"); | ||
err.code = "not_found"; | ||
err.status = 404; | ||
return reject(err); | ||
} else { | ||
delete node.loaded; | ||
putNode(node,enabled).then(function(result) { | ||
runtime.log.audit({event: "nodes.info.set",id:id,enabled:enabled}, opts.req); | ||
return resolve(result); | ||
}).catch(function(err) { | ||
runtime.log.audit({event: "nodes.info.set",id:id,enabled:enabled,error:err.code||"unexpected_error",message:err.toString()}, opts.req); | ||
err.status = 400; | ||
return reject(err); | ||
}); | ||
} | ||
} catch(error) { | ||
runtime.log.audit({event: "nodes.info.set",id:id,enabled:enabled,error:error.code||"unexpected_error",message:error.toString()}, opts.req); | ||
error.status = 400; | ||
return reject(error); | ||
var id = opts.id; | ||
var enabled = opts.enabled; | ||
try { | ||
var node = runtime.nodes.getNodeInfo(id); | ||
if (!node) { | ||
runtime.log.audit({event: "nodes.info.set",id:id,error:"not_found"}, opts.req); | ||
var err = new Error("Node not found"); | ||
err.code = "not_found"; | ||
err.status = 404; | ||
throw err; | ||
} else { | ||
delete node.loaded; | ||
return putNode(node,enabled).then(function(result) { | ||
runtime.log.audit({event: "nodes.info.set",id:id,enabled:enabled}, opts.req); | ||
return result; | ||
}).catch(function(err) { | ||
runtime.log.audit({event: "nodes.info.set",id:id,enabled:enabled,error:err.code||"unexpected_error",message:err.toString()}, opts.req); | ||
err.status = 400; | ||
throw err; | ||
}); | ||
} | ||
}); | ||
} catch(error) { | ||
runtime.log.audit({event: "nodes.info.set",id:id,enabled:enabled,error:error.code||"unexpected_error",message:error.toString()}, opts.req); | ||
error.status = 400; | ||
throw err; | ||
} | ||
}, | ||
@@ -414,12 +392,12 @@ | ||
*/ | ||
getModuleCatalogs: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
var namespace = opts.module; | ||
var lang = opts.lang; | ||
var prevLang = runtime.i18n.i.language; | ||
if (/[^0-9a-z=\-\*]/i.test(lang)) { | ||
reject(new Error("Invalid language: "+lang)); | ||
return | ||
} | ||
// Trigger a load from disk of the language if it is not the default | ||
getModuleCatalogs: async function(opts) { | ||
var namespace = opts.module; | ||
var lang = opts.lang; | ||
if (/[^0-9a-z=\-\*]/i.test(lang)) { | ||
reject(new Error("Invalid language: "+lang)); | ||
return | ||
} | ||
var prevLang = runtime.i18n.i.language; | ||
// Trigger a load from disk of the language if it is not the default | ||
return new Promise( (resolve,reject) => { | ||
runtime.i18n.i.changeLanguage(lang, function(){ | ||
@@ -433,5 +411,5 @@ var nodeList = runtime.nodes.getNodeList(); | ||
}); | ||
runtime.i18n.i.changeLanguage(prevLang); | ||
resolve(result); | ||
}); | ||
runtime.i18n.i.changeLanguage(prevLang); | ||
}); | ||
@@ -450,17 +428,17 @@ }, | ||
*/ | ||
getModuleCatalog: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
var namespace = opts.module; | ||
var lang = opts.lang; | ||
if (/[^0-9a-z=\-\*]/i.test(lang)) { | ||
reject(new Error("Invalid language: "+lang)); | ||
return | ||
} | ||
var prevLang = runtime.i18n.i.language; | ||
// Trigger a load from disk of the language if it is not the default | ||
runtime.i18n.i.changeLanguage(lang, function(){ | ||
getModuleCatalog: async function(opts) { | ||
var namespace = opts.module; | ||
var lang = opts.lang; | ||
if (/[^0-9a-z=\-\*]/i.test(lang)) { | ||
reject(new Error("Invalid language: "+lang)); | ||
return | ||
} | ||
var prevLang = runtime.i18n.i.language; | ||
// Trigger a load from disk of the language if it is not the default | ||
return new Promise(resolve => { | ||
runtime.i18n.i.changeLanguage(lang, function() { | ||
var catalog = runtime.i18n.i.getResourceBundle(lang, namespace); | ||
runtime.i18n.i.changeLanguage(prevLang); | ||
resolve(catalog||{}); | ||
}); | ||
runtime.i18n.i.changeLanguage(prevLang); | ||
}); | ||
@@ -477,8 +455,5 @@ }, | ||
*/ | ||
getIconList: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
runtime.log.audit({event: "nodes.icons.get"}, opts.req); | ||
return resolve(runtime.nodes.getNodeIcons()); | ||
}); | ||
getIconList: async function(opts) { | ||
runtime.log.audit({event: "nodes.icons.get"}, opts.req); | ||
return runtime.nodes.getNodeIcons(); | ||
}, | ||
@@ -495,18 +470,13 @@ /** | ||
*/ | ||
getIcon: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
var iconPath = runtime.nodes.getNodeIconPath(opts.module,opts.icon); | ||
if (iconPath) { | ||
fs.readFile(iconPath,function(err,data) { | ||
if (err) { | ||
err.status = 400; | ||
return reject(err); | ||
} | ||
return resolve(data) | ||
}); | ||
} else { | ||
resolve(null); | ||
} | ||
}); | ||
getIcon: async function(opts) { | ||
var iconPath = runtime.nodes.getNodeIconPath(opts.module,opts.icon); | ||
if (iconPath) { | ||
return fs.readFile(iconPath).catch(err => { | ||
err.status = 400; | ||
throw err; | ||
}); | ||
} else { | ||
return null | ||
} | ||
} | ||
} |
@@ -27,4 +27,4 @@ /** | ||
}, | ||
available: function(opts) { | ||
return Promise.resolve(!!runtime.storage.projects); | ||
available: async function(opts) { | ||
return !!runtime.storage.projects; | ||
}, | ||
@@ -40,3 +40,3 @@ /** | ||
*/ | ||
listProjects: function(opts) { | ||
listProjects: async function(opts) { | ||
return runtime.storage.projects.listProjects(opts.user).then(function(list) { | ||
@@ -66,3 +66,3 @@ var active = runtime.storage.projects.getActiveProject(opts.user); | ||
*/ | ||
createProject: function(opts) { | ||
createProject: async function(opts) { | ||
runtime.log.audit({event: "projects.create",name:opts.project?opts.project.name:"missing-name"}, opts.req); | ||
@@ -82,3 +82,3 @@ return runtime.storage.projects.createProject(opts.user, opts.project) | ||
*/ | ||
initialiseProject: function(opts) { | ||
initialiseProject: async function(opts) { | ||
// Initialised set when creating default files for an empty repo | ||
@@ -97,4 +97,4 @@ runtime.log.audit({event: "projects.initialise",id:opts.id}, opts.req); | ||
*/ | ||
getActiveProject: function(opts) { | ||
return Promise.resolve(runtime.storage.projects.getActiveProject(opts.user)); | ||
getActiveProject: async function(opts) { | ||
return runtime.storage.projects.getActiveProject(opts.user); | ||
}, | ||
@@ -111,3 +111,3 @@ | ||
*/ | ||
setActiveProject: function(opts) { | ||
setActiveProject: async function(opts) { | ||
var currentProject = runtime.storage.projects.getActiveProject(opts.user); | ||
@@ -117,4 +117,2 @@ runtime.log.audit({event: "projects.set",id:opts.id}, opts.req); | ||
return runtime.storage.projects.setActiveProject(opts.user, opts.id); | ||
} else { | ||
return Promise.resolve(); | ||
} | ||
@@ -132,3 +130,3 @@ }, | ||
*/ | ||
getProject: function(opts) { | ||
getProject: async function(opts) { | ||
return runtime.storage.projects.getProject(opts.user, opts.id) | ||
@@ -147,3 +145,3 @@ }, | ||
*/ | ||
updateProject: function(opts) { | ||
updateProject: async function(opts) { | ||
runtime.log.audit({event: "projects.update",id:opts.id}, opts.req); | ||
@@ -162,3 +160,3 @@ return runtime.storage.projects.updateProject(opts.user, opts.id, opts.project); | ||
*/ | ||
deleteProject: function(opts) { | ||
deleteProject: async function(opts) { | ||
runtime.log.audit({event: "projects.delete",id:opts.id}, opts.req); | ||
@@ -178,3 +176,3 @@ return runtime.storage.projects.deleteProject(opts.user, opts.id); | ||
*/ | ||
getStatus: function(opts) { | ||
getStatus: async function(opts) { | ||
return runtime.storage.projects.getStatus(opts.user, opts.id, opts.remote) | ||
@@ -193,3 +191,3 @@ }, | ||
*/ | ||
getBranches: function(opts) { | ||
getBranches: async function(opts) { | ||
return runtime.storage.projects.getBranches(opts.user, opts.id, opts.remote); | ||
@@ -208,3 +206,3 @@ }, | ||
*/ | ||
getBranchStatus: function(opts) { | ||
getBranchStatus: async function(opts) { | ||
return runtime.storage.projects.getBranchStatus(opts.user, opts.id, opts.branch); | ||
@@ -224,3 +222,3 @@ }, | ||
*/ | ||
setBranch: function(opts) { | ||
setBranch: async function(opts) { | ||
runtime.log.audit({event: "projects.branch.set",id:opts.id, branch: opts.branch, create:opts.create}, opts.req); | ||
@@ -241,3 +239,3 @@ return runtime.storage.projects.setBranch(opts.user, opts.id, opts.branch, opts.create) | ||
*/ | ||
deleteBranch: function(opts) { | ||
deleteBranch: async function(opts) { | ||
runtime.log.audit({event: "projects.branch.delete",id:opts.id, branch: opts.branch, force:opts.force}, opts.req); | ||
@@ -257,3 +255,3 @@ return runtime.storage.projects.deleteBranch(opts.user, opts.id, opts.branch, false, opts.force); | ||
*/ | ||
commit: function(opts) { | ||
commit: async function(opts) { | ||
runtime.log.audit({event: "projects.commit",id:opts.id}, opts.req); | ||
@@ -273,3 +271,3 @@ return runtime.storage.projects.commit(opts.user, opts.id,{message: opts.message}); | ||
*/ | ||
getCommit: function(opts) { | ||
getCommit: async function(opts) { | ||
return runtime.storage.projects.getCommit(opts.user, opts.id, opts.sha); | ||
@@ -289,3 +287,3 @@ }, | ||
*/ | ||
getCommits: function(opts) { | ||
getCommits: async function(opts) { | ||
return runtime.storage.projects.getCommits(opts.user, opts.id, { | ||
@@ -306,3 +304,3 @@ limit: opts.limit || 20, | ||
*/ | ||
abortMerge: function(opts) { | ||
abortMerge: async function(opts) { | ||
runtime.log.audit({event: "projects.merge.abort",id:opts.id}, opts.req); | ||
@@ -323,3 +321,3 @@ return runtime.storage.projects.abortMerge(opts.user, opts.id); | ||
*/ | ||
resolveMerge: function(opts) { | ||
resolveMerge: async function(opts) { | ||
runtime.log.audit({event: "projects.merge.resolve",id:opts.id, file:opts.path}, opts.req); | ||
@@ -338,3 +336,3 @@ return runtime.storage.projects.resolveMerge(opts.user, opts.id, opts.path, opts.resolution); | ||
*/ | ||
getFiles: function(opts) { | ||
getFiles: async function(opts) { | ||
return runtime.storage.projects.getFiles(opts.user, opts.id); | ||
@@ -354,3 +352,3 @@ }, | ||
*/ | ||
getFile: function(opts) { | ||
getFile: async function(opts) { | ||
return runtime.storage.projects.getFile(opts.user, opts.id,opts.path,opts.tree); | ||
@@ -369,3 +367,3 @@ }, | ||
*/ | ||
stageFile: function(opts) { | ||
stageFile: async function(opts) { | ||
runtime.log.audit({event: "projects.file.stage",id:opts.id, file:opts.path}, opts.req); | ||
@@ -385,3 +383,3 @@ return runtime.storage.projects.stageFile(opts.user, opts.id, opts.path); | ||
*/ | ||
unstageFile: function(opts) { | ||
unstageFile: async function(opts) { | ||
runtime.log.audit({event: "projects.file.unstage",id:opts.id, file:opts.path}, opts.req); | ||
@@ -401,3 +399,3 @@ return runtime.storage.projects.unstageFile(opts.user, opts.id, opts.path); | ||
*/ | ||
revertFile: function(opts) { | ||
revertFile: async function(opts) { | ||
runtime.log.audit({event: "projects.file.revert",id:opts.id, file:opts.path}, opts.req); | ||
@@ -418,3 +416,3 @@ return runtime.storage.projects.revertFile(opts.user, opts.id,opts.path) | ||
*/ | ||
getFileDiff: function(opts) { | ||
getFileDiff: async function(opts) { | ||
return runtime.storage.projects.getFileDiff(opts.user, opts.id, opts.path, opts.type); | ||
@@ -432,3 +430,3 @@ }, | ||
*/ | ||
getRemotes: function(opts) { | ||
getRemotes: async function(opts) { | ||
return runtime.storage.projects.getRemotes(opts.user, opts.id); | ||
@@ -450,3 +448,3 @@ | ||
*/ | ||
addRemote: function(opts) { | ||
addRemote: async function(opts) { | ||
runtime.log.audit({event: "projects.remote.add",id:opts.id, remote:opts.remote.name}, opts.req); | ||
@@ -466,3 +464,3 @@ return runtime.storage.projects.addRemote(opts.user, opts.id, opts.remote) | ||
*/ | ||
removeRemote: function(opts) { | ||
removeRemote: async function(opts) { | ||
runtime.log.audit({event: "projects.remote.delete",id:opts.id, remote:opts.remote}, opts.req); | ||
@@ -483,3 +481,3 @@ return runtime.storage.projects.removeRemote(opts.user, opts.id, opts.remote); | ||
*/ | ||
updateRemote: function(opts) { | ||
updateRemote: async function(opts) { | ||
runtime.log.audit({event: "projects.remote.update",id:opts.id, remote:opts.remote.name}, opts.req); | ||
@@ -500,3 +498,3 @@ return runtime.storage.projects.updateRemote(opts.user, opts.id, opts.remote.name, opts.remote) | ||
*/ | ||
pull: function(opts) { | ||
pull: async function(opts) { | ||
runtime.log.audit({event: "projects.pull",id:opts.id, remote: opts.remote, track:opts.track}, opts.req); | ||
@@ -517,3 +515,3 @@ return runtime.storage.projects.pull(opts.user, opts.id, opts.remote, opts.track, opts.allowUnrelatedHistories); | ||
*/ | ||
push: function(opts) { | ||
push: async function(opts) { | ||
runtime.log.audit({event: "projects.push",id:opts.id, remote: opts.remote, track:opts.track}, opts.req); | ||
@@ -520,0 +518,0 @@ return runtime.storage.projects.push(opts.user, opts.id, opts.remote, opts.track); |
@@ -67,60 +67,72 @@ /** | ||
*/ | ||
getRuntimeSettings: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
try { | ||
var safeSettings = { | ||
httpNodeRoot: runtime.settings.httpNodeRoot||"/", | ||
version: runtime.settings.version | ||
getRuntimeSettings: async function(opts) { | ||
var safeSettings = { | ||
httpNodeRoot: runtime.settings.httpNodeRoot||"/", | ||
version: runtime.settings.version | ||
} | ||
if (opts.user) { | ||
safeSettings.user = {} | ||
var props = ["anonymous","username","image","permissions"]; | ||
props.forEach(prop => { | ||
if (opts.user.hasOwnProperty(prop)) { | ||
safeSettings.user[prop] = opts.user[prop]; | ||
} | ||
if (opts.user) { | ||
safeSettings.user = {} | ||
var props = ["anonymous","username","image","permissions"]; | ||
props.forEach(prop => { | ||
if (opts.user.hasOwnProperty(prop)) { | ||
safeSettings.user[prop] = opts.user[prop]; | ||
} | ||
}) | ||
} | ||
}) | ||
} | ||
if (!runtime.settings.disableEditor) { | ||
safeSettings.context = runtime.nodes.listContextStores(); | ||
if (!runtime.settings.disableEditor) { | ||
safeSettings.context = runtime.nodes.listContextStores(); | ||
safeSettings.libraries = runtime.library.getLibraries(); | ||
if (util.isArray(runtime.settings.paletteCategories)) { | ||
safeSettings.paletteCategories = runtime.settings.paletteCategories; | ||
} | ||
if (util.isArray(runtime.settings.paletteCategories)) { | ||
safeSettings.paletteCategories = runtime.settings.paletteCategories; | ||
} | ||
if (runtime.settings.flowFilePretty) { | ||
safeSettings.flowFilePretty = runtime.settings.flowFilePretty; | ||
} | ||
if (runtime.settings.flowFilePretty) { | ||
safeSettings.flowFilePretty = runtime.settings.flowFilePretty; | ||
} | ||
if (runtime.settings.editorTheme && runtime.settings.editorTheme.palette) { | ||
if (runtime.settings.editorTheme.palette.upload === false || runtime.settings.editorTheme.palette.editable === false) { | ||
safeSettings.externalModules = {palette: { } } | ||
} | ||
if (runtime.settings.editorTheme.palette.upload === false) { | ||
safeSettings.externalModules.palette.allowUpload = false; | ||
} | ||
if (runtime.settings.editorTheme.palette.editable === false) { | ||
safeSettings.externalModules.palette.allowInstall = false; | ||
safeSettings.externalModules.palette.allowUpload = false; | ||
} | ||
} | ||
if (!runtime.nodes.paletteEditorEnabled()) { | ||
safeSettings.editorTheme = safeSettings.editorTheme || {}; | ||
safeSettings.editorTheme.palette = safeSettings.editorTheme.palette || {}; | ||
safeSettings.editorTheme.palette.editable = false; | ||
if (runtime.settings.externalModules) { | ||
safeSettings.externalModules = extend(safeSettings.externalModules||{},runtime.settings.externalModules); | ||
} | ||
if (!runtime.nodes.installerEnabled()) { | ||
safeSettings.externalModules = safeSettings.externalModules || {}; | ||
safeSettings.externalModules.palette = safeSettings.externalModules.palette || {}; | ||
safeSettings.externalModules.palette.allowInstall = false; | ||
safeSettings.externalModules.palette.allowUpload = false; | ||
} | ||
if (runtime.storage.projects) { | ||
var activeProject = runtime.storage.projects.getActiveProject(); | ||
if (activeProject) { | ||
safeSettings.project = activeProject; | ||
} else if (runtime.storage.projects.flowFileExists()) { | ||
safeSettings.files = { | ||
flow: runtime.storage.projects.getFlowFilename(), | ||
credentials: runtime.storage.projects.getCredentialsFilename() | ||
} | ||
if (runtime.storage.projects) { | ||
var activeProject = runtime.storage.projects.getActiveProject(); | ||
if (activeProject) { | ||
safeSettings.project = activeProject; | ||
} else if (runtime.storage.projects.flowFileExists()) { | ||
safeSettings.files = { | ||
flow: runtime.storage.projects.getFlowFilename(), | ||
credentials: runtime.storage.projects.getCredentialsFilename() | ||
} | ||
} | ||
safeSettings.git = { | ||
globalUser: runtime.storage.projects.getGlobalGitUser() | ||
} | ||
} | ||
safeSettings.flowEncryptionType = runtime.nodes.getCredentialKeyType(); | ||
runtime.settings.exportNodeSettings(safeSettings); | ||
} | ||
safeSettings.git = { | ||
globalUser: runtime.storage.projects.getGlobalGitUser() | ||
} | ||
} | ||
safeSettings.flowEncryptionType = runtime.nodes.getCredentialKeyType(); | ||
runtime.settings.exportNodeSettings(safeSettings); | ||
runtime.plugins.exportPluginSettings(safeSettings); | ||
} | ||
resolve(safeSettings); | ||
}catch(err) { | ||
console.log(err); | ||
} | ||
}); | ||
return safeSettings; | ||
}, | ||
@@ -136,3 +148,3 @@ | ||
*/ | ||
getUserSettings: function(opts) { | ||
getUserSettings: async function(opts) { | ||
var username; | ||
@@ -144,3 +156,3 @@ if (!opts.user || opts.user.anonymous) { | ||
} | ||
return Promise.resolve(runtime.settings.getUserSettings(username)||{}); | ||
return runtime.settings.getUserSettings(username)||{}; | ||
}, | ||
@@ -157,3 +169,3 @@ | ||
*/ | ||
updateUserSettings: function(opts) { | ||
updateUserSettings: async function(opts) { | ||
var username; | ||
@@ -165,21 +177,19 @@ if (!opts.user || opts.user.anonymous) { | ||
} | ||
return new Promise(function(resolve,reject) { | ||
var currentSettings = runtime.settings.getUserSettings(username)||{}; | ||
currentSettings = extend(currentSettings, opts.settings); | ||
try { | ||
runtime.settings.setUserSettings(username, currentSettings).then(function() { | ||
runtime.log.audit({event: "settings.update",username:username}, opts.req); | ||
return resolve(); | ||
}).catch(function(err) { | ||
runtime.log.audit({event: "settings.update",username:username,error:err.code||"unexpected_error",message:err.toString()}, opts.req); | ||
err.status = 400; | ||
return reject(err); | ||
}); | ||
} catch(err) { | ||
runtime.log.warn(runtime.log._("settings.user-not-available",{message:runtime.log._("settings.not-available")})); | ||
var currentSettings = runtime.settings.getUserSettings(username)||{}; | ||
currentSettings = extend(currentSettings, opts.settings); | ||
try { | ||
return runtime.settings.setUserSettings(username, currentSettings).then(function() { | ||
runtime.log.audit({event: "settings.update",username:username}, opts.req); | ||
return; | ||
}).catch(function(err) { | ||
runtime.log.audit({event: "settings.update",username:username,error:err.code||"unexpected_error",message:err.toString()}, opts.req); | ||
err.status = 400; | ||
return reject(err); | ||
} | ||
}); | ||
throw err; | ||
}); | ||
} catch(err) { | ||
runtime.log.warn(runtime.log._("settings.user-not-available",{message:runtime.log._("settings.not-available")})); | ||
runtime.log.audit({event: "settings.update",username:username,error:err.code||"unexpected_error",message:err.toString()}, opts.req); | ||
err.status = 400; | ||
throw err; | ||
} | ||
}, | ||
@@ -195,11 +205,8 @@ | ||
*/ | ||
getUserKeys: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
var username = getSSHKeyUsername(opts.user); | ||
runtime.storage.projects.ssh.listSSHKeys(username).then(function(list) { | ||
return resolve(list); | ||
}).catch(function(err) { | ||
err.status = 400; | ||
return reject(err); | ||
}); | ||
getUserKeys: async function(opts) { | ||
var username = getSSHKeyUsername(opts.user); | ||
return runtime.storage.projects.ssh.listSSHKeys(username).catch(function(err) { | ||
err.status = 400; | ||
throw err; | ||
return reject(err); | ||
}); | ||
@@ -217,19 +224,19 @@ }, | ||
*/ | ||
getUserKey: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
var username = getSSHKeyUsername(opts.user); | ||
// console.log('username:', username); | ||
runtime.storage.projects.ssh.getSSHKey(username, opts.id).then(function(data) { | ||
if (data) { | ||
return resolve(data); | ||
} else { | ||
var err = new Error("Key not found"); | ||
err.code = "not_found"; | ||
err.status = 404; | ||
return reject(err); | ||
} | ||
}).catch(function(err) { | ||
getUserKey: async function(opts) { | ||
var username = getSSHKeyUsername(opts.user); | ||
// console.log('username:', username); | ||
return runtime.storage.projects.ssh.getSSHKey(username, opts.id).then(function(data) { | ||
if (data) { | ||
return data; | ||
} else { | ||
var err = new Error("Key not found"); | ||
err.code = "not_found"; | ||
err.status = 404; | ||
throw err; | ||
} | ||
}).catch(function(err) { | ||
if (!err.status) { | ||
err.status = 400; | ||
return reject(err); | ||
}); | ||
} | ||
throw err; | ||
}); | ||
@@ -250,11 +257,7 @@ }, | ||
*/ | ||
generateUserKey: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
var username = getSSHKeyUsername(opts.user); | ||
runtime.storage.projects.ssh.generateSSHKey(username, opts).then(function(name) { | ||
return resolve(name); | ||
}).catch(function(err) { | ||
err.status = 400; | ||
return reject(err); | ||
}); | ||
generateUserKey: async function(opts) { | ||
var username = getSSHKeyUsername(opts.user); | ||
return runtime.storage.projects.ssh.generateSSHKey(username, opts).catch(function(err) { | ||
err.status = 400; | ||
throw err; | ||
}); | ||
@@ -272,14 +275,9 @@ }, | ||
*/ | ||
removeUserKey: function(opts) { | ||
return new Promise(function(resolve,reject) { | ||
var username = getSSHKeyUsername(opts.user); | ||
runtime.storage.projects.ssh.deleteSSHKey(username, opts.id).then(function() { | ||
return resolve(); | ||
}).catch(function(err) { | ||
err.status = 400; | ||
return reject(err); | ||
}); | ||
removeUserKey: async function(opts) { | ||
var username = getSSHKeyUsername(opts.user); | ||
return runtime.storage.projects.ssh.deleteSSHKey(username, opts.id).catch(function(err) { | ||
err.status = 400; | ||
throw err; | ||
}); | ||
} | ||
} |
@@ -19,4 +19,4 @@ /** | ||
var redUtil = require("@node-red/util").util; | ||
const events = require("@node-red/util").events; | ||
var flowUtil = require("./util"); | ||
var events = require("../events"); | ||
const context = require('../nodes/context'); | ||
@@ -97,3 +97,3 @@ const hooks = require("../hooks"); | ||
*/ | ||
log(msg) { | ||
info(msg) { | ||
Log.log({ | ||
@@ -121,2 +121,13 @@ id: this.id||"global", | ||
/** | ||
* [log description] | ||
* @param {[type]} msg [description] | ||
* @return {[type]} [description] | ||
*/ | ||
log(msg) { | ||
if (!msg.path) { | ||
msg.path = this.path; | ||
} | ||
this.parent.log(msg); | ||
} | ||
@@ -303,2 +314,13 @@ /** | ||
let nodesToStop = []; | ||
let configsToStop = []; | ||
stopList.forEach(id => { | ||
if (this.flow.configs[id]) { | ||
configsToStop.push(id); | ||
} else { | ||
nodesToStop.push(id); | ||
} | ||
}); | ||
stopList = nodesToStop.concat(configsToStop); | ||
var promises = []; | ||
@@ -310,18 +332,10 @@ for (i=0;i<stopList.length;i++) { | ||
if (this.subflowInstanceNodes[stopList[i]]) { | ||
try { | ||
(function(subflow) { | ||
promises.push(stopNode(node,false).then(() => subflow.stop())); | ||
})(this.subflowInstanceNodes[stopList[i]]); | ||
} catch(err) { | ||
node.error(err); | ||
} | ||
delete this.subflowInstanceNodes[stopList[i]]; | ||
} else { | ||
try { | ||
var removed = removedMap[stopList[i]]; | ||
promises.push(stopNode(node,removed).catch(()=>{})); | ||
} catch(err) { | ||
node.error(err); | ||
} | ||
} | ||
try { | ||
var removed = removedMap[stopList[i]]; | ||
promises.push(stopNode(node,removed).catch(()=>{})); | ||
} catch(err) { | ||
node.error(err); | ||
} | ||
if (removedMap[stopList[i]]) { | ||
@@ -422,2 +436,8 @@ events.emit("node-status",{ | ||
if (!muteStatusEvent) { | ||
if (statusMessage.hasOwnProperty("text") && typeof(statusMessage.text !== "string")) { | ||
try { | ||
statusMessage.text = statusMessage.text.toString(); | ||
} | ||
catch(e) {} | ||
} | ||
events.emit("node-status",{ | ||
@@ -688,3 +708,2 @@ id: node.id, | ||
Subflow = require("./Subflow"); | ||
Subflow.init(runtime); | ||
}, | ||
@@ -691,0 +710,0 @@ create: function(parent,global,conf) { |
@@ -28,5 +28,4 @@ /** | ||
var log; | ||
var events = require("../events"); | ||
const events = require("@node-red/util").events; | ||
var redUtil = require("@node-red/util").util; | ||
const hooks = require("../hooks"); | ||
@@ -192,31 +191,31 @@ var storage = null; | ||
return configSavePromise | ||
.then(function(flowRevision) { | ||
if (!isLoad) { | ||
log.debug("saved flow revision: "+flowRevision); | ||
} | ||
activeConfig = { | ||
flows:config, | ||
rev:flowRevision | ||
}; | ||
activeFlowConfig = newFlowConfig; | ||
if (forceStart || started) { | ||
// Flows are running (or should be) | ||
// Stop the active flows (according to deploy type and the diff) | ||
return stop(type,diff,muteLog).then(() => { | ||
// Once stopped, allow context to remove anything no longer needed | ||
return context.clean(activeFlowConfig) | ||
}).then(() => { | ||
// Start the active flows | ||
start(type,diff,muteLog).then(() => { | ||
events.emit("runtime-event",{id:"runtime-deploy",payload:{revision:flowRevision},retain: true}); | ||
}); | ||
// Return the new revision asynchronously to the actual start | ||
return flowRevision; | ||
}).catch(function(err) { }) | ||
} else { | ||
events.emit("runtime-event",{id:"runtime-deploy",payload:{revision:flowRevision},retain: true}); | ||
} | ||
}); | ||
return configSavePromise.then(flowRevision => { | ||
if (!isLoad) { | ||
log.debug("saved flow revision: "+flowRevision); | ||
} | ||
activeConfig = { | ||
flows:config, | ||
rev:flowRevision | ||
}; | ||
activeFlowConfig = newFlowConfig; | ||
if (forceStart || started) { | ||
// Flows are running (or should be) | ||
// Stop the active flows (according to deploy type and the diff) | ||
return stop(type,diff,muteLog).then(() => { | ||
// Once stopped, allow context to remove anything no longer needed | ||
return context.clean(activeFlowConfig) | ||
}).then(() => { | ||
// Start the active flows | ||
start(type,diff,muteLog).then(() => { | ||
events.emit("runtime-event",{id:"runtime-deploy",payload:{revision:flowRevision},retain: true}); | ||
}); | ||
// Return the new revision asynchronously to the actual start | ||
return flowRevision; | ||
}).catch(function(err) { }) | ||
} else { | ||
events.emit("runtime-event",{id:"runtime-deploy",payload:{revision:flowRevision},retain: true}); | ||
} | ||
}); | ||
} | ||
@@ -252,3 +251,3 @@ | ||
function start(type,diff,muteLog) { | ||
async function start(type,diff,muteLog) { | ||
type = type||"full"; | ||
@@ -278,5 +277,19 @@ started = true; | ||
events.emit("runtime-event",{id:"runtime-state",payload:{error:"missing-types", type:"warning",text:"notification.warnings.missing-types",types:activeFlowConfig.missingTypes},retain:true}); | ||
return Promise.resolve(); | ||
return; | ||
} | ||
try { | ||
await typeRegistry.checkFlowDependencies(activeConfig.flows); | ||
} catch(err) { | ||
log.info("Failed to load external modules required by this flow:"); | ||
const missingModules = []; | ||
for (i=0;i<err.length;i++) { | ||
let errMessage = err[i].error.toString() | ||
missingModules.push({module:err[i].module.module, error: err[i].error.code || err[i].error.toString()}) | ||
log.info(` - ${err[i].module.spec} [${err[i].error.code || "unknown_error"}]`); | ||
} | ||
events.emit("runtime-event",{id:"runtime-state",payload:{error:"missing-modules", type:"warning",text:"notification.warnings.missing-modules",modules:missingModules},retain:true}); | ||
return; | ||
} | ||
// In safe mode, don't actually start anything, emit the necessary runtime event and return | ||
@@ -288,3 +301,3 @@ if (settings.safeMode) { | ||
events.emit("runtime-event",{id:"runtime-state",payload:{error:"safe-mode", type:"warning",text:"notification.warnings.safe-mode"},retain:true}); | ||
return Promise.resolve(); | ||
return; | ||
} | ||
@@ -379,3 +392,3 @@ | ||
} | ||
return Promise.resolve(); | ||
return; | ||
} | ||
@@ -414,3 +427,11 @@ | ||
for (var id in activeFlows) { | ||
// Stop the global flow object last | ||
let activeFlowIds = Object.keys(activeFlows); | ||
let globalIndex = activeFlowIds.indexOf("global"); | ||
if (globalIndex !== -1) { | ||
activeFlowIds.splice(globalIndex,1); | ||
activeFlowIds.push("global"); | ||
} | ||
activeFlowIds.forEach(id => { | ||
if (activeFlows.hasOwnProperty(id)) { | ||
@@ -424,6 +445,6 @@ var flowStateChanged = diff && (diff.added.indexOf(id) !== -1 || diff.removed.indexOf(id) !== -1); | ||
} | ||
} | ||
}); | ||
return Promise.all(promises).then(function() { | ||
for (id in activeNodesToFlow) { | ||
for (let id in activeNodesToFlow) { | ||
if (activeNodesToFlow.hasOwnProperty(id)) { | ||
@@ -710,3 +731,4 @@ if (!activeFlows[activeNodesToFlow[id]]) { | ||
handleStatus: () => false, | ||
getSetting: k => flowUtil.getEnvVar(k) | ||
getSetting: k => flowUtil.getEnvVar(k), | ||
log: m => log.log(m) | ||
} | ||
@@ -724,3 +746,3 @@ | ||
loadFlows: load, | ||
get:getNode, | ||
@@ -727,0 +749,0 @@ eachNode: eachNode, |
@@ -21,12 +21,7 @@ /** | ||
const util = require("util"); | ||
const events = require("../events"); | ||
const redUtil = require("@node-red/util").util; | ||
const events = require("@node-red/util").events; | ||
const flowUtil = require("./util"); | ||
const credentials = require("../nodes/credentials"); | ||
var Log; | ||
/** | ||
@@ -217,3 +212,8 @@ * Create deep copy of object | ||
this.node.on("input", function(msg) { this.send(msg);}); | ||
this.node.on("close", function() { this.status({}); }) | ||
// Called when the subflow instance node is being stopped | ||
this.node.on("close", function(done) { | ||
this.status({}); | ||
// Stop the complete subflow | ||
self.stop().finally(done) | ||
}) | ||
this.node.status = status => this.parent.handleStatus(this.node,status); | ||
@@ -509,2 +509,34 @@ // Create a context instance | ||
class SubflowModule extends Subflow { | ||
/** | ||
* Create a Subflow Module object. | ||
* This is a node that has been published as a subflow. | ||
* @param {[type]} parent [description] | ||
* @param {[type]} globalFlow [description] | ||
* @param {[type]} subflowDef [description] | ||
* @param {[type]} subflowInstance [description] | ||
*/ | ||
constructor(type, parent,globalFlow,subflowDef,subflowInstance) { | ||
super(parent,globalFlow,subflowDef,subflowInstance); | ||
this.TYPE = `module:${type}`; | ||
this.subflowType = type; | ||
} | ||
/** | ||
* [log description] | ||
* @param {[type]} msg [description] | ||
* @return {[type]} [description] | ||
*/ | ||
log(msg) { | ||
if (msg.id) { | ||
msg.id = this.id | ||
} | ||
if (msg.type) { | ||
msg.type = this.subflowType | ||
} | ||
super.log(msg); | ||
} | ||
} | ||
function createSubflow(parent,globalFlow,subflowDef,subflowInstance) { | ||
@@ -514,7 +546,11 @@ return new Subflow(parent,globalFlow,subflowDef,subflowInstance) | ||
function createModuleInstance(type, parent,globalFlow,subflowDef,subflowInstance) { | ||
return new SubflowModule(type, parent,globalFlow,subflowDef,subflowInstance); | ||
} | ||
module.exports = { | ||
init: function(runtime) { | ||
Log = runtime.log; | ||
}, | ||
create: createSubflow | ||
init: function(runtime) {}, | ||
create: createSubflow, | ||
createModuleInstance: createModuleInstance | ||
} |
@@ -22,2 +22,3 @@ /** | ||
var envVarExcludes = {}; | ||
@@ -70,2 +71,191 @@ | ||
function createNode(flow,config) { | ||
var newNode = null; | ||
var type = config.type; | ||
try { | ||
var nodeTypeConstructor = typeRegistry.get(type); | ||
if (typeof nodeTypeConstructor === "function") { | ||
var conf = clone(config); | ||
delete conf.credentials; | ||
for (var p in conf) { | ||
if (conf.hasOwnProperty(p)) { | ||
mapEnvVarProperties(conf,p,flow); | ||
} | ||
} | ||
try { | ||
Object.defineProperty(conf,'_flow', {value: flow, enumerable: false, writable: true }) | ||
newNode = new nodeTypeConstructor(conf); | ||
} catch (err) { | ||
Log.log({ | ||
level: Log.ERROR, | ||
id:conf.id, | ||
type: type, | ||
msg: err | ||
}); | ||
} | ||
} else if (nodeTypeConstructor) { | ||
// console.log(nodeTypeConstructor) | ||
var subflowConfig = parseConfig([nodeTypeConstructor.subflow].concat(nodeTypeConstructor.subflow.flow)); | ||
var instanceConfig = clone(config); | ||
instanceConfig.env = clone(nodeTypeConstructor.subflow.env); | ||
instanceConfig.env = nodeTypeConstructor.subflow.env.map(nodeProp => { | ||
var nodePropType; | ||
var nodePropValue = config[nodeProp.name]; | ||
if (nodeProp.type === "cred") { | ||
nodePropType = "cred"; | ||
} else { | ||
switch(typeof config[nodeProp.name]) { | ||
case "string": nodePropType = "str"; break; | ||
case "number": nodePropType = "num"; break; | ||
case "boolean": nodePropType = "bool"; nodePropValue = nodeProp?"true":"false"; break; | ||
default: | ||
nodePropType = config[nodeProp.name].type; | ||
nodePropValue = config[nodeProp.name].value; | ||
} | ||
} | ||
return { | ||
name: nodeProp.name, | ||
type: nodePropType, | ||
value: nodePropValue | ||
} | ||
}) | ||
var subflow = require("./Subflow").createModuleInstance( | ||
nodeTypeConstructor.type, | ||
flow, | ||
flow.global, | ||
subflowConfig.subflows[nodeTypeConstructor.subflow.id], | ||
instanceConfig | ||
); | ||
subflow.start(); | ||
return subflow.node; | ||
Log.error(Log._("nodes.flow.unknown-type", {type:type})); | ||
} | ||
} catch(err) { | ||
Log.error(err); | ||
} | ||
return newNode; | ||
} | ||
function parseConfig(config) { | ||
var flow = {}; | ||
flow.allNodes = {}; | ||
flow.subflows = {}; | ||
flow.configs = {}; | ||
flow.flows = {}; | ||
flow.groups = {}; | ||
flow.missingTypes = []; | ||
config.forEach(function(n) { | ||
flow.allNodes[n.id] = clone(n); | ||
if (n.type === 'tab') { | ||
flow.flows[n.id] = n; | ||
flow.flows[n.id].subflows = {}; | ||
flow.flows[n.id].configs = {}; | ||
flow.flows[n.id].nodes = {}; | ||
} | ||
if (n.type === 'group') { | ||
flow.groups[n.id] = n; | ||
} | ||
}); | ||
// TODO: why a separate forEach? this can be merged with above | ||
config.forEach(function(n) { | ||
if (n.type === 'subflow') { | ||
flow.subflows[n.id] = n; | ||
flow.subflows[n.id].configs = {}; | ||
flow.subflows[n.id].nodes = {}; | ||
flow.subflows[n.id].instances = []; | ||
} | ||
}); | ||
var linkWires = {}; | ||
var linkOutNodes = []; | ||
config.forEach(function(n) { | ||
if (n.type !== 'subflow' && n.type !== 'tab' && n.type !== 'group') { | ||
var subflowDetails = subflowInstanceRE.exec(n.type); | ||
if ( (subflowDetails && !flow.subflows[subflowDetails[1]]) || (!subflowDetails && !typeRegistry.get(n.type)) ) { | ||
if (flow.missingTypes.indexOf(n.type) === -1) { | ||
flow.missingTypes.push(n.type); | ||
} | ||
} | ||
var container = null; | ||
if (flow.flows[n.z]) { | ||
container = flow.flows[n.z]; | ||
} else if (flow.subflows[n.z]) { | ||
container = flow.subflows[n.z]; | ||
} | ||
if (n.hasOwnProperty('x') && n.hasOwnProperty('y')) { | ||
if (subflowDetails) { | ||
var subflowType = subflowDetails[1] | ||
n.subflow = subflowType; | ||
flow.subflows[subflowType].instances.push(n) | ||
} | ||
if (container) { | ||
container.nodes[n.id] = n; | ||
} | ||
} else { | ||
if (container) { | ||
container.configs[n.id] = n; | ||
} else { | ||
flow.configs[n.id] = n; | ||
flow.configs[n.id]._users = []; | ||
} | ||
} | ||
if (n.type === 'link in' && n.links) { | ||
// Ensure wires are present in corresponding link out nodes | ||
n.links.forEach(function(id) { | ||
linkWires[id] = linkWires[id]||{}; | ||
linkWires[id][n.id] = true; | ||
}) | ||
} else if (n.type === 'link out' && n.links) { | ||
linkWires[n.id] = linkWires[n.id]||{}; | ||
n.links.forEach(function(id) { | ||
linkWires[n.id][id] = true; | ||
}) | ||
linkOutNodes.push(n); | ||
} | ||
} | ||
}); | ||
linkOutNodes.forEach(function(n) { | ||
var links = linkWires[n.id]; | ||
var targets = Object.keys(links); | ||
n.wires = [targets]; | ||
}); | ||
var addedTabs = {}; | ||
config.forEach(function(n) { | ||
if (n.type !== 'subflow' && n.type !== 'tab' && n.type !== 'group') { | ||
for (var prop in n) { | ||
if (n.hasOwnProperty(prop) && prop !== 'id' && prop !== 'wires' && prop !== 'type' && prop !== '_users' && flow.configs.hasOwnProperty(n[prop])) { | ||
// This property references a global config node | ||
flow.configs[n[prop]]._users.push(n.id) | ||
} | ||
} | ||
if (n.z && !flow.subflows[n.z]) { | ||
if (!flow.flows[n.z]) { | ||
flow.flows[n.z] = {type:'tab',id:n.z}; | ||
flow.flows[n.z].subflows = {}; | ||
flow.flows[n.z].configs = {}; | ||
flow.flows[n.z].nodes = {}; | ||
addedTabs[n.z] = flow.flows[n.z]; | ||
} | ||
if (addedTabs[n.z]) { | ||
if (n.hasOwnProperty('x') && n.hasOwnProperty('y')) { | ||
addedTabs[n.z].nodes[n.id] = n; | ||
} else { | ||
addedTabs[n.z].configs[n.id] = n; | ||
} | ||
} | ||
} | ||
} | ||
}); | ||
return flow; | ||
} | ||
module.exports = { | ||
@@ -84,120 +274,4 @@ init: function(runtime) { | ||
parseConfig: function(config) { | ||
var flow = {}; | ||
flow.allNodes = {}; | ||
flow.subflows = {}; | ||
flow.configs = {}; | ||
flow.flows = {}; | ||
flow.groups = {}; | ||
flow.missingTypes = []; | ||
parseConfig: parseConfig, | ||
config.forEach(function(n) { | ||
flow.allNodes[n.id] = clone(n); | ||
if (n.type === 'tab') { | ||
flow.flows[n.id] = n; | ||
flow.flows[n.id].subflows = {}; | ||
flow.flows[n.id].configs = {}; | ||
flow.flows[n.id].nodes = {}; | ||
} | ||
if (n.type === 'group') { | ||
flow.groups[n.id] = n; | ||
} | ||
}); | ||
// TODO: why a separate forEach? this can be merged with above | ||
config.forEach(function(n) { | ||
if (n.type === 'subflow') { | ||
flow.subflows[n.id] = n; | ||
flow.subflows[n.id].configs = {}; | ||
flow.subflows[n.id].nodes = {}; | ||
flow.subflows[n.id].instances = []; | ||
} | ||
}); | ||
var linkWires = {}; | ||
var linkOutNodes = []; | ||
config.forEach(function(n) { | ||
if (n.type !== 'subflow' && n.type !== 'tab' && n.type !== 'group') { | ||
var subflowDetails = subflowInstanceRE.exec(n.type); | ||
if ( (subflowDetails && !flow.subflows[subflowDetails[1]]) || (!subflowDetails && !typeRegistry.get(n.type)) ) { | ||
if (flow.missingTypes.indexOf(n.type) === -1) { | ||
flow.missingTypes.push(n.type); | ||
} | ||
} | ||
var container = null; | ||
if (flow.flows[n.z]) { | ||
container = flow.flows[n.z]; | ||
} else if (flow.subflows[n.z]) { | ||
container = flow.subflows[n.z]; | ||
} | ||
if (n.hasOwnProperty('x') && n.hasOwnProperty('y')) { | ||
if (subflowDetails) { | ||
var subflowType = subflowDetails[1] | ||
n.subflow = subflowType; | ||
flow.subflows[subflowType].instances.push(n) | ||
} | ||
if (container) { | ||
container.nodes[n.id] = n; | ||
} | ||
} else { | ||
if (container) { | ||
container.configs[n.id] = n; | ||
} else { | ||
flow.configs[n.id] = n; | ||
flow.configs[n.id]._users = []; | ||
} | ||
} | ||
if (n.type === 'link in' && n.links) { | ||
// Ensure wires are present in corresponding link out nodes | ||
n.links.forEach(function(id) { | ||
linkWires[id] = linkWires[id]||{}; | ||
linkWires[id][n.id] = true; | ||
}) | ||
} else if (n.type === 'link out' && n.links) { | ||
linkWires[n.id] = linkWires[n.id]||{}; | ||
n.links.forEach(function(id) { | ||
linkWires[n.id][id] = true; | ||
}) | ||
linkOutNodes.push(n); | ||
} | ||
} | ||
}); | ||
linkOutNodes.forEach(function(n) { | ||
var links = linkWires[n.id]; | ||
var targets = Object.keys(links); | ||
n.wires = [targets]; | ||
}); | ||
var addedTabs = {}; | ||
config.forEach(function(n) { | ||
if (n.type !== 'subflow' && n.type !== 'tab' && n.type !== 'group') { | ||
for (var prop in n) { | ||
if (n.hasOwnProperty(prop) && prop !== 'id' && prop !== 'wires' && prop !== 'type' && prop !== '_users' && flow.configs.hasOwnProperty(n[prop])) { | ||
// This property references a global config node | ||
flow.configs[n[prop]]._users.push(n.id) | ||
} | ||
} | ||
if (n.z && !flow.subflows[n.z]) { | ||
if (!flow.flows[n.z]) { | ||
flow.flows[n.z] = {type:'tab',id:n.z}; | ||
flow.flows[n.z].subflows = {}; | ||
flow.flows[n.z].configs = {}; | ||
flow.flows[n.z].nodes = {}; | ||
addedTabs[n.z] = flow.flows[n.z]; | ||
} | ||
if (addedTabs[n.z]) { | ||
if (n.hasOwnProperty('x') && n.hasOwnProperty('y')) { | ||
addedTabs[n.z].nodes[n.id] = n; | ||
} else { | ||
addedTabs[n.z].configs[n.id] = n; | ||
} | ||
} | ||
} | ||
} | ||
}); | ||
return flow; | ||
}, | ||
diffConfigs: function(oldConfig, newConfig) { | ||
@@ -374,4 +448,17 @@ var id; | ||
// changed. | ||
if (changed[node[prop]] || removed[node[prop]]) { | ||
var changeOrigin = changed[node[prop]]; | ||
if (changeOrigin || removed[node[prop]]) { | ||
if (!changed[node.id]) { | ||
if (changeOrigin && | ||
(prop === "g") && | ||
(changeOrigin.type === "group")) { | ||
var oldNode = oldConfig.allNodes[node.id]; | ||
// ignore change of group node | ||
// if group of this node not changed | ||
if (oldNode && | ||
(node.g === oldNode.g)) { | ||
continue; | ||
} | ||
} | ||
madeChange = true; | ||
@@ -482,34 +569,3 @@ changed[node.id] = node; | ||
*/ | ||
createNode: function(flow,config) { | ||
var newNode = null; | ||
var type = config.type; | ||
try { | ||
var nodeTypeConstructor = typeRegistry.get(type); | ||
if (nodeTypeConstructor) { | ||
var conf = clone(config); | ||
delete conf.credentials; | ||
for (var p in conf) { | ||
if (conf.hasOwnProperty(p)) { | ||
mapEnvVarProperties(conf,p,flow); | ||
} | ||
} | ||
try { | ||
Object.defineProperty(conf,'_flow', {value: flow, enumerable: false, writable: true }) | ||
newNode = new nodeTypeConstructor(conf); | ||
} catch (err) { | ||
Log.log({ | ||
level: Log.ERROR, | ||
id:conf.id, | ||
type: type, | ||
msg: err | ||
}); | ||
} | ||
} else { | ||
Log.error(Log._("nodes.flow.unknown-type", {type:type})); | ||
} | ||
} catch(err) { | ||
Log.error(err); | ||
} | ||
return newNode; | ||
} | ||
createNode: createNode | ||
} |
@@ -17,4 +17,2 @@ /*! | ||
var when = require('when'); | ||
var externalAPI = require("./api"); | ||
@@ -26,6 +24,5 @@ | ||
var library = require("./library"); | ||
var events = require("./events"); | ||
var hooks = require("./hooks"); | ||
var plugins = require("./plugins"); | ||
var settings = require("./settings"); | ||
var exec = require("./exec"); | ||
@@ -37,5 +34,3 @@ var express = require("express"); | ||
var redUtil = require("@node-red/util"); | ||
var log = redUtil.log; | ||
var i18n = redUtil.i18n; | ||
const {log,i18n,events,exec,util} = require("@node-red/util"); | ||
@@ -73,3 +68,3 @@ var runtimeMetricInterval = null; | ||
*/ | ||
function init(userSettings,httpServer,_adminApi,__util) { | ||
function init(userSettings,httpServer,_adminApi) { | ||
server = httpServer; | ||
@@ -86,12 +81,3 @@ userSettings.version = getVersion(); | ||
redNodes.init(runtime); | ||
library.init(runtime); | ||
externalAPI.init(runtime); | ||
exec.init(runtime); | ||
if (__util) { | ||
log = __util.log; | ||
i18n = __util.i18n; | ||
} else { | ||
log = redUtil.log; | ||
i18n = redUtil.i18n; | ||
} | ||
} | ||
@@ -125,2 +111,3 @@ | ||
.then(function() { return settings.load(storage)}) | ||
.then(function() { return library.init(runtime)}) | ||
.then(function() { | ||
@@ -146,3 +133,11 @@ | ||
return redNodes.load().then(function() { | ||
let autoInstallModules = false; | ||
if (settings.hasOwnProperty('autoInstallModules')) { | ||
log.warn(log._("server.deprecatedOption",{old:"autoInstallModules", new:"externalModules.autoInstall"})); | ||
autoInstallModules = true; | ||
} | ||
if (settings.externalModules) { | ||
// autoInstallModules = autoInstall enabled && (no palette setting || palette install not disabled) | ||
autoInstallModules = settings.externalModules.autoInstall && (!settings.externalModules.palette || settings.externalModules.palette.allowInstall !== false) ; | ||
} | ||
var i; | ||
@@ -180,3 +175,3 @@ var nodeErrors = redNodes.getNodeList(function(n) { return n.err!=null;}); | ||
log.warn(" - "+i+" ("+missingModules[i].version+"): "+missingModules[i].types.join(", ")); | ||
if (settings.autoInstallModules && i != "node-red") { | ||
if (autoInstallModules && i != "node-red") { | ||
installingModules.push({id:i,version:missingModules[i].version}); | ||
@@ -186,3 +181,3 @@ } | ||
} | ||
if (!settings.autoInstallModules) { | ||
if (!autoInstallModules) { | ||
log.info(log._("server.removing-modules")); | ||
@@ -209,25 +204,31 @@ redNodes.cleanModuleList(); | ||
var reinstallAttempts; | ||
var reinstallAttempts = 0; | ||
var reinstallTimeout; | ||
function reinstallModules(moduleList) { | ||
var promises = []; | ||
var failedModules = []; | ||
const promises = []; | ||
const reinstallList = []; | ||
const installRetry = 30000; | ||
if (settings.hasOwnProperty('autoInstallModulesRetry')) { | ||
log.warn(log._("server.deprecatedOption",{old:"autoInstallModulesRetry", new:"externalModules.autoInstallRetry"})); | ||
installRetry = settings.autoInstallModulesRetry; | ||
} | ||
if (settings.externalModules && settings.externalModules.hasOwnProperty('autoInstallRetry')) { | ||
installRetry = settings.externalModules.autoInstallRetry * 1000; | ||
} | ||
for (var i=0;i<moduleList.length;i++) { | ||
if (settings.autoInstallModules && i != "node-red") { | ||
promises.push(redNodes.installModule(moduleList[i].id,moduleList[i].version)); | ||
if (moduleList[i].id != "node-red") { | ||
(function(mod) { | ||
promises.push(redNodes.installModule(mod.id,mod.version).then(m => { | ||
events.emit("runtime-event",{id:"node/added",retain:false,payload:m.nodes}); | ||
}).catch(err => { | ||
reinstallList.push(mod); | ||
})); | ||
})(moduleList[i]) | ||
} | ||
} | ||
when.settle(promises).then(function(results) { | ||
var reinstallList = []; | ||
for (var i=0;i<results.length;i++) { | ||
if (results[i].state === 'rejected') { | ||
reinstallList.push(moduleList[i]); | ||
} else { | ||
events.emit("runtime-event",{id:"node/added",retain:false,payload:results[i].value.nodes}); | ||
} | ||
} | ||
Promise.all(promises).then(function(results) { | ||
if (reinstallList.length > 0) { | ||
reinstallAttempts++; | ||
// First 5 at 1x timeout, next 5 at 2x, next 5 at 4x, then 8x | ||
var timeout = (settings.autoInstallModulesRetry||30000) * Math.pow(2,Math.min(Math.floor(reinstallAttempts/5),3)); | ||
var timeout = installRetry * Math.pow(2,Math.min(Math.floor(reinstallAttempts/5),3)); | ||
reinstallTimeout = setTimeout(function() { | ||
@@ -262,2 +263,6 @@ reinstallModules(reinstallList); | ||
* Stops the runtime. | ||
* | ||
* Once called, Node-RED should not be restarted until the Node.JS process is | ||
* restarted. | ||
* | ||
* @return {Promise} - resolves when the runtime is stopped. | ||
@@ -280,16 +285,18 @@ * @memberof @node-red/runtime | ||
// This is the internal api | ||
var runtime = { | ||
version: getVersion, | ||
get log() { return log }, | ||
get i18n() { return i18n }, | ||
log: log, | ||
i18n: i18n, | ||
events: events, | ||
settings: settings, | ||
storage: storage, | ||
events: events, | ||
hooks: hooks, | ||
nodes: redNodes, | ||
plugins: plugins, | ||
flows: flows, | ||
library: library, | ||
exec: exec, | ||
util: require("@node-red/util").util, | ||
util: util, | ||
get adminApi() { return adminApi }, | ||
@@ -353,2 +360,8 @@ get adminApp() { return adminApp }, | ||
/** | ||
* @memberof @node-red/runtime | ||
* @mixes @node-red/runtime_plugins | ||
*/ | ||
plugins: externalAPI.plugins, | ||
/** | ||
* Returns whether the runtime is started | ||
@@ -355,0 +368,0 @@ * @param {Object} opts |
@@ -98,5 +98,9 @@ /** | ||
module.exports = { | ||
name: '_examples_', | ||
id: "examples", | ||
label: "editor:library.types.examples", | ||
icon: "font-awesome/fa-life-ring", | ||
types: ["flows"], | ||
readOnly: true, | ||
init: init, | ||
getEntry: getEntry | ||
} |
@@ -18,19 +18,77 @@ /** | ||
var knownTypes = {}; | ||
const {events,log} = require("@node-red/util") | ||
const knownTypes = {}; | ||
const libraries = {}; | ||
const libraryConfigs = {}; | ||
const libraryPlugins = {}; | ||
var libraries = {}; | ||
// Libraries defined in the settings file. Their configurations | ||
// cannot be modified in the editor. | ||
let runtimeLibraries = []; | ||
// Libraries defined by the user in the editor. | ||
let userLibraries = []; | ||
function init(runtime) { | ||
knownTypes = { | ||
'flows': 'node-red' | ||
}; | ||
let runtime; | ||
libraries["_examples_"] = require("./examples"); | ||
libraries["_examples_"].init(runtime); | ||
function init(_runtime) { | ||
runtime = _runtime; | ||
events.removeListener("registry:plugin-added",onPluginAdded); | ||
events.on("registry:plugin-added",onPluginAdded); | ||
knownTypes.flows = 'node-red'; | ||
libraries["local"] = require("./local"); | ||
libraries["local"].init(runtime); | ||
libraryConfigs["local"] = libraries["local"] | ||
libraries["examples"] = require("./examples"); | ||
libraries["examples"].init(runtime); | ||
libraryConfigs["examples"] = libraries["examples"] | ||
try { | ||
runtimeLibraries = runtime.settings.editorTheme.library.sources; | ||
} catch(err) { | ||
runtimeLibraries = []; | ||
} | ||
// userLibraries = runtime.settings.get("library") | ||
} | ||
function onPluginAdded(id) { | ||
const plugin = runtime.plugins.getPlugin(id); | ||
if (plugin.type === "node-red-library-source") { | ||
libraryPlugins[plugin.id] = plugin; | ||
runtimeLibraries.forEach(library => { | ||
if (library.type === id) { | ||
library.local = false; | ||
if (!/^[a-z0-9-_]+$/.test(library.id)) { | ||
log.warn(log._("library.failedToInit",{error:log._("library.invalidProperty",{prop:"id",value:library.id})})); | ||
return; | ||
} | ||
try { | ||
libraries[library.id] = new plugin.class(library) | ||
libraryConfigs[library.id] = library; | ||
libraryConfigs[library.id].type = id; | ||
if (libraries[library.id].init) { | ||
libraries[library.id].init().catch(err => { | ||
delete libraries[library.id]; | ||
delete libraryConfigs[library.id]; | ||
log.warn(log._("library.failedToInit",{library:library.id, error:err.toString()})); | ||
}); | ||
} | ||
} catch(err) { | ||
log.warn(log._("library.failedToInit",{library:library.id, error:err.toString()})); | ||
} | ||
} | ||
}) | ||
} | ||
} | ||
function registerType(id,type) { | ||
@@ -47,3 +105,3 @@ // TODO: would like to enforce this, but currently the tests register the same type multiple | ||
if (!knownTypes.hasOwnProperty(type)) { | ||
throw new Error(`Unknown library type '${type}'`); | ||
throw new Error(log._("library.unknownType",{type: type})) | ||
} | ||
@@ -53,3 +111,3 @@ if (libraries.hasOwnProperty(library)) { | ||
} else { | ||
throw new Error(`Unknown library '${library}'`); | ||
throw new Error(log._("library.unknownLibrary",{library: library})) | ||
} | ||
@@ -59,17 +117,68 @@ } | ||
if (!knownTypes.hasOwnProperty(type)) { | ||
throw new Error(`Unknown library type '${type}'`); | ||
throw new Error(log._("library.unknownType",{type: type})) | ||
} | ||
if (libraries.hasOwnProperty(library)) { | ||
if (libraries[library].hasOwnProperty("saveEntry")) { | ||
if (libraries[library].saveEntry) { | ||
return libraries[library].saveEntry(type,path,meta,body); | ||
} else { | ||
throw new Error(`Library '${library}' is read-only`); | ||
throw new Error(log._("library.readOnly",{library: library})) | ||
} | ||
} else { | ||
throw new Error(`Unknown library '${library}'`); | ||
throw new Error(log._("library.unknownLibrary",{library: library})) | ||
} | ||
} | ||
function getLibraries() { | ||
const libraryList = [] | ||
for (let id in libraries) { | ||
if (libraries.hasOwnProperty(id)) { | ||
var config = getConfig(id); | ||
// Don't include the full configuration of each library when providing | ||
// the list of all libraries | ||
delete config.config; | ||
libraryList.push(config); | ||
} | ||
} | ||
return libraryList; | ||
} | ||
function getConfig(id) { | ||
var lib = { | ||
id: id, | ||
label: libraryConfigs[id].label || id, | ||
user: false, | ||
icon: libraryConfigs[id].icon | ||
} | ||
if (libraryConfigs[id].types) { | ||
lib.types = libraryConfigs[id].types | ||
} | ||
if (libraryConfigs[id].readOnly) { | ||
lib.readOnly = libraryConfigs[id].readOnly | ||
} | ||
if (libraryConfigs[id].type) { | ||
lib.type = libraryConfigs[id].type; | ||
var def = libraryPlugins[lib.type]; | ||
if (def && def.defaults) { | ||
lib.config = {}; | ||
for (var d in def.defaults) { | ||
if (def.defaults.hasOwnProperty(d)) { | ||
if (def.defaults[d].type !== 'password') { | ||
lib.config[d] = libraryConfigs[id][d]; | ||
} else if (!!libraryConfigs[id][d]) { | ||
lib.config["has_"+d] = true; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
return lib; | ||
} | ||
module.exports = { | ||
init: init, | ||
getLibraries: getLibraries, | ||
// getConfig: getConfig, | ||
register: registerType, | ||
@@ -76,0 +185,0 @@ getEntry: getEntry, |
@@ -33,3 +33,5 @@ /** | ||
module.exports = { | ||
name: 'local', | ||
id: "local", | ||
label: "editor:library.types.local", | ||
icon: "font-awesome/fa-hdd-o", | ||
init: init, | ||
@@ -36,0 +38,0 @@ getEntry: getEntry, |
@@ -17,3 +17,2 @@ /** | ||
var when = require("when"); | ||
var crypto = require('crypto'); | ||
@@ -64,3 +63,3 @@ var runtime; | ||
*/ | ||
load: function (credentials) { | ||
load: async function (credentials) { | ||
dirty = false; | ||
@@ -82,3 +81,3 @@ var credentialsEncrypted = credentials.hasOwnProperty("$") && Object.keys(credentials).length === 1; | ||
var setupEncryptionPromise = when.resolve(); | ||
var setupEncryptionPromise = Promise.resolve(); | ||
@@ -140,3 +139,3 @@ var projectKey = false; | ||
error.code = "credentials_load_failed"; | ||
return when.reject(error); | ||
throw error; | ||
} | ||
@@ -170,3 +169,3 @@ } | ||
error.code = "credentials_load_failed"; | ||
return when.reject(error); | ||
throw error; | ||
} | ||
@@ -225,5 +224,5 @@ } | ||
activeProject.credentialSecretInvalid = true; | ||
return when.reject(error); | ||
throw error; | ||
} | ||
return when.reject(error); | ||
throw error; | ||
} | ||
@@ -244,5 +243,5 @@ // These are encrypted credentials | ||
activeProject.credentialSecretInvalid = true; | ||
return when.reject(error); | ||
throw error; | ||
} | ||
return when.reject(error); | ||
throw error; | ||
} | ||
@@ -267,3 +266,3 @@ } else { | ||
*/ | ||
add: function (id, creds) { | ||
add: async function (id, creds) { | ||
if (!credentialCache.hasOwnProperty(id) || JSON.stringify(creds) !== JSON.stringify(credentialCache[id])) { | ||
@@ -273,3 +272,2 @@ credentialCache[id] = creds; | ||
} | ||
return when.resolve(); | ||
}, | ||
@@ -305,3 +303,3 @@ | ||
*/ | ||
clean: function (config) { | ||
clean: async function (config) { | ||
var existingIds = {}; | ||
@@ -326,3 +324,2 @@ config.forEach(function(n) { | ||
} | ||
return when.resolve(); | ||
}, | ||
@@ -446,3 +443,3 @@ | ||
}, | ||
export: function() { | ||
export: async function() { | ||
var result = credentialCache; | ||
@@ -470,5 +467,5 @@ | ||
} else { | ||
return when.resolve(result); | ||
return result; | ||
} | ||
} | ||
} |
@@ -17,3 +17,2 @@ /** | ||
var when = require("when"); | ||
var path = require("path"); | ||
@@ -33,3 +32,3 @@ var fs = require("fs"); | ||
var events = require("../events"); | ||
const events = require("@node-red/util").events; | ||
@@ -87,3 +86,3 @@ var settings; | ||
} | ||
registry.registerType(nodeSet,type,constructor); | ||
registry.registerType(nodeSet,type,constructor,opts); | ||
} | ||
@@ -119,2 +118,21 @@ | ||
function registerSubflow(nodeSet, subflow) { | ||
// TODO: extract credentials definition from subflow properties | ||
var registeredType = registry.registerSubflow(nodeSet,subflow); | ||
if (subflow.env) { | ||
var creds = {}; | ||
var hasCreds = false; | ||
subflow.env.forEach(e => { | ||
if (e.type === "cred") { | ||
creds[e.name] = {type: "password"}; | ||
hasCreds = true; | ||
} | ||
}) | ||
if (hasCreds) { | ||
credentials.register(registeredType.type,creds); | ||
} | ||
} | ||
} | ||
function init(runtime) { | ||
@@ -170,7 +188,8 @@ settings = runtime.settings; | ||
var info = registry.getModuleInfo(module); | ||
if (!info) { | ||
if (!info || !info.user) { | ||
throw new Error(log._("nodes.index.unrecognised-module", {module:module})); | ||
} else { | ||
for (var i=0;i<info.nodes.length;i++) { | ||
flows.checkTypeInUse(module+"/"+info.nodes[i].name); | ||
var nodeTypesToCheck = info.nodes.map(n => `${module}/${n.name}`); | ||
for (var i=0;i<nodeTypesToCheck.length;i++) { | ||
flows.checkTypeInUse(nodeTypesToCheck[i]); | ||
} | ||
@@ -196,3 +215,3 @@ return registry.uninstallModule(module).then(function(list) { | ||
paletteEditorEnabled: registry.paletteEditorEnabled, | ||
installerEnabled: registry.installerEnabled, | ||
installModule: installModule, | ||
@@ -206,2 +225,3 @@ uninstallModule: uninstallModule, | ||
registerType: registerType, | ||
registerSubflow: registerSubflow, | ||
getType: registry.get, | ||
@@ -251,3 +271,3 @@ | ||
closeContextsPlugin: context.close, | ||
listContextStores: context.listStores | ||
listContextStores: context.listStores, | ||
}; |
@@ -489,5 +489,3 @@ /** | ||
} | ||
if (self._flow) { | ||
o.path = self._flow.path; | ||
} | ||
if (self.z) { | ||
@@ -499,3 +497,3 @@ o.z = self.z; | ||
} | ||
Log.log(o); | ||
self._flow.log(o); | ||
} | ||
@@ -502,0 +500,0 @@ /** |
@@ -17,3 +17,2 @@ /** | ||
var when = require("when"); | ||
var clone = require("clone"); | ||
@@ -94,6 +93,6 @@ var assert = require("assert"); | ||
assert.deepEqual(current,value); | ||
return when.resolve(); | ||
} catch(err) { | ||
return storage.saveSettings(clone(globalSettings)); | ||
} | ||
return Promise.resolve(); | ||
}, | ||
@@ -111,3 +110,3 @@ delete: function(prop) { | ||
} | ||
return when.resolve(); | ||
return Promise.resolve(); | ||
}, | ||
@@ -186,3 +185,3 @@ | ||
assert.deepEqual(current,settings); | ||
return when.resolve(); | ||
return Promise.resolve(); | ||
} catch(err) { | ||
@@ -189,0 +188,0 @@ globalSettings.users = userSettings; |
@@ -17,7 +17,6 @@ /** | ||
var when = require('when'); | ||
var Path = require('path'); | ||
var crypto = require('crypto'); | ||
var log = require("@node-red/util").log; // TODO: separate module | ||
var log = require("@node-red/util").log; | ||
@@ -54,11 +53,9 @@ var runtime; | ||
var storageModuleInterface = { | ||
init: function(_runtime) { | ||
init: async function(_runtime) { | ||
runtime = _runtime; | ||
try { | ||
storageModule = moduleSelector(runtime.settings); | ||
settingsAvailable = storageModule.hasOwnProperty("getSettings") && storageModule.hasOwnProperty("saveSettings"); | ||
sessionsAvailable = storageModule.hasOwnProperty("getSessions") && storageModule.hasOwnProperty("saveSessions"); | ||
} catch (e) { | ||
return when.reject(e); | ||
} | ||
// Any errors thrown by the module will get passed up to the called | ||
// as a rejected promise | ||
storageModule = moduleSelector(runtime.settings); | ||
settingsAvailable = storageModule.hasOwnProperty("getSettings") && storageModule.hasOwnProperty("saveSettings"); | ||
sessionsAvailable = storageModule.hasOwnProperty("getSessions") && storageModule.hasOwnProperty("saveSessions"); | ||
if (!!storageModule.projects) { | ||
@@ -78,3 +75,3 @@ var projectsEnabled = false; | ||
}, | ||
getFlows: function() { | ||
getFlows: async function() { | ||
return storageModule.getFlows().then(function(flows) { | ||
@@ -91,3 +88,3 @@ return storageModule.getCredentials().then(function(creds) { | ||
}, | ||
saveFlows: function(config, user) { | ||
saveFlows: async function(config, user) { | ||
var flows = config.flows; | ||
@@ -99,3 +96,3 @@ var credentials = config.credentials; | ||
} else { | ||
credentialSavePromise = when.resolve(); | ||
credentialSavePromise = Promise.resolve(); | ||
} | ||
@@ -113,31 +110,27 @@ delete config.credentialsDirty; | ||
// }, | ||
saveCredentials: function(credentials) { | ||
saveCredentials: async function(credentials) { | ||
return storageModule.saveCredentials(credentials); | ||
}, | ||
getSettings: function() { | ||
getSettings: async function() { | ||
if (settingsAvailable) { | ||
return storageModule.getSettings(); | ||
} else { | ||
return when.resolve(null); | ||
return null | ||
} | ||
}, | ||
saveSettings: function(settings) { | ||
saveSettings: async function(settings) { | ||
if (settingsAvailable) { | ||
return settingsSaveMutex.runExclusive(() => storageModule.saveSettings(settings)) | ||
} else { | ||
return when.resolve(); | ||
} | ||
}, | ||
getSessions: function() { | ||
getSessions: async function() { | ||
if (sessionsAvailable) { | ||
return storageModule.getSessions(); | ||
} else { | ||
return when.resolve(null); | ||
return null | ||
} | ||
}, | ||
saveSessions: function(sessions) { | ||
saveSessions: async function(sessions) { | ||
if (sessionsAvailable) { | ||
return storageModule.saveSessions(sessions); | ||
} else { | ||
return when.resolve(); | ||
} | ||
@@ -148,15 +141,15 @@ }, | ||
getLibraryEntry: function(type, path) { | ||
getLibraryEntry: async function(type, path) { | ||
if (is_malicious(path)) { | ||
var err = new Error(); | ||
err.code = "forbidden"; | ||
return when.reject(err); | ||
throw err; | ||
} | ||
return storageModule.getLibraryEntry(type, path); | ||
}, | ||
saveLibraryEntry: function(type, path, meta, body) { | ||
saveLibraryEntry: async function(type, path, meta, body) { | ||
if (is_malicious(path)) { | ||
var err = new Error(); | ||
err.code = "forbidden"; | ||
return when.reject(err); | ||
throw err; | ||
} | ||
@@ -167,3 +160,3 @@ return storageModule.saveLibraryEntry(type, path, meta, body); | ||
/* Deprecated functions */ | ||
getAllFlows: function() { | ||
getAllFlows: async function() { | ||
if (storageModule.hasOwnProperty("getAllFlows")) { | ||
@@ -173,3 +166,3 @@ return storageModule.getAllFlows(); | ||
if (libraryFlowsCachedResult) { | ||
return Promise.resolve(libraryFlowsCachedResult); | ||
return libraryFlowsCachedResult; | ||
} else { | ||
@@ -187,3 +180,3 @@ return listFlows("/").then(function(result) { | ||
err.code = "forbidden"; | ||
return when.reject(err); | ||
throw err; | ||
} | ||
@@ -201,3 +194,3 @@ if (storageModule.hasOwnProperty("getFlow")) { | ||
err.code = "forbidden"; | ||
return when.reject(err); | ||
throw err; | ||
} | ||
@@ -218,32 +211,30 @@ libraryFlowsCachedResult = null; | ||
return storageModule.getLibraryEntry("flows",path).then(function(res) { | ||
return when.promise(function(resolve) { | ||
var promises = []; | ||
res.forEach(function(r) { | ||
if (typeof r === "string") { | ||
promises.push(listFlows(Path.join(path,r))); | ||
const promises = []; | ||
res.forEach(function(r) { | ||
if (typeof r === "string") { | ||
promises.push(listFlows(Path.join(path,r))); | ||
} else { | ||
promises.push(Promise.resolve(r)); | ||
} | ||
}); | ||
return Promise.all(promises).then(res2 => { | ||
let i = 0; | ||
const result = {}; | ||
res2.forEach(function(r) { | ||
// TODO: name||fn | ||
if (r.fn) { | ||
var name = r.name; | ||
if (!name) { | ||
name = r.fn.replace(/\.json$/, ""); | ||
} | ||
result.f = result.f || []; | ||
result.f.push(name); | ||
} else { | ||
promises.push(when.resolve(r)); | ||
result.d = result.d || {}; | ||
result.d[res[i]] = r; | ||
//console.log(">",r.value); | ||
} | ||
i++; | ||
}); | ||
var i=0; | ||
when.settle(promises).then(function(res2) { | ||
var result = {}; | ||
res2.forEach(function(r) { | ||
// TODO: name||fn | ||
if (r.value.fn) { | ||
var name = r.value.name; | ||
if (!name) { | ||
name = r.value.fn.replace(/\.json$/, ""); | ||
} | ||
result.f = result.f || []; | ||
result.f.push(name); | ||
} else { | ||
result.d = result.d || {}; | ||
result.d[res[i]] = r.value; | ||
//console.log(">",r.value); | ||
} | ||
i++; | ||
}); | ||
resolve(result); | ||
}); | ||
return result; | ||
}); | ||
@@ -253,4 +244,2 @@ }); | ||
module.exports = storageModuleInterface; |
@@ -18,5 +18,3 @@ /** | ||
var fs = require('fs-extra'); | ||
var when = require('when'); | ||
var fspath = require("path"); | ||
var nodeFn = require('when/node/function'); | ||
@@ -94,3 +92,3 @@ var util = require("./util"); | ||
// don't create the folder if it does not exist - we are only reading.... | ||
return nodeFn.call(fs.lstat, rootPath).then(function(stats) { | ||
return fs.lstat(rootPath).then(function(stats) { | ||
if (stats.isFile()) { | ||
@@ -102,3 +100,3 @@ return getFileBody(root,path); | ||
} | ||
return nodeFn.call(fs.readdir, rootPath).then(function(fns) { | ||
return fs.readdir(rootPath).then(function(fns) { | ||
var dirs = []; | ||
@@ -149,3 +147,3 @@ var files = []; | ||
module.exports = { | ||
init: function(_settings) { | ||
init: async function(_settings) { | ||
settings = _settings; | ||
@@ -156,4 +154,2 @@ libDir = fspath.join(settings.userDir,"lib"); | ||
return fs.ensureDir(libFlowsDir); | ||
} else { | ||
return when.resolve(); | ||
} | ||
@@ -163,5 +159,5 @@ }, | ||
saveLibraryEntry: function(type,path,meta,body) { | ||
saveLibraryEntry: async function(type,path,meta,body) { | ||
if (settings.readOnly) { | ||
return when.resolve(); | ||
return; | ||
} | ||
@@ -168,0 +164,0 @@ if (type === "flows" && !path.endsWith(".json")) { |
@@ -17,4 +17,2 @@ /** | ||
var exec = require("../../../../exec"); | ||
var authResponseServer = require('./authServer').ResponseServer; | ||
@@ -27,3 +25,3 @@ var sshResponseServer = require('./authServer').ResponseSSHServer; | ||
var gitVersion; | ||
var log = require("@node-red/util").log; | ||
const {log,exec} = require("@node-red/util"); | ||
@@ -30,0 +28,0 @@ function runGitCommand(args,cwd,env,emit) { |
@@ -18,5 +18,3 @@ /** | ||
var fs = require('fs-extra'); | ||
var when = require('when'); | ||
var fspath = require("path"); | ||
var nodeFn = require('when/node/function'); | ||
var crypto = require('crypto'); | ||
@@ -34,2 +32,3 @@ | ||
var log = require("@node-red/util").log; | ||
const events = require("@node-red/util").events; | ||
@@ -40,3 +39,3 @@ var projectsEnabled = false; | ||
var projectsDir; | ||
var activeProject | ||
var activeProject; | ||
@@ -113,6 +112,16 @@ var globalGitUser = false; | ||
} else { | ||
// Ensure there's a default workflow mode set | ||
settings.editorTheme.projects.workflow = { | ||
mode: (settings.editorTheme.projects.workflow || {}).mode || "manual" | ||
} | ||
globalGitUser = gitConfig.user; | ||
Projects.init(settings,runtime); | ||
sshTools.init(settings); | ||
projectsDir = fspath.resolve(fspath.join(settings.userDir,"projects")); | ||
if(settings.editorTheme.projects.path) { | ||
projectsDir = settings.editorTheme.projects.path; | ||
} | ||
if (!settings.readOnly) { | ||
@@ -237,3 +246,2 @@ return fs.ensureDir(projectsDir) | ||
checkActiveProject(name); | ||
//return when.resolve(activeProject.info); | ||
return Promise.resolve(activeProject.export()); | ||
@@ -377,7 +385,7 @@ } | ||
return runtime.nodes.loadFlows(true).then(function() { | ||
runtime.events.emit("runtime-event",{id:"project-update", payload:{ project: activeProject.name, action:action}}); | ||
events.emit("runtime-event",{id:"project-update", payload:{ project: activeProject.name, action:action}}); | ||
}).catch(function(err) { | ||
// We're committed to the project change now, so notify editors | ||
// that it has changed. | ||
runtime.events.emit("runtime-event",{id:"project-update", payload:{ project: activeProject.name, action:action}}); | ||
events.emit("runtime-event",{id:"project-update", payload:{ project: activeProject.name, action:action}}); | ||
throw err; | ||
@@ -519,6 +527,11 @@ }); | ||
function getFlows() { | ||
async function getFlows() { | ||
if (!initialFlowLoadComplete) { | ||
initialFlowLoadComplete = true; | ||
log.info(log._("storage.localfilesystem.user-dir",{path:settings.userDir})); | ||
if (projectsEnabled) { | ||
log.info(log._("storage.localfilesystem.projects.projects-directory", {projectsDirectory: projectsDir})); | ||
} | ||
if (activeProject) { | ||
@@ -547,3 +560,3 @@ // At this point activeProject will be a string, so go load it and | ||
error.code = "project_empty"; | ||
return when.reject(error); | ||
throw error; | ||
} | ||
@@ -554,3 +567,3 @@ if (activeProject.missingFiles && activeProject.missingFiles.indexOf('package.json') !== -1) { | ||
error.code = "missing_package_file"; | ||
return when.reject(error); | ||
throw error; | ||
} | ||
@@ -561,3 +574,3 @@ if (!activeProject.getFlowFile()) { | ||
error.code = "missing_flow_file"; | ||
return when.reject(error); | ||
throw error; | ||
} | ||
@@ -568,3 +581,3 @@ if (activeProject.isMerging()) { | ||
error.code = "git_merge_conflict"; | ||
return when.reject(error); | ||
throw error; | ||
} | ||
@@ -583,5 +596,5 @@ | ||
function saveFlows(flows, user) { | ||
async function saveFlows(flows, user) { | ||
if (settings.readOnly) { | ||
return when.resolve(); | ||
return | ||
} | ||
@@ -591,3 +604,3 @@ if (activeProject && activeProject.isMerging()) { | ||
error.code = "git_merge_conflict"; | ||
return when.reject(error); | ||
throw error; | ||
} | ||
@@ -607,7 +620,9 @@ | ||
var gitSettings = getUserGitSettings(user) || {}; | ||
var workflowMode = (gitSettings.workflow||{}).mode || "manual"; | ||
if (activeProject && workflowMode === 'auto') { | ||
return activeProject.stageFile([flowsFullPath, credentialsFile]).then(() => { | ||
return activeProject.commit(user,{message:"Update flow files"}) | ||
}) | ||
if (activeProject) { | ||
var workflowMode = (gitSettings.workflow||{}).mode || settings.editorTheme.projects.workflow.mode; | ||
if (workflowMode === 'auto') { | ||
return activeProject.stageFile([flowsFullPath, credentialsFile]).then(() => { | ||
return activeProject.commit(user,{message:"Update flow files"}) | ||
}) | ||
} | ||
} | ||
@@ -621,5 +636,5 @@ }); | ||
function saveCredentials(credentials) { | ||
async function saveCredentials(credentials) { | ||
if (settings.readOnly) { | ||
return when.resolve(); | ||
return; | ||
} | ||
@@ -626,0 +641,0 @@ |
@@ -19,3 +19,2 @@ /** | ||
var fs = require('fs-extra'); | ||
var when = require('when'); | ||
var fspath = require("path"); | ||
@@ -31,2 +30,3 @@ var os = require('os'); | ||
var log = require("@node-red/util").log; | ||
const events = require("@node-red/util").events; | ||
@@ -113,3 +113,3 @@ var projectsDir; | ||
} | ||
})); | ||
}).catch(err => {})); // | ||
if (missingFiles.indexOf('README.md') === -1) { | ||
@@ -119,3 +119,3 @@ project.paths['README.md'] = fspath.join(project.paths.root,"README.md"); | ||
project.description = content; | ||
})); | ||
}).catch(err => {})); | ||
} else { | ||
@@ -140,5 +140,5 @@ project.description = ""; | ||
promises.push(project.loadRemotes()); | ||
promises.push(project.loadRemotes().catch(err => {})); | ||
return when.settle(promises).then(function(results) { | ||
return Promise.all(promises).then(function(results) { | ||
return project; | ||
@@ -247,3 +247,3 @@ }) | ||
Project.prototype.update = function (user, data) { | ||
Project.prototype.update = async function (user, data) { | ||
var username; | ||
@@ -288,3 +288,3 @@ if (!user) { | ||
e.code = "missing_current_credential_key"; | ||
return when.reject(e); | ||
throw e; | ||
} | ||
@@ -302,3 +302,3 @@ this.credentialSecret = secret; | ||
// Cannot update a project that doesn't have a known package.json | ||
return Promise.reject("Cannot update project with missing package.json"); | ||
throw new Error("Cannot update project with missing package.json"); | ||
} | ||
@@ -313,3 +313,3 @@ } | ||
if (!/package\.json$/.test(data.files.package)) { | ||
return Promise.reject("Invalid package file: "+data.files.package) | ||
return new Error("Invalid package file: "+data.files.package) | ||
} | ||
@@ -412,3 +412,3 @@ var root = data.files.package.substring(0,data.files.package.length-12); | ||
}); | ||
promises.push(modifyRemotesPromise); | ||
promises.push(modifyRemotesPromise.catch(err => {})); | ||
} | ||
@@ -420,3 +420,3 @@ } | ||
if (saveSettings) { | ||
promises.push(settings.set("projects",globalProjectSettings)); | ||
promises.push(settings.set("projects",globalProjectSettings).catch(err => {})); | ||
} | ||
@@ -427,3 +427,3 @@ | ||
if (saveREADME) { | ||
promises.push(util.writeFile(fspath.join(this.path,this.paths['README.md']), this.description)); | ||
promises.push(util.writeFile(fspath.join(this.path,this.paths['README.md']), this.description).catch(err => {})); | ||
modifiedFiles.push('README.md'); | ||
@@ -440,8 +440,8 @@ } | ||
return util.writeFile(fspath.join(project.path,this.paths['package.json']), JSON.stringify(this.package,"",4)); | ||
})); | ||
}).catch(err => {})); | ||
modifiedFiles.push('package.json'); | ||
} | ||
return when.settle(promises).then(function(res) { | ||
return Promise.all(promises).then(function(res) { | ||
var gitSettings = getUserGitSettings(user) || {}; | ||
var workflowMode = (gitSettings.workflow||{}).mode || "manual"; | ||
var workflowMode = (gitSettings.workflow||{}).mode || settings.editorTheme.projects.workflow.mode; | ||
if (workflowMode === 'auto') { | ||
@@ -562,3 +562,3 @@ return project.stageFile(modifiedFiles.map(f => project.paths[f])).then(() => { | ||
self.merging = true; | ||
runtime.events.emit("runtime-event",{ | ||
events.emit("runtime-event",{ | ||
id:"runtime-state", | ||
@@ -587,3 +587,3 @@ payload:{ | ||
if (!self.empty) { | ||
runtime.events.emit("runtime-event",{ | ||
events.emit("runtime-event",{ | ||
id:"runtime-state", | ||
@@ -602,5 +602,5 @@ payload:{ | ||
if (self.paths.flowFile) { | ||
runtime.events.emit("runtime-event",{id:"runtime-state",retain:true}); | ||
events.emit("runtime-event",{id:"runtime-state",retain:true}); | ||
} else { | ||
runtime.events.emit("runtime-event",{ | ||
events.emit("runtime-event",{ | ||
id:"runtime-state", | ||
@@ -981,28 +981,13 @@ payload:{ | ||
var promises = []; | ||
var paths = []; | ||
var missing = []; | ||
for (var file in defaultFileSet) { | ||
if (defaultFileSet.hasOwnProperty(file)) { | ||
paths.push(file); | ||
promises.push(fs.stat(fspath.join(project.path,project.paths.root,file))); | ||
(function(f) { | ||
promises.push(fs.stat(fspath.join(project.path,project.paths.root,f)).catch(err => { | ||
missing.push(f); | ||
})); | ||
})(file); | ||
} | ||
} | ||
return when.settle(promises).then(function(results) { | ||
var missing = []; | ||
results.forEach(function(result,i) { | ||
if (result.state === 'rejected') { | ||
missing.push(paths[i]); | ||
} | ||
}); | ||
return missing; | ||
}).then(function(missing) { | ||
// if (createMissing) { | ||
// var promises = []; | ||
// missing.forEach(function(file) { | ||
// promises.push(util.writeFile(fspath.join(projectPath,file),defaultFileSet[file](project))); | ||
// }); | ||
// return promises; | ||
// } else { | ||
return missing; | ||
// } | ||
}); | ||
return Promise.all(promises).then(() => missing); | ||
} | ||
@@ -1101,2 +1086,5 @@ function createProject(user, metadata) { | ||
projectsDir = fspath.resolve(fspath.join(settings.userDir,"projects")); | ||
if(settings.editorTheme.projects.path) { | ||
projectsDir = settings.editorTheme.projects.path; | ||
} | ||
authCache.init(); | ||
@@ -1103,0 +1091,0 @@ } |
@@ -18,3 +18,2 @@ /** | ||
var fs = require('fs-extra'); | ||
var when = require('when'); | ||
var fspath = require("path"); | ||
@@ -21,0 +20,0 @@ var keygen = require("./keygen"); |
@@ -17,3 +17,2 @@ /** | ||
var when = require('when'); | ||
var fs = require('fs-extra'); | ||
@@ -34,4 +33,4 @@ var fspath = require("path"); | ||
}, | ||
getSessions: function() { | ||
return when.promise(function(resolve,reject) { | ||
getSessions: async function() { | ||
return new Promise(function(resolve,reject) { | ||
fs.readFile(sessionsFile,'utf8',function(err,data){ | ||
@@ -49,5 +48,5 @@ if (!err) { | ||
}, | ||
saveSessions: function(sessions) { | ||
saveSessions: async function(sessions) { | ||
if (settings.readOnly) { | ||
return when.resolve(); | ||
return; | ||
} | ||
@@ -54,0 +53,0 @@ return util.writeFile(sessionsFile,JSON.stringify(sessions)); |
@@ -45,2 +45,3 @@ { | ||
}, | ||
"deprecatedOption": "Use of __old__ is deprecated. Use __new__ instead", | ||
"unable-to-listen": "Unable to listen on __listenpath__", | ||
@@ -92,3 +93,9 @@ "port-in-use": "Error: port in use", | ||
}, | ||
"library": { | ||
"unknownLibrary": "Unknown library: __library__", | ||
"unknownType": "Unknown library type: __type__", | ||
"readOnly": "Library __library__ is read-only", | ||
"failedToInit": "Failed to initialise library __library__: __error__", | ||
"invalidProperty": "Invalid property __prop__: '__value__'" | ||
}, | ||
"nodes": { | ||
@@ -160,2 +167,3 @@ "credentials": { | ||
"active-project": "Active project : __project__", | ||
"projects-directory": "Projects directory: __projectsDirectory__", | ||
"project-not-found": "Project not found : __project__", | ||
@@ -162,0 +170,0 @@ "no-active-project": "No active project : using default flows file", |
@@ -44,2 +44,3 @@ { | ||
}, | ||
"deprecatedOption": "__old__ の利用は非推奨です。代わりに __new__ を使用してください", | ||
"unable-to-listen": "__listenpath__ に対してlistenできません", | ||
@@ -153,2 +154,3 @@ "port-in-use": "エラー: ポートが使用中です", | ||
"active-project": "選択中のプロジェクト : __project__", | ||
"projects-directory": "プロジェクトディレクトリ: __projectsDirectory__", | ||
"project-not-found": "プロジェクトが見つかりません : __project__", | ||
@@ -155,0 +157,0 @@ "no-active-project": "プロジェクトが選択されていません : デフォルトのフローファイルを使用します", |
{ | ||
"name": "@node-red/runtime", | ||
"version": "1.2.9", | ||
"version": "1.3.0-beta.1", | ||
"license": "Apache-2.0", | ||
@@ -19,4 +19,4 @@ "main": "./lib/index.js", | ||
"dependencies": { | ||
"@node-red/registry": "1.2.9", | ||
"@node-red/util": "1.2.9", | ||
"@node-red/registry": "1.3.0-beta.1", | ||
"@node-red/util": "1.3.0-beta.1", | ||
"async-mutex": "0.2.6", | ||
@@ -26,5 +26,4 @@ "clone": "2.1.2", | ||
"fs-extra": "8.1.0", | ||
"json-stringify-safe": "5.0.1", | ||
"when": "3.7.8" | ||
"json-stringify-safe": "5.0.1" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
530489
7
12520
3
2
+ Added@node-red/registry@1.3.0-beta.1(transitive)
+ Added@node-red/util@1.3.0-beta.1(transitive)
- Removedwhen@3.7.8
- Removed@node-red/registry@1.2.9(transitive)
- Removed@node-red/util@1.2.9(transitive)
- Removedwhen@3.7.8(transitive)
Updated@node-red/util@1.3.0-beta.1