From 848a69dc26b5dfb099f5735bc97f884023254237 Mon Sep 17 00:00:00 2001 From: Nicholas O'Leary Date: Tue, 12 Nov 2013 17:13:06 +0000 Subject: [PATCH] Make storage.init return a promise to async initialisation part of #62 --- red/library.js | 2 +- red/nodes.js | 2 +- red/server.js | 49 ++-- red/storage/index.js | 16 +- red/storage/localfilesystem.js | 4 +- test/storage_localfilesystem_spec.js | 329 ++++++++++++++------------- 6 files changed, 205 insertions(+), 197 deletions(-) diff --git a/red/library.js b/red/library.js index 9eefa0bce..2519d9417 100644 --- a/red/library.js +++ b/red/library.js @@ -19,7 +19,7 @@ var storage = null; function init() { redApp = require("./server").app; - storage = require("./storage").storage; + storage = require("./storage"); // -------- Flow Library -------- redApp.post(new RegExp("/library/flows\/(.*)"), function(req,res) { diff --git a/red/nodes.js b/red/nodes.js index 8a5dc342e..ecb7664c7 100644 --- a/red/nodes.js +++ b/red/nodes.js @@ -277,7 +277,7 @@ module.exports.setConfig = function(conf) { if (!storage) { // Do this lazily to ensure the storage provider as been initialised - storage = require("./storage").storage; + storage = require("./storage"); } storage.getCredentials().then(function(creds) { credentials = creds; diff --git a/red/server.js b/red/server.js index f83731612..d29a2f2c2 100644 --- a/red/server.js +++ b/red/server.js @@ -20,12 +20,13 @@ var redNodes = require("./nodes"); var app = null; var server = null; +var settings = null; +var storage = null; -function createServer(_server,settings) { +function createServer(_server,_settings) { server = _server; - - storage = require("./storage").init(settings); - + settings = _settings; + storage = require("./storage"); app = createUI(settings); flowfile = settings.flowFile || 'flows_'+require('os').hostname()+'.json'; @@ -61,25 +62,27 @@ function createServer(_server,settings) { } function start() { - console.log("\nWelcome to Node-RED\n===================\n"); - util.log("[red] Loading palette nodes"); - util.log("------------------------------------------"); - redNodes.load(); - util.log(""); - util.log('You may ignore any errors above here if they are for'); - util.log('nodes you are not using. The nodes indicated will not'); - util.log('be available in the main palette until any missing'); - util.log('modules are installed, typically by running:'); - util.log(' npm install {the module name}'); - util.log('or any other errors are resolved'); - util.log("------------------------------------------"); - - storage.getFlows().then(function(flows) { - if (flows.length > 0) { - redNodes.setConfig(flows); - } - }).otherwise(function(err) { - util.log("[red] Error loading flows : "+err); + storage.init(settings).then(function() { + console.log("\nWelcome to Node-RED\n===================\n"); + util.log("[red] Loading palette nodes"); + util.log("------------------------------------------"); + redNodes.load(); + util.log(""); + util.log('You may ignore any errors above here if they are for'); + util.log('nodes you are not using. The nodes indicated will not'); + util.log('be available in the main palette until any missing'); + util.log('modules are installed, typically by running:'); + util.log(' npm install {the module name}'); + util.log('or any other errors are resolved'); + util.log("------------------------------------------"); + + storage.getFlows().then(function(flows) { + if (flows.length > 0) { + redNodes.setConfig(flows); + } + }).otherwise(function(err) { + util.log("[red] Error loading flows : "+err); + }); }); } diff --git a/red/storage/index.js b/red/storage/index.js index e30e61d94..1dfc320db 100644 --- a/red/storage/index.js +++ b/red/storage/index.js @@ -15,19 +15,9 @@ **/ -var settings; -var storage; +var settings = require('../red').settings; -module.exports = { - init: function(_settings) { - settings = _settings; - - var storageType = settings.storageModule || "localfilesystem"; - - storage = require("./"+storageType).init(settings); - return storage; - }, -}; +var storageType = settings.storageModule || "localfilesystem"; -module.exports.__defineGetter__("storage", function() { return storage; }); +module.exports = require("./"+storageType); diff --git a/red/storage/localfilesystem.js b/red/storage/localfilesystem.js index 300f7db9f..1e639d631 100644 --- a/red/storage/localfilesystem.js +++ b/red/storage/localfilesystem.js @@ -160,7 +160,9 @@ var localfilesystem = { if (!fs.existsSync(libFlowsDir)) { fs.mkdirSync(libFlowsDir); } - return this; + var defer = when.defer(); + defer.resolve(); + return defer.promise; }, getFlows: function() { var defer = when.defer(); diff --git a/test/storage_localfilesystem_spec.js b/test/storage_localfilesystem_spec.js index ae712b52a..f0946e3d1 100644 --- a/test/storage_localfilesystem_spec.js +++ b/test/storage_localfilesystem_spec.js @@ -18,40 +18,42 @@ describe('LocalFileSystem', function() { }); it('should initialise the user directory',function() { - localfilesystem.init({userDir:userDir}); - fs.existsSync(path.join(userDir,"lib")).should.be.true; - fs.existsSync(path.join(userDir,"lib",'flows')).should.be.true; + localfilesystem.init({userDir:userDir}).then(function() { + fs.existsSync(path.join(userDir,"lib")).should.be.true; + fs.existsSync(path.join(userDir,"lib",'flows')).should.be.true; + }); }); it('should handle missing flow file',function(done) { - localfilesystem.init({userDir:userDir}); - var flowFile = 'flows_'+require('os').hostname()+'.json'; - var flowFilePath = path.join(userDir,flowFile); - fs.existsSync(flowFilePath).should.be.false; - localfilesystem.getFlows().then(function(flows) { - flows.should.eql([]); - done(); - }).otherwise(function(err) { - done(err); - }); - - }); - - it('should save flows to the default file',function(done) { - localfilesystem.init({userDir:userDir}); - var flowFile = 'flows_'+require('os').hostname()+'.json'; - var flowFilePath = path.join(userDir,flowFile); - fs.existsSync(flowFilePath).should.be.false; - localfilesystem.saveFlows(testFlow).then(function() { - fs.existsSync(flowFilePath).should.be.true; + localfilesystem.init({userDir:userDir}).then(function() { + var flowFile = 'flows_'+require('os').hostname()+'.json'; + var flowFilePath = path.join(userDir,flowFile); + fs.existsSync(flowFilePath).should.be.false; localfilesystem.getFlows().then(function(flows) { - flows.should.eql(testFlow); + flows.should.eql([]); done(); }).otherwise(function(err) { done(err); }); - }).otherwise(function(err) { - done(err); + }); + }); + + it('should save flows to the default file',function(done) { + localfilesystem.init({userDir:userDir}).then(function() { + var flowFile = 'flows_'+require('os').hostname()+'.json'; + var flowFilePath = path.join(userDir,flowFile); + fs.existsSync(flowFilePath).should.be.false; + localfilesystem.saveFlows(testFlow).then(function() { + fs.existsSync(flowFilePath).should.be.true; + localfilesystem.getFlows().then(function(flows) { + flows.should.eql(testFlow); + done(); + }).otherwise(function(err) { + done(err); + }); + }).otherwise(function(err) { + done(err); + }); }); }); @@ -61,129 +63,137 @@ describe('LocalFileSystem', function() { var flowFile = 'test.json'; var flowFilePath = path.join(userDir,flowFile); - localfilesystem.init({userDir:userDir, flowFile:flowFilePath}); - - fs.existsSync(defaultFlowFilePath).should.be.false; - fs.existsSync(flowFilePath).should.be.false; - - localfilesystem.saveFlows(testFlow).then(function() { + localfilesystem.init({userDir:userDir, flowFile:flowFilePath}).then(function() { fs.existsSync(defaultFlowFilePath).should.be.false; - fs.existsSync(flowFilePath).should.be.true; - localfilesystem.getFlows().then(function(flows) { - flows.should.eql(testFlow); - done(); + fs.existsSync(flowFilePath).should.be.false; + + localfilesystem.saveFlows(testFlow).then(function() { + fs.existsSync(defaultFlowFilePath).should.be.false; + fs.existsSync(flowFilePath).should.be.true; + localfilesystem.getFlows().then(function(flows) { + flows.should.eql(testFlow); + done(); + }).otherwise(function(err) { + done(err); + }); }).otherwise(function(err) { done(err); }); - }).otherwise(function(err) { - done(err); }); }); it('should handle missing credentials', function(done) { var credFile = path.join(userDir,"credentials.json"); - localfilesystem.init({userDir:userDir}); - fs.existsSync(credFile).should.be.false; - - localfilesystem.getCredentials().then(function(creds) { - creds.should.eql({}); - done(); - }).otherwise(function(err) { - done(err); + localfilesystem.init({userDir:userDir}).then(function() { + fs.existsSync(credFile).should.be.false; + + localfilesystem.getCredentials().then(function(creds) { + creds.should.eql({}); + done(); + }).otherwise(function(err) { + done(err); + }); }); }); it('should handle credentials', function(done) { var credFile = path.join(userDir,"credentials.json"); - localfilesystem.init({userDir:userDir}); - - fs.existsSync(credFile).should.be.false; - - var credentials = {"abc":{"type":"creds"}}; - - localfilesystem.saveCredentials(credentials).then(function() { - fs.existsSync(credFile).should.be.true; - localfilesystem.getCredentials().then(function(creds) { - creds.should.eql(credentials); - done(); + localfilesystem.init({userDir:userDir}).then(function() { + + fs.existsSync(credFile).should.be.false; + + var credentials = {"abc":{"type":"creds"}}; + + localfilesystem.saveCredentials(credentials).then(function() { + fs.existsSync(credFile).should.be.true; + localfilesystem.getCredentials().then(function(creds) { + creds.should.eql(credentials); + done(); + }).otherwise(function(err) { + done(err); + }); }).otherwise(function(err) { done(err); }); - }).otherwise(function(err) { - done(err); }); }); it('should return an empty list of library flows',function(done) { - localfilesystem.init({userDir:userDir}); - localfilesystem.getAllFlows().then(function(flows) { - flows.should.eql({}); - done(); - }).otherwise(function(err) { - done(err); - }); - }); - - it('should return a valid list of library flows',function(done) { - localfilesystem.init({userDir:userDir}); - var flowLib = path.join(userDir,"lib","flows"); - fs.closeSync(fs.openSync(path.join(flowLib,"A.json"),"w")); - fs.closeSync(fs.openSync(path.join(flowLib,"B.json"),"w")); - fs.mkdirSync(path.join(flowLib,"C")); - fs.closeSync(fs.openSync(path.join(flowLib,"C","D.json"),"w")); - var testFlowsList = {"d":{"C":{"f":["D"]}},"f":["A","B"]}; - - localfilesystem.getAllFlows().then(function(flows) { - flows.should.eql(testFlowsList); - done(); - }).otherwise(function(err) { - done(err); - }); - }); - - it('should fail a non-existent flow', function(done) { - localfilesystem.init({userDir:userDir}); - localfilesystem.getFlow("a/b/c.json").then(function(flow) { - should.fail(flow,"No flow","Flow found"); - }).otherwise(function(err) { - // err should be null, so this will pass - done(err); - }); - }); - - it('should return a flow',function(done) { - localfilesystem.init({userDir:userDir}); - var testflowString = JSON.stringify(testFlow); - localfilesystem.saveFlow("a/b/c/d.json",testflowString).then(function() { - localfilesystem.getFlow("a/b/c/d.json").then(function(flow) { - flow.should.eql(testflowString); + localfilesystem.init({userDir:userDir}).then(function() { + localfilesystem.getAllFlows().then(function(flows) { + flows.should.eql({}); done(); }).otherwise(function(err) { done(err); }); - }).otherwise(function(err) { - done(err); + }); + }); + + it('should return a valid list of library flows',function(done) { + localfilesystem.init({userDir:userDir}).then(function() { + var flowLib = path.join(userDir,"lib","flows"); + fs.closeSync(fs.openSync(path.join(flowLib,"A.json"),"w")); + fs.closeSync(fs.openSync(path.join(flowLib,"B.json"),"w")); + fs.mkdirSync(path.join(flowLib,"C")); + fs.closeSync(fs.openSync(path.join(flowLib,"C","D.json"),"w")); + var testFlowsList = {"d":{"C":{"f":["D"]}},"f":["A","B"]}; + + localfilesystem.getAllFlows().then(function(flows) { + flows.should.eql(testFlowsList); + done(); + }).otherwise(function(err) { + done(err); + }); + }); + }); + + it('should fail a non-existent flow', function(done) { + localfilesystem.init({userDir:userDir}).then(function() { + localfilesystem.getFlow("a/b/c.json").then(function(flow) { + should.fail(flow,"No flow","Flow found"); + }).otherwise(function(err) { + // err should be null, so this will pass + done(err); + }); + }); + }); + + it('should return a flow',function(done) { + localfilesystem.init({userDir:userDir}).then(function() { + var testflowString = JSON.stringify(testFlow); + localfilesystem.saveFlow("a/b/c/d.json",testflowString).then(function() { + localfilesystem.getFlow("a/b/c/d.json").then(function(flow) { + flow.should.eql(testflowString); + done(); + }).otherwise(function(err) { + done(err); + }); + }).otherwise(function(err) { + done(err); + }); }); }); it('should return an empty list of library objects',function(done) { - localfilesystem.init({userDir:userDir}); - localfilesystem.getLibraryEntry('object','').then(function(flows) { - flows.should.eql({}); - done(); - }).otherwise(function(err) { - done(err); + localfilesystem.init({userDir:userDir}).then(function() { + localfilesystem.getLibraryEntry('object','').then(function(flows) { + flows.should.eql({}); + done(); + }).otherwise(function(err) { + done(err); + }); }); }); it('should return an error for a non-existent library object',function(done) { - localfilesystem.init({userDir:userDir}); - localfilesystem.getLibraryEntry('object','A/B').then(function(flows) { - should.fail(null,null,"non-existent flow"); - }).otherwise(function(err) { - should.exist(err); - done(); + localfilesystem.init({userDir:userDir}).then(function() { + localfilesystem.getLibraryEntry('object','A/B').then(function(flows) { + should.fail(null,null,"non-existent flow"); + }).otherwise(function(err) { + should.exist(err); + done(); + }); }); }); @@ -198,48 +208,15 @@ describe('LocalFileSystem', function() { } it('should return a directory listing of library objects',function(done) { - localfilesystem.init({userDir:userDir}); - createObjectLibrary(); - - localfilesystem.getLibraryEntry('object','').then(function(flows) { - flows.should.eql([ 'A', 'B', { abc: 'def', fn: 'file1.js' } ]); - localfilesystem.getLibraryEntry('object','B').then(function(flows) { - flows.should.eql([ 'C', { ghi: 'jkl', fn: 'file2.js' } ]); - localfilesystem.getLibraryEntry('object','B/C').then(function(flows) { - flows.should.eql([]); - done(); - }).otherwise(function(err) { - done(err); - }); - }).otherwise(function(err) { - done(err); - }); - }).otherwise(function(err) { - done(err); - }); - }); + localfilesystem.init({userDir:userDir}).then(function() { + createObjectLibrary(); - it('should return a library object',function(done) { - localfilesystem.init({userDir:userDir}); - createObjectLibrary(); - localfilesystem.getLibraryEntry('object','B/file2.js').then(function(body) { - body.should.eql("// not a metaline \n\n Hi"); - done(); - }).otherwise(function(err) { - done(err); - }); - }); - - it('should return a newly saved library object',function(done) { - localfilesystem.init({userDir:userDir}); - createObjectLibrary(); - localfilesystem.getLibraryEntry('object','B').then(function(flows) { - flows.should.eql([ 'C', { ghi: 'jkl', fn: 'file2.js' } ]); - localfilesystem.saveLibraryEntry('object','B/D/file3.js',{mno:'pqr'},"// another non meta line\n\n Hi There").then(function() { - localfilesystem.getLibraryEntry('object','B/D').then(function(flows) { - flows.should.eql([ { mno: 'pqr', fn: 'file3.js' } ]); - localfilesystem.getLibraryEntry('object','B/D/file3.js').then(function(body) { - body.should.eql("// another non meta line\n\n Hi There"); + localfilesystem.getLibraryEntry('object','').then(function(flows) { + flows.should.eql([ 'A', 'B', { abc: 'def', fn: 'file1.js' } ]); + localfilesystem.getLibraryEntry('object','B').then(function(flows) { + flows.should.eql([ 'C', { ghi: 'jkl', fn: 'file2.js' } ]); + localfilesystem.getLibraryEntry('object','B/C').then(function(flows) { + flows.should.eql([]); done(); }).otherwise(function(err) { done(err); @@ -250,8 +227,44 @@ describe('LocalFileSystem', function() { }).otherwise(function(err) { done(err); }); - }).otherwise(function(err) { - done(err); + }); + }); + + it('should return a library object',function(done) { + localfilesystem.init({userDir:userDir}).then(function() { + createObjectLibrary(); + localfilesystem.getLibraryEntry('object','B/file2.js').then(function(body) { + body.should.eql("// not a metaline \n\n Hi"); + done(); + }).otherwise(function(err) { + done(err); + }); + }); + }); + + it('should return a newly saved library object',function(done) { + localfilesystem.init({userDir:userDir}).then(function() { + createObjectLibrary(); + localfilesystem.getLibraryEntry('object','B').then(function(flows) { + flows.should.eql([ 'C', { ghi: 'jkl', fn: 'file2.js' } ]); + localfilesystem.saveLibraryEntry('object','B/D/file3.js',{mno:'pqr'},"// another non meta line\n\n Hi There").then(function() { + localfilesystem.getLibraryEntry('object','B/D').then(function(flows) { + flows.should.eql([ { mno: 'pqr', fn: 'file3.js' } ]); + localfilesystem.getLibraryEntry('object','B/D/file3.js').then(function(body) { + body.should.eql("// another non meta line\n\n Hi There"); + done(); + }).otherwise(function(err) { + done(err); + }); + }).otherwise(function(err) { + done(err); + }); + }).otherwise(function(err) { + done(err); + }); + }).otherwise(function(err) { + done(err); + }); }); });