Refactored config loader

This commit is contained in:
Dallon Feldner
2012-09-19 11:48:14 -07:00
parent 9d4363fd88
commit ac273b89ee
3 changed files with 120 additions and 142 deletions

View File

@@ -1,15 +1,14 @@
var fs = require('fs')
, path = require('path')
, Resource = require('./resource')
, loadTypes = require('./type-loader')
, _loadTypes = require('./type-loader')
, InternalResources = require('./resources/internal-resources')
, Files = require('./resources/files')
, ClientLib = require('./resources/client-lib')
, Dashboard = require('./resources/dashboard')
, debug = require('debug')('config-loader')
, ignore = {}
, domain = require('domain');
, domain = require('domain')
, async = require('async');
/*!
* Loads resources from a project folder
* Callback receives two arguments `(err, resources)`.
@@ -18,157 +17,124 @@ var fs = require('fs')
* @param {Function} callback
*/
module.exports.loadConfig = function(basepath, server, fn) {
var remaining = 0
, finished = false
, resourceConfig = resourceConfig || {}
, resources = server.__resourceCache || []
, src = {}
, error;
var resources = server.__resourceCache || [];
server.__resourceCache = null;
if(resources.length) {
if (resources.length) {
debug("Loading from cache");
fn(null, resources);
if(server.options.env === 'development') {
// dump the cache in two seconds
setTimeout(function () {
delete server.__resourceCache;
}, 2000);
}
return;
}
function done() {
if(!finished && !remaining) {
if(error) return fn(error);
var getTypes = async.memoize(loadTypes);
remaining = -1;
finished = true;
async.waterfall([
async.apply(loadResourceDir, basepath)
, async.apply(loadResources, getTypes, basepath, server)
, async.apply(addInternalResources, server, basepath)
], function(err, result) {
fn(err, result);
});
};
var InternalResources = require('./resources/internal-resources');
debug('done, adding internals');
var clientLib = new ClientLib('dpd.js', { config: { resources: resources }, server: server});
clientLib.load(function(err) {
if (err) return fn(err);
resources.push(new Files('', { config: { 'public': './public' }, server: server }));
resources.push(clientLib);
resources.push(new InternalResources('__resources', {config: {configPath: basepath}, server: server}));
resources.push(new Dashboard('dashboard', {server: server}));
server.__resourceCache = resources;
fn(null, resources);
});
}
}
loadTypes(function(defaults, types) {
function loadTypes(fn) {
_loadTypes(function(defaults, types) {
Object.keys(types).forEach(function(key) {
defaults[key] = types[key];
});
types = defaults;
loadResources(types);
types = defaults;
fn(null, types);
});
}
function loadResource(name, path, config, types) {
debug("Loading resource: %s", name);
var type = config.type
, resource
, o = {
config: config
, server: server
, db: server.db
, configPath: path
};
function loadResourceDir(basepath, fn) {
fs.readdir(path.join(basepath, 'resources'), fn);
}
if (types[type]) {
var d = domain.create();
d.on('error', function (err) {
err.message += ' - when initializing: ' + o.config.type;
console.error(err.stack || err);
process.exit();
});
remaining++;
d.run(function () {
process.nextTick(function () {
remaining--;
resource = new types[o.config.type](name, o);
if (resource.load) {
remaining++;
resource.load(function(err) {
remaining--;
if (err) {
error = err;
return done();
}
resources.push(resource);
done();
});
} else {
resources.push(resource);
}
function loadResources(getTypes, basepath, server, files, fn) {
async.map(files, function(resourceName, fn) {
var resourcePath = path.join(basepath, 'resources', resourceName);
var configPath = path.join(resourcePath, 'config.json');
async.auto({
types: function(fn) {
getTypes(fn);
},
configJsonFile: function(fn) {
debug("reading %s", configPath);
fs.readFile(configPath, 'utf-8', fn);
},
configJson: ['configJsonFile', function(fn, results) {
try {
var settings = JSON.parse(results.configJsonFile);
fn(null, settings);
} catch (ex) {
fn(ex);
}
}],
instance: ['configJson', 'types', function(fn, results) {
debug("Loading resource: %s", resourceName);
var config = results.configJson
, types = results.types
, type = config.type
, resource
, o;
o = {
config: config
, server: server
, db: server.db
, configPath: resourcePath
};
if (!types[type]) return fn(new Error("Cannot find type \"" + type + "\" for resource " + resourceName));
var d = domain.create();
d.on('error', function (err) {
err.message += ' - when initializing: ' + o.config.type;
console.error(err.stack || err);
process.exit();
});
});
} else {
error = 'cannot find type ' + o.config.type + ' for resource ' + name;
}
if(error) throw error;
}
function loadResources(types) {
fs.readdir(path.join(basepath, 'resources'), function (err, dir) {
if(dir && dir.length) {
dir.forEach(function (file) {
if(!ignore[file]) {
remaining++;
fs.stat(path.join(basepath, 'resources', file), function (err, stat) {
remaining--;
if(err) throw err;
if(stat && stat.isDirectory()) {
var spath = path.join(basepath, 'resources', file, 'config.json')
, resource = file;
(fs.exists || path.exists)(spath, function (exists) {
if(exists) {
remaining++;
fs.readFile(spath, 'utf-8', function(err, data) {
remaining--;
var settings;
if(err) throw err;
try {
settings = JSON.parse(data);
loadResource(file, path.join(basepath, 'resources', file), settings, types);
} catch(e) {
if(err) throw err;
}
done();
});
} else {
done();
}
});
} else {
done();
}
});
}
d.run(function() {
process.nextTick(function() {
resource = new types[type](resourceName, o);
loadResourceExtras(resource, fn);
});
});
} else {
done();
}
}]
}, function(err, results) {
fn(err, results && results.instance);
});
}
}, fn);
}
function loadResourceExtras(resource, fn) {
async.series([
function(fn) {
if (resource.load) {
resource.load(fn);
} else {
fn();
}
}
], function(err) {
fn(err, resource);
});
}
function addInternalResources(server, basepath, resources, fn) {
var internals = [
new Files('', { config: { 'public': './public' }, server: server })
, new ClientLib('dpd.js', { config: { resources: resources }, server: server})
, new InternalResources('__resources', {config: {configPath: basepath}, server: server})
, new Dashboard('dashboard', {server: server})
];
async.forEach(internals, loadResourceExtras, function(err) {
fn(err, resources.concat(internals));
});
};
}