UNPKG

xud

Version:
331 lines 15.2 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const assert_1 = __importDefault(require("assert")); const fs_1 = require("fs"); const os_1 = __importDefault(require("os")); const path_1 = __importDefault(require("path")); const toml_1 = __importDefault(require("toml")); const enums_1 = require("./constants/enums"); const Logger_1 = require("./Logger"); const utils_1 = require("./utils/utils"); const propAssertions = { port: (val) => assert_1.default(val >= 0 && val <= 65535, 'port must be between 0 and 65535'), cltvdelta: (val) => assert_1.default(val > 0, 'cltvdelta must be a positive number'), discoverminutes: (val) => assert_1.default(val > 0, 'discoverminutes must be a positive number'), minQuantity: (val) => assert_1.default(val >= 0, 'minQuantity must be 0 or a positive number'), }; function validateConfig(propVal, defaultVal, propKey, prefix) { const actualType = typeof propVal; const expectedType = typeof defaultVal; if (actualType === 'undefined') { return; // this is an unspecified property that will use the default value } if (expectedType === 'undefined') { return; // this is a superfluous property that we ignore for now } assert_1.default.equal(actualType, expectedType, `${prefix || ''}${propKey} is type ${actualType} but should be ${expectedType}`); if (actualType === 'object') { // if this is an object, we recurse for (const nestedPropKey in propVal) { const nestedPrefix = propKey ? `${prefix || ''}${propKey}.` : undefined; validateConfig(propVal[nestedPropKey], defaultVal[nestedPropKey], nestedPropKey, nestedPrefix); } } else { if (propKey && propKey in propAssertions) { // shortcoming in typescript 3.6.4 `in` keyword type guard requires manual cast to any below propAssertions[propKey](propVal); } } } let Config = /** @class */ (() => { class Config { constructor() { this.lnd = {}; this.instanceid = 0; /** Whether to intialize a new database with default values. */ this.initdb = true; /** Whether matching will be disabled */ this.nomatching = false; /** Whether a password should not be used to encrypt the xud key and underlying wallets. */ this.noencrypt = false; /** * Whether to disable sanity swaps that verify that the orders can possibly be swapped * before adding trading pairs as active. */ this.nosanityswaps = true; /** * Whether to disable balance checks that verify that the orders can possibly be swapped * before adding them to the order book. */ this.nobalancechecks = false; /** * Loads the xud configuration from an optional file and any command line arguments. * @returns a promise that resolves to `true` if a config file was found and loaded, otherwise `false` */ this.load = (args) => __awaiter(this, void 0, void 0, function* () { if (args) { if (args.xudir) { this.xudir = args.xudir; } const argNetwork = this.getNetwork(args); if (argNetwork) { this.network = argNetwork; args.network = argNetwork; } } yield this.mkDirIfNotExist(this.xudir); const configPath = path_1.default.join(this.xudir, 'xud.conf'); const configProps = yield Config.readConfigProps(configPath); if (configProps) { validateConfig(configProps, this); // set the network and xudir props up front because they influence default config values if (configProps.network && (!args || !args.network)) { this.network = configProps.network; if (![enums_1.XuNetwork.MainNet, enums_1.XuNetwork.TestNet, enums_1.XuNetwork.SimNet, enums_1.XuNetwork.RegTest].includes(configProps.network)) { throw new Error(`Invalid network config: ${configProps.network}`); } } if (configProps.xudir && (!args || !args.xudir)) { this.xudir = configProps.xudir; } if (configProps.thresholds) { this.orderthresholds = Object.assign(Object.assign({}, this.orderthresholds), configProps.thresholds); } } // update defaults based on the xudir and network from the args or config file this.logpath = this.getDefaultLogPath(); this.dbpath = this.getDefaultDbPath(); this.p2p.port = this.getDefaultP2pPort(); this.rpc.port = this.getDefaultRpcPort(); this.http.port = this.getDefaultHttpPort(); this.setDefaultMacaroonPaths(); if (configProps) { // merge parsed json properties from config file to the default config utils_1.deepMerge(this, configProps); } if (args) { validateConfig(args, this); // override our config file with command line arguments utils_1.deepMerge(this, args); } if (!Object.values(Logger_1.Level).includes(this.loglevel)) { this.loglevel = this.getDefaultLogLevel(); } const logDir = path_1.default.dirname(this.logpath); yield this.mkDirIfNotExist(logDir); return !!configProps; }); /** * Creates a directory if it does not exist, otherwise does nothing. */ this.mkDirIfNotExist = (dirPath) => __awaiter(this, void 0, void 0, function* () { try { yield fs_1.promises.mkdir(dirPath); } catch (err) { if (err.code !== 'EEXIST') { // ignore the error if the directory already exists, otherwise throw throw err; } } }); this.getNetwork = (args) => { const networks = { [enums_1.XuNetwork.MainNet]: args.mainnet, [enums_1.XuNetwork.TestNet]: args.testnet, [enums_1.XuNetwork.SimNet]: args.simnet, [enums_1.XuNetwork.RegTest]: args.regtest, }; const selected = Object.keys(networks).filter(key => networks[key]); if (selected.length > 1) { throw Error('only one network selection is allowed'); } if (selected.length === 0) { return undefined; } else { return selected[0]; } }; this.setDefaultMacaroonPaths = () => { for (const currency in this.lnd) { switch (currency) { case 'LTC': // litecoin uses a specific folder name for testnet this.lnd.LTC.macaroonpath = path_1.default.join(this.lnd.LTC.macaroonpath, '..', '..', this.network === enums_1.XuNetwork.TestNet ? 'testnet4' : this.network, 'admin.macaroon'); break; default: // by default we want to update the network folder name to the selected network this.lnd[currency].macaroonpath = path_1.default.join(this.lnd[currency].macaroonpath, '..', '..', this.network, 'admin.macaroon'); break; } } }; this.getDefaultP2pPort = () => { switch (this.network) { case enums_1.XuNetwork.MainNet: return 8885; // X = 88, U = 85 in ASCII case enums_1.XuNetwork.TestNet: return 18885; case enums_1.XuNetwork.SimNet: return 28885; case enums_1.XuNetwork.RegTest: return 38885; default: throw new Error('unrecognized network'); } }; this.getDefaultRpcPort = () => { switch (this.network) { case enums_1.XuNetwork.MainNet: return 8886; case enums_1.XuNetwork.TestNet: return 18886; case enums_1.XuNetwork.SimNet: return 28886; case enums_1.XuNetwork.RegTest: return 38886; default: throw new Error('unrecognized network'); } }; this.getDefaultHttpPort = () => { switch (this.network) { case enums_1.XuNetwork.MainNet: return 8887; case enums_1.XuNetwork.TestNet: return 18887; case enums_1.XuNetwork.SimNet: return 28887; case enums_1.XuNetwork.RegTest: return 38887; default: throw new Error('unrecognized network'); } }; this.getDefaultDbPath = () => { return path_1.default.join(this.xudir, `xud-${this.network}.db`); }; this.getDefaultLogPath = () => { return path_1.default.resolve(this.xudir, 'logs', 'xud.log'); }; this.getDefaultLogLevel = () => { return process.env.NODE_ENV === 'production' ? Logger_1.Level.Info : Logger_1.Level.Debug; }; const platform = os_1.default.platform(); let lndDefaultDatadir; switch (platform) { case 'win32': { // windows const homeDir = process.env.LOCALAPPDATA; this.xudir = path_1.default.join(homeDir, 'Xud'); lndDefaultDatadir = path_1.default.join(homeDir, 'Lnd'); break; } case 'darwin': { // mac const homeDir = process.env.HOME; this.xudir = path_1.default.join(homeDir, '.xud'); lndDefaultDatadir = path_1.default.join(homeDir, 'Library', 'Application Support', 'Lnd'); break; } default: { // linux const homeDir = process.env.HOME; this.xudir = path_1.default.join(homeDir, '.xud'); lndDefaultDatadir = path_1.default.join(homeDir, '.lnd'); break; } } // default configuration this.loglevel = this.getDefaultLogLevel(); this.logpath = this.getDefaultLogPath(); this.logdateformat = 'DD/MM/YYYY HH:mm:ss.SSS'; this.network = enums_1.XuNetwork.SimNet; this.dbpath = this.getDefaultDbPath(); this.strict = false; this.p2p = { listen: true, discover: true, tor: false, torport: 0, discoverminutes: 60 * 12, detectexternalip: false, port: this.getDefaultP2pPort(), addresses: [], }; this.rpc = { disable: false, host: 'localhost', port: this.getDefaultRpcPort(), }; this.http = { host: 'localhost', port: this.getDefaultHttpPort(), }; this.webproxy = { disable: true, port: 8080, }; // TODO: add dynamic max/min price limits this.orderthresholds = { minQuantity: 0, }; this.lnd.BTC = { disable: false, certpath: path_1.default.join(lndDefaultDatadir, 'tls.cert'), macaroonpath: path_1.default.join(lndDefaultDatadir, 'data', 'chain', 'bitcoin', this.network, 'admin.macaroon'), host: 'localhost', port: 10009, nomacaroons: false, cltvdelta: 40, }; this.lnd.LTC = { disable: false, certpath: path_1.default.join(lndDefaultDatadir, 'tls.cert'), macaroonpath: path_1.default.join(lndDefaultDatadir, 'data', 'chain', 'litecoin', this.network, 'admin.macaroon'), host: 'localhost', port: 10010, nomacaroons: false, cltvdelta: 576, }; this.connext = { disable: false, host: 'localhost', port: 5040, webhookhost: 'localhost', webhookport: 8887, }; } } Config.readConfigProps = (configPath) => __awaiter(void 0, void 0, void 0, function* () { let configText; try { configText = yield fs_1.promises.readFile(configPath, 'utf8'); } catch (err) { } let configProps; if (configText) { try { configProps = toml_1.default.parse(configText); } catch (e) { throw new Error(`Error parsing config file at ${configPath} on line ${e.line}, column ${e.column}: ${e.message}`); } } return configProps; }); return Config; })(); exports.default = Config; //# sourceMappingURL=Config.js.map