UNPKG

@owstack/wallet-service

Version:

A service for multisignature HD wallets

175 lines (147 loc) 4.96 kB
const owsCommon = require('@owstack/ows-common'); const async = require('async'); const baseConfig = require('config'); const Context = owsCommon.util.Context; const Defaults = require('./common/defaults'); const log = require('npmlog'); const request = require('request'); const Storage = require('./storage'); const lodash = owsCommon.deps.lodash; const $ = require('preconditions').singleton(); log.debug = log.verbose; class FiatRateService { constructor(config) { this.config = config || baseConfig; this.setLog(); } } FiatRateService.prototype.setLog = function () { if (this.config.log) { log.level = (this.config.log.disable == true ? 'silent' : this.config.log.level || 'info'); } else { log.level = 'info'; } }; FiatRateService.prototype.start = function (cb) { const self = this; self.init({}, function (err) { if (err) { cb(err); } self.startCron(function (err) { if (err) { cb(err); } cb(); }); }); }; FiatRateService.prototype.init = function (opts, cb) { const self = this; self.request = opts.request || request; async.parallel([ function (done) { if (opts.storage) { self.storage = opts.storage; done(); } else if (self.config.storage) { self.storage = self.config.storage; done(); } else { // Create with empty context (none for this service). self.storage = new Storage(new Context(), self.config.storageOpts, { creator: 'FiatRateService' }); self.storage.connect(done); } }, ], function (err) { if (err) { log.error(err); } return cb(err); }); }; FiatRateService.prototype.startCron = function (cb) { const self = this; self.providers = lodash.values(require('./fiatrateproviders')); const interval = self.config.fiatRateServiceOpts.fetchInterval || Defaults.FIAT_RATE_FETCH_INTERVAL; if (interval) { self._fetch(); setInterval(function () { self._fetch(); }, interval * 60 * 1000); } return cb(); }; FiatRateService.prototype._fetch = function (cb) { const self = this; cb = cb || function () {}; lodash.forEach(self.providers, function (provider) { lodash.forEach(Object.keys(provider.currency), function (currencyCode) { self._retrieve(provider, currencyCode, function (err, res) { if (err) { log.warn(`Error retrieving data for ${provider.name}`, err); return; } self.storage.storeFiatRate(provider.name, currencyCode, res, function (err) { if (err) { log.warn(`Error storing ${currencyCode} data for ${provider.name}`, err); } return; }); }); }); }); cb(); }; FiatRateService.prototype._retrieve = function (provider, currencyCode, cb) { const self = this; log.debug(`Fetching data for ${provider.name}`); self.request.get({ url: provider.currency[currencyCode].url, json: true, }, function (err, res, body) { if (err || !body) { return cb(err); } log.debug(`Data for ${provider.name} fetched successfully`); if (!provider.currency[currencyCode].parseFn) { return cb(new Error(`No parse function for provider ${provider.name}`)); } const rates = provider.currency[currencyCode].parseFn(body); return cb(null, rates); }); }; FiatRateService.prototype.getRate = function (opts, cb) { const self = this; $.shouldBeFunction(cb); opts = opts || {}; const now = Date.now(); const provider = opts.provider || self.config.fiatRateServiceOpts.provider || Defaults.FIAT_RATE_PROVIDER; const ts = (lodash.isNumber(opts.ts) || lodash.isArray(opts.ts)) ? opts.ts : now; async.map([].concat(ts), function (ts, cb) { self.storage.fetchFiatRate(provider, opts.currency, opts.code, ts, function (err, rate) { if (err) { return cb(err); } if (rate && (ts - rate.ts) > Defaults.FIAT_RATE_MAX_LOOK_BACK_TIME * 60 * 1000) { rate = null; } return cb(null, { ts: +ts, rate: rate ? rate.value : undefined, fetchedOn: rate ? rate.ts : undefined, }); }); }, function (err, res) { if (err) { return cb(err); } if (!lodash.isArray(ts)) { res = res[0]; } return cb(null, res); }); }; module.exports = FiatRateService;