diff --git a/bin/cli b/bin/cli index 07998461..d501d50b 100755 --- a/bin/cli +++ b/bin/cli @@ -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; } diff --git a/lib/node/config.js b/lib/node/config.js index 157c8190..4d0f8f7d 100644 --- a/lib/node/config.js +++ b/lib/node/config.js @@ -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 */ diff --git a/lib/node/node.js b/lib/node/node.js index f0856d2d..f0922e84 100644 --- a/lib/node/node.js +++ b/lib/node/node.js @@ -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; }; /**