config: refactor config parsing.

This commit is contained in:
Christopher Jeffrey 2017-01-25 16:18:40 -08:00
parent f576ab6e6c
commit 0a1c0d1890
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
3 changed files with 197 additions and 121 deletions

View File

@ -11,13 +11,13 @@ var Amount = require('../lib/btc/amount');
var main;
function CLI() {
this.config = config({
this.config = config.parseRaw({
config: true,
arg: true,
env: true,
network: 'main'
}).data;
this.argv = this.config.args;
});
this.argv = this.config.argv;
this.client = null;
this.wallet = null;
}

View File

@ -6,10 +6,9 @@
'use strict';
var Network = require('../protocol/network');
var util = require('../utils/util');
var assert = require('assert');
var fs = require('fs');
var util = require('../utils/util');
var global = util.global;
/**
@ -38,6 +37,90 @@ config.alias = {
}
};
/**
* Parse env and args.
* @param {Object} options
* @returns {Object}
*/
config.parseArgs = function parseArgs(options) {
var data = Object.create(null);
var argv = [];
var raw;
if (options.network != null) {
assert(isAlpha(options.network), 'Bad network.');
data.network = options.network;
}
if (options.prefix != null) {
assert(typeof options.prefix === 'string');
assert(typeof options.prefix.length > 0);
data.prefix = options.prefix;
}
if (options.config != null) {
if (typeof options.config === 'string') {
assert(options.config.length > 0);
data.config = options.config;
} else {
assert(typeof options.config === 'boolean');
}
}
if (options.env) {
raw = config.parseEnv();
merge(data, raw);
}
if (options.arg) {
raw = config.parseArg();
argv = raw.argv;
merge(data, raw.data);
}
if (options.query) {
raw = config.parseQuery();
merge(data, raw);
}
if (options.hash) {
raw = config.parseHash();
merge(data, raw);
}
data.argv = argv;
return data;
};
/**
* Parse env, args, and config.
* @param {Object} options
* @returns {Object}
*/
config.parseRaw = function parseRaw(options) {
var data = config.parseArgs(options);
var prefix = config.getPrefix(data);
var file = config.getFile(prefix, data);
var argv = data.argv;
var raw;
if (options.config) {
raw = config.readConfig(file);
merge(raw, data);
data = raw;
prefix = config.getPrefix(data);
}
data.argv = argv;
data.prefix = prefix;
data.config = file;
return data;
};
/**
* Parse options and potentially env, args, and config.
* @param {Object} options
@ -45,108 +128,101 @@ config.alias = {
*/
config.parse = function parse(options) {
var data = Object.create(null);
var raw = Object.create(null);
var arg, conf, prefix, filename, dirname;
var data = config.parseRaw(options);
var opt = config.toOptions(data);
var keys = Object.keys(options);
var i, key, file;
if (!options)
options = {};
for (i = 0; i < keys.length; i++) {
key = keys[i];
merge(data, options);
if (options.env) {
arg = config.parseEnv();
merge(raw, arg.data);
merge(data, arg);
}
if (options.arg) {
arg = config.parseArg();
merge(raw, arg.data);
merge(data, arg);
}
if (options.query) {
arg = config.parseQuery();
merge(raw, arg.data);
merge(data, arg);
}
if (options.hash) {
arg = config.parseHash();
merge(raw, arg.data);
merge(data, arg);
}
if (data.config && !util.isBrowser) {
prefix = config.getPrefix(data);
filename = data.config;
if (typeof filename !== 'string')
filename = resolve(prefix, 'bcoin.conf');
dirname = util.normalize(filename, true);
conf = config.readConfig(filename, prefix, dirname);
raw = merge(conf.data, raw);
data = merge(conf, data);
prefix = config.getPrefix(data);
if (!data.knownPeers) {
filename = resolve(prefix, 'known-peers');
data.knownPeers = config.readKnown(filename);
switch (key) {
case 'env':
case 'arg':
case 'query':
case 'hash':
case 'config':
case 'raw':
continue;
}
if (!data.authPeers) {
filename = resolve(prefix, 'authorized-peers');
data.authPeers = config.readAuth(filename);
if (opt[key] != null)
continue;
opt[key] = options[key];
}
if (options.config) {
if (!opt.knownPeers) {
file = resolve(data.prefix, 'known-peers');
opt.knownPeers = config.readKnown(file);
}
if (!opt.authPeers) {
file = resolve(data.prefix, 'authorized-peers');
opt.authPeers = config.readAuth(file);
}
}
data.data = raw;
// Force fast properties
// after all those merges.
util.fastProp(data);
return data;
return opt;
};
/**
* Grab prefix from env, args, and options.
* @param {Object} env
* @param {Object} arg
* @param {Object} options
* Grab prefix from data.
* @private
* @param {Object} data
* @returns {String}
*/
config.getPrefix = function getPrefix(data) {
var prefix = data.prefix;
var network;
if (!prefix)
prefix = util.HOME + '/.bcoin';
if (prefix)
return prefix;
network = Network.get(data.network).type;
prefix = util.HOME + '/.bcoin';
prefix = util.normalize(prefix);
if (data.network) {
assert(isAlpha(data.network), 'Bad network.');
network = data.network;
} else {
network = 'main';
}
if (network !== 'main')
prefix += '/' + network;
return prefix;
return util.normalize(prefix);
};
/**
* Grab config file from data.
* @private
* @param {String} prefix
* @param {Object} data
* @returns {String}
*/
config.getFile = function getFile(prefix, data) {
var file = data.config;
if (!file)
return resolve(prefix, 'bcoin.conf');
return util.normalize(file);
};
/**
* Enforce types on parsed data.
* @param {Object} data
* @returns {Object}
*/
config.parseData = function parseData(data, prefix, dirname) {
config.toOptions = function toOptions(data) {
var prefix = data.prefix;
var options = {};
// Config
options.config = path(data.config);
// Options
options.network = str(data.network);
options.useWorkers = bool(data.useworkers);
@ -155,20 +231,15 @@ config.parseData = function parseData(data, prefix, dirname) {
options.sigcacheSize = num(data.sigcachesize);
// Node
options.prefix = path(data.prefix, null, dirname);
options.prefix = path(prefix, prefix);
options.db = str(data.db);
options.maxFiles = num(data.maxfiles);
options.cacheSize = mul(data.cachesize, 1024 * 1024);
options.fast = bool(data.fast);
// Update the prefix if we're using one.
if (prefix && options.prefix)
prefix = config.getPrefix(options);
// Logger
options.logLevel = str(data.loglevel);
options.logConsole = bool(data.logconsole);
options.logFile = boolpath(data.logfile, prefix, dirname);
options.logFile = boolpath(data.logfile, prefix);
// Chain
options.forceWitness = bool(data.forcewitness);
@ -203,16 +274,16 @@ config.parseData = function parseData(data, prefix, dirname) {
options.host = str(data.host);
options.port = num(data.port);
options.listen = bool(data.listen);
options.knownPeers = file(data.knownpeers, prefix, dirname, 'utf8');
options.authPeers = file(data.authpeers, prefix, dirname, 'utf8');
options.knownPeers = file(data.knownpeers, prefix, 'utf8');
options.authPeers = file(data.authpeers, prefix, 'utf8');
// Miner
options.payoutAddress = list(data.payoutaddress);
options.coinbaseFlags = str(data.coinbaseflags);
// HTTP
options.sslCert = file(data.sslcert, prefix, dirname);
options.sslKey = file(data.sslkey, prefix, dirname);
options.sslCert = file(data.sslcert, prefix);
options.sslKey = file(data.sslkey, prefix);
options.httpPort = num(data.httpport);
options.httpHost = str(data.httphost);
options.apiKey = str(data.apikey);
@ -224,14 +295,14 @@ config.parseData = function parseData(data, prefix, dirname) {
options.startHeight = num(data.startheight);
options.wipeNoReally = bool(data.wipenoreally);
options.data = data;
if (options.knownPeers != null)
options.knownPeers = config.parseKnown(options.knownPeers);
if (options.authPeers != null)
options.authPeers = config.parseAuth(options.authPeers);
options.raw = data;
return options;
};
@ -241,8 +312,8 @@ config.parseData = function parseData(data, prefix, dirname) {
* @returns {Object}
*/
config.readConfig = function readConfig(file, prefix, dirname) {
return config.parseConfig(readFile(file), prefix, dirname);
config.readConfig = function readConfig(file) {
return config.parseConfig(readFile(file));
};
/**
@ -271,7 +342,7 @@ config.readAuth = function readAuth(file) {
* @returns {Object}
*/
config.parseConfig = function parseConfig(text, prefix, dirname) {
config.parseConfig = function parseConfig(text) {
var data = Object.create(null);
var i, parts, line, key, value, eq, col, alias;
@ -318,7 +389,7 @@ config.parseConfig = function parseConfig(text, prefix, dirname) {
data[key] = value;
}
return config.parseData(data, prefix, dirname);
return data;
};
/**
@ -330,15 +401,13 @@ config.parseConfig = function parseConfig(text, prefix, dirname) {
config.parseArg = function parseArg(argv) {
var data = Object.create(null);
var args = [];
var i, arg, key, value, alias, equals;
var i, j, arg, key, value, alias, equals;
if (!argv)
argv = process.argv;
argv = argv.slice(2);
while (argv.length) {
arg = argv.shift();
for (i = 2; i < argv.length; i++) {
arg = argv[i];
if (arg.indexOf('--') === 0) {
// e.g. --opt
@ -375,8 +444,8 @@ config.parseArg = function parseArg(argv) {
// e.g. -abc
arg = arg.substring(1);
for (i = 0; i < arg.length; i++) {
key = arg[i];
for (j = 0; j < arg.length; j++) {
key = arg[j];
alias = config.alias.arg[key];
if (alias)
key = alias;
@ -401,9 +470,10 @@ config.parseArg = function parseArg(argv) {
}
}
data.args = args;
return config.parseData(data);
return {
data: data,
argv: args
};
};
/**
@ -448,7 +518,7 @@ config.parseEnv = function parseEnv(env, prefix) {
data[key] = value;
}
return config.parseData(data);
return data;
};
/**
@ -535,7 +605,7 @@ config.parseForm = function parseForm(query) {
data[key] = value;
}
return config.parseData(data);
return data;
};
/**
@ -659,7 +729,7 @@ function key(value) {
return key;
}
function path(value, prefix, dirname) {
function path(value, prefix) {
if (!value)
return null;
@ -668,12 +738,9 @@ function path(value, prefix, dirname) {
value = util.HOME + value.substring(1);
break;
case '@': // prefix
if (prefix)
value = prefix + value.substring(1);
value = prefix + value.substring(1);
break;
default: // dirname of config, or cwd
if (dirname)
value = resolve(dirname, value);
default: // cwd
break;
}
@ -712,7 +779,7 @@ function mul(value, mult) {
return value * mult;
}
function boolpath(value, prefix, dirname) {
function boolpath(value, prefix) {
if (!value)
return null;
@ -722,14 +789,14 @@ function boolpath(value, prefix, dirname) {
if (value === 'false' || value === '0')
return false;
return path(value, prefix, dirname);
return path(value, prefix);
}
function file(value, prefix, dirname, enc) {
function file(value, prefix, enc) {
if (fs.unsupported)
return null;
value = path(value, prefix, dirname);
value = path(value, prefix);
if (!value)
return null;
@ -789,6 +856,16 @@ function unescape(str) {
}
}
function isAlpha(str) {
if (typeof str !== 'string')
return false;
if (!/^[a-z0-9]+$/.test(str))
return false;
return true;
}
/*
* Expose
*/

View File

@ -69,8 +69,11 @@ Node.prototype.initOptions = function initOptions(options) {
this.options = options;
if (options.network != null)
if (options.network != null) {
this.network = Network.get(options.network);
if (this.network !== Network.main)
this.prefix += '/' + this.network.type;
}
if (options.prefix != null) {
assert(typeof options.prefix === 'string');
@ -266,11 +269,7 @@ Node.prototype.error = function error(err) {
*/
Node.prototype.location = function location(name) {
var path = this.prefix;
if (this.network !== Network.main)
path += '/' + this.network.type;
path += '/' + name;
return path;
return this.prefix + '/' + name;
};
/**