From 5992ed1fab40ee764c7c04473a18a619104f2dfc Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 30 Nov 2020 14:38:48 +0000 Subject: [PATCH 1/5] Fully remove when.js dependency --- package.json | 1 - .../editor-api/lib/editor/library.js | 1 - .../@node-red/editor-api/lib/index.js | 8 +- .../@node-red/editor-api/package.json | 1 - .../@node-red/registry/lib/loader.js | 9 +- .../@node-red/registry/lib/localfilesystem.js | 4 - .../@node-red/registry/package.json | 3 +- .../@node-red/runtime/lib/index.js | 27 ++--- .../runtime/lib/nodes/credentials.js | 27 ++--- .../@node-red/runtime/lib/nodes/index.js | 1 - .../@node-red/runtime/lib/settings.js | 6 +- .../@node-red/runtime/lib/storage/index.js | 111 ++++++++---------- .../lib/storage/localfilesystem/library.js | 14 +-- .../localfilesystem/projects/Project.js | 56 ++++----- .../storage/localfilesystem/projects/index.js | 23 ++-- .../localfilesystem/projects/ssh/index.js | 1 - .../lib/storage/localfilesystem/sessions.js | 9 +- .../@node-red/runtime/package.json | 3 +- .../node_modules/@node-red/util/lib/i18n.js | 9 +- .../node_modules/@node-red/util/package.json | 3 +- packages/node_modules/node-red/lib/red.js | 23 +++- packages/node_modules/node-red/red.js | 3 +- .../nodes/core/network/21-httprequest_spec.js | 1 - test/nodes/core/network/22-websocket_spec.js | 41 ++++--- .../editor-api/lib/admin/flow_spec.js | 1 - .../editor-api/lib/admin/nodes_spec.js | 1 - .../editor-api/lib/auth/index_spec.js | 3 +- .../editor-api/lib/auth/strategies_spec.js | 37 +++--- .../editor-api/lib/auth/tokens_spec.js | 21 ++-- .../editor-api/lib/auth/users_spec.js | 5 +- .../editor-api/lib/editor/comms_spec.js | 29 +++-- .../editor-api/lib/editor/credentials_spec.js | 1 - .../editor-api/lib/editor/index_spec.js | 4 - .../editor-api/lib/editor/theme_spec.js | 1 - .../@node-red/editor-api/lib/index_spec.js | 1 - .../unit/@node-red/registry/lib/index_spec.js | 11 +- .../@node-red/registry/lib/installer_spec.js | 22 ++-- .../@node-red/registry/lib/loader_spec.js | 1 - .../registry/lib/localfilesystem_spec.js | 1 - .../@node-red/registry/lib/registry_spec.js | 5 +- .../resources/local/TestNode2/TestNode2.js | 3 +- .../resources/local/TestNode3/TestNode3.js | 3 +- .../@node-red/runtime/lib/api/nodes_spec.js | 41 ++++--- .../runtime/lib/api/settings_spec.js | 5 +- .../@node-red/runtime/lib/flows/index_spec.js | 41 ++++--- .../@node-red/runtime/lib/flows/util_spec.js | 1 - .../runtime/lib/nodes/credentials_spec.js | 5 +- .../@node-red/runtime/lib/nodes/index_spec.js | 11 +- .../runtime/lib/storage/index_spec.js | 17 ++- 49 files changed, 299 insertions(+), 357 deletions(-) diff --git a/package.json b/package.json index 3ff26d859..b1981d8cc 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,6 @@ "semver": "6.3.0", "tar": "6.0.5", "uglify-js": "3.11.6", - "when": "3.7.8", "ws": "6.2.1", "xml2js": "0.4.23" }, diff --git a/packages/node_modules/@node-red/editor-api/lib/editor/library.js b/packages/node_modules/@node-red/editor-api/lib/editor/library.js index 47a41bb7b..89b92fd11 100644 --- a/packages/node_modules/@node-red/editor-api/lib/editor/library.js +++ b/packages/node_modules/@node-red/editor-api/lib/editor/library.js @@ -17,7 +17,6 @@ var apiUtils = require("../util"); var fs = require('fs'); var fspath = require('path'); -var when = require('when'); var runtimeAPI; diff --git a/packages/node_modules/@node-red/editor-api/lib/index.js b/packages/node_modules/@node-red/editor-api/lib/index.js index 457b99cc9..972e8daa6 100644 --- a/packages/node_modules/@node-red/editor-api/lib/index.js +++ b/packages/node_modules/@node-red/editor-api/lib/index.js @@ -28,7 +28,6 @@ var express = require("express"); var bodyParser = require("body-parser"); var util = require('util'); var passport = require('passport'); -var when = require('when'); var cors = require('cors'); var auth = require("./auth"); @@ -111,11 +110,9 @@ function init(settings,_server,storage,runtimeAPI) { * @return {Promise} resolves when the application is ready to handle requests * @memberof @node-red/editor-api */ -function start() { +async function start() { if (editor) { return editor.start(); - } else { - return when.resolve(); } } @@ -124,11 +121,10 @@ function start() { * @return {Promise} resolves when the application is stopped * @memberof @node-red/editor-api */ -function stop() { +async function stop() { if (editor) { editor.stop(); } - return when.resolve(); } module.exports = { init: init, diff --git a/packages/node_modules/@node-red/editor-api/package.json b/packages/node_modules/@node-red/editor-api/package.json index 6885aaabb..516532e37 100644 --- a/packages/node_modules/@node-red/editor-api/package.json +++ b/packages/node_modules/@node-red/editor-api/package.json @@ -32,7 +32,6 @@ "passport-http-bearer": "1.0.1", "passport-oauth2-client-password": "0.1.2", "passport": "0.4.1", - "when": "3.7.8", "ws": "6.2.1" }, "optionalDependencies": { diff --git a/packages/node_modules/@node-red/registry/lib/loader.js b/packages/node_modules/@node-red/registry/lib/loader.js index 14e2a0b7e..3a960c73c 100644 --- a/packages/node_modules/@node-red/registry/lib/loader.js +++ b/packages/node_modules/@node-red/registry/lib/loader.js @@ -14,7 +14,6 @@ * limitations under the License. **/ -var when = require("when"); var fs = require("fs-extra"); var path = require("path"); var semver = require("semver"); @@ -92,7 +91,7 @@ function loadNodeFiles(nodeFiles) { nodeFiles[m].nodes[n] = nodeSet; nodes.push(nodeSet); } - })())); + })()).catch(err => {})); } catch(err) { // } @@ -101,7 +100,7 @@ function loadNodeFiles(nodeFiles) { } } } - return when.settle(promises).then(function(results) { + return Promise.all(promises).then(function(results) { for (var module in nodeFiles) { if (nodeFiles.hasOwnProperty(module)) { if (!nodeFiles[module].err) { @@ -293,13 +292,13 @@ function loadNodeSetList(nodes) { var promises = []; nodes.forEach(function(node) { if (!node.err) { - promises.push(loadNodeSet(node)); + promises.push(loadNodeSet(node).catch(err => {})); } else { promises.push(node); } }); - return when.settle(promises).then(function() { + return Promise.all(promises).then(function() { if (settings.available()) { return registry.saveNodeList(); } else { diff --git a/packages/node_modules/@node-red/registry/lib/localfilesystem.js b/packages/node_modules/@node-red/registry/lib/localfilesystem.js index 7233d1da3..d5bef63cd 100644 --- a/packages/node_modules/@node-red/registry/lib/localfilesystem.js +++ b/packages/node_modules/@node-red/registry/lib/localfilesystem.js @@ -17,7 +17,6 @@ var fs = require("fs"); var path = require("path"); -var events; var log; var log = require("@node-red/util").log; @@ -29,7 +28,6 @@ var iconFileExtensions = [".png", ".gif", ".svg"]; function init(runtime) { settings = runtime.settings; - events = runtime.events; } function isIncluded(name) { @@ -75,7 +73,6 @@ function getLocalFile(file) { /** * Synchronously walks the directory looking for node files. - * Emits 'node-icon-dir' events for an icon dirs found * @param dir the directory to search * @return an array of fully-qualified paths to .js files */ @@ -229,7 +226,6 @@ function getModuleNodeFiles(module) { try { fs.statSync(examplesDir) result.examples = {path:examplesDir}; - // events.emit("node-examples-dir",{name:pkg.name,path:examplesDir}); } catch(err) { } return result; diff --git a/packages/node_modules/@node-red/registry/package.json b/packages/node_modules/@node-red/registry/package.json index 47472f38e..3d517421c 100644 --- a/packages/node_modules/@node-red/registry/package.json +++ b/packages/node_modules/@node-red/registry/package.json @@ -19,7 +19,6 @@ "@node-red/util": "1.3.0-beta.1", "semver": "6.3.0", "tar": "6.0.5", - "uglify-js": "3.11.6", - "when": "3.7.8" + "uglify-js": "3.11.6" } } diff --git a/packages/node_modules/@node-red/runtime/lib/index.js b/packages/node_modules/@node-red/runtime/lib/index.js index f9a772ea3..89b0dcfd6 100644 --- a/packages/node_modules/@node-red/runtime/lib/index.js +++ b/packages/node_modules/@node-red/runtime/lib/index.js @@ -14,8 +14,6 @@ * limitations under the License. **/ -var when = require('when'); - var externalAPI = require("./api"); var redNodes = require("./nodes"); @@ -197,25 +195,24 @@ function start() { }); } -var reinstallAttempts; +var reinstallAttempts = 0; var reinstallTimeout; function reinstallModules(moduleList) { var promises = []; - var failedModules = []; + var reinstallList = []; + for (var i=0;i { + 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 0) { reinstallAttempts++; // First 5 at 1x timeout, next 5 at 2x, next 5 at 4x, then 8x diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/credentials.js b/packages/node_modules/@node-red/runtime/lib/nodes/credentials.js index 153ef4b06..86ea1d3a1 100644 --- a/packages/node_modules/@node-red/runtime/lib/nodes/credentials.js +++ b/packages/node_modules/@node-red/runtime/lib/nodes/credentials.js @@ -14,7 +14,6 @@ * limitations under the License. **/ -var when = require("when"); var crypto = require('crypto'); var runtime; var settings; @@ -60,7 +59,7 @@ var api = module.exports = { /** * Sets the credentials from storage. */ - load: function (credentials) { + load: async function (credentials) { dirty = false; var credentialsEncrypted = credentials.hasOwnProperty("$") && Object.keys(credentials).length === 1; @@ -77,7 +76,7 @@ var api = module.exports = { // Case 4: credentialSecret set // - use it - var setupEncryptionPromise = when.resolve(); + var setupEncryptionPromise = Promise.resolve(); var projectKey = false; var activeProject; @@ -134,7 +133,7 @@ var api = module.exports = { log.warn(log._("nodes.credentials.error",{message:err.toString()})) var error = new Error("Failed to decrypt credentials"); error.code = "credentials_load_failed"; - return when.reject(error); + throw error; } } dirty = true; @@ -163,7 +162,7 @@ var api = module.exports = { log.warn(log._("nodes.credentials.error",{message:err.toString()})) var error = new Error("Failed to decrypt credentials"); error.code = "credentials_load_failed"; - return when.reject(error); + throw error; } } dirty = true; @@ -217,9 +216,9 @@ var api = module.exports = { // This is a project with a bad key. Mark it as invalid // TODO: this delves too deep into Project structure activeProject.credentialSecretInvalid = true; - return when.reject(error); + throw error; } - return when.reject(error); + throw error; } // These are encrypted credentials try { @@ -235,9 +234,9 @@ var api = module.exports = { // This is a project with a bad key. Mark it as invalid // TODO: this delves too deep into Project structure activeProject.credentialSecretInvalid = true; - return when.reject(error); + throw error; } - return when.reject(error); + throw error; } } else { credentialCache = credentials; @@ -257,12 +256,11 @@ var api = module.exports = { * @param creds an object of credential key/value pairs * @return a promise for backwards compatibility TODO: can this be removed? */ - add: function (id, creds) { + add: async function (id, creds) { if (!credentialCache.hasOwnProperty(id) || JSON.stringify(creds) !== JSON.stringify(credentialCache[id])) { credentialCache[id] = creds; dirty = true; } - return when.resolve(); }, /** @@ -293,7 +291,7 @@ var api = module.exports = { * @param config a flow config * @return a promise for the saving of credentials to storage */ - clean: function (config) { + clean: async function (config) { var existingIds = {}; config.forEach(function(n) { existingIds[n.id] = true; @@ -313,7 +311,6 @@ var api = module.exports = { if (deletedCredentials) { dirty = true; } - return when.resolve(); }, /** @@ -432,7 +429,7 @@ var api = module.exports = { getKeyType: function() { return encryptionKeyType; }, - export: function() { + export: async function() { var result = credentialCache; if (encryptionEnabled) { @@ -455,7 +452,7 @@ var api = module.exports = { return result; }) } else { - return when.resolve(result); + return result; } } } diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/index.js b/packages/node_modules/@node-red/runtime/lib/nodes/index.js index 42fcd72f6..be31df2f7 100644 --- a/packages/node_modules/@node-red/runtime/lib/nodes/index.js +++ b/packages/node_modules/@node-red/runtime/lib/nodes/index.js @@ -14,7 +14,6 @@ * limitations under the License. **/ -var when = require("when"); var path = require("path"); var fs = require("fs"); var clone = require("clone"); diff --git a/packages/node_modules/@node-red/runtime/lib/settings.js b/packages/node_modules/@node-red/runtime/lib/settings.js index 16667d177..e17600305 100644 --- a/packages/node_modules/@node-red/runtime/lib/settings.js +++ b/packages/node_modules/@node-red/runtime/lib/settings.js @@ -14,7 +14,6 @@ * limitations under the License. **/ -var when = require("when"); var clone = require("clone"); var assert = require("assert"); var log = require("@node-red/util").log; // TODO: separate module @@ -90,10 +89,10 @@ var persistentSettings = { globalSettings[prop] = clone(value); try { assert.deepEqual(current,value); - return when.resolve(); } catch(err) { return storage.saveSettings(clone(globalSettings)); } + return Promise.resolve(); }, delete: function(prop) { if (localSettings.hasOwnProperty(prop)) { @@ -106,7 +105,7 @@ var persistentSettings = { delete globalSettings[prop]; return storage.saveSettings(clone(globalSettings)); } - return when.resolve(); + return Promise.resolve(); }, available: function() { @@ -180,7 +179,6 @@ var persistentSettings = { userSettings[username] = settings; try { assert.deepEqual(current,settings); - return when.resolve(); } catch(err) { globalSettings.users = userSettings; return storage.saveSettings(clone(globalSettings)); diff --git a/packages/node_modules/@node-red/runtime/lib/storage/index.js b/packages/node_modules/@node-red/runtime/lib/storage/index.js index d3350a95e..e7f09c20f 100644 --- a/packages/node_modules/@node-red/runtime/lib/storage/index.js +++ b/packages/node_modules/@node-red/runtime/lib/storage/index.js @@ -14,7 +14,6 @@ * limitations under the License. **/ -var when = require('when'); var Path = require('path'); var crypto = require('crypto'); @@ -50,15 +49,13 @@ function is_malicious(path) { } 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) { var projectsEnabled = false; if (runtime.settings.hasOwnProperty("editorTheme") && runtime.settings.editorTheme.hasOwnProperty("projects")) { @@ -73,7 +70,7 @@ var storageModuleInterface = { } return storageModule.init(runtime.settings,runtime); }, - getFlows: function() { + getFlows: async function() { return storageModule.getFlows().then(function(flows) { return storageModule.getCredentials().then(function(creds) { var result = { @@ -85,14 +82,14 @@ var storageModuleInterface = { }) }); }, - saveFlows: function(config, user) { + saveFlows: async function(config, user) { var flows = config.flows; var credentials = config.credentials; var credentialSavePromise; if (config.credentialsDirty) { credentialSavePromise = storageModule.saveCredentials(credentials); } else { - credentialSavePromise = when.resolve(); + credentialSavePromise = Promise.resolve(); } delete config.credentialsDirty; @@ -105,64 +102,60 @@ var storageModuleInterface = { // getCredentials: function() { // return storageModule.getCredentials(); // }, - 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(); } }, /* Library Functions */ - 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; } return storageModule.saveLibraryEntry(type, path, meta, body); }, /* Deprecated functions */ - getAllFlows: function() { + getAllFlows: async function() { if (storageModule.hasOwnProperty("getAllFlows")) { return storageModule.getAllFlows(); } else { if (libraryFlowsCachedResult) { - return Promise.resolve(libraryFlowsCachedResult); + return libraryFlowsCachedResult; } else { return listFlows("/").then(function(result) { libraryFlowsCachedResult = result; @@ -175,7 +168,7 @@ var storageModuleInterface = { if (is_malicious(fn)) { var err = new Error(); err.code = "forbidden"; - return when.reject(err); + throw err; } if (storageModule.hasOwnProperty("getFlow")) { return storageModule.getFlow(fn); @@ -188,7 +181,7 @@ var storageModuleInterface = { if (is_malicious(fn)) { var err = new Error(); err.code = "forbidden"; - return when.reject(err); + throw err; } libraryFlowsCachedResult = null; if (storageModule.hasOwnProperty("saveFlow")) { @@ -204,40 +197,36 @@ var storageModuleInterface = { function listFlows(path) { 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))); - } else { - promises.push(when.resolve(r)); - } - }); - 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); + 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$/, ""); } - i++; - }); - resolve(result); + result.f = result.f || []; + result.f.push(name); + } else { + result.d = result.d || {}; + result.d[res[i]] = r; + //console.log(">",r.value); + } + i++; }); + return result; }); }); } - - module.exports = storageModuleInterface; diff --git a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/library.js b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/library.js index 22f01c978..fbcb44e2f 100644 --- a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/library.js +++ b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/library.js @@ -15,9 +15,7 @@ **/ var fs = require('fs-extra'); -var when = require('when'); var fspath = require("path"); -var nodeFn = require('when/node/function'); var util = require("./util"); @@ -90,14 +88,14 @@ function getLibraryEntry(type,path) { var rootPath = fspath.join(libDir,type,path); // 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()) { return getFileBody(root,path); } if (path.substr(-1) == '/') { path = path.substr(0,path.length-1); } - return nodeFn.call(fs.readdir, rootPath).then(function(fns) { + return fs.readdir(rootPath).then(function(fns) { var dirs = []; var files = []; fns.sort().filter(function(fn) { @@ -143,21 +141,19 @@ function getLibraryEntry(type,path) { } module.exports = { - init: function(_settings) { + init: async function(_settings) { settings = _settings; libDir = fspath.join(settings.userDir,"lib"); libFlowsDir = fspath.join(libDir,"flows"); if (!settings.readOnly) { return fs.ensureDir(libFlowsDir); - } else { - return when.resolve(); } }, getLibraryEntry: getLibraryEntry, - saveLibraryEntry: function(type,path,meta,body) { + saveLibraryEntry: async function(type,path,meta,body) { if (settings.readOnly) { - return when.resolve(); + return; } if (type === "flows" && !path.endsWith(".json")) { path += ".json"; diff --git a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/Project.js b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/Project.js index 0fbf89de4..55bb9d078 100644 --- a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/Project.js +++ b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/Project.js @@ -16,7 +16,6 @@ var fs = require('fs-extra'); -var when = require('when'); var fspath = require("path"); var os = require('os'); @@ -108,12 +107,12 @@ Project.prototype.load = function () { // package.json isn't valid JSON... is a merge underway? project.package = {}; } - })); + }).catch(err => {})); // if (missingFiles.indexOf('README.md') === -1) { project.paths['README.md'] = fspath.join(project.paths.root,"README.md"); promises.push(fs.readFile(fspath.join(project.path,project.paths['README.md']),"utf8").then(function(content) { project.description = content; - })); + }).catch(err => {})); } else { project.description = ""; } @@ -133,9 +132,9 @@ Project.prototype.load = function () { // project.paths.credentialsFile = fspath.join(project.path,"flow_cred.json"); // } - 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; }) }); @@ -239,7 +238,7 @@ Project.prototype.isMerging = function() { return this.merging; } -Project.prototype.update = function (user, data) { +Project.prototype.update = async function (user, data) { var username; if (!user) { username = "_"; @@ -279,7 +278,7 @@ Project.prototype.update = function (user, data) { this.credentialSecret !== existingSecret) { // key doesn't match provided existing key var e = new Error("Cannot change credentialSecret without current key"); e.code = "missing_current_credential_key"; - return when.reject(e); + throw e; } this.credentialSecret = secret; @@ -292,7 +291,7 @@ Project.prototype.update = function (user, data) { if (this.missingFiles.indexOf('package.json') !== -1) { if (!data.files || !data.files.package) { // 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"); } } @@ -302,7 +301,7 @@ Project.prototype.update = function (user, data) { // We have a package file. It could be one that doesn't exist yet, // or it does exist and we need to load it. 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) } var root = data.files.package.substring(0,data.files.package.length-12); this.paths.root = root; @@ -391,20 +390,20 @@ Project.prototype.update = function (user, data) { modifyRemotesPromise = modifyRemotesPromise.then(function() { return project.loadRemotes(); }); - promises.push(modifyRemotesPromise); + promises.push(modifyRemotesPromise.catch(err => {})); } } } if (saveSettings) { - promises.push(settings.set("projects",globalProjectSettings)); + promises.push(settings.set("projects",globalProjectSettings).catch(err => {})); } var modifiedFiles = []; 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'); } if (savePackage) { @@ -416,10 +415,10 @@ Project.prototype.update = function (user, data) { } this.package = Object.assign(currentPackage,this.package); 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"; if (workflowMode === 'auto') { @@ -944,32 +943,17 @@ function createDefaultProject(user, project) { } function checkProjectFiles(project) { 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); } function createProject(user, metadata) { var username; diff --git a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/index.js b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/index.js index 5e1d4f15b..80a3f31e4 100644 --- a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/index.js +++ b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/index.js @@ -15,9 +15,7 @@ **/ var fs = require('fs-extra'); -var when = require('when'); var fspath = require("path"); -var nodeFn = require('when/node/function'); var crypto = require('crypto'); var storageSettings = require("../settings"); @@ -223,7 +221,6 @@ function loadProject(name) { function getProject(user, name) { checkActiveProject(name); - //return when.resolve(activeProject.info); return Promise.resolve(activeProject.export()); } @@ -495,7 +492,7 @@ var flowsFileBackup; var credentialsFile; var credentialsFileBackup; -function getFlows() { +async function getFlows() { if (!initialFlowLoadComplete) { initialFlowLoadComplete = true; log.info(log._("storage.localfilesystem.user-dir",{path:settings.userDir})); @@ -522,25 +519,25 @@ function getFlows() { log.warn("Project repository is empty"); error = new Error("Project repository is empty"); error.code = "project_empty"; - return when.reject(error); + throw error; } if (activeProject.missingFiles && activeProject.missingFiles.indexOf('package.json') !== -1) { log.warn("Project missing package.json"); error = new Error("Project missing package.json"); error.code = "missing_package_file"; - return when.reject(error); + throw error; } if (!activeProject.getFlowFile()) { log.warn("Project has no flow file"); error = new Error("Project has no flow file"); error.code = "missing_flow_file"; - return when.reject(error); + throw error; } if (activeProject.isMerging()) { log.warn("Project has unmerged changes"); error = new Error("Project has unmerged changes. Cannot load flows"); error.code = "git_merge_conflict"; - return when.reject(error); + throw error; } } @@ -554,14 +551,14 @@ function getFlows() { }); } -function saveFlows(flows, user) { +async function saveFlows(flows, user) { if (settings.readOnly) { - return when.resolve(); + return } if (activeProject && activeProject.isMerging()) { var error = new Error("Project has unmerged changes. Cannot deploy new flows"); error.code = "git_merge_conflict"; - return when.reject(error); + throw error; } flowsFileExists = true; @@ -589,9 +586,9 @@ function getCredentials() { return util.readFile(credentialsFile,credentialsFileBackup,{},'credentials'); } -function saveCredentials(credentials) { +async function saveCredentials(credentials) { if (settings.readOnly) { - return when.resolve(); + return; } var credentialData; diff --git a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/ssh/index.js b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/ssh/index.js index 25dacd3b1..cafe9bcb7 100644 --- a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/ssh/index.js +++ b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/ssh/index.js @@ -15,7 +15,6 @@ **/ var fs = require('fs-extra'); -var when = require('when'); var fspath = require("path"); var keygen = require("./keygen"); diff --git a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/sessions.js b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/sessions.js index 6b4deaa5a..575b0c056 100644 --- a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/sessions.js +++ b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/sessions.js @@ -14,7 +14,6 @@ * limitations under the License. **/ -var when = require('when'); var fs = require('fs-extra'); var fspath = require("path"); @@ -30,8 +29,8 @@ module.exports = { settings = _settings; sessionsFile = fspath.join(settings.userDir,".sessions.json"); }, - getSessions: function() { - return when.promise(function(resolve,reject) { + getSessions: async function() { + return new Promise(function(resolve,reject) { fs.readFile(sessionsFile,'utf8',function(err,data){ if (!err) { try { @@ -44,9 +43,9 @@ module.exports = { }) }); }, - saveSessions: function(sessions) { + saveSessions: async function(sessions) { if (settings.readOnly) { - return when.resolve(); + return; } return util.writeFile(sessionsFile,JSON.stringify(sessions)); } diff --git a/packages/node_modules/@node-red/runtime/package.json b/packages/node_modules/@node-red/runtime/package.json index 17622c6b4..1a549e0c6 100644 --- a/packages/node_modules/@node-red/runtime/package.json +++ b/packages/node_modules/@node-red/runtime/package.json @@ -22,7 +22,6 @@ "clone": "2.1.2", "express": "4.17.1", "fs-extra": "8.1.0", - "json-stringify-safe": "5.0.1", - "when": "3.7.8" + "json-stringify-safe": "5.0.1" } } diff --git a/packages/node_modules/@node-red/util/lib/i18n.js b/packages/node_modules/@node-red/util/lib/i18n.js index d95f4bec6..cce2e8149 100644 --- a/packages/node_modules/@node-red/util/lib/i18n.js +++ b/packages/node_modules/@node-red/util/lib/i18n.js @@ -22,7 +22,6 @@ var i18n = require("i18next"); -var when = require("when"); var path = require("path"); var fs = require("fs"); @@ -38,16 +37,16 @@ var initPromise; */ function registerMessageCatalogs(catalogs) { var promises = catalogs.map(function(catalog) { - return registerMessageCatalog(catalog.namespace,catalog.dir,catalog.file); + return registerMessageCatalog(catalog.namespace,catalog.dir,catalog.file).catch(err => {}); }); - return when.settle(promises); + return Promise.all(promises); } /** * Register a message catalog with i18n. * @memberof @node-red/util_i18n */ -function registerMessageCatalog(namespace,dir,file) { +async function registerMessageCatalog(namespace,dir,file) { return initPromise.then(function() { return new Promise((resolve,reject) => { resourceMap[namespace] = { basedir:dir, file:file, lngs: []}; @@ -147,7 +146,7 @@ function init() { if (!initPromise) { // Keep this as a 'when' promise as top-level red.js uses 'otherwise' // and embedded users of NR may have copied that. - initPromise = when.promise((resolve,reject) => { + initPromise = new Promise((resolve,reject) => { i18n.use(MessageFileLoader); var opt = { // debug: true, diff --git a/packages/node_modules/@node-red/util/package.json b/packages/node_modules/@node-red/util/package.json index 9d447a280..41e858c7a 100644 --- a/packages/node_modules/@node-red/util/package.json +++ b/packages/node_modules/@node-red/util/package.json @@ -20,7 +20,6 @@ "json-stringify-safe": "5.0.1", "jsonata": "1.8.4", "lodash.clonedeep": "^4.5.0", - "moment-timezone": "0.5.32", - "when": "3.7.8" + "moment-timezone": "0.5.32" } } diff --git a/packages/node_modules/node-red/lib/red.js b/packages/node_modules/node-red/lib/red.js index 684ff6d8a..86fa513d1 100644 --- a/packages/node_modules/node-red/lib/red.js +++ b/packages/node_modules/node-red/lib/red.js @@ -92,11 +92,32 @@ module.exports = { * @memberof node-red */ start: function() { - return runtime.start().then(function() { + // The top level red.js has always used 'otherwise' on the promise returned + // here. This is a non-standard promise function coming from our early use + // of the when.js library. + // We want to remove all dependency on when.js as native Promises now exist. + // But we have the issue that some embedders of Node-RED may have copied our + // top-level red.js a bit too much. + // + let startPromise = runtime.start().then(function() { if (apiEnabled) { return api.start(); } }); + startPromise._then = startPromise.then; + startPromise.then = function(resolve,reject) { + var inner = startPromise._then(resolve,reject); + inner.otherwise = function(cb) { + redUtil.log.error("**********************************************"); + redUtil.log.error("* Deprecated call to RED.start().otherwise() *"); + redUtil.log.error("* This will be removed in Node-RED 2.x *"); + redUtil.log.error("* Use RED.start().catch() instead *") + redUtil.log.error("**********************************************"); + return inner.catch(cb); + } + return inner; + } + return startPromise; }, /** * Stop the Node-RED application. diff --git a/packages/node_modules/node-red/red.js b/packages/node_modules/node-red/red.js index 32639ea3c..55e355a7c 100755 --- a/packages/node_modules/node-red/red.js +++ b/packages/node_modules/node-red/red.js @@ -429,7 +429,7 @@ httpsPromise.then(function(startupHttps) { } else { RED.log.info(RED.log._("server.headless-mode")); } - }).otherwise(function(err) { + }).catch(function(err) { RED.log.error(RED.log._("server.failed-to-start")); if (err.stack) { RED.log.error(err.stack); @@ -468,4 +468,5 @@ httpsPromise.then(function(startupHttps) { }).catch(function(err) { console.log("Failed to get https settings: " + err); + console.log(err.stack) }); diff --git a/test/nodes/core/network/21-httprequest_spec.js b/test/nodes/core/network/21-httprequest_spec.js index ab9020a64..e9792dd54 100644 --- a/test/nodes/core/network/21-httprequest_spec.js +++ b/test/nodes/core/network/21-httprequest_spec.js @@ -14,7 +14,6 @@ * limitations under the License. **/ -var when = require("when"); var http = require("http"); var https = require("https"); var should = require("should"); diff --git a/test/nodes/core/network/22-websocket_spec.js b/test/nodes/core/network/22-websocket_spec.js index e13b513c8..995248279 100644 --- a/test/nodes/core/network/22-websocket_spec.js +++ b/test/nodes/core/network/22-websocket_spec.js @@ -15,7 +15,6 @@ **/ var ws = require("ws"); -var when = require("when"); var should = require("should"); var helper = require("node-red-node-test-helper"); var websocketNode = require("nr-test-utils").require("@node-red/nodes/core/network/22-websocket.js"); @@ -27,7 +26,7 @@ function getWsUrl(path) { } function createClient(listenerid) { - return when.promise(function(resolve, reject) { + return new Promise(function(resolve, reject) { var node = helper.getNode(listenerid); var url = getWsUrl(node.path); var sock = new ws(url); @@ -300,23 +299,33 @@ describe('websocket Node', function() { { id: "n2", type: "websocket out", server: "n1" }, { id: "n3", type: "helper", wires: [["n2"]] }]; helper.load(websocketNode, flow, function() { - var def1 = when.defer(), - def2 = when.defer(); - when.all([createClient("n1"), createClient("n1")]).then(function(socks) { - socks[0].on("message", function(msg, flags) { - msg.should.equal("hello"); - def1.resolve(); - }); - socks[1].on("message", function(msg, flags) { - msg.should.equal("hello"); - def2.resolve(); - }); + Promise.all([createClient("n1"), createClient("n1")]).then(function(socks) { + var promises = [ + new Promise((resolve,reject) => { + socks[0].on("message", function(msg, flags) { + try { + msg.should.equal("hello"); + resolve(); + } catch(err) { + reject(err); + } + }); + }), + new Promise((resolve,reject) => { + socks[1].on("message", function(msg, flags) { + try { + msg.should.equal("hello"); + resolve(); + } catch(err) { + reject(err); + } + }); + }) + ]; helper.getNode("n3").send({ payload: "hello" }); - return when.all([def1.promise, def2.promise]).then(function() { - done(); - }); + return Promise.all(promises).then(() => {done()}); }).catch(function(err) { done(err); }); diff --git a/test/unit/@node-red/editor-api/lib/admin/flow_spec.js b/test/unit/@node-red/editor-api/lib/admin/flow_spec.js index 278c6a3f3..807fc8fb9 100644 --- a/test/unit/@node-red/editor-api/lib/admin/flow_spec.js +++ b/test/unit/@node-red/editor-api/lib/admin/flow_spec.js @@ -19,7 +19,6 @@ var request = require('supertest'); var express = require('express'); var bodyParser = require('body-parser'); var sinon = require('sinon'); -var when = require('when'); var NR_TEST_UTILS = require("nr-test-utils"); diff --git a/test/unit/@node-red/editor-api/lib/admin/nodes_spec.js b/test/unit/@node-red/editor-api/lib/admin/nodes_spec.js index f921d907d..872f76e23 100644 --- a/test/unit/@node-red/editor-api/lib/admin/nodes_spec.js +++ b/test/unit/@node-red/editor-api/lib/admin/nodes_spec.js @@ -19,7 +19,6 @@ var request = require('supertest'); var express = require('express'); var bodyParser = require('body-parser'); var sinon = require('sinon'); -var when = require('when'); var NR_TEST_UTILS = require("nr-test-utils"); diff --git a/test/unit/@node-red/editor-api/lib/auth/index_spec.js b/test/unit/@node-red/editor-api/lib/auth/index_spec.js index 3cf0111d6..def2335a7 100644 --- a/test/unit/@node-red/editor-api/lib/auth/index_spec.js +++ b/test/unit/@node-red/editor-api/lib/auth/index_spec.js @@ -15,7 +15,6 @@ **/ var should = require("should"); -var when = require("when"); var sinon = require("sinon"); var passport = require("passport"); @@ -60,7 +59,7 @@ describe("api/auth/index",function() { describe("revoke", function() { it("revokes a token", function(done) { var revokeToken = sinon.stub(Tokens,"revoke",function() { - return when.resolve(); + return Promise.resolve(); }); var req = { body: { token: "abcdef" } }; diff --git a/test/unit/@node-red/editor-api/lib/auth/strategies_spec.js b/test/unit/@node-red/editor-api/lib/auth/strategies_spec.js index 848aaf99d..d95d78db2 100644 --- a/test/unit/@node-red/editor-api/lib/auth/strategies_spec.js +++ b/test/unit/@node-red/editor-api/lib/auth/strategies_spec.js @@ -15,7 +15,6 @@ **/ var should = require("should"); -var when = require('when'); var sinon = require('sinon'); var NR_TEST_UTILS = require("nr-test-utils"); @@ -37,7 +36,7 @@ describe("api/auth/strategies", function() { it('Handles authentication failure',function(done) { userAuthentication = sinon.stub(Users,"authenticate",function(username,password) { - return when.resolve(null); + return Promise.resolve(null); }); strategies.passwordTokenExchange({},"user","password","scope",function(err,token) { @@ -53,7 +52,7 @@ describe("api/auth/strategies", function() { it('Handles scope overreach',function(done) { userAuthentication = sinon.stub(Users,"authenticate",function(username,password) { - return when.resolve({username:"user",permissions:"read"}); + return Promise.resolve({username:"user",permissions:"read"}); }); strategies.passwordTokenExchange({},"user","password","*",function(err,token) { @@ -69,14 +68,14 @@ describe("api/auth/strategies", function() { it('Creates new token on authentication success',function(done) { userAuthentication = sinon.stub(Users,"authenticate",function(username,password) { - return when.resolve({username:"user",permissions:"*"}); + return Promise.resolve({username:"user",permissions:"*"}); }); var tokenDetails = {}; var tokenCreate = sinon.stub(Tokens,"create",function(username,client,scope) { tokenDetails.username = username; tokenDetails.client = client; tokenDetails.scope = scope; - return when.resolve({accessToken: "123456"}); + return Promise.resolve({accessToken: "123456"}); }); strategies.passwordTokenExchange({id:"myclient"},"user","password","read",function(err,token) { @@ -100,7 +99,7 @@ describe("api/auth/strategies", function() { describe("Anonymous Strategy", function() { it('Succeeds if anon user enabled',function(done) { var userDefault = sinon.stub(Users,"default",function() { - return when.resolve("anon"); + return Promise.resolve("anon"); }); strategies.anonymousStrategy._success = strategies.anonymousStrategy.success; strategies.anonymousStrategy.success = function(user) { @@ -113,7 +112,7 @@ describe("api/auth/strategies", function() { }); it('Fails if anon user not enabled',function(done) { var userDefault = sinon.stub(Users,"default",function() { - return when.resolve(null); + return Promise.resolve(null); }); strategies.anonymousStrategy._fail = strategies.anonymousStrategy.fail; strategies.anonymousStrategy.fail = function(err) { @@ -132,7 +131,7 @@ describe("api/auth/strategies", function() { describe("Tokens Strategy", function() { it('Succeeds if tokens user enabled custom header',function(done) { var userTokens = sinon.stub(Users,"tokens",function(token) { - return when.resolve("tokens-"+token); + return Promise.resolve("tokens-"+token); }); var userTokenHeader = sinon.stub(Users,"tokenHeader",function(token) { return "x-test-token"; @@ -148,7 +147,7 @@ describe("api/auth/strategies", function() { }); it('Succeeds if tokens user enabled default header',function(done) { var userTokens = sinon.stub(Users,"tokens",function(token) { - return when.resolve("tokens-"+token); + return Promise.resolve("tokens-"+token); }); var userTokenHeader = sinon.stub(Users,"tokenHeader",function(token) { return "authorization"; @@ -164,7 +163,7 @@ describe("api/auth/strategies", function() { }); it('Fails if tokens user not enabled',function(done) { var userTokens = sinon.stub(Users,"tokens",function() { - return when.resolve(null); + return Promise.resolve(null); }); var userTokenHeader = sinon.stub(Users,"tokenHeader",function(token) { return "authorization"; @@ -187,7 +186,7 @@ describe("api/auth/strategies", function() { describe("Bearer Strategy", function() { it('Rejects invalid token',function(done) { var getToken = sinon.stub(Tokens,"get",function(token) { - return when.resolve(null); + return Promise.resolve(null); }); strategies.bearerStrategy("1234",function(err,user) { @@ -204,10 +203,10 @@ describe("api/auth/strategies", function() { }); it('Accepts valid token',function(done) { var getToken = sinon.stub(Tokens,"get",function(token) { - return when.resolve({user:"user",scope:"scope"}); + return Promise.resolve({user:"user",scope:"scope"}); }); var getUser = sinon.stub(Users,"get",function(username) { - return when.resolve("aUser"); + return Promise.resolve("aUser"); }); strategies.bearerStrategy("1234",function(err,user,opts) { @@ -226,10 +225,10 @@ describe("api/auth/strategies", function() { }); it('Fail if no user for token',function(done) { var getToken = sinon.stub(Tokens,"get",function(token) { - return when.resolve({user:"user",scope:"scope"}); + return Promise.resolve({user:"user",scope:"scope"}); }); var getUser = sinon.stub(Users,"get",function(username) { - return when.resolve(null); + return Promise.resolve(null); }); strategies.bearerStrategy("1234",function(err,user,opts) { @@ -252,7 +251,7 @@ describe("api/auth/strategies", function() { it('Accepts valid client',function(done) { var testClient = {id:"node-red-editor",secret:"not_available"}; var getClient = sinon.stub(Clients,"get",function(client) { - return when.resolve(testClient); + return Promise.resolve(testClient); }); strategies.clientPasswordStrategy(testClient.id,testClient.secret,function(err,client) { @@ -270,7 +269,7 @@ describe("api/auth/strategies", function() { it('Rejects invalid client secret',function(done) { var testClient = {id:"node-red-editor",secret:"not_available"}; var getClient = sinon.stub(Clients,"get",function(client) { - return when.resolve(testClient); + return Promise.resolve(testClient); }); strategies.clientPasswordStrategy(testClient.id,"invalid_secret",function(err,client) { @@ -287,7 +286,7 @@ describe("api/auth/strategies", function() { }); it('Rejects invalid client id',function(done) { var getClient = sinon.stub(Clients,"get",function(client) { - return when.resolve(null); + return Promise.resolve(null); }); strategies.clientPasswordStrategy("invalid_id","invalid_secret",function(err,client) { try { @@ -305,7 +304,7 @@ describe("api/auth/strategies", function() { var userAuthentication; it('Blocks after 5 failures',function(done) { userAuthentication = sinon.stub(Users,"authenticate",function(username,password) { - return when.resolve(null); + return Promise.resolve(null); }); for (var z=0; z<5; z++) { strategies.passwordTokenExchange({},"user","badpassword","scope",function(err,token) { diff --git a/test/unit/@node-red/editor-api/lib/auth/tokens_spec.js b/test/unit/@node-red/editor-api/lib/auth/tokens_spec.js index 2b06932c7..9bb231eb5 100644 --- a/test/unit/@node-red/editor-api/lib/auth/tokens_spec.js +++ b/test/unit/@node-red/editor-api/lib/auth/tokens_spec.js @@ -15,7 +15,6 @@ **/ var should = require("should"); -var when = require("when"); var sinon = require("sinon"); var NR_TEST_UTILS = require("nr-test-utils"); @@ -35,7 +34,7 @@ describe("api/auth/tokens", function() { it('returns a valid token', function(done) { Tokens.init({},{ getSessions:function() { - return when.resolve({"1234":{"user":"fred","expires":Date.now()+1000}}); + return Promise.resolve({"1234":{"user":"fred","expires":Date.now()+1000}}); } }).then(function() { Tokens.get("1234").then(function(token) { @@ -52,7 +51,7 @@ describe("api/auth/tokens", function() { it('returns null for an invalid token', function(done) { Tokens.init({},{ getSessions:function() { - return when.resolve({}); + return Promise.resolve({}); } }).then(function() { Tokens.get("1234").then(function(token) { @@ -66,11 +65,11 @@ describe("api/auth/tokens", function() { }); }); it('returns null for an expired token', function(done) { - var saveSessions = sinon.stub().returns(when.resolve()); + var saveSessions = sinon.stub().returns(Promise.resolve()); var expiryTime = Date.now()+50; Tokens.init({},{ getSessions:function() { - return when.resolve({"1234":{"user":"fred","expires":expiryTime}}); + return Promise.resolve({"1234":{"user":"fred","expires":expiryTime}}); }, saveSessions: saveSessions }).then(function() { @@ -100,10 +99,10 @@ describe("api/auth/tokens", function() { tokens: [{ token: "1234", user: "fred", - }] + }] },{ getSessions:function() { - return when.resolve({}); + return Promise.resolve({}); } }).then(function() { Tokens.get("1234").then(function(token) { @@ -124,11 +123,11 @@ describe("api/auth/tokens", function() { var savedSession; Tokens.init({sessionExpiryTime: 10},{ getSessions:function() { - return when.resolve({}); + return Promise.resolve({}); }, saveSessions:function(sess) { savedSession = sess; - return when.resolve(); + return Promise.resolve(); } }); var expectedExpiryTime = Date.now()+10000; @@ -159,11 +158,11 @@ describe("api/auth/tokens", function() { var savedSession; Tokens.init({},{ getSessions:function() { - return when.resolve({"1234":{"user":"fred","expires":Date.now()+1000}}); + return Promise.resolve({"1234":{"user":"fred","expires":Date.now()+1000}}); }, saveSessions:function(sess) { savedSession = sess; - return when.resolve(); + return Promise.resolve(); } }).then(function() { Tokens.revoke("1234").then(function() { diff --git a/test/unit/@node-red/editor-api/lib/auth/users_spec.js b/test/unit/@node-red/editor-api/lib/auth/users_spec.js index 18a179ac7..e07a35a03 100644 --- a/test/unit/@node-red/editor-api/lib/auth/users_spec.js +++ b/test/unit/@node-red/editor-api/lib/auth/users_spec.js @@ -15,7 +15,6 @@ **/ var should = require("should"); -var when = require('when'); var sinon = require('sinon'); var NR_TEST_UTILS = require("nr-test-utils"); @@ -144,12 +143,12 @@ describe("api/auth/users", function() { Users.init({ type:"credentials", users:function(username) { - return when.resolve({'username':'dave','permissions':'read'}); + return Promise.resolve({'username':'dave','permissions':'read'}); }, authenticate: function(username,password) { authUsername = username; authPassword = password; - return when.resolve({'username':'pete','permissions':'write'}); + return Promise.resolve({'username':'pete','permissions':'write'}); } }); }); diff --git a/test/unit/@node-red/editor-api/lib/editor/comms_spec.js b/test/unit/@node-red/editor-api/lib/editor/comms_spec.js index 8f6f78315..06743e87e 100644 --- a/test/unit/@node-red/editor-api/lib/editor/comms_spec.js +++ b/test/unit/@node-red/editor-api/lib/editor/comms_spec.js @@ -18,7 +18,6 @@ var should = require("should"); var sinon = require("sinon"); const stoppable = require('stoppable'); -var when = require("when"); var http = require('http'); var express = require('express'); var app = express(); @@ -59,7 +58,7 @@ describe("api/editor/comms", function() { var url; var port; before(function(done) { - sinon.stub(Users,"default",function() { return when.resolve(null);}); + sinon.stub(Users,"default",function() { return Promise.resolve(null);}); server = stoppable(http.createServer(function(req,res){app(req,res)})); comms.init(server, {}, {comms: mockComms}); server.listen(listenPort, address); @@ -165,7 +164,7 @@ describe("api/editor/comms", function() { var url; var port; before(function(done) { - sinon.stub(Users,"default",function() { return when.resolve(null);}); + sinon.stub(Users,"default",function() { return Promise.resolve(null);}); server = stoppable(http.createServer(function(req,res){app(req,res)})); comms.init(server, {httpAdminRoot:"/adminPath"}, {comms: mockComms}); server.listen(listenPort, address); @@ -203,7 +202,7 @@ describe("api/editor/comms", function() { var url; var port; before(function(done) { - sinon.stub(Users,"default",function() { return when.resolve(null);}); + sinon.stub(Users,"default",function() { return Promise.resolve(null);}); server = stoppable(http.createServer(function(req,res){app(req,res)})); comms.init(server, {httpAdminRoot:"/adminPath/"}, {comms: mockComms}); server.listen(listenPort, address); @@ -241,7 +240,7 @@ describe("api/editor/comms", function() { var url; var port; before(function(done) { - sinon.stub(Users,"default",function() { return when.resolve(null);}); + sinon.stub(Users,"default",function() { return Promise.resolve(null);}); server = stoppable(http.createServer(function(req,res){app(req,res)})); comms.init(server, {httpAdminRoot:"adminPath"}, {comms: mockComms}); server.listen(listenPort, address); @@ -279,7 +278,7 @@ describe("api/editor/comms", function() { var url; var port; before(function(done) { - sinon.stub(Users,"default",function() { return when.resolve(null);}); + sinon.stub(Users,"default",function() { return Promise.resolve(null);}); server = stoppable(http.createServer(function(req,res){app(req,res)})); comms.init(server, {webSocketKeepAliveTime: 100}, {comms: mockComms}); server.listen(listenPort, address); @@ -345,28 +344,28 @@ describe("api/editor/comms", function() { var getToken; var getUserToken; before(function(done) { - getDefaultUser = sinon.stub(Users,"default",function() { return when.resolve(null);}); + getDefaultUser = sinon.stub(Users,"default",function() { return Promise.resolve(null);}); getUser = sinon.stub(Users,"get", function(username) { if (username == "fred") { - return when.resolve({permissions:"read"}); + return Promise.resolve({permissions:"read"}); } else { - return when.resolve(null); + return Promise.resolve(null); } }); getUserToken = sinon.stub(Users,"tokens", function(token) { if (token == "abcde") { - return when.resolve({user:"wilma", permissions:"*"}) + return Promise.resolve({user:"wilma", permissions:"*"}) } else { - return when.resolve(null); + return Promise.resolve(null); } }); getToken = sinon.stub(Tokens,"get",function(token) { if (token == "1234") { - return when.resolve({user:"fred",scope:["*"]}); + return Promise.resolve({user:"fred",scope:["*"]}); } else if (token == "5678") { - return when.resolve({user:"barney",scope:["*"]}); + return Promise.resolve({user:"barney",scope:["*"]}); } else { - return when.resolve(null); + return Promise.resolve(null); } }); @@ -484,7 +483,7 @@ describe("api/editor/comms", function() { var port; var getDefaultUser; before(function(done) { - getDefaultUser = sinon.stub(Users,"default",function() { return when.resolve({permissions:"read"});}); + getDefaultUser = sinon.stub(Users,"default",function() { return Promise.resolve({permissions:"read"});}); server = stoppable(http.createServer(function(req,res){app(req,res)})); comms.init(server, {adminAuth:{}}, {comms: mockComms}); server.listen(listenPort, address); diff --git a/test/unit/@node-red/editor-api/lib/editor/credentials_spec.js b/test/unit/@node-red/editor-api/lib/editor/credentials_spec.js index 2fc1ea5a3..c5a6c74f8 100644 --- a/test/unit/@node-red/editor-api/lib/editor/credentials_spec.js +++ b/test/unit/@node-red/editor-api/lib/editor/credentials_spec.js @@ -18,7 +18,6 @@ var should = require("should"); var request = require('supertest'); var express = require('express'); var sinon = require('sinon'); -var when = require('when'); var NR_TEST_UTILS = require("nr-test-utils"); diff --git a/test/unit/@node-red/editor-api/lib/editor/index_spec.js b/test/unit/@node-red/editor-api/lib/editor/index_spec.js index e45fcbdba..e142f8984 100644 --- a/test/unit/@node-red/editor-api/lib/editor/index_spec.js +++ b/test/unit/@node-red/editor-api/lib/editor/index_spec.js @@ -28,10 +28,6 @@ var auth = NR_TEST_UTILS.require("@node-red/editor-api/lib/auth"); var log = NR_TEST_UTILS.require("@node-red/util").log; - -var when = require("when"); - - describe("api/editor/index", function() { var app; describe("disabled the editor", function() { diff --git a/test/unit/@node-red/editor-api/lib/editor/theme_spec.js b/test/unit/@node-red/editor-api/lib/editor/theme_spec.js index 67e305f71..55006f71b 100644 --- a/test/unit/@node-red/editor-api/lib/editor/theme_spec.js +++ b/test/unit/@node-red/editor-api/lib/editor/theme_spec.js @@ -17,7 +17,6 @@ var should = require("should"); var express = require('express'); var sinon = require('sinon'); -var when = require('when'); var fs = require("fs"); var app = express(); diff --git a/test/unit/@node-red/editor-api/lib/index_spec.js b/test/unit/@node-red/editor-api/lib/index_spec.js index 1d5e9380b..ec846cf65 100644 --- a/test/unit/@node-red/editor-api/lib/index_spec.js +++ b/test/unit/@node-red/editor-api/lib/index_spec.js @@ -18,7 +18,6 @@ var should = require("should"); var sinon = require("sinon"); var request = require("supertest"); var express = require("express"); -var when = require("when"); var fs = require("fs"); var path = require("path"); diff --git a/test/unit/@node-red/registry/lib/index_spec.js b/test/unit/@node-red/registry/lib/index_spec.js index 753486e9f..75a057730 100644 --- a/test/unit/@node-red/registry/lib/index_spec.js +++ b/test/unit/@node-red/registry/lib/index_spec.js @@ -17,7 +17,6 @@ var should = require("should"); var sinon = require("sinon"); var path = require("path"); -var when = require("when"); var fs = require("fs"); var NR_TEST_UTILS = require("nr-test-utils"); @@ -51,7 +50,7 @@ describe('red/registry/index', function() { describe('#addModule', function() { it('loads the module and returns its info', function(done) { stubs.push(sinon.stub(loader,"addModule",function(module) { - return when.resolve(); + return Promise.resolve(); })); stubs.push(sinon.stub(typeRegistry,"getModuleInfo", function(module) { return "info"; @@ -63,7 +62,7 @@ describe('red/registry/index', function() { }); it('rejects if loader rejects', function(done) { stubs.push(sinon.stub(loader,"addModule",function(module) { - return when.reject("error"); + return Promise.reject("error"); })); stubs.push(sinon.stub(typeRegistry,"getModuleInfo", function(module) { return "info"; @@ -80,7 +79,7 @@ describe('red/registry/index', function() { describe('#enableNode',function() { it('enables a node set',function(done) { stubs.push(sinon.stub(typeRegistry,"enableNodeSet",function() { - return when.resolve(); + return Promise.resolve(); })); stubs.push(sinon.stub(typeRegistry,"getNodeInfo", function() { return {id:"node-set",loaded:true}; @@ -104,14 +103,14 @@ describe('red/registry/index', function() { it('triggers a node load',function(done) { stubs.push(sinon.stub(typeRegistry,"enableNodeSet",function() { - return when.resolve(); + return Promise.resolve(); })); var calls = 0; stubs.push(sinon.stub(typeRegistry,"getNodeInfo", function() { // loaded=false on first call, true on subsequent return {id:"node-set",loaded:(calls++>0)}; })); - stubs.push(sinon.stub(loader,"loadNodeSet",function(){return when.resolve();})); + stubs.push(sinon.stub(loader,"loadNodeSet",function(){return Promise.resolve();})); stubs.push(sinon.stub(typeRegistry,"getFullNodeInfo")); registry.enableNode("node-set").then(function(ns) { diff --git a/test/unit/@node-red/registry/lib/installer_spec.js b/test/unit/@node-red/registry/lib/installer_spec.js index ad658fd16..b344dbbea 100644 --- a/test/unit/@node-red/registry/lib/installer_spec.js +++ b/test/unit/@node-red/registry/lib/installer_spec.js @@ -16,7 +16,6 @@ var should = require("should"); var sinon = require("sinon"); -var when = require("when"); var path = require("path"); var fs = require('fs-extra'); var EventEmitter = require('events'); @@ -185,7 +184,7 @@ describe('nodes/registry/installer', function() { initInstaller(p) var addModule = sinon.stub(registry,"addModule",function(md) { - return when.resolve(nodeInfo); + return Promise.resolve(nodeInfo); }); installer.installModule("this_wont_exist").then(function(info) { @@ -216,7 +215,7 @@ describe('nodes/registry/installer', function() { it("succeeds when path is valid node-red module", function(done) { var nodeInfo = {nodes:{module:"foo",types:["a"]}}; var addModule = sinon.stub(registry,"addModule",function(md) { - return when.resolve(nodeInfo); + return Promise.resolve(nodeInfo); }); var resourcesDir = path.resolve(path.join(__dirname,"resources","local","TestNodeModule","node_modules","TestNodeModule")); @@ -246,7 +245,7 @@ describe('nodes/registry/installer', function() { initInstaller(p) var addModule = sinon.stub(registry,"addModule",function(md) { - return when.resolve(nodeInfo); + return Promise.resolve(nodeInfo); }); installer.installModule("this_wont_exist",null,"https://example/foo-0.1.1.tgz").then(function(info) { @@ -259,19 +258,20 @@ describe('nodes/registry/installer', function() { describe("uninstalls module", function() { it("rejects invalid module names", function(done) { var promises = []; - promises.push(installer.uninstallModule("this_wont_exist ")); - promises.push(installer.uninstallModule("this_wont_exist;no_it_really_wont")); - when.settle(promises).then(function(results) { - results[0].state.should.be.eql("rejected"); - results[1].state.should.be.eql("rejected"); + var rejectedCount = 0; + + promises.push(installer.uninstallModule("this_wont_exist ").catch(() => {rejectedCount++})); + promises.push(installer.uninstallModule("this_wont_exist;no_it_really_wont").catch(() => {rejectedCount++})); + Promise.all(promises).then(function() { + rejectedCount.should.eql(2); done(); - }); + }).catch(done); }); it("rejects with generic error", function(done) { var nodeInfo = [{module:"foo",types:["a"]}]; var removeModule = sinon.stub(registry,"removeModule",function(md) { - return when.resolve(nodeInfo); + return Promise.resolve(nodeInfo); }); var res = { code: 1, diff --git a/test/unit/@node-red/registry/lib/loader_spec.js b/test/unit/@node-red/registry/lib/loader_spec.js index 6dc9daa55..d62a8a9b4 100644 --- a/test/unit/@node-red/registry/lib/loader_spec.js +++ b/test/unit/@node-red/registry/lib/loader_spec.js @@ -15,7 +15,6 @@ **/ var should = require("should"); -var when = require("when"); var sinon = require("sinon"); var path = require("path"); var fs = require("fs-extra"); diff --git a/test/unit/@node-red/registry/lib/localfilesystem_spec.js b/test/unit/@node-red/registry/lib/localfilesystem_spec.js index 82e4d1b2d..d86a08adb 100644 --- a/test/unit/@node-red/registry/lib/localfilesystem_spec.js +++ b/test/unit/@node-red/registry/lib/localfilesystem_spec.js @@ -15,7 +15,6 @@ **/ var should = require("should"); -var when = require("when"); var sinon = require("sinon"); var path = require("path"); diff --git a/test/unit/@node-red/registry/lib/registry_spec.js b/test/unit/@node-red/registry/lib/registry_spec.js index c7ad930c4..d493ed688 100644 --- a/test/unit/@node-red/registry/lib/registry_spec.js +++ b/test/unit/@node-red/registry/lib/registry_spec.js @@ -15,7 +15,6 @@ **/ var should = require("should"); -var when = require("when"); var sinon = require("sinon"); var path = require("path"); @@ -34,7 +33,7 @@ describe("red/nodes/registry/registry",function() { function stubSettings(s,available,initialConfig) { s.available = function() {return available;}; - s.set = sinon.spy(function(s,v) { return when.resolve();}); + s.set = sinon.spy(function(s,v) { return Promise.resolve();}); s.get = function(s) { return initialConfig;}; return s; } @@ -95,7 +94,7 @@ describe("red/nodes/registry/registry",function() { it('migrates legacy format', function(done) { var legacySettings = { available: function() { return true; }, - set: sinon.stub().returns(when.resolve()), + set: sinon.stub().returns(Promise.resolve()), get: function() { return { "123": { "name": "72-sentiment.js", diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNode2/TestNode2.js b/test/unit/@node-red/registry/lib/resources/local/TestNode2/TestNode2.js index faf61a8f3..1bf2fa6c9 100644 --- a/test/unit/@node-red/registry/lib/resources/local/TestNode2/TestNode2.js +++ b/test/unit/@node-red/registry/lib/resources/local/TestNode2/TestNode2.js @@ -1,8 +1,7 @@ // A test node that exports a function which returns a resolving promise -var when = require("when"); module.exports = function(RED) { - return when.promise(function(resolve,reject) { + return new Promise(function(resolve,reject) { function TestNode(n) {} RED.nodes.registerType("test-node-2",TestNode); resolve(); diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNode3/TestNode3.js b/test/unit/@node-red/registry/lib/resources/local/TestNode3/TestNode3.js index 756dc1398..b9ee6a624 100644 --- a/test/unit/@node-red/registry/lib/resources/local/TestNode3/TestNode3.js +++ b/test/unit/@node-red/registry/lib/resources/local/TestNode3/TestNode3.js @@ -1,8 +1,7 @@ // A test node that exports a function which returns a rejecting promise -var when = require("when"); module.exports = function(RED) { - return when.promise(function(resolve,reject) { + return new Promise(function(resolve,reject) { reject("fail"); }); } diff --git a/test/unit/@node-red/runtime/lib/api/nodes_spec.js b/test/unit/@node-red/runtime/lib/api/nodes_spec.js index 6481c653d..327df15e0 100644 --- a/test/unit/@node-red/runtime/lib/api/nodes_spec.js +++ b/test/unit/@node-red/runtime/lib/api/nodes_spec.js @@ -185,7 +185,6 @@ var request = require('supertest'); var express = require('express'); var bodyParser = require('body-parser'); var sinon = require('sinon'); -var when = require('when'); var nodes = require("../../../../red/api/admin/nodes"); var apiUtil = require("../../../../red/api/util"); @@ -418,7 +417,7 @@ describe("api/admin/nodes", function() { nodes:{ getModuleInfo: function(id) { return null; }, installModule: function() { - return when.resolve({ + return Promise.resolve({ name:"foo", nodes:[{id:"123"}] }); @@ -446,7 +445,7 @@ describe("api/admin/nodes", function() { nodes:{ getModuleInfo: function(id) { return {nodes:{id:"123"}}; }, installModule: function() { - return when.resolve({id:"123"}); + return Promise.resolve({id:"123"}); } } }); @@ -468,7 +467,7 @@ describe("api/admin/nodes", function() { nodes:{ getModuleInfo: function(id) { return null }, installModule: function() { - return when.reject(new Error("test error")); + return Promise.reject(new Error("test error")); } } }); @@ -492,7 +491,7 @@ describe("api/admin/nodes", function() { installModule: function() { var err = new Error("test error"); err.code = 404; - return when.reject(err); + return Promise.reject(err); } } }); @@ -533,7 +532,7 @@ describe("api/admin/nodes", function() { nodes:{ getModuleInfo: function(id) { return {nodes:[{id:"123"}]} }, getNodeInfo: function() { return null }, - uninstallModule: function() { return when.resolve({id:"123"});} + uninstallModule: function() { return Promise.resolve({id:"123"});} } }); request(app) @@ -572,7 +571,7 @@ describe("api/admin/nodes", function() { nodes:{ getModuleInfo: function(id) { return {nodes:[{id:"123"}]} }, getNodeInfo: function() { return null }, - uninstallModule: function() { return when.reject(new Error("test error"));} + uninstallModule: function() { return Promise.reject(new Error("test error"));} } }); request(app) @@ -686,7 +685,7 @@ describe("api/admin/nodes", function() { settings:{available:function(){return true}}, nodes:{ getNodeInfo: function() { return {id:"123",enabled: false} }, - enableNode: function() { return when.resolve({id:"123",enabled: true,types:['a']}); } + enableNode: function() { return Promise.resolve({id:"123",enabled: true,types:['a']}); } } }); request(app) @@ -709,7 +708,7 @@ describe("api/admin/nodes", function() { settings:{available:function(){return true}}, nodes:{ getNodeInfo: function() { return {id:"123",enabled: true} }, - disableNode: function() { return when.resolve({id:"123",enabled: false,types:['a']}); } + disableNode: function() { return Promise.resolve({id:"123",enabled: false,types:['a']}); } } }); request(app) @@ -729,8 +728,8 @@ describe("api/admin/nodes", function() { describe('no-ops if already in the right state', function() { function run(state,done) { - var enableNode = sinon.spy(function() { return when.resolve({id:"123",enabled: true,types:['a']}) }); - var disableNode = sinon.spy(function() { return when.resolve({id:"123",enabled: false,types:['a']}) }); + var enableNode = sinon.spy(function() { return Promise.resolve({id:"123",enabled: true,types:['a']}) }); + var disableNode = sinon.spy(function() { return Promise.resolve({id:"123",enabled: false,types:['a']}) }); initNodes({ settings:{available:function(){return true}}, @@ -768,8 +767,8 @@ describe("api/admin/nodes", function() { describe('does not no-op if err on node', function() { function run(state,done) { - var enableNode = sinon.spy(function() { return when.resolve({id:"123",enabled: true,types:['a']}) }); - var disableNode = sinon.spy(function() { return when.resolve({id:"123",enabled: false,types:['a']}) }); + var enableNode = sinon.spy(function() { return Promise.resolve({id:"123",enabled: true,types:['a']}) }); + var disableNode = sinon.spy(function() { return Promise.resolve({id:"123",enabled: false,types:['a']}) }); initNodes({ settings:{available:function(){return true}}, @@ -811,11 +810,11 @@ describe("api/admin/nodes", function() { var enableNode = sinon.stub(); enableNode.onFirstCall().returns((function() { n1.enabled = true; - return when.resolve(n1); + return Promise.resolve(n1); })()); enableNode.onSecondCall().returns((function() { n2.enabled = true; - return when.resolve(n2); + return Promise.resolve(n2); })()); enableNode.returns(null); initNodes({ @@ -849,11 +848,11 @@ describe("api/admin/nodes", function() { var disableNode = sinon.stub(); disableNode.onFirstCall().returns((function() { n1.enabled = false; - return when.resolve(n1); + return Promise.resolve(n1); })()); disableNode.onSecondCall().returns((function() { n2.enabled = false; - return when.resolve(n2); + return Promise.resolve(n2); })()); disableNode.returns(null); initNodes({ @@ -886,11 +885,11 @@ describe("api/admin/nodes", function() { var node = {id:"123",enabled:state,types:['a']}; var enableNode = sinon.spy(function(id) { node.enabled = true; - return when.resolve(node); + return Promise.resolve(node); }); var disableNode = sinon.spy(function(id) { node.enabled = false; - return when.resolve(node); + return Promise.resolve(node); }); initNodes({ @@ -933,11 +932,11 @@ describe("api/admin/nodes", function() { var node = {id:"123",enabled:state,types:['a'],err:"foo"}; var enableNode = sinon.spy(function(id) { node.enabled = true; - return when.resolve(node); + return Promise.resolve(node); }); var disableNode = sinon.spy(function(id) { node.enabled = false; - return when.resolve(node); + return Promise.resolve(node); }); initNodes({ diff --git a/test/unit/@node-red/runtime/lib/api/settings_spec.js b/test/unit/@node-red/runtime/lib/api/settings_spec.js index 3830e9ab2..02bbf48e7 100644 --- a/test/unit/@node-red/runtime/lib/api/settings_spec.js +++ b/test/unit/@node-red/runtime/lib/api/settings_spec.js @@ -588,7 +588,6 @@ var comms = require("../../../../red/api/editor/comms"); var info = require("../../../../red/api/editor/settings"); var auth = require("../../../../red/api/auth"); var sshkeys = require("../../../../red/api/editor/sshkeys"); -var when = require("when"); var bodyParser = require("body-parser"); var fs = require("fs-extra"); var fspath = require("path"); @@ -611,11 +610,11 @@ describe("api/editor/sshkeys", function() { exportNodeSettings:function(){}, storage: { getSessions: function(){ - return when.resolve(session_data); + return Promise.resolve(session_data); }, setSessions: function(_session) { session_data = _session; - return when.resolve(); + return Promise.resolve(); } } }, diff --git a/test/unit/@node-red/runtime/lib/flows/index_spec.js b/test/unit/@node-red/runtime/lib/flows/index_spec.js index df5012844..6f6066100 100644 --- a/test/unit/@node-red/runtime/lib/flows/index_spec.js +++ b/test/unit/@node-red/runtime/lib/flows/index_spec.js @@ -16,7 +16,6 @@ var should = require("should"); var sinon = require("sinon"); -var when = require("when"); var clone = require("clone"); var NR_TEST_UTILS = require("nr-test-utils"); @@ -65,13 +64,13 @@ describe('flows/index', function() { conf.forEach(function(n) { delete n.credentials; }); - return when.resolve(); + return Promise.resolve(); }); credentialsLoad = sinon.stub(credentials,"load",function(creds) { if (creds && creds.hasOwnProperty("$") && creds['$'] === "fail") { - return when.reject("creds error"); + return Promise.reject("creds error"); } - return when.resolve(); + return Promise.resolve(); }); flowCreate = sinon.stub(Flow,"create",function(parent, global, flow) { var id; @@ -101,7 +100,7 @@ describe('flows/index', function() { storage = { saveFlows: function(conf) { storage.conf = conf; - return when.resolve(); + return Promise.resolve(); } } }); @@ -145,10 +144,10 @@ describe('flows/index', function() { var loadStorage = { saveFlows: function(conf) { loadStorage.conf = conf; - return when.resolve(456); + return Promise.resolve(456); }, getFlows: function() { - return when.resolve({flows:originalConfig,rev:123}) + return Promise.resolve({flows:originalConfig,rev:123}) } } flows.init({log:mockLog, settings:{},storage:loadStorage}); @@ -207,7 +206,7 @@ describe('flows/index', function() { newConfig.push({id:"t2",type:"tab"}); newConfig.push({id:"t2-1",x:10,y:10,z:"t2",type:"test",wires:[]}); storage.getFlows = function() { - return when.resolve({flows:originalConfig}); + return Promise.resolve({flows:originalConfig}); } events.once('flows:started',function() { flows.setFlows(newConfig,"nodes").then(function() { @@ -235,7 +234,7 @@ describe('flows/index', function() { newConfig.push({id:"t2",type:"tab"}); newConfig.push({id:"t2-1",x:10,y:10,z:"t2",type:"test",wires:[]}); storage.getFlows = function() { - return when.resolve({flows:originalConfig}); + return Promise.resolve({flows:originalConfig}); } events.once('flows:started',function() { @@ -277,7 +276,7 @@ describe('flows/index', function() { {id:"t1",type:"tab"} ]; storage.getFlows = function() { - return when.resolve({flows:originalConfig}); + return Promise.resolve({flows:originalConfig}); } flows.init({log:mockLog, settings:{},storage:storage}); flows.load().then(function() { @@ -297,7 +296,7 @@ describe('flows/index', function() { {id:"t1",type:"tab"} ]; storage.getFlows = function() { - return when.resolve({flows:originalConfig}); + return Promise.resolve({flows:originalConfig}); } events.once('flows:started',function() { @@ -317,7 +316,7 @@ describe('flows/index', function() { {id:"t1",type:"tab"} ]; storage.getFlows = function() { - return when.resolve({flows:originalConfig}); + return Promise.resolve({flows:originalConfig}); } flows.init({log:mockLog, settings:{},storage:storage}); @@ -336,7 +335,7 @@ describe('flows/index', function() { {id:"t1",type:"tab"} ]; storage.getFlows = function() { - return when.resolve({flows:originalConfig}); + return Promise.resolve({flows:originalConfig}); } flows.init({log:mockLog, settings:{},storage:storage}); flows.load().then(function() { @@ -370,7 +369,7 @@ describe('flows/index', function() { {id:"t1",type:"tab"} ]; storage.getFlows = function() { - return when.resolve({flows:originalConfig}); + return Promise.resolve({flows:originalConfig}); } flows.init({log:mockLog, settings:{},storage:storage}); flows.load().then(function() { @@ -394,7 +393,7 @@ describe('flows/index', function() { // {id:"t1",type:"tab"} // ]; // storage.getFlows = function() { - // return when.resolve({flows:originalConfig}); + // return Promise.resolve({flows:originalConfig}); // } // // events.once('flows:started',function() { @@ -419,7 +418,7 @@ describe('flows/index', function() { // {id:"t3-1",x:10,y:10,z:"t3",type:"test",config:"configNode",wires:[]} // ]; // storage.getFlows = function() { - // return when.resolve({flows:originalConfig}); + // return Promise.resolve({flows:originalConfig}); // } // // events.once('flows:started',function() { @@ -447,7 +446,7 @@ describe('flows/index', function() { // {id:"t1",type:"tab"} // ]; // storage.getFlows = function() { - // return when.resolve({flows:originalConfig}); + // return Promise.resolve({flows:originalConfig}); // } // // events.once('flows:started',function() { @@ -473,7 +472,7 @@ describe('flows/index', function() { // {id:"t3-1",x:10,y:10,z:"t3",type:"test",config:"configNode",wires:[]} // ]; // storage.getFlows = function() { - // return when.resolve({flows:originalConfig}); + // return Promise.resolve({flows:originalConfig}); // } // // events.once('flows:started',function() { @@ -548,7 +547,7 @@ describe('flows/index', function() { {id:"t1",type:"tab"} ]; storage.getFlows = function() { - return when.resolve({flows:originalConfig}); + return Promise.resolve({flows:originalConfig}); } flows.init({log:mockLog, settings:{},storage:storage}); flows.load().then(function() { @@ -572,10 +571,10 @@ describe('flows/index', function() { {id:"t1",type:"tab"} ]; storage.getFlows = function() { - return when.resolve({flows:originalConfig}); + return Promise.resolve({flows:originalConfig}); } storage.setFlows = function() { - return when.resolve(); + return Promise.resolve(); } flows.init({log:mockLog, settings:{},storage:storage}); flows.load().then(function() { diff --git a/test/unit/@node-red/runtime/lib/flows/util_spec.js b/test/unit/@node-red/runtime/lib/flows/util_spec.js index 8e1f15754..59169376e 100644 --- a/test/unit/@node-red/runtime/lib/flows/util_spec.js +++ b/test/unit/@node-red/runtime/lib/flows/util_spec.js @@ -16,7 +16,6 @@ var should = require("should"); var sinon = require("sinon"); -var when = require("when"); var clone = require("clone"); var NR_TEST_UTILS = require("nr-test-utils"); var flowUtil = NR_TEST_UTILS.require("@node-red/runtime/lib/flows/util"); diff --git a/test/unit/@node-red/runtime/lib/nodes/credentials_spec.js b/test/unit/@node-red/runtime/lib/nodes/credentials_spec.js index 63050a8b9..5e4bc8094 100644 --- a/test/unit/@node-red/runtime/lib/nodes/credentials_spec.js +++ b/test/unit/@node-red/runtime/lib/nodes/credentials_spec.js @@ -16,7 +16,6 @@ var should = require("should"); var sinon = require("sinon"); -var when = require("when"); var util = require("util"); var NR_TEST_UTILS = require("nr-test-utils"); @@ -228,11 +227,11 @@ describe('red/runtime/nodes/credentials', function() { }, set: function(key,value) { settings[key] = value; - return when.resolve(); + return Promise.resolve(); }, delete: function(key) { delete settings[key]; - return when.resolve(); + return Promise.resolve(); } } } diff --git a/test/unit/@node-red/runtime/lib/nodes/index_spec.js b/test/unit/@node-red/runtime/lib/nodes/index_spec.js index 7a4992624..a73e0a246 100644 --- a/test/unit/@node-red/runtime/lib/nodes/index_spec.js +++ b/test/unit/@node-red/runtime/lib/nodes/index_spec.js @@ -17,7 +17,6 @@ var should = require("should"); var fs = require('fs-extra'); var path = require('path'); -var when = require("when"); var sinon = require('sinon'); var inherits = require("util").inherits; @@ -47,11 +46,11 @@ describe("red/nodes/index", function() { var testCredentials = {"tab1":{"b":1, "c":"2", "d":"$(foo)"}}; var storage = { getFlows: function() { - return when({red:123,flows:testFlows,credentials:testCredentials}); + return Promise.resolve({red:123,flows:testFlows,credentials:testCredentials}); }, saveFlows: function(conf) { should.deepEqual(testFlows, conf.flows); - return when.resolve(123); + return Promise.resolve(123); } }; @@ -182,12 +181,12 @@ describe("red/nodes/index", function() { fs.remove(userDir,function(err) { fs.mkdir(userDir,function() { sinon.stub(index, 'load', function() { - return when.promise(function(resolve,reject){ + return new Promise(function(resolve,reject){ resolve([]); }); }); sinon.stub(localfilesystem, 'getCredentials', function() { - return when.promise(function(resolve,reject) { + return new Promise(function(resolve,reject) { resolve({"tab1":{"b":1,"c":2}}); }); }) ; @@ -282,7 +281,7 @@ describe("red/nodes/index", function() { } }); sinon.stub(registry,"disableNode",function(id) { - return when.resolve(randomNodeInfo); + return Promise.resolve(randomNodeInfo); }); }); afterEach(function() { diff --git a/test/unit/@node-red/runtime/lib/storage/index_spec.js b/test/unit/@node-red/runtime/lib/storage/index_spec.js index 3ede68c86..dd9fa6e9b 100644 --- a/test/unit/@node-red/runtime/lib/storage/index_spec.js +++ b/test/unit/@node-red/runtime/lib/storage/index_spec.js @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ -var when = require("when"); var should = require("should"); var paff = require('path'); @@ -79,16 +78,16 @@ describe("red/storage/index", function() { }, getFlows : function() { calledFlagGetFlows = true; - return when.resolve([]); + return Promise.resolve([]); }, saveFlows : function (flows) { flows.should.be.an.Array(); flows.should.have.lengthOf(0); - return when.resolve(""); + return Promise.resolve(""); }, getCredentials : function() { calledFlagGetCredentials = true; - return when.resolve({}); + return Promise.resolve({}); }, saveCredentials : function(credentials) { credentials.should.be.true(); @@ -147,7 +146,7 @@ describe("red/storage/index", function() { storage.getLibraryEntry(true, "name"); storage.saveLibraryEntry(true, "name", true, true); - when.settle(promises).then(function() { + Promise.all(promises).then(function() { try { calledInit.should.be.true(); calledFlagGetFlows.should.be.true(); @@ -174,11 +173,11 @@ describe("red/storage/index", function() { getLibraryEntry : function(type, path) { if (type === "flows") { if (path === "/" || path === "\\") { - return when.resolve(["a",{fn:"test.json"}]); + return Promise.resolve(["a",{fn:"test.json"}]); } else if (path == "/a" || path == "\\a") { - return when.resolve([{fn:"test2.json"}]); + return Promise.resolve([{fn:"test2.json"}]); } else if (path == paff.join("","a","test2.json")) { - return when.resolve("test content"); + return Promise.resolve("test content"); } } }, @@ -187,7 +186,7 @@ describe("red/storage/index", function() { savePath = path; saveContent = body; saveMeta = meta; - return when.resolve(); + return Promise.resolve(); } }; From a1f565f7560bd291002b7b35e7f7dc7f249aef34 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Mon, 30 Nov 2020 16:58:05 +0000 Subject: [PATCH 2/5] Use more async funcs in runtime/lib/api to reduce Promise creation --- .../@node-red/runtime/lib/api/comms.js | 11 +- .../@node-red/runtime/lib/api/context.js | 4 +- .../@node-red/runtime/lib/api/index.js | 8 +- .../@node-red/runtime/lib/api/library.js | 81 ++- .../@node-red/runtime/lib/api/nodes.js | 516 ++++++++---------- .../@node-red/runtime/lib/api/projects.js | 68 ++- .../@node-red/runtime/lib/api/settings.js | 215 ++++---- 7 files changed, 419 insertions(+), 484 deletions(-) diff --git a/packages/node_modules/@node-red/runtime/lib/api/comms.js b/packages/node_modules/@node-red/runtime/lib/api/comms.js index 55789b806..42e727412 100644 --- a/packages/node_modules/@node-red/runtime/lib/api/comms.js +++ b/packages/node_modules/@node-red/runtime/lib/api/comms.js @@ -106,9 +106,8 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_comms */ - addConnection: function(opts) { + addConnection: async function(opts) { connections.push(opts.client); - return Promise.resolve(); }, /** @@ -119,14 +118,13 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_comms */ - removeConnection: function(opts) { + removeConnection: async function(opts) { for (var i=0;i} - resolves when complete * @memberof @node-red/runtime_comms */ - subscribe: function(opts) { + subscribe: async function(opts) { var re = new RegExp("^"+opts.topic.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$"); for (var t in retained) { if (re.test(t)) { opts.client.send(t,retained[t]); } } - return Promise.resolve(); }, /** @@ -159,5 +156,5 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_comms */ - unsubscribe: function(opts) {} + unsubscribe: async function(opts) {} }; diff --git a/packages/node_modules/@node-red/runtime/lib/api/context.js b/packages/node_modules/@node-red/runtime/lib/api/context.js index f69349a62..6716b6831 100644 --- a/packages/node_modules/@node-red/runtime/lib/api/context.js +++ b/packages/node_modules/@node-red/runtime/lib/api/context.js @@ -71,7 +71,7 @@ var api = module.exports = { * @return {Promise} - the node information * @memberof @node-red/runtime_context */ - getValue: function(opts) { + getValue: async function(opts) { return new Promise(function(resolve,reject) { var scope = opts.scope; var id = opts.id; @@ -165,7 +165,7 @@ var api = module.exports = { * @return {Promise} - the node information * @memberof @node-red/runtime_context */ - delete: function(opts) { + delete: async function(opts) { return new Promise(function(resolve,reject) { var scope = opts.scope; var id = opts.id; diff --git a/packages/node_modules/@node-red/runtime/lib/api/index.js b/packages/node_modules/@node-red/runtime/lib/api/index.js index 8856ac3c2..b131470b0 100644 --- a/packages/node_modules/@node-red/runtime/lib/api/index.js +++ b/packages/node_modules/@node-red/runtime/lib/api/index.js @@ -38,10 +38,10 @@ var api = module.exports = { projects: require("./projects"), context: require("./context"), - 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(); } } diff --git a/packages/node_modules/@node-red/runtime/lib/api/library.js b/packages/node_modules/@node-red/runtime/lib/api/library.js index f252d3264..6b7ed6218 100644 --- a/packages/node_modules/@node-red/runtime/lib/api/library.js +++ b/packages/node_modules/@node-red/runtime/lib/api/library.js @@ -36,32 +36,30 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_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; + }); }, /** @@ -77,23 +75,20 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_library */ - 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; + }); } } diff --git a/packages/node_modules/@node-red/runtime/lib/api/nodes.js b/packages/node_modules/@node-red/runtime/lib/api/nodes.js index a06cbed96..6a05b4c17 100644 --- a/packages/node_modules/@node-red/runtime/lib/api/nodes.js +++ b/packages/node_modules/@node-red/runtime/lib/api/nodes.js @@ -18,7 +18,7 @@ * @mixin @node-red/runtime_nodes */ -var fs = require("fs"); +var fs = require("fs-extra"); var runtime; @@ -52,22 +52,20 @@ var api = module.exports = { * @return {Promise} - the node information * @memberof @node-red/runtime_nodes */ - 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; + } }, /** @@ -78,11 +76,9 @@ var api = module.exports = { * @return {Promise} - the list of node modules * @memberof @node-red/runtime_nodes */ - 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(); }, /** @@ -95,22 +91,20 @@ var api = module.exports = { * @return {Promise} - the node html content * @memberof @node-red/runtime_nodes */ - getNodeConfig: function(opts) { - return new Promise(function(resolve,reject) { - var id = opts.id; - var lang = opts.lang; - 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; + 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; + } }, /** * Gets all node html content @@ -121,11 +115,9 @@ var api = module.exports = { * @return {Promise} - the node html content * @memberof @node-red/runtime_nodes */ - getNodeConfigs: function(opts) { - return new Promise(function(resolve,reject) { - runtime.log.audit({event: "nodes.configs.get"}, opts.req); - return resolve(runtime.nodes.getNodeConfigs(opts.lang)); - }); + getNodeConfigs: async function(opts) { + runtime.log.audit({event: "nodes.configs.get"}, opts.req); + return runtime.nodes.getNodeConfigs(opts.lang); }, /** @@ -137,20 +129,18 @@ var api = module.exports = { * @return {Promise} - the node module info * @memberof @node-red/runtime_nodes */ - 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; + } }, /** @@ -165,83 +155,78 @@ var api = module.exports = { * @return {Promise} - the node module info * @memberof @node-red/runtime_nodes */ - 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"; - err.status = 400; - return reject(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"; - err.status = 400; - return reject(err); - } - 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; - return reject(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); - } - } - 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); + 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.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"; err.status = 400; - return reject(err); + throw err; } - - }); + 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; + 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); + } + throw err; + }) + } + 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; + throw 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); + } + 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; + } }, /** * Removes a module from the runtime @@ -252,38 +237,35 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_nodes */ - 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; + } }, /** @@ -296,43 +278,41 @@ var api = module.exports = { * @return {Promise} - the module info object * @memberof @node-red/runtime_nodes */ - 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; + } }, /** @@ -345,43 +325,41 @@ var api = module.exports = { * @return {Promise} - the module info object * @memberof @node-red/runtime_nodes */ - 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; + } }, /** @@ -393,23 +371,21 @@ var api = module.exports = { * @return {Promise} - the message catalogs * @memberof @node-red/runtime_nodes */ - getModuleCatalogs: function(opts) { - return new Promise(function(resolve,reject) { - var namespace = opts.module; - var lang = opts.lang; - 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(){ - var nodeList = runtime.nodes.getNodeList(); - var result = {}; - nodeList.forEach(function(n) { - if (n.module !== "node-red") { - result[n.id] = runtime.i18n.i.getResourceBundle(lang, n.id)||{}; - } - }); - resolve(result); + getModuleCatalogs: async function(opts) { + var namespace = opts.module; + var lang = opts.lang; + var prevLang = runtime.i18n.i.language; + // Trigger a load from disk of the language if it is not the default + return runtime.i18n.i.changeLanguage(lang, function(){ + var nodeList = runtime.nodes.getNodeList(); + var result = {}; + nodeList.forEach(function(n) { + if (n.module !== "node-red") { + result[n.id] = runtime.i18n.i.getResourceBundle(lang, n.id)||{}; + } }); runtime.i18n.i.changeLanguage(prevLang); + return result; }); }, @@ -423,17 +399,15 @@ var api = module.exports = { * @return {Promise} - the message catalog * @memberof @node-red/runtime_nodes */ - getModuleCatalog: function(opts) { - return new Promise(function(resolve,reject) { - var namespace = opts.module; - var lang = opts.lang; - 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(){ - var catalog = runtime.i18n.i.getResourceBundle(lang, namespace); - resolve(catalog||{}); - }); + getModuleCatalog: async function(opts) { + var namespace = opts.module; + var lang = opts.lang; + var prevLang = runtime.i18n.i.language; + // Trigger a load from disk of the language if it is not the default + return runtime.i18n.i.changeLanguage(lang, function(){ + var catalog = runtime.i18n.i.getResourceBundle(lang, namespace); runtime.i18n.i.changeLanguage(prevLang); + return catalog||{}; }); }, @@ -445,12 +419,9 @@ var api = module.exports = { * @return {Promise} - the list of all icons * @memberof @node-red/runtime_nodes */ - 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(); }, /** * Gets a node icon @@ -462,20 +433,15 @@ var api = module.exports = { * @return {Promise} - the icon file as a Buffer or null if no icon available * @memberof @node-red/runtime_nodes */ - 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 + } } } diff --git a/packages/node_modules/@node-red/runtime/lib/api/projects.js b/packages/node_modules/@node-red/runtime/lib/api/projects.js index d792f3765..14d1d0ec1 100644 --- a/packages/node_modules/@node-red/runtime/lib/api/projects.js +++ b/packages/node_modules/@node-red/runtime/lib/api/projects.js @@ -24,8 +24,8 @@ var api = module.exports = { init: function(_runtime) { runtime = _runtime; }, - available: function(opts) { - return Promise.resolve(!!runtime.storage.projects); + available: async function(opts) { + return !!runtime.storage.projects; }, /** * List projects known to the runtime @@ -36,7 +36,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - listProjects: function(opts) { + listProjects: async function(opts) { return runtime.storage.projects.listProjects(opts.user).then(function(list) { var active = runtime.storage.projects.getActiveProject(opts.user); var response = { @@ -61,7 +61,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - createProject: function(opts) { + createProject: async function(opts) { runtime.log.audit({event: "projects.create",name:opts.project?opts.project.name:"missing-name"}, opts.req); return runtime.storage.projects.createProject(opts.user, opts.project) }, @@ -76,7 +76,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - initialiseProject: function(opts) { + initialiseProject: async function(opts) { // Initialised set when creating default files for an empty repo runtime.log.audit({event: "projects.initialise",id:opts.id}, opts.req); return runtime.storage.projects.initialiseProject(opts.user, opts.id, opts.project) @@ -90,8 +90,8 @@ var api = module.exports = { * @return {Promise} - the active project * @memberof @node-red/runtime_projects */ - getActiveProject: function(opts) { - return Promise.resolve(runtime.storage.projects.getActiveProject(opts.user)); + getActiveProject: async function(opts) { + return runtime.storage.projects.getActiveProject(opts.user); }, /** @@ -103,13 +103,11 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - setActiveProject: function(opts) { + setActiveProject: async function(opts) { var currentProject = runtime.storage.projects.getActiveProject(opts.user); runtime.log.audit({event: "projects.set",id:opts.id}, opts.req); if (!currentProject || opts.id !== currentProject.name) { return runtime.storage.projects.setActiveProject(opts.user, opts.id); - } else { - return Promise.resolve(); } }, @@ -122,7 +120,7 @@ var api = module.exports = { * @return {Promise} - the project metadata * @memberof @node-red/runtime_projects */ - getProject: function(opts) { + getProject: async function(opts) { return runtime.storage.projects.getProject(opts.user, opts.id) }, @@ -136,7 +134,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - updateProject: function(opts) { + updateProject: async function(opts) { runtime.log.audit({event: "projects.update",id:opts.id}, opts.req); return runtime.storage.projects.updateProject(opts.user, opts.id, opts.project); }, @@ -150,7 +148,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - deleteProject: function(opts) { + deleteProject: async function(opts) { runtime.log.audit({event: "projects.delete",id:opts.id}, opts.req); return runtime.storage.projects.deleteProject(opts.user, opts.id); }, @@ -165,7 +163,7 @@ var api = module.exports = { * @return {Promise} - the project status * @memberof @node-red/runtime_projects */ - getStatus: function(opts) { + getStatus: async function(opts) { return runtime.storage.projects.getStatus(opts.user, opts.id, opts.remote) }, @@ -179,7 +177,7 @@ var api = module.exports = { * @return {Promise} - a list of the local branches * @memberof @node-red/runtime_projects */ - getBranches: function(opts) { + getBranches: async function(opts) { return runtime.storage.projects.getBranches(opts.user, opts.id, opts.remote); }, @@ -193,7 +191,7 @@ var api = module.exports = { * @return {Promise} - the status of the branch * @memberof @node-red/runtime_projects */ - getBranchStatus: function(opts) { + getBranchStatus: async function(opts) { return runtime.storage.projects.getBranchStatus(opts.user, opts.id, opts.branch); }, @@ -208,7 +206,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - 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); return runtime.storage.projects.setBranch(opts.user, opts.id, opts.branch, opts.create) }, @@ -224,7 +222,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - 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); return runtime.storage.projects.deleteBranch(opts.user, opts.id, opts.branch, false, opts.force); }, @@ -239,7 +237,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - commit: function(opts) { + commit: async function(opts) { runtime.log.audit({event: "projects.commit",id:opts.id}, opts.req); return runtime.storage.projects.commit(opts.user, opts.id,{message: opts.message}); }, @@ -254,7 +252,7 @@ var api = module.exports = { * @return {Promise} - the commit details * @memberof @node-red/runtime_projects */ - getCommit: function(opts) { + getCommit: async function(opts) { return runtime.storage.projects.getCommit(opts.user, opts.id, opts.sha); }, @@ -269,7 +267,7 @@ var api = module.exports = { * @return {Promise} - an array of commits * @memberof @node-red/runtime_projects */ - getCommits: function(opts) { + getCommits: async function(opts) { return runtime.storage.projects.getCommits(opts.user, opts.id, { limit: opts.limit || 20, before: opts.before @@ -285,7 +283,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - abortMerge: function(opts) { + abortMerge: async function(opts) { runtime.log.audit({event: "projects.merge.abort",id:opts.id}, opts.req); return runtime.storage.projects.abortMerge(opts.user, opts.id); }, @@ -301,7 +299,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - resolveMerge: function(opts) { + resolveMerge: async function(opts) { runtime.log.audit({event: "projects.merge.resolve",id:opts.id, file:opts.path}, opts.req); return runtime.storage.projects.resolveMerge(opts.user, opts.id, opts.path, opts.resolution); }, @@ -315,7 +313,7 @@ var api = module.exports = { * @return {Promise} - the file listing * @memberof @node-red/runtime_projects */ - getFiles: function(opts) { + getFiles: async function(opts) { return runtime.storage.projects.getFiles(opts.user, opts.id); }, @@ -330,7 +328,7 @@ var api = module.exports = { * @return {Promise} - the content of the file * @memberof @node-red/runtime_projects */ - getFile: function(opts) { + getFile: async function(opts) { return runtime.storage.projects.getFile(opts.user, opts.id,opts.path,opts.tree); }, @@ -344,7 +342,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - stageFile: function(opts) { + stageFile: async function(opts) { runtime.log.audit({event: "projects.file.stage",id:opts.id, file:opts.path}, opts.req); return runtime.storage.projects.stageFile(opts.user, opts.id, opts.path); }, @@ -359,7 +357,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - unstageFile: function(opts) { + unstageFile: async function(opts) { runtime.log.audit({event: "projects.file.unstage",id:opts.id, file:opts.path}, opts.req); return runtime.storage.projects.unstageFile(opts.user, opts.id, opts.path); }, @@ -374,7 +372,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - revertFile: function(opts) { + revertFile: async function(opts) { runtime.log.audit({event: "projects.file.revert",id:opts.id, file:opts.path}, opts.req); return runtime.storage.projects.revertFile(opts.user, opts.id,opts.path) }, @@ -390,7 +388,7 @@ var api = module.exports = { * @return {Promise} - the requested diff * @memberof @node-red/runtime_projects */ - getFileDiff: function(opts) { + getFileDiff: async function(opts) { return runtime.storage.projects.getFileDiff(opts.user, opts.id, opts.path, opts.type); }, @@ -403,7 +401,7 @@ var api = module.exports = { * @return {Promise} - a list of project remotes * @memberof @node-red/runtime_projects */ - getRemotes: function(opts) { + getRemotes: async function(opts) { return runtime.storage.projects.getRemotes(opts.user, opts.id); }, @@ -420,7 +418,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - addRemote: function(opts) { + addRemote: async function(opts) { runtime.log.audit({event: "projects.remote.add",id:opts.id, remote:opts.remote.name}, opts.req); return runtime.storage.projects.addRemote(opts.user, opts.id, opts.remote) }, @@ -435,7 +433,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - removeRemote: function(opts) { + removeRemote: async function(opts) { runtime.log.audit({event: "projects.remote.delete",id:opts.id, remote:opts.remote}, opts.req); return runtime.storage.projects.removeRemote(opts.user, opts.id, opts.remote); }, @@ -451,7 +449,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - updateRemote: function(opts) { + updateRemote: async function(opts) { runtime.log.audit({event: "projects.remote.update",id:opts.id, remote:opts.remote.name}, opts.req); return runtime.storage.projects.updateRemote(opts.user, opts.id, opts.remote.name, opts.remote) }, @@ -467,7 +465,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - pull: function(opts) { + pull: async function(opts) { runtime.log.audit({event: "projects.pull",id:opts.id, remote: opts.remote, track:opts.track}, opts.req); return runtime.storage.projects.pull(opts.user, opts.id, opts.remote, opts.track, opts.allowUnrelatedHistories); }, @@ -483,7 +481,7 @@ var api = module.exports = { * @return {Promise} - resolves when complete * @memberof @node-red/runtime_projects */ - push: function(opts) { + push: async function(opts) { runtime.log.audit({event: "projects.push",id:opts.id, remote: opts.remote, track:opts.track}, opts.req); return runtime.storage.projects.push(opts.user, opts.id, opts.remote, opts.track); } diff --git a/packages/node_modules/@node-red/runtime/lib/api/settings.js b/packages/node_modules/@node-red/runtime/lib/api/settings.js index 6ebeeccfb..b34e9a27c 100644 --- a/packages/node_modules/@node-red/runtime/lib/api/settings.js +++ b/packages/node_modules/@node-red/runtime/lib/api/settings.js @@ -64,64 +64,57 @@ var api = module.exports = { * @return {Promise} - the runtime settings * @memberof @node-red/runtime_settings */ - getRuntimeSettings: function(opts) { - return new Promise(function(resolve,reject) { - try { - 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]; - } - }) + 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 (!runtime.settings.disableEditor) { - safeSettings.context = runtime.nodes.listContextStores(); + if (!runtime.settings.disableEditor) { + safeSettings.context = runtime.nodes.listContextStores(); - if (util.isArray(runtime.settings.paletteCategories)) { - safeSettings.paletteCategories = runtime.settings.paletteCategories; - } - - if (runtime.settings.flowFilePretty) { - safeSettings.flowFilePretty = runtime.settings.flowFilePretty; - } - - if (!runtime.nodes.paletteEditorEnabled()) { - safeSettings.editorTheme = safeSettings.editorTheme || {}; - safeSettings.editorTheme.palette = safeSettings.editorTheme.palette || {}; - safeSettings.editorTheme.palette.editable = 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() - } - } - safeSettings.git = { - globalUser: runtime.storage.projects.getGlobalGitUser() - } - } - - safeSettings.flowEncryptionType = runtime.nodes.getCredentialKeyType(); - runtime.settings.exportNodeSettings(safeSettings); - } - - - resolve(safeSettings); - }catch(err) { - console.log(err); + if (util.isArray(runtime.settings.paletteCategories)) { + safeSettings.paletteCategories = runtime.settings.paletteCategories; } - }); + + if (runtime.settings.flowFilePretty) { + safeSettings.flowFilePretty = runtime.settings.flowFilePretty; + } + + if (!runtime.nodes.paletteEditorEnabled()) { + safeSettings.editorTheme = safeSettings.editorTheme || {}; + safeSettings.editorTheme.palette = safeSettings.editorTheme.palette || {}; + safeSettings.editorTheme.palette.editable = 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() + } + } + safeSettings.git = { + globalUser: runtime.storage.projects.getGlobalGitUser() + } + } + + safeSettings.flowEncryptionType = runtime.nodes.getCredentialKeyType(); + runtime.settings.exportNodeSettings(safeSettings); + } + + return safeSettings; }, /** @@ -132,14 +125,14 @@ var api = module.exports = { * @return {Promise} - the user settings * @memberof @node-red/runtime_settings */ - getUserSettings: function(opts) { + getUserSettings: async function(opts) { var username; if (!opts.user || opts.user.anonymous) { username = '_'; } else { username = opts.user.username; } - return Promise.resolve(runtime.settings.getUserSettings(username)||{}); + return runtime.settings.getUserSettings(username)||{}; }, /** @@ -151,32 +144,30 @@ var api = module.exports = { * @return {Promise} - the user settings * @memberof @node-red/runtime_settings */ - updateUserSettings: function(opts) { + updateUserSettings: async function(opts) { var username; if (!opts.user || opts.user.anonymous) { username = '_'; } else { username = opts.user.username; } - 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; + } }, /** @@ -187,15 +178,12 @@ var api = module.exports = { * @return {Promise} - the user's ssh keys * @memberof @node-red/runtime_settings */ - 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); }); }, @@ -208,23 +196,23 @@ var api = module.exports = { * @return {Promise} - the user's ssh public key * @memberof @node-red/runtime_settings */ - 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; }); }, @@ -240,15 +228,11 @@ var api = module.exports = { * @return {Promise} - the id of the generated key * @memberof @node-red/runtime_settings */ - 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; }); }, @@ -261,16 +245,11 @@ var api = module.exports = { * @return {Promise} - resolves when deleted * @memberof @node-red/runtime_settings */ - 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; }); - } } From 6fb96fa3c157e6f34e2a99a2fd87c52e2fad0a2d Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 2 Dec 2020 09:25:10 +0000 Subject: [PATCH 3/5] Move exec and events components to util module The exec and events components are common components that are used by both runtime and registry. It makes sense to move them into the util package. This also adds some docs to the registry module --- API.md | 2 +- Gruntfile.js | 3 +- .../@node-red/registry/lib/index.js | 210 +++++++++++++++++- .../@node-red/registry/lib/installer.js | 13 +- .../@node-red/registry/lib/library.js | 62 +++--- .../@node-red/registry/lib/loader.js | 15 +- .../@node-red/registry/lib/localfilesystem.js | 7 +- .../@node-red/registry/lib/registry.js | 6 +- .../@node-red/registry/lib/util.js | 14 +- .../@node-red/runtime/lib/api/comms.js | 17 +- .../@node-red/runtime/lib/api/nodes.js | 20 +- .../@node-red/runtime/lib/flows/Flow.js | 3 +- .../@node-red/runtime/lib/flows/Subflow.js | 11 +- .../@node-red/runtime/lib/flows/index.js | 5 +- .../@node-red/runtime/lib/index.js | 28 +-- .../@node-red/runtime/lib/nodes/index.js | 2 +- .../@node-red/runtime/lib/storage/index.js | 2 +- .../localfilesystem/projects/Project.js | 9 +- .../localfilesystem/projects/git/index.js | 4 +- .../storage/localfilesystem/projects/index.js | 5 +- packages/node_modules/@node-red/util/index.js | 16 ++ .../@node-red/{runtime => util}/lib/events.js | 11 +- .../@node-red/{runtime => util}/lib/exec.js | 36 ++- .../node_modules/@node-red/util/lib/log.js | 5 +- packages/node_modules/node-red/lib/red.js | 8 +- .../@node-red/registry/lib/installer_spec.js | 37 ++- .../registry/lib/localfilesystem_spec.js | 59 ++--- .../@node-red/registry/lib/registry_spec.js | 50 ++--- .../@node-red/runtime/lib/api/comms_spec.js | 35 ++- .../@node-red/runtime/lib/flows/index_spec.js | 2 +- test/unit/@node-red/runtime/lib/index_spec.js | 85 ++++--- .../{runtime => util}/lib/events_spec.js | 4 +- .../{runtime => util}/lib/exec_spec.js | 24 +- 33 files changed, 491 insertions(+), 319 deletions(-) rename packages/node_modules/@node-red/{runtime => util}/lib/events.js (92%) rename packages/node_modules/@node-red/{runtime => util}/lib/exec.js (67%) rename test/unit/@node-red/{runtime => util}/lib/events_spec.js (88%) rename test/unit/@node-red/{runtime => util}/lib/exec_spec.js (90%) diff --git a/API.md b/API.md index f349ea8fe..692a34723 100644 --- a/API.md +++ b/API.md @@ -10,6 +10,6 @@ Module | Description [@node-red/editor-api](@node-red_editor-api.html) | an Express application that serves the Node-RED editor and provides the Admin HTTP API [@node-red/runtime](@node-red_runtime.html) | the core runtime of Node-RED [@node-red/util](@node-red_util.html) | common utilities for the Node-RED runtime and editor modules -@node-red/registry | the internal node registry +[@node-red/registry](@node-red_registry.html) | the internal node registry @node-red/nodes | the default set of core nodes @node-red/editor-client | the client-side resources of the Node-RED editor application diff --git a/Gruntfile.js b/Gruntfile.js index b01763ab0..2bdc2e3aa 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -461,7 +461,8 @@ module.exports = function(grunt) { 'packages/node_modules/@node-red/runtime/lib/hooks.js', 'packages/node_modules/@node-red/util/**/*.js', 'packages/node_modules/@node-red/editor-api/lib/index.js', - 'packages/node_modules/@node-red/editor-api/lib/auth/index.js' + 'packages/node_modules/@node-red/editor-api/lib/auth/index.js', + 'packages/node_modules/@node-red/registry/lib/index.js' ], options: { destination: 'docs', diff --git a/packages/node_modules/@node-red/registry/lib/index.js b/packages/node_modules/@node-red/registry/lib/index.js index 2805534a2..ebcde8cea 100644 --- a/packages/node_modules/@node-red/registry/lib/index.js +++ b/packages/node_modules/@node-red/registry/lib/index.js @@ -1,4 +1,4 @@ -/** +/*! * Copyright JS Foundation and other contributors, http://js.foundation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,16 +29,27 @@ var loader = require("./loader"); var installer = require("./installer"); var library = require("./library"); -var settings; - +/** + * Initialise the registry with a reference to a runtime object + * @param {Object} runtime - a runtime object + * @memberof @node-red/registry + */ function init(runtime) { - settings = runtime.settings; - installer.init(runtime); + installer.init(runtime.settings); + // Loader requires the full runtime object because it initialises + // the util module it. The Util module is responsible for constructing the + // RED object passed to node modules when they are loaded. loader.init(runtime); - registry.init(settings,loader,runtime.events); + registry.init(runtime.settings,loader); library.init(); } +/** + * Triggers the intial discovery and loading of all Node-RED node modules. + * found on the node path. + * @return {Promise} - resolves when the registry has finised discovering node modules. + * @memberof @node-red/registry + */ function load() { registry.load(); return installer.checkPrereq().then(loader.load); @@ -66,34 +77,221 @@ module.exports = { init:init, load:load, clear: registry.clear, + + /** + * Register a node constructor function. + * + * @param {Object} nodeSet - the Node Set object the constructor is for + * @param {String} type - the node type + * @param {Function} constructor - the node constructor function + * @function + * @memberof @node-red/registry + */ registerType: registry.registerNodeConstructor, + /** + * Get a node constructor function. + * + * @param {String} type - the node type + * @return {Function} the node constructor function + * @function + * @memberof @node-red/registry + */ get: registry.getNodeConstructor, + + /** + * Get a node's set information. + * + * @param {String} type - the node type or set identifier + * @return {Object} the node set information + * @function + * @memberof @node-red/registry + */ getNodeInfo: registry.getNodeInfo, + + + /** + * Get a list of all nodes in the registry. + * + * @return {Object} the node list + * @function + * @memberof @node-red/registry + */ getNodeList: registry.getNodeList, + /** + * Get a modules's information. + * + * @param {String} type - the module identifier + * @return {Object} the module information + * @function + * @memberof @node-red/registry + */ getModuleInfo: registry.getModuleInfo, + + /** + * Get a list of all moduless in the registry. + * + * @return {Object} the module list + * @function + * @memberof @node-red/registry + */ getModuleList: registry.getModuleList, + /** + * Get the HTML configs for all nodes in the registry. + * + * @param {String} lang - the language to return, default `en-US` + * @return {String} the node configs + * @function + * @memberof @node-red/registry + */ getNodeConfigs: registry.getAllNodeConfigs, + + /** + * Get the HTML config for a single node set. + * + * @param {String} id - the node identifier + * @param {String} lang - the language to return, default `en-US` + * @return {String} the node config + * @function + * @memberof @node-red/registry + */ getNodeConfig: registry.getNodeConfig, + + /** + * Get the local path to a node's icon file. + * + * @param {String} module - the module that provides the icon + * @param {String} icon - the name of the icon + * @return {String} the local path to the icon + * @function + * @memberof @node-red/registry + */ getNodeIconPath: registry.getNodeIconPath, + + + /** + * Get the full list of all icons available. + * + * @return {String} the icon list + * @function + * @memberof @node-red/registry + */ getNodeIcons: registry.getNodeIcons, + /** + * Enables a node set, making it available for use. + * + * @param {String} type - the node type or set identifier + * @return {Promise} A promise that resolves when the node set has been enabled + * @throws if the identifier is not recognised or runtime settings are unavailable + * @function + * @memberof @node-red/registry + */ enableNode: enableNodeSet, + + /** + * Disables a node set, making it unavailable for use. + * + * @param {String} type - the node type or set identifier + * @return {Promise} A promise that resolves when the node set has been disabled + * @throws if the identifier is not recognised or runtime settings are unavailable + * @function + * @memberof @node-red/registry + */ disableNode: registry.disableNodeSet, + + /** + * Loads a new module into the registry. + * + * This will rescan the node module paths looking for this module. + * + * @param {String} module - the name of the module to add + * @return {Promise} A promise that resolves with the module information once it has been added + * @throws if the module has already been added or the runtime settings are unavailable + * @function + * @memberof @node-red/registry + */ addModule: addModule, + + /** + * Removes a module from the registry. + * + * @param {String} module - the name of the module to remove + * @return {Promise} A promise that resolves with the list of removed node sets + * @throws if the module is not found or the runtime settings are unavailable + * @function + * @memberof @node-red/registry + */ removeModule: registry.removeModule, + /** + * Installs a new node module using npm and then add to the registry + * + * @param {String|Buffer} module - the name of the module to install, or a Buffer containing a module tar file + * @param {String} version - the version of the module to install, default: `latest` + * @param {String} url - (optional) a url to install the module from + * @return {Promise} A promise that resolves with the module information once it has been installed + * @function + * @memberof @node-red/registry + */ installModule: installer.installModule, + + + /** + * Uninstalls a module using npm + * + * @param {String} module - the name of the module to uninstall + * @return {Promise} A promise that resolves when the module has been removed + * @function + * @memberof @node-red/registry + */ uninstallModule: installer.uninstallModule, + /** + * Update to internal list of available modules based on what has been actually + * loaded. + * + * The `autoInstallModules` runtime option means the runtime may try to install + * missing modules after the initial load is complete. If that flag is not set + * this function is used to remove the modules from the registry's saved list. + * @function + * @memberof @node-red/registry + */ cleanModuleList: registry.cleanModuleList, + /** + * Check if the regisrty is able to install/remove modules. + * + * This is based on whether it has found `npm` on the command-line. + * @return {Boolean} whether the installer is enabled + * + * @function + * @memberof @node-red/registry + */ paletteEditorEnabled: installer.paletteEditorEnabled, + /** + * Get a list of all example flows provided by nodes in the registry. + * @return {Object} an object, indexed by module, listing all example flows + * + * @function + * @memberof @node-red/registry + */ getNodeExampleFlows: library.getExampleFlows, + + + /** + * Gets the full path to a node example + * @param {String} module - the name of the module providing the example + * @param {String} path - the relative path of the example + * @return {String} the full path to the example + * + * @function + * @memberof @node-red/registry + */ getNodeExampleFlowPath: library.getExampleFlowPath, deprecated: require("./deprecated") diff --git a/packages/node_modules/@node-red/registry/lib/installer.js b/packages/node_modules/@node-red/registry/lib/installer.js index 03f9eb11c..9735aa8a1 100644 --- a/packages/node_modules/@node-red/registry/lib/installer.js +++ b/packages/node_modules/@node-red/registry/lib/installer.js @@ -22,11 +22,7 @@ var tar = require("tar"); var registry = require("./registry"); var library = require("./library"); -var log; -var exec; - -var events; - +const {exec,log,events} = require("@node-red/util"); var child_process = require('child_process'); var npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm'; var paletteEditorEnabled = false; @@ -37,11 +33,8 @@ const slashRe = process.platform === "win32" ? /\\|[/]/ : /[/]/; const pkgurlRe = /^(https?|git(|\+https?|\+ssh|\+file)):\/\//; const localtgzRe = /^([a-zA-Z]:|\/).+tgz$/; -function init(runtime) { - events = runtime.events; - settings = runtime.settings; - log = runtime.log; - exec = runtime.exec; +function init(_settings) { + settings = _settings; } var activePromise = Promise.resolve(); diff --git a/packages/node_modules/@node-red/registry/lib/library.js b/packages/node_modules/@node-red/registry/lib/library.js index a8ca8a775..90b0fda82 100644 --- a/packages/node_modules/@node-red/registry/lib/library.js +++ b/packages/node_modules/@node-red/registry/lib/library.js @@ -14,7 +14,7 @@ * limitations under the License. **/ -var fs = require('fs'); +var fs = require('fs-extra'); var fspath = require('path'); var runtime; @@ -22,38 +22,34 @@ var runtime; var exampleRoots = {}; var exampleFlows = null; -function getFlowsFromPath(path) { - return new Promise(function(resolve,reject) { - var result = {}; - fs.readdir(path,function(err,files) { - var promises = []; - var validFiles = []; - files.forEach(function(file) { - var fullPath = fspath.join(path,file); - var stats = fs.lstatSync(fullPath); - if (stats.isDirectory()) { - validFiles.push(file); - promises.push(getFlowsFromPath(fullPath)); - } else if (/\.json$/.test(file)){ - validFiles.push(file); - promises.push(Promise.resolve(file.split(".")[0])) - } - }) - var i=0; - Promise.all(promises).then(function(results) { - results.forEach(function(r) { - if (typeof r === 'string') { - result.f = result.f||[]; - result.f.push(r); - } else { - result.d = result.d||{}; - result.d[validFiles[i]] = r; - } - i++; - }) - resolve(result); - }) - }); +async function getFlowsFromPath(path) { + var result = {}; + var validFiles = []; + return fs.readdir(path).then(files => { + var promises = []; + files.forEach(function(file) { + var fullPath = fspath.join(path,file); + var stats = fs.lstatSync(fullPath); + if (stats.isDirectory()) { + validFiles.push(file); + promises.push(getFlowsFromPath(fullPath)); + } else if (/\.json$/.test(file)){ + validFiles.push(file); + promises.push(Promise.resolve(file.split(".")[0])) + } + }) + return Promise.all(promises) + }).then(results => { + results.forEach(function(r,i) { + if (typeof r === 'string') { + result.f = result.f||[]; + result.f.push(r); + } else { + result.d = result.d||{}; + result.d[validFiles[i]] = r; + } + }) + return result; }) } diff --git a/packages/node_modules/@node-red/registry/lib/loader.js b/packages/node_modules/@node-red/registry/lib/loader.js index 3a960c73c..18d202420 100644 --- a/packages/node_modules/@node-red/registry/lib/loader.js +++ b/packages/node_modules/@node-red/registry/lib/loader.js @@ -22,15 +22,14 @@ var localfilesystem = require("./localfilesystem"); var registry = require("./registry"); var registryUtil = require("./util") var i18n = require("@node-red/util").i18n; +var log = require("@node-red/util").log; var settings; -var runtime; function init(_runtime) { - runtime = _runtime; - settings = runtime.settings; - localfilesystem.init(runtime); - registryUtil.init(runtime); + settings = _runtime.settings; + localfilesystem.init(settings); + registryUtil.init(_runtime); } function load(disableNodePathScan) { @@ -38,7 +37,7 @@ function load(disableNodePathScan) { // We should expose that as an option at some point, although the // performance gains are minimal. //return loadNodeFiles(registry.getModuleList()); - runtime.log.info(runtime.log._("server.loading")); + log.info(log._("server.loading")); var nodeFiles = localfilesystem.getNodeFiles(disableNodePathScan); return loadNodeFiles(nodeFiles); @@ -51,9 +50,9 @@ function loadNodeFiles(nodeFiles) { /* istanbul ignore else */ if (nodeFiles.hasOwnProperty(module)) { if (nodeFiles[module].redVersion && - !semver.satisfies(runtime.version().replace(/(\-[1-9A-Za-z-][0-9A-Za-z-\.]*)?(\+[0-9A-Za-z-\.]+)?$/,""), nodeFiles[module].redVersion)) { + !semver.satisfies((settings.version||"0.0.0").replace(/(\-[1-9A-Za-z-][0-9A-Za-z-\.]*)?(\+[0-9A-Za-z-\.]+)?$/,""), nodeFiles[module].redVersion)) { //TODO: log it - runtime.log.warn("["+module+"] "+runtime.log._("server.node-version-mismatch",{version:nodeFiles[module].redVersion})); + log.warn("["+module+"] "+log._("server.node-version-mismatch",{version:nodeFiles[module].redVersion})); nodeFiles[module].err = "version_mismatch"; continue; } diff --git a/packages/node_modules/@node-red/registry/lib/localfilesystem.js b/packages/node_modules/@node-red/registry/lib/localfilesystem.js index d5bef63cd..7aea3f57b 100644 --- a/packages/node_modules/@node-red/registry/lib/localfilesystem.js +++ b/packages/node_modules/@node-red/registry/lib/localfilesystem.js @@ -16,9 +16,6 @@ var fs = require("fs"); var path = require("path"); - -var log; - var log = require("@node-red/util").log; var i18n = require("@node-red/util").i18n; @@ -26,8 +23,8 @@ var settings; var disableNodePathScan = false; var iconFileExtensions = [".png", ".gif", ".svg"]; -function init(runtime) { - settings = runtime.settings; +function init(_settings) { + settings = _settings; } function isIncluded(name) { diff --git a/packages/node_modules/@node-red/registry/lib/registry.js b/packages/node_modules/@node-red/registry/lib/registry.js index 89f04eacc..a91735071 100644 --- a/packages/node_modules/@node-red/registry/lib/registry.js +++ b/packages/node_modules/@node-red/registry/lib/registry.js @@ -19,8 +19,7 @@ var path = require("path"); var fs = require("fs"); var library = require("./library"); - -var events; +const {events} = require("@node-red/util") var settings; var loader; @@ -31,10 +30,9 @@ var nodeConstructors = {}; var nodeTypeToId = {}; var moduleNodes = {}; -function init(_settings,_loader, _events) { +function init(_settings,_loader) { settings = _settings; loader = _loader; - events = _events; moduleNodes = {}; nodeTypeToId = {}; nodeConstructors = {}; diff --git a/packages/node_modules/@node-red/registry/lib/util.js b/packages/node_modules/@node-red/registry/lib/util.js index 5a6d3da38..dbb6c6fc7 100644 --- a/packages/node_modules/@node-red/registry/lib/util.js +++ b/packages/node_modules/@node-red/registry/lib/util.js @@ -14,9 +14,8 @@ * limitations under the License. **/ -var path = require("path"); -var i18n = require("@node-red/util").i18n; -var registry; +const path = require("path"); +const {events,i18n,log} = require("@node-red/util"); var runtime; function copyObjectProperties(src,dst,copyList,blockList) { @@ -40,7 +39,7 @@ function copyObjectProperties(src,dst,copyList,blockList) { } } function requireModule(name) { - var moduleInfo = registry.getModuleInfo(name); + var moduleInfo = require("./index").getModuleInfo(name); if (moduleInfo && moduleInfo.path) { var relPath = path.relative(__dirname, moduleInfo.path); return require(relPath); @@ -56,14 +55,14 @@ function createNodeApi(node) { nodes: {}, log: {}, settings: {}, - events: runtime.events, + events: events, hooks: runtime.hooks, util: runtime.util, version: runtime.version, require: requireModule, comms: { publish: function(topic,data,retain) { - runtime.events.emit("comms",{ + events.emit("comms",{ topic: topic, data: data, retain: retain @@ -83,7 +82,7 @@ function createNodeApi(node) { red.nodes.registerType = function(type,constructor,opts) { runtime.nodes.registerType(node.id,type,constructor,opts); } - copyObjectProperties(runtime.log,red.log,null,["init"]); + copyObjectProperties(log,red.log,null,["init"]); copyObjectProperties(runtime.settings,red.settings,null,["init","load","reset"]); if (runtime.adminApi) { red.auth = runtime.adminApi.auth; @@ -108,7 +107,6 @@ function createNodeApi(node) { module.exports = { init: function(_runtime) { runtime = _runtime; - registry = require("@node-red/registry/lib"); }, createNodeApi: createNodeApi } diff --git a/packages/node_modules/@node-red/runtime/lib/api/comms.js b/packages/node_modules/@node-red/runtime/lib/api/comms.js index 42e727412..90f1603cd 100644 --- a/packages/node_modules/@node-red/runtime/lib/api/comms.js +++ b/packages/node_modules/@node-red/runtime/lib/api/comms.js @@ -33,6 +33,7 @@ var runtime; var retained = {}; var connections = []; +const events = require("@node-red/util").events; function handleCommsEvent(event) { publish(event.topic,event.data,event.retain); @@ -88,14 +89,14 @@ var api = module.exports = { runtime = _runtime; connections = []; 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); }, /** diff --git a/packages/node_modules/@node-red/runtime/lib/api/nodes.js b/packages/node_modules/@node-red/runtime/lib/api/nodes.js index 6a05b4c17..9ac83c814 100644 --- a/packages/node_modules/@node-red/runtime/lib/api/nodes.js +++ b/packages/node_modules/@node-red/runtime/lib/api/nodes.js @@ -376,16 +376,18 @@ var api = module.exports = { var lang = opts.lang; var prevLang = runtime.i18n.i.language; // Trigger a load from disk of the language if it is not the default - return runtime.i18n.i.changeLanguage(lang, function(){ - var nodeList = runtime.nodes.getNodeList(); - var result = {}; - nodeList.forEach(function(n) { - if (n.module !== "node-red") { - result[n.id] = runtime.i18n.i.getResourceBundle(lang, n.id)||{}; - } + return new Promise( (resolve,reject) => { + runtime.i18n.i.changeLanguage(lang, function(){ + var nodeList = runtime.nodes.getNodeList(); + var result = {}; + nodeList.forEach(function(n) { + if (n.module !== "node-red") { + result[n.id] = runtime.i18n.i.getResourceBundle(lang, n.id)||{}; + } + }); + runtime.i18n.i.changeLanguage(prevLang); + resolve(result); }); - runtime.i18n.i.changeLanguage(prevLang); - return result; }); }, diff --git a/packages/node_modules/@node-red/runtime/lib/flows/Flow.js b/packages/node_modules/@node-red/runtime/lib/flows/Flow.js index a7e00bfbc..a4791e084 100644 --- a/packages/node_modules/@node-red/runtime/lib/flows/Flow.js +++ b/packages/node_modules/@node-red/runtime/lib/flows/Flow.js @@ -16,8 +16,8 @@ var clone = require("clone"); 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'); const hooks = require("../hooks"); @@ -679,7 +679,6 @@ module.exports = { asyncMessageDelivery = !runtime.settings.runtimeSyncDelivery Log = runtime.log; Subflow = require("./Subflow"); - Subflow.init(runtime); }, create: function(parent,global,conf) { return new Flow(parent,global,conf); diff --git a/packages/node_modules/@node-red/runtime/lib/flows/Subflow.js b/packages/node_modules/@node-red/runtime/lib/flows/Subflow.js index 78ec9ee75..da15ecfe4 100644 --- a/packages/node_modules/@node-red/runtime/lib/flows/Subflow.js +++ b/packages/node_modules/@node-red/runtime/lib/flows/Subflow.js @@ -18,16 +18,11 @@ const clone = require("clone"); const Flow = require('./Flow').Flow; const context = require('../nodes/context'); 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; - /** * Create deep copy of object */ @@ -509,8 +504,6 @@ function createSubflow(parent,globalFlow,subflowDef,subflowInstance) { } module.exports = { - init: function(runtime) { - Log = runtime.log; - }, + init: function(runtime) {}, create: createSubflow } diff --git a/packages/node_modules/@node-red/runtime/lib/flows/index.js b/packages/node_modules/@node-red/runtime/lib/flows/index.js index a207b8f05..350115f81 100644 --- a/packages/node_modules/@node-red/runtime/lib/flows/index.js +++ b/packages/node_modules/@node-red/runtime/lib/flows/index.js @@ -25,9 +25,8 @@ var context = require("../nodes/context") var credentials = require("../nodes/credentials"); var flowUtil = require("./util"); var log; -var events = require("../events"); +const events = require("@node-red/util").events; var redUtil = require("@node-red/util").util; -const hooks = require("../hooks"); var storage = null; var settings = null; @@ -712,7 +711,7 @@ module.exports = { */ load: load, loadFlows: load, - + get:getNode, eachNode: eachNode, diff --git a/packages/node_modules/@node-red/runtime/lib/index.js b/packages/node_modules/@node-red/runtime/lib/index.js index 89b0dcfd6..dd1594467 100644 --- a/packages/node_modules/@node-red/runtime/lib/index.js +++ b/packages/node_modules/@node-red/runtime/lib/index.js @@ -20,19 +20,15 @@ var redNodes = require("./nodes"); var flows = require("./flows"); var storage = require("./storage"); var library = require("./library"); -var events = require("./events"); var hooks = require("./hooks"); var settings = require("./settings"); -var exec = require("./exec"); var express = require("express"); var path = require('path'); var fs = require("fs"); var os = require("os"); -var redUtil = require("@node-red/util"); -var log = redUtil.log; -var i18n = redUtil.i18n; +const {log,i18n,events,exec,util} = require("@node-red/util"); var runtimeMetricInterval = null; @@ -65,7 +61,7 @@ var server; * better abstracted. * @memberof @node-red/runtime */ -function init(userSettings,httpServer,_adminApi,__util) { +function init(userSettings,httpServer,_adminApi) { server = httpServer; userSettings.version = getVersion(); settings.init(userSettings); @@ -79,14 +75,6 @@ function init(userSettings,httpServer,_adminApi,__util) { 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; - } } var version; @@ -246,6 +234,10 @@ function reportMetrics() { /** * 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. * @memberof @node-red/runtime */ @@ -266,17 +258,17 @@ function stop() { // 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, flows: flows, library: library, exec: exec, - util: require("@node-red/util").util, + util: util, get adminApi() { return adminApi }, get adminApp() { return adminApp }, get nodeApp() { return nodeApp }, diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/index.js b/packages/node_modules/@node-red/runtime/lib/nodes/index.js index be31df2f7..858274be2 100644 --- a/packages/node_modules/@node-red/runtime/lib/nodes/index.js +++ b/packages/node_modules/@node-red/runtime/lib/nodes/index.js @@ -28,7 +28,7 @@ var context = require("./context"); var Node = require("./Node"); var log; -var events = require("../events"); +const events = require("@node-red/util").events; var settings; diff --git a/packages/node_modules/@node-red/runtime/lib/storage/index.js b/packages/node_modules/@node-red/runtime/lib/storage/index.js index e7f09c20f..f5e07e254 100644 --- a/packages/node_modules/@node-red/runtime/lib/storage/index.js +++ b/packages/node_modules/@node-red/runtime/lib/storage/index.js @@ -17,7 +17,7 @@ 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; var runtime; var storageModule; diff --git a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/Project.js b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/Project.js index 55bb9d078..d87001f1f 100644 --- a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/Project.js +++ b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/Project.js @@ -26,6 +26,7 @@ var sshKeys = require("./ssh"); var settings; var runtime; var log = require("@node-red/util").log; +const events = require("@node-red/util").events; var projectsDir; @@ -532,7 +533,7 @@ Project.prototype.status = function(user, includeRemote) { result.merging = true; if (!self.merging) { self.merging = true; - runtime.events.emit("runtime-event",{ + events.emit("runtime-event",{ id:"runtime-state", payload:{ type:"warning", @@ -556,7 +557,7 @@ Project.prototype.status = function(user, includeRemote) { } if (result.commits.total === 0 && Object.keys(result.files).length === 0) { if (!self.empty) { - runtime.events.emit("runtime-event",{ + events.emit("runtime-event",{ id:"runtime-state", payload:{ type:"warning", @@ -570,9 +571,9 @@ Project.prototype.status = function(user, includeRemote) { } else { if (self.empty) { 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", payload:{ type:"warning", diff --git a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/git/index.js b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/git/index.js index dbcb5fb61..e1ded4337 100644 --- a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/git/index.js +++ b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/git/index.js @@ -14,8 +14,6 @@ * limitations under the License. **/ -var exec = require("../../../../exec"); - var authResponseServer = require('./authServer').ResponseServer; var sshResponseServer = require('./authServer').ResponseSSHServer; var clone = require('clone'); @@ -23,7 +21,7 @@ var path = require("path"); var gitCommand = "git"; var gitVersion; -var log = require("@node-red/util").log; +const {log,exec} = require("@node-red/util"); function runGitCommand(args,cwd,env,emit) { log.trace(gitCommand + JSON.stringify(args)); diff --git a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/index.js b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/index.js index 80a3f31e4..3bbeb823b 100644 --- a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/index.js +++ b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/index.js @@ -28,6 +28,7 @@ var Projects = require("./Project"); var settings; var runtime; var log = require("@node-red/util").log; +const events = require("@node-red/util").events; var projectsEnabled = false; var projectLogMessages = []; @@ -355,11 +356,11 @@ function getActiveProject(user) { function reloadActiveProject(action) { return runtime.nodes.stopFlows().then(function() { 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; }); }); diff --git a/packages/node_modules/@node-red/util/index.js b/packages/node_modules/@node-red/util/index.js index 66ac91bd3..29e1a480c 100644 --- a/packages/node_modules/@node-red/util/index.js +++ b/packages/node_modules/@node-red/util/index.js @@ -17,6 +17,8 @@ const log = require("./lib/log"); const i18n = require("./lib/i18n"); const util = require("./lib/util"); +const events = require("./lib/events"); +const exec = require("./lib/exec"); /** * This module provides common utilities for the Node-RED runtime and editor @@ -54,4 +56,18 @@ module.exports = { * @memberof @node-red/util */ util: util, + + /** + * Runtime events + * @mixes @node-red/util_event + * @memberof @node-red/util + */ + events: events, + + /** + * Run system commands with event-log integration + * @mixes @node-red/util_exec + * @memberof @node-red/util + */ + exec: exec } diff --git a/packages/node_modules/@node-red/runtime/lib/events.js b/packages/node_modules/@node-red/util/lib/events.js similarity index 92% rename from packages/node_modules/@node-red/runtime/lib/events.js rename to packages/node_modules/@node-red/util/lib/events.js index 8e6935222..df45b4d16 100644 --- a/packages/node_modules/@node-red/runtime/lib/events.js +++ b/packages/node_modules/@node-red/util/lib/events.js @@ -14,6 +14,11 @@ * limitations under the License. **/ + /** + * Runtime events + * @mixin @node-red/util_events + */ + const events = new (require("events")).EventEmitter(); @@ -45,14 +50,14 @@ module.exports = events; /** * Runtime events emitter - * @mixin @node-red/runtime_events + * @mixin @node-red/util_events */ /** * Register an event listener for a runtime event * @name on * @function - * @memberof @node-red/runtime_events + * @memberof @node-red/util_events * @param {String} eventName - the name of the event to listen to * @param {Function} listener - the callback function for the event */ @@ -61,7 +66,7 @@ module.exports = events; * Emit an event to all of its registered listeners * @name emit * @function - * @memberof @node-red/runtime_events + * @memberof @node-red/util_events * @param {String} eventName - the name of the event to emit * @param {any} ...args - the arguments to pass in the event * @return {Boolean} - whether the event had listeners or not diff --git a/packages/node_modules/@node-red/runtime/lib/exec.js b/packages/node_modules/@node-red/util/lib/exec.js similarity index 67% rename from packages/node_modules/@node-red/runtime/lib/exec.js rename to packages/node_modules/@node-red/util/lib/exec.js index 0ef3c069c..c7197ef65 100644 --- a/packages/node_modules/@node-red/runtime/lib/exec.js +++ b/packages/node_modules/@node-red/util/lib/exec.js @@ -1,4 +1,4 @@ -/** +/*! * Copyright JS Foundation and other contributors, http://js.foundation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,19 +14,41 @@ * limitations under the License. **/ -const child_process = require('child_process'); -const { util } = require('@node-red/util'); +/** + * Run system commands with event-log integration + * @mixin @node-red/util_exec + */ -var events; +const child_process = require('child_process'); +const events = require("./events"); +const util = require('./util'); function logLines(id,type,data) { events.emit("event-log", {id:id,payload:{ts: Date.now(),data:data,type:type}}); } module.exports = { - init: function(_runtime) { - events = _runtime.events; - }, + /** + * Run a system command with stdout/err being emitted as 'event-log' events + * on the @node-red/util/events handler. + * + * The main arguments to this function are the same as passed to `child_process.spawn` + * + * @param {String} command - the command to run + * @param {Array} args - arguments for the command + * @param {Object} options - options to pass child_process.spawn + * @param {Boolean} emit - whether to emit events to the event-log for each line of stdout/err + * @return {Promise} A promise that resolves (rc=0) or rejects (rc!=0) when the command completes. The value + * of the promise is an object of the form: + * + * { + * code: , + * stdout: , + * stderr: + * } + + * @memberof @node-red/util_exec + */ run: function(command,args,options,emit) { var invocationId = util.generateId(); diff --git a/packages/node_modules/@node-red/util/lib/log.js b/packages/node_modules/@node-red/util/lib/log.js index 8d7b84966..341019080 100644 --- a/packages/node_modules/@node-red/util/lib/log.js +++ b/packages/node_modules/@node-red/util/lib/log.js @@ -1,4 +1,4 @@ -/** +/*! * Copyright JS Foundation and other contributors, http://js.foundation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -12,7 +12,6 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * @ignore **/ /** @@ -91,7 +90,7 @@ var consoleLogger = function(msg) { } catch(e){ message = 'Exception trying to log: '+util.inspect(message); } - + util.log("["+levelNames[msg.level]+"] "+(msg.type?"["+msg.type+":"+(msg.name||msg.id)+"] ":"")+message); } } diff --git a/packages/node_modules/node-red/lib/red.js b/packages/node_modules/node-red/lib/red.js index 86fa513d1..e46e40e26 100644 --- a/packages/node_modules/node-red/lib/red.js +++ b/packages/node_modules/node-red/lib/red.js @@ -121,6 +121,10 @@ module.exports = { }, /** * Stop the Node-RED application. + * + * Once called, Node-RED should not be restarted until the Node.JS process is + * restarted. + * * @return {Promise} - resolves when complete * @memberof node-red */ @@ -161,10 +165,10 @@ module.exports = { /** * Runtime events emitter - * @see @node-red/runtime_events + * @see @node-red/util_events * @memberof node-red */ - events: runtime.events, + events: redUtil.events, /** * Runtime hooks engine diff --git a/test/unit/@node-red/registry/lib/installer_spec.js b/test/unit/@node-red/registry/lib/installer_spec.js index b344dbbea..e0e7380f6 100644 --- a/test/unit/@node-red/registry/lib/installer_spec.js +++ b/test/unit/@node-red/registry/lib/installer_spec.js @@ -25,6 +25,7 @@ var NR_TEST_UTILS = require("nr-test-utils"); var installer = NR_TEST_UTILS.require("@node-red/registry/lib/installer"); var registry = NR_TEST_UTILS.require("@node-red/registry/lib/index"); var typeRegistry = NR_TEST_UTILS.require("@node-red/registry/lib/registry"); +const { events, exec, log } = NR_TEST_UTILS.require("@node-red/util"); describe('nodes/registry/installer', function() { @@ -38,21 +39,15 @@ describe('nodes/registry/installer', function() { _: function(msg) { return msg } } + var execResponse; + beforeEach(function() { - installer.init({log:mockLog, settings:{}, events: new EventEmitter(), exec: { - run: function() { - return Promise.resolve(""); - } - }}); + sinon.stub(exec,"run", () => execResponse || Promise.resolve("")) + installer.init({}) }); - function initInstaller(execResult) { - installer.init({log:mockLog, settings:{}, events: new EventEmitter(), exec: { - run: function() { - return execResult; - } - }}); - } + afterEach(function() { + execResponse = null; if (registry.addModule.restore) { registry.addModule.restore(); } @@ -72,7 +67,7 @@ describe('nodes/registry/installer', function() { if (fs.statSync.restore) { fs.statSync.restore(); } - + exec.run.restore(); }); describe("installs module", function() { @@ -108,7 +103,7 @@ describe('nodes/registry/installer', function() { } var p = Promise.reject(res); p.catch((err)=>{}); - initInstaller(p) + execResponse = p; installer.installModule("this_wont_exist").catch(function(err) { err.should.have.property("code",404); done(); @@ -122,7 +117,7 @@ describe('nodes/registry/installer', function() { } var p = Promise.reject(res); p.catch((err)=>{}); - initInstaller(p) + execResponse = p; sinon.stub(typeRegistry,"getModuleInfo", function() { return { version: "0.1.1" @@ -163,7 +158,7 @@ describe('nodes/registry/installer', function() { } var p = Promise.reject(res); p.catch((err)=>{}); - initInstaller(p) + execResponse = p; installer.installModule("this_wont_exist").then(function() { done(new Error("Unexpected success")); }).catch(err => { @@ -181,7 +176,7 @@ describe('nodes/registry/installer', function() { } var p = Promise.resolve(res); p.catch((err)=>{}); - initInstaller(p) + execResponse = p; var addModule = sinon.stub(registry,"addModule",function(md) { return Promise.resolve(nodeInfo); @@ -226,7 +221,7 @@ describe('nodes/registry/installer', function() { } var p = Promise.resolve(res); p.catch((err)=>{}); - initInstaller(p) + execResponse = p; installer.installModule(resourcesDir).then(function(info) { info.should.eql(nodeInfo); done(); @@ -242,7 +237,7 @@ describe('nodes/registry/installer', function() { } var p = Promise.resolve(res); p.catch((err)=>{}); - initInstaller(p) + execResponse = p; var addModule = sinon.stub(registry,"addModule",function(md) { return Promise.resolve(nodeInfo); @@ -280,7 +275,7 @@ describe('nodes/registry/installer', function() { } var p = Promise.reject(res); p.catch((err)=>{}); - initInstaller(p) + execResponse = p; installer.uninstallModule("this_wont_exist").then(function() { done(new Error("Unexpected success")); @@ -304,7 +299,7 @@ describe('nodes/registry/installer', function() { } var p = Promise.resolve(res); p.catch((err)=>{}); - initInstaller(p) + execResponse = p; sinon.stub(fs,"statSync", function(fn) { return {}; }); diff --git a/test/unit/@node-red/registry/lib/localfilesystem_spec.js b/test/unit/@node-red/registry/lib/localfilesystem_spec.js index d86a08adb..5cb3c180d 100644 --- a/test/unit/@node-red/registry/lib/localfilesystem_spec.js +++ b/test/unit/@node-red/registry/lib/localfilesystem_spec.js @@ -53,7 +53,7 @@ describe("red/nodes/registry/localfilesystem",function() { } describe("#getNodeFiles",function() { it("Finds all the node files in the resources tree",function(done) { - localfilesystem.init({settings:{coreNodesDir:resourcesDir}}); + localfilesystem.init({coreNodesDir:resourcesDir}); var nodeList = localfilesystem.getNodeFiles(true); nodeList.should.have.a.property("node-red"); var nm = nodeList['node-red']; @@ -68,7 +68,7 @@ describe("red/nodes/registry/localfilesystem",function() { done(); }); it("Includes node files from settings",function(done) { - localfilesystem.init({settings:{nodesIncludes:['TestNode1.js'],coreNodesDir:resourcesDir}}); + localfilesystem.init({nodesIncludes:['TestNode1.js'],coreNodesDir:resourcesDir}); var nodeList = localfilesystem.getNodeFiles(true); nodeList.should.have.a.property("node-red"); var nm = nodeList['node-red']; @@ -78,7 +78,7 @@ describe("red/nodes/registry/localfilesystem",function() { done(); }); it("Excludes node files from settings",function(done) { - localfilesystem.init({settings:{nodesExcludes:['TestNode1.js'],coreNodesDir:resourcesDir}}); + localfilesystem.init({nodesExcludes:['TestNode1.js'],coreNodesDir:resourcesDir}); var nodeList = localfilesystem.getNodeFiles(true); nodeList.should.have.a.property("node-red"); var nm = nodeList['node-red']; @@ -88,7 +88,7 @@ describe("red/nodes/registry/localfilesystem",function() { done(); }); it("Finds nodes in userDir/nodes",function(done) { - localfilesystem.init({settings:{userDir:userDir}}); + localfilesystem.init({userDir:userDir}); var nodeList = localfilesystem.getNodeFiles(true); nodeList.should.have.a.property("node-red"); var nm = nodeList['node-red']; @@ -99,7 +99,7 @@ describe("red/nodes/registry/localfilesystem",function() { }); it("Finds nodes in settings.nodesDir (string)",function(done) { - localfilesystem.init({settings:{nodesDir:userDir}}); + localfilesystem.init({nodesDir:userDir}); var nodeList = localfilesystem.getNodeFiles(true); nodeList.should.have.a.property("node-red"); var nm = nodeList['node-red']; @@ -110,7 +110,7 @@ describe("red/nodes/registry/localfilesystem",function() { }); it("Finds nodes in settings.nodesDir (string,relative path)",function(done) { var relativeUserDir = path.join("test","unit","@node-red","registry","lib","resources","userDir"); - localfilesystem.init({settings:{nodesDir:relativeUserDir}}); + localfilesystem.init({nodesDir:relativeUserDir}); var nodeList = localfilesystem.getNodeFiles(true); nodeList.should.have.a.property("node-red"); var nm = nodeList['node-red']; @@ -120,7 +120,7 @@ describe("red/nodes/registry/localfilesystem",function() { done(); }); it("Finds nodes in settings.nodesDir (array)",function(done) { - localfilesystem.init({settings:{nodesDir:[userDir]}}); + localfilesystem.init({nodesDir:[userDir]}); var nodeList = localfilesystem.getNodeFiles(true); nodeList.should.have.a.property("node-red"); var nm = nodeList['node-red']; @@ -139,7 +139,7 @@ describe("red/nodes/registry/localfilesystem",function() { } return _join.apply(null,arguments); })); - localfilesystem.init({settings:{coreNodesDir:moduleDir}}); + localfilesystem.init({coreNodesDir:moduleDir}); var nodeList = localfilesystem.getNodeFiles(); nodeList.should.have.a.property("node-red"); var nm = nodeList['node-red']; @@ -175,18 +175,7 @@ describe("red/nodes/registry/localfilesystem",function() { it("scans icon files in the resources tree",function(done) { var count = 0; localfilesystem.init({ - - // events:{emit:function(eventName,dir){ - // if (count === 0) { - // eventName.should.equal("node-icon-dir"); - // dir.name.should.equal("node-red"); - // dir.icons.should.be.an.Array(); - // count = 1; - // } else if (count === 1) { - // done(); - // } - // }}, - settings:{coreNodesDir:resourcesDir} + coreNodesDir: resourcesDir }); var list = localfilesystem.getNodeFiles(true); list.should.have.property("node-red"); @@ -201,22 +190,7 @@ describe("red/nodes/registry/localfilesystem",function() { it("scans icons dir in library",function(done) { var count = 0; localfilesystem.init({ - // - // events:{emit:function(eventName,dir){ - // eventName.should.equal("node-icon-dir"); - // if (count === 0) { - // dir.name.should.equal("node-red"); - // dir.icons.should.be.an.Array(); - // count = 1; - // } else if (count === 1) { - // dir.name.should.equal("Library"); - // dir.icons.should.be.an.Array(); - // dir.icons.length.should.equal(1); - // dir.icons[0].should.be.equal("test_icon.png"); - // done(); - // } - // }}, - settings:{userDir:userDir} + userDir: userDir }); var list = localfilesystem.getNodeFiles(true); list.should.have.property("node-red"); @@ -240,7 +214,7 @@ describe("red/nodes/registry/localfilesystem",function() { } return _join.apply(null,arguments); })); - localfilesystem.init({settings:{coreNodesDir:moduleDir}}); + localfilesystem.init({coreNodesDir:moduleDir}); var nodeModule = localfilesystem.getModuleFiles('TestNodeModule'); nodeModule.should.have.a.property('TestNodeModule'); nodeModule['TestNodeModule'].should.have.a.property('name','TestNodeModule'); @@ -266,7 +240,7 @@ describe("red/nodes/registry/localfilesystem",function() { } return _join.apply(null,arguments); })); - localfilesystem.init({settings:{coreNodesDir:moduleDir}}); + localfilesystem.init({coreNodesDir:moduleDir}); /*jshint immed: false */ (function(){ localfilesystem.getModuleFiles('WontExistModule'); @@ -286,14 +260,7 @@ describe("red/nodes/registry/localfilesystem",function() { return _join.apply(null,arguments); })); localfilesystem.init({ - - // events:{emit:function(eventName,dir){ - // eventName.should.equal("node-icon-dir"); - // dir.name.should.equal("TestNodeModule"); - // dir.icons.should.be.an.Array(); - // done(); - // }}, - settings:{coreNodesDir:moduleDir} + coreNodesDir: moduleDir }); var nodeModule = localfilesystem.getModuleFiles('TestNodeModule'); nodeModule.should.have.property("TestNodeModule"); diff --git a/test/unit/@node-red/registry/lib/registry_spec.js b/test/unit/@node-red/registry/lib/registry_spec.js index d493ed688..60b48938d 100644 --- a/test/unit/@node-red/registry/lib/registry_spec.js +++ b/test/unit/@node-red/registry/lib/registry_spec.js @@ -21,9 +21,7 @@ var path = require("path"); var NR_TEST_UTILS = require("nr-test-utils"); var typeRegistry = NR_TEST_UTILS.require("@node-red/registry/lib/registry"); -var EventEmitter = require('events'); - -var events = new EventEmitter(); +const { events } = NR_TEST_UTILS.require("@node-red/util"); describe("red/nodes/registry/registry",function() { @@ -84,7 +82,7 @@ describe("red/nodes/registry/registry",function() { describe('#init/load', function() { it('loads initial config', function(done) { - typeRegistry.init(settingsWithStorageAndInitialConfig,null,events); + typeRegistry.init(settingsWithStorageAndInitialConfig,null); typeRegistry.getNodeList().should.have.lengthOf(0); typeRegistry.load(); typeRegistry.getNodeList().should.have.lengthOf(1); @@ -121,7 +119,7 @@ describe("red/nodes/registry/registry",function() { }} }; var expected = JSON.parse('{"node-red":{"name":"node-red","nodes":{"sentiment":{"name":"sentiment","types":["sentiment"],"enabled":true,"module":"node-red"},"inject":{"name":"inject","types":["inject"],"enabled":true,"module":"node-red"}}},"testModule":{"name":"testModule","nodes":{"a-module.js":{"name":"a-module.js","types":["example"],"enabled":true,"module":"testModule"}}}}'); - typeRegistry.init(legacySettings,null,events); + typeRegistry.init(legacySettings,null); typeRegistry.load(); legacySettings.set.calledOnce.should.be.true(); legacySettings.set.args[0][1].should.eql(expected); @@ -133,7 +131,7 @@ describe("red/nodes/registry/registry",function() { describe.skip('#addNodeSet', function() { it('adds a node set for an unknown module', function() { - typeRegistry.init(settings,null,events); + typeRegistry.init(settings,null); typeRegistry.getNodeList().should.have.lengthOf(0); typeRegistry.getModuleList().should.eql({}); @@ -162,7 +160,7 @@ describe("red/nodes/registry/registry",function() { it('adds a node set to an existing module', function() { - typeRegistry.init(settings,null,events); + typeRegistry.init(settings,null); typeRegistry.getNodeList().should.have.lengthOf(0); typeRegistry.getModuleList().should.eql({}); @@ -191,7 +189,7 @@ describe("red/nodes/registry/registry",function() { }); it('doesnt add node set types if node set has an error', function() { - typeRegistry.init(settings,null,events); + typeRegistry.init(settings,null); typeRegistry.getNodeList().should.have.lengthOf(0); typeRegistry.getModuleList().should.eql({}); @@ -207,7 +205,7 @@ describe("red/nodes/registry/registry",function() { }); it('doesnt add node set if type already exists', function() { - typeRegistry.init(settings,null,events); + typeRegistry.init(settings,null); typeRegistry.getNodeList().should.have.lengthOf(0); typeRegistry.getModuleList().should.eql({}); @@ -241,7 +239,7 @@ describe("red/nodes/registry/registry",function() { describe("#enableNodeSet", function() { it('throws error if settings unavailable', function() { - typeRegistry.init(settings,null,events); + typeRegistry.init(settings,null); /*jshint immed: false */ (function(){ typeRegistry.enableNodeSet("test-module/test-name"); @@ -249,7 +247,7 @@ describe("red/nodes/registry/registry",function() { }); it('throws error if module unknown', function() { - typeRegistry.init(settingsWithStorageAndInitialConfig,null,events); + typeRegistry.init(settingsWithStorageAndInitialConfig,null); /*jshint immed: false */ (function(){ typeRegistry.enableNodeSet("test-module/unknown"); @@ -260,7 +258,7 @@ describe("red/nodes/registry/registry",function() { }); describe("#disableNodeSet", function() { it('throws error if settings unavailable', function() { - typeRegistry.init(settings,null,events); + typeRegistry.init(settings,null); /*jshint immed: false */ (function(){ typeRegistry.disableNodeSet("test-module/test-name"); @@ -268,7 +266,7 @@ describe("red/nodes/registry/registry",function() { }); it('throws error if module unknown', function() { - typeRegistry.init(settingsWithStorageAndInitialConfig,null,events); + typeRegistry.init(settingsWithStorageAndInitialConfig,null); /*jshint immed: false */ (function(){ typeRegistry.disableNodeSet("test-module/unknown"); @@ -279,7 +277,7 @@ describe("red/nodes/registry/registry",function() { describe('#getNodeConfig', function() { it('returns nothing for an unregistered type config', function(done) { - typeRegistry.init(settings,null,events); + typeRegistry.init(settings,null); var config = typeRegistry.getNodeConfig("imaginary-shark"); (config === null).should.be.true(); done(); @@ -288,7 +286,7 @@ describe("red/nodes/registry/registry",function() { describe('#saveNodeList',function() { it('rejects when settings unavailable',function(done) { - typeRegistry.init(stubSettings({},false,{}),null,events); + typeRegistry.init(stubSettings({},false,{}),null); typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {"test-name":{module:"test-module",name:"test-name",types:[]}}}); typeRegistry.saveNodeList().catch(function(err) { done(); @@ -296,7 +294,7 @@ describe("red/nodes/registry/registry",function() { }); it('saves the list',function(done) { var s = stubSettings({},true,{}); - typeRegistry.init(s,null,events); + typeRegistry.init(s,null); typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { "test-name":testNodeSet1, @@ -325,7 +323,7 @@ describe("red/nodes/registry/registry",function() { describe('#removeModule',function() { it('throws error for unknown module', function() { var s = stubSettings({},true,{}); - typeRegistry.init(s,null,events); + typeRegistry.init(s,null); /*jshint immed: false */ (function(){ typeRegistry.removeModule("test-module/unknown"); @@ -333,7 +331,7 @@ describe("red/nodes/registry/registry",function() { }); it('throws error for unavaiable settings', function() { var s = stubSettings({},false,{}); - typeRegistry.init(s,null,events); + typeRegistry.init(s,null); /*jshint immed: false */ (function(){ typeRegistry.removeModule("test-module/unknown"); @@ -341,7 +339,7 @@ describe("red/nodes/registry/registry",function() { }); it('removes a known module', function() { var s = stubSettings({},true,{}); - typeRegistry.init(s,null,events); + typeRegistry.init(s,null); typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { "test-name":testNodeSet1 }}); @@ -360,7 +358,7 @@ describe("red/nodes/registry/registry",function() { it('returns node config', function() { typeRegistry.init(settings,{ getNodeHelp: function(config) { return "HE"+config.name+"LP" } - },events); + }); typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { "test-name":{ @@ -389,7 +387,7 @@ describe("red/nodes/registry/registry",function() { }); describe('#getModuleInfo', function() { it('returns module info', function() { - typeRegistry.init(settings,{},events); + typeRegistry.init(settings,{}); typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { "test-name":{ id: "test-module/test-name", @@ -413,7 +411,7 @@ describe("red/nodes/registry/registry",function() { }); describe('#getNodeInfo', function() { it('returns node info', function() { - typeRegistry.init(settings,{},events); + typeRegistry.init(settings,{}); typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { "test-name":{ id: "test-module/test-name", @@ -434,7 +432,7 @@ describe("red/nodes/registry/registry",function() { }); describe('#getFullNodeInfo', function() { it('returns node info', function() { - typeRegistry.init(settings,{},events); + typeRegistry.init(settings,{}); typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { "test-name":{ id: "test-module/test-name", @@ -459,7 +457,7 @@ describe("red/nodes/registry/registry",function() { }); describe('#getNodeList', function() { it("returns a filtered list", function() { - typeRegistry.init(settings,{},events); + typeRegistry.init(settings,{}); typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { "test-name":{ id: "test-module/test-name", @@ -526,7 +524,7 @@ describe("red/nodes/registry/registry",function() { it('returns a registered icon' , function() { var testIcon = path.resolve(__dirname+'/resources/userDir/lib/icons/'); - typeRegistry.init(settings,{},events); + typeRegistry.init(settings,{}); typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { "test-name":{ id: "test-module/test-name", @@ -558,7 +556,7 @@ describe("red/nodes/registry/registry",function() { it('returns an icon list of registered node module', function() { var testIcon = path.resolve(__dirname+'/resources/userDir/lib/icons/'); - typeRegistry.init(settings,{},events); + typeRegistry.init(settings,{}); typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { "test-name":{ id: "test-module/test-name", diff --git a/test/unit/@node-red/runtime/lib/api/comms_spec.js b/test/unit/@node-red/runtime/lib/api/comms_spec.js index e1359cb7d..2f2e35a54 100644 --- a/test/unit/@node-red/runtime/lib/api/comms_spec.js +++ b/test/unit/@node-red/runtime/lib/api/comms_spec.js @@ -19,6 +19,7 @@ var sinon = require("sinon"); var NR_TEST_UTILS = require("nr-test-utils"); var comms = NR_TEST_UTILS.require("@node-red/runtime/lib/api/comms"); +var events = NR_TEST_UTILS.require("@node-red/util/lib/events"); describe("runtime-api/comms", function() { describe("listens for events", function() { @@ -30,21 +31,19 @@ describe("runtime-api/comms", function() { } var eventHandlers = {}; before(function(done) { + sinon.stub(events,"removeListener", function() {}) + sinon.stub(events,"on", function(evt,handler) { eventHandlers[evt] = handler }) comms.init({ log: { trace: function(){} - }, - events: { - removeListener: function() {}, - on: function(evt,handler) { - eventHandlers[evt] = handler; - } } }) comms.addConnection({client: clientConnection}).then(done); }) after(function(done) { comms.removeConnection({client: clientConnection}).then(done); + events.removeListener.restore(); + events.on.restore(); }) afterEach(function() { messages = []; @@ -98,18 +97,18 @@ describe("runtime-api/comms", function() { } } before(function() { + sinon.stub(events,"removeListener", function() {}) + sinon.stub(events,"on", function(evt,handler) { eventHandlers[evt] = handler }) comms.init({ log: { trace: function(){} - }, - events: { - removeListener: function() {}, - on: function(evt,handler) { - eventHandlers[evt] = handler; - } } }) }) + after(function() { + events.removeListener.restore(); + events.on.restore(); + }) afterEach(function(done) { comms.removeConnection({client: clientConnection1}).then(function() { comms.removeConnection({client: clientConnection2}).then(done); @@ -178,18 +177,18 @@ describe("runtime-api/comms", function() { } var eventHandlers = {}; before(function() { + sinon.stub(events,"removeListener", function() {}) + sinon.stub(events,"on", function(evt,handler) { eventHandlers[evt] = handler }) comms.init({ log: { trace: function(){} - }, - events: { - removeListener: function() {}, - on: function(evt,handler) { - eventHandlers[evt] = handler; - } } }) }) + after(function() { + events.removeListener.restore(); + events.on.restore(); + }) afterEach(function(done) { messages = []; comms.removeConnection({client: clientConnection}).then(done); diff --git a/test/unit/@node-red/runtime/lib/flows/index_spec.js b/test/unit/@node-red/runtime/lib/flows/index_spec.js index 6f6066100..e230d2407 100644 --- a/test/unit/@node-red/runtime/lib/flows/index_spec.js +++ b/test/unit/@node-red/runtime/lib/flows/index_spec.js @@ -22,7 +22,7 @@ var NR_TEST_UTILS = require("nr-test-utils"); var flows = NR_TEST_UTILS.require("@node-red/runtime/lib/flows"); var RedNode = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/Node"); var RED = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes"); -var events = NR_TEST_UTILS.require("@node-red/runtime/lib/events"); +var events = NR_TEST_UTILS.require("@node-red/util/lib/events"); var credentials = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/credentials"); var typeRegistry = NR_TEST_UTILS.require("@node-red/registry") var Flow = NR_TEST_UTILS.require("@node-red/runtime/lib/flows/Flow"); diff --git a/test/unit/@node-red/runtime/lib/index_spec.js b/test/unit/@node-red/runtime/lib/index_spec.js index f6a506de1..60bdc286b 100644 --- a/test/unit/@node-red/runtime/lib/index_spec.js +++ b/test/unit/@node-red/runtime/lib/index_spec.js @@ -28,6 +28,7 @@ var settings = NR_TEST_UTILS.require("@node-red/runtime/lib/settings"); var util = NR_TEST_UTILS.require("@node-red/util"); var log = NR_TEST_UTILS.require("@node-red/util").log; +var i18n = NR_TEST_UTILS.require("@node-red/util").i18n; describe("runtime", function() { afterEach(function() { @@ -43,43 +44,45 @@ describe("runtime", function() { delete process.env.NODE_RED_HOME; }); function mockUtil(metrics) { - - return { - log:{ - log: sinon.stub(), - warn: sinon.stub(), - info: sinon.stub(), - trace: sinon.stub(), - metric: sinon.stub().returns(!!metrics), - _: function() { return "abc"} - }, - i18n: { - registerMessageCatalog: function(){ - return Promise.resolve(); - } - } - } + sinon.stub(log,"log",function(){}) + sinon.stub(log,"warn",function(){}) + sinon.stub(log,"info",function(){}) + sinon.stub(log,"trace",function(){}) + sinon.stub(log,"metric",function(){ return !!metrics }) + sinon.stub(log,"_",function(){ return "abc"}) + sinon.stub(i18n,"registerMessageCatalog",function(){ return Promise.resolve()}) + } + function unmockUtil() { + log.log.restore && log.log.restore(); + log.warn.restore && log.warn.restore(); + log.info.restore && log.info.restore(); + log.trace.restore && log.trace.restore(); + log.metric.restore && log.metric.restore(); + log._.restore && log._.restore(); + i18n.registerMessageCatalog.restore && i18n.registerMessageCatalog.restore(); } describe("init", function() { beforeEach(function() { sinon.stub(log,"init",function() {}); sinon.stub(settings,"init",function() {}); sinon.stub(redNodes,"init",function() {}) + mockUtil(); }); afterEach(function() { log.init.restore(); settings.init.restore(); redNodes.init.restore(); + unmockUtil(); }) it("initialises components", function() { - runtime.init({testSettings: true, httpAdminRoot:"/"},mockUtil()); + runtime.init({testSettings: true, httpAdminRoot:"/"}); settings.init.called.should.be.true(); redNodes.init.called.should.be.true(); }); it("returns version", function() { - runtime.init({testSettings: true, httpAdminRoot:"/"},mockUtil()); + runtime.init({testSettings: true, httpAdminRoot:"/"}); return runtime.version().then(version => { /^\d+\.\d+\.\d+(-.*)?$/.test(version).should.be.true(); }); @@ -98,7 +101,6 @@ describe("runtime", function() { var redNodesLoadFlows; var redNodesStartFlows; var redNodesLoadContextsPlugin; - var i18nRegisterMessageCatalog; beforeEach(function() { storageInit = sinon.stub(storage,"init",function(settings) {return Promise.resolve();}); @@ -108,7 +110,7 @@ describe("runtime", function() { redNodesLoadFlows = sinon.stub(redNodes,"loadFlows",function() {return Promise.resolve()}); redNodesStartFlows = sinon.stub(redNodes,"startFlows",function() {}); redNodesLoadContextsPlugin = sinon.stub(redNodes,"loadContextsPlugin",function() {return Promise.resolve()}); - i18nRegisterMessageCatalog = sinon.stub(util.i18n,"registerMessageCatalog",function() {return Promise.resolve()}); + mockUtil(); }); afterEach(function() { storageInit.restore(); @@ -119,7 +121,7 @@ describe("runtime", function() { redNodesLoadFlows.restore(); redNodesStartFlows.restore(); redNodesLoadContextsPlugin.restore(); - i18nRegisterMessageCatalog.restore(); + unmockUtil(); }); it("reports errored/missing modules",function(done) { redNodesGetNodeList = sinon.stub(redNodes,"getNodeList", function(cb) { @@ -128,8 +130,7 @@ describe("runtime", function() { { module:"module",enabled:true,loaded:false,types:["typeA","typeB"]} // missing ].filter(cb); }); - var util = mockUtil(); - runtime.init({testSettings: true, httpAdminRoot:"/", load:function() { return Promise.resolve();}},util); + runtime.init({testSettings: true, httpAdminRoot:"/", load:function() { return Promise.resolve();}}); // sinon.stub(console,"log"); runtime.start().then(function() { // console.log.restore(); @@ -139,9 +140,9 @@ describe("runtime", function() { redNodesLoad.calledOnce.should.be.true(); redNodesLoadFlows.calledOnce.should.be.true(); - util.log.warn.calledWithMatch("Failed to register 1 node type"); - util.log.warn.calledWithMatch("Missing node modules"); - util.log.warn.calledWithMatch(" - module: typeA, typeB"); + log.warn.calledWithMatch("Failed to register 1 node type"); + log.warn.calledWithMatch("Missing node modules"); + log.warn.calledWithMatch(" - module: typeA, typeB"); redNodesCleanModuleList.calledOnce.should.be.true(); done(); } catch(err) { @@ -159,16 +160,15 @@ describe("runtime", function() { ].filter(cb); }); var serverInstallModule = sinon.stub(redNodes,"installModule",function(name) { return Promise.resolve({nodes:[]});}); - var util = mockUtil(); - runtime.init({testSettings: true, autoInstallModules:true, httpAdminRoot:"/", load:function() { return Promise.resolve();}},util); + runtime.init({testSettings: true, autoInstallModules:true, httpAdminRoot:"/", load:function() { return Promise.resolve();}}); sinon.stub(console,"log"); runtime.start().then(function() { console.log.restore(); try { - util.log.warn.calledWithMatch("Failed to register 2 node types"); - util.log.warn.calledWithMatch("Missing node modules"); - util.log.warn.calledWithMatch(" - module: typeA, typeB"); - util.log.warn.calledWithMatch(" - node-red: typeC, typeD"); + log.warn.calledWithMatch("Failed to register 2 node types"); + log.warn.calledWithMatch("Missing node modules"); + log.warn.calledWithMatch(" - module: typeA, typeB"); + log.warn.calledWithMatch(" - node-red: typeC, typeD"); redNodesCleanModuleList.calledOnce.should.be.false(); serverInstallModule.calledOnce.should.be.true(); serverInstallModule.calledWithMatch("module"); @@ -186,14 +186,13 @@ describe("runtime", function() { { err:"errored",name:"errName" } // error ].filter(cb); }); - var util = mockUtil(); - runtime.init({testSettings: true, verbose:true, httpAdminRoot:"/", load:function() { return Promise.resolve();}},util); + runtime.init({testSettings: true, verbose:true, httpAdminRoot:"/", load:function() { return Promise.resolve();}}); sinon.stub(console,"log"); runtime.start().then(function() { console.log.restore(); try { - util.log.warn.neverCalledWithMatch("Failed to register 1 node type"); - util.log.warn.calledWithMatch("[errName] errored"); + log.warn.neverCalledWithMatch("Failed to register 1 node type"); + log.warn.calledWithMatch("[errName] errored"); done(); } catch(err) { done(err); @@ -204,21 +203,21 @@ describe("runtime", function() { it("reports runtime metrics",function(done) { var stopFlows = sinon.stub(redNodes,"stopFlows",function() { return Promise.resolve();} ); redNodesGetNodeList = sinon.stub(redNodes,"getNodeList", function() {return []}); - var util = mockUtil(true); + unmockUtil(); + mockUtil(true); runtime.init( {testSettings: true, runtimeMetricInterval:200, httpAdminRoot:"/", load:function() { return Promise.resolve();}}, {}, - undefined, - util); + undefined); // sinon.stub(console,"log"); runtime.start().then(function() { // console.log.restore(); setTimeout(function() { try { - util.log.log.args.should.have.lengthOf(3); - util.log.log.args[0][0].should.have.property("event","runtime.memory.rss"); - util.log.log.args[1][0].should.have.property("event","runtime.memory.heapTotal"); - util.log.log.args[2][0].should.have.property("event","runtime.memory.heapUsed"); + log.log.args.should.have.lengthOf(3); + log.log.args[0][0].should.have.property("event","runtime.memory.rss"); + log.log.args[1][0].should.have.property("event","runtime.memory.heapTotal"); + log.log.args[2][0].should.have.property("event","runtime.memory.heapUsed"); done(); } catch(err) { done(err); diff --git a/test/unit/@node-red/runtime/lib/events_spec.js b/test/unit/@node-red/util/lib/events_spec.js similarity index 88% rename from test/unit/@node-red/runtime/lib/events_spec.js rename to test/unit/@node-red/util/lib/events_spec.js index 09b47693d..09f5d2ae0 100644 --- a/test/unit/@node-red/runtime/lib/events_spec.js +++ b/test/unit/@node-red/util/lib/events_spec.js @@ -17,9 +17,9 @@ var should = require("should"); var NR_TEST_UTILS = require("nr-test-utils"); -describe("runtime/events", function() { +describe("@node-red/util/events", function() { it('can be required without errors', function() { - NR_TEST_UTILS.require("@node-red/runtime/lib/events"); + NR_TEST_UTILS.require("@node-red/util/lib/events"); }); it.skip('more tests needed', function(){}) }); diff --git a/test/unit/@node-red/runtime/lib/exec_spec.js b/test/unit/@node-red/util/lib/exec_spec.js similarity index 90% rename from test/unit/@node-red/runtime/lib/exec_spec.js rename to test/unit/@node-red/util/lib/exec_spec.js index 1e37b7cc1..887938d16 100644 --- a/test/unit/@node-red/runtime/lib/exec_spec.js +++ b/test/unit/@node-red/util/lib/exec_spec.js @@ -16,30 +16,31 @@ var should = require("should"); var sinon = require("sinon"); var path = require("path"); -var events = require("events"); +var EventEmitter = require("events").EventEmitter; var child_process = require('child_process'); var NR_TEST_UTILS = require("nr-test-utils"); -var exec = NR_TEST_UTILS.require("@node-red/runtime/lib/exec"); +var events = NR_TEST_UTILS.require("@node-red/util/lib/events"); +var exec = NR_TEST_UTILS.require("@node-red/util/lib/exec"); describe("runtime/exec", function() { var logEvents; var mockProcess; + const eventLogHandler = function(ev) { + logEvents.push(ev); + } beforeEach(function() { - var logEventHandler = new events.EventEmitter(); - logEvents = []; - logEventHandler.on('event-log', function(ev) { - logEvents.push(ev); - }); - exec.init({events:logEventHandler}); - mockProcess = new events.EventEmitter(); - mockProcess.stdout = new events.EventEmitter(); - mockProcess.stderr = new events.EventEmitter(); + logEvents = []; + events.on("event-log", eventLogHandler); + + mockProcess = new EventEmitter(); + mockProcess.stdout = new EventEmitter(); + mockProcess.stderr = new EventEmitter(); sinon.stub(child_process,'spawn',function(command,args,options) { mockProcess._args = {command,args,options}; return mockProcess; @@ -47,6 +48,7 @@ describe("runtime/exec", function() { }); afterEach(function() { + events.removeListener("event-log", eventLogHandler); if (child_process.spawn.restore) { child_process.spawn.restore(); } From fca21ac1268f47f99aede1c83748444be2e0dbda Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Wed, 2 Dec 2020 13:14:39 +0000 Subject: [PATCH 4/5] Rename paletteEditorEnabled to installerEnabled --- .../node_modules/@node-red/registry/lib/index.js | 2 +- .../@node-red/registry/lib/installer.js | 14 +++++++------- .../@node-red/runtime/lib/api/settings.js | 2 +- .../@node-red/runtime/lib/nodes/index.js | 2 +- .../@node-red/runtime/lib/api/settings_spec.js | 14 +++++++------- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/node_modules/@node-red/registry/lib/index.js b/packages/node_modules/@node-red/registry/lib/index.js index ebcde8cea..3632f40cf 100644 --- a/packages/node_modules/@node-red/registry/lib/index.js +++ b/packages/node_modules/@node-red/registry/lib/index.js @@ -271,7 +271,7 @@ module.exports = { * @function * @memberof @node-red/registry */ - paletteEditorEnabled: installer.paletteEditorEnabled, + installerEnabled: installer.installerEnabled, /** * Get a list of all example flows provided by nodes in the registry. diff --git a/packages/node_modules/@node-red/registry/lib/installer.js b/packages/node_modules/@node-red/registry/lib/installer.js index 9735aa8a1..0c3359382 100644 --- a/packages/node_modules/@node-red/registry/lib/installer.js +++ b/packages/node_modules/@node-red/registry/lib/installer.js @@ -25,7 +25,7 @@ var library = require("./library"); const {exec,log,events} = require("@node-red/util"); var child_process = require('child_process'); var npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm'; -var paletteEditorEnabled = false; +var installerEnabled = false; var settings; const moduleRe = /^(@[^/@]+?[/])?[^/@]+?$/; @@ -342,20 +342,20 @@ function checkPrereq() { settings.editorTheme.palette.editable === false ) { log.info(log._("server.palette-editor.disabled")); - paletteEditorEnabled = false; + installerEnabled = false; return Promise.resolve(); } else { return new Promise(resolve => { child_process.execFile(npmCommand,['-v'],function(err,stdout) { if (err) { log.info(log._("server.palette-editor.npm-not-found")); - paletteEditorEnabled = false; + installerEnabled = false; } else { if (parseInt(stdout.split(".")[0]) < 3) { log.info(log._("server.palette-editor.npm-too-old")); - paletteEditorEnabled = false; + installerEnabled = false; } else { - paletteEditorEnabled = true; + installerEnabled = true; } } resolve(); @@ -369,7 +369,7 @@ module.exports = { checkPrereq: checkPrereq, installModule: installModule, uninstallModule: uninstallModule, - paletteEditorEnabled: function() { - return paletteEditorEnabled + installerEnabled: function() { + return installerEnabled } } diff --git a/packages/node_modules/@node-red/runtime/lib/api/settings.js b/packages/node_modules/@node-red/runtime/lib/api/settings.js index b34e9a27c..067a8e83a 100644 --- a/packages/node_modules/@node-red/runtime/lib/api/settings.js +++ b/packages/node_modules/@node-red/runtime/lib/api/settings.js @@ -90,7 +90,7 @@ var api = module.exports = { safeSettings.flowFilePretty = runtime.settings.flowFilePretty; } - if (!runtime.nodes.paletteEditorEnabled()) { + if (!runtime.nodes.installerEnabled()) { safeSettings.editorTheme = safeSettings.editorTheme || {}; safeSettings.editorTheme.palette = safeSettings.editorTheme.palette || {}; safeSettings.editorTheme.palette.editable = false; diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/index.js b/packages/node_modules/@node-red/runtime/lib/nodes/index.js index 858274be2..7c6b6085e 100644 --- a/packages/node_modules/@node-red/runtime/lib/nodes/index.js +++ b/packages/node_modules/@node-red/runtime/lib/nodes/index.js @@ -187,7 +187,7 @@ module.exports = { getContext: context.get, - paletteEditorEnabled: registry.paletteEditorEnabled, + installerEnabled: registry.installerEnabled, installModule: installModule, uninstallModule: uninstallModule, diff --git a/test/unit/@node-red/runtime/lib/api/settings_spec.js b/test/unit/@node-red/runtime/lib/api/settings_spec.js index 02bbf48e7..d01235604 100644 --- a/test/unit/@node-red/runtime/lib/api/settings_spec.js +++ b/test/unit/@node-red/runtime/lib/api/settings_spec.js @@ -48,7 +48,7 @@ describe("runtime-api/settings", function() { }, nodes: { listContextStores: () => { return {stores:["file","memory"], default: "file"} }, - paletteEditorEnabled: () => false, + installerEnabled: () => false, getCredentialKeyType: () => "test-key-type" }, storage: {} @@ -79,7 +79,7 @@ describe("runtime-api/settings", function() { }, nodes: { listContextStores: () => { return {stores:["file","memory"], default: "file"} }, - paletteEditorEnabled: () => false, + installerEnabled: () => false, getCredentialKeyType: () => "test-key-type" }, storage: {} @@ -115,7 +115,7 @@ describe("runtime-api/settings", function() { }, nodes: { listContextStores: () => { return {stores:["file","memory"], default: "file"} }, - paletteEditorEnabled: () => false, + installerEnabled: () => false, getCredentialKeyType: () => "test-key-type" }, storage: { @@ -166,7 +166,7 @@ describe("runtime-api/settings", function() { }, nodes: { listContextStores: () => { return {stores:["file","memory"], default: "file"} }, - paletteEditorEnabled: () => false, + installerEnabled: () => false, getCredentialKeyType: () => "test-key-type" }, storage: { @@ -207,7 +207,7 @@ describe("runtime-api/settings", function() { }, nodes: { listContextStores: () => { return {stores:["file","memory"], default: "file"} }, - paletteEditorEnabled: () => false, + installerEnabled: () => false, getCredentialKeyType: () => "test-key-type" }, storage: { @@ -252,7 +252,7 @@ describe("runtime-api/settings", function() { }, nodes: { listContextStores: () => { return {stores:["file","memory"], default: "file"} }, - paletteEditorEnabled: () => false, + installerEnabled: () => false, getCredentialKeyType: () => "test-key-type" }, storage: { @@ -632,7 +632,7 @@ describe("api/editor/sshkeys", function() { }, events:{on:function(){},removeListener:function(){}}, isStarted: function() { return isStarted; }, - nodes: {paletteEditorEnabled: function() { return false }} + nodes: {installerEnabled: function() { return false }} }; before(function() { From fc7967d455a75d5eea57932a26c0fbf4c87de551 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Thu, 3 Dec 2020 11:24:28 +0000 Subject: [PATCH 5/5] Fix missing promise on setUserSettings --- packages/node_modules/@node-red/runtime/lib/settings.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/node_modules/@node-red/runtime/lib/settings.js b/packages/node_modules/@node-red/runtime/lib/settings.js index e17600305..989b83d9b 100644 --- a/packages/node_modules/@node-red/runtime/lib/settings.js +++ b/packages/node_modules/@node-red/runtime/lib/settings.js @@ -179,6 +179,7 @@ var persistentSettings = { userSettings[username] = settings; try { assert.deepEqual(current,settings); + return Promise.resolve(); } catch(err) { globalSettings.users = userSettings; return storage.saveSettings(clone(globalSettings));