UNPKG

@ducatus/ducatus-wallet-service-rev

Version:
208 lines (178 loc) 5.32 kB
import * as async from 'async'; import _ from 'lodash'; import * as request from 'request'; import { Storage } from './storage'; const $ = require('preconditions').singleton(); const Common = require('./common'); const Defaults = Common.Defaults; let log = require('npmlog'); log.debug = log.verbose; const fiatCodes = { USD: 1, INR: 1, GBP: 1, EUR: 1, CAD: 1, // 5 COP: 1, NGN: 1, BRL: 1, ARS: 1, AUD: 1 }; const customCoins = ['duc', 'ducx']; export class FiatRateService { request: request.RequestAPI<any, any, any>; defaultProvider: any; providers: any[]; storage: Storage; init(opts, cb) { opts = opts || {}; this.request = opts.request || request; this.defaultProvider = opts.defaultProvider || Defaults.FIAT_RATE_PROVIDER; async.parallel( [ done => { if (opts.storage) { this.storage = opts.storage; done(); } else { this.storage = new Storage(); this.storage.connect(opts.storageOpts, done); } } ], err => { if (err) { log.error(err); } return cb(err); } ); } startCron(opts, cb) { opts = opts || {}; this.providers = _.values(require('./fiatrateproviders')); const interval = opts.fetchInterval || Defaults.FIAT_RATE_FETCH_INTERVAL; if (interval) { this._fetch(); setInterval(() => { this._fetch(); }, interval * 60 * 1000); } return cb(); } _fetch(cb?) { cb = cb || function() {}; const coins = ['btc', 'bch', 'eth', 'xrp', 'duc', 'ducx']; // async.each(this.providers, (provider, next) => { async.each( coins, (coin, next2) => { const provider = customCoins.includes(coin) ? this.providers[1] : this.providers[0]; if (customCoins.includes(coin)) { console.log(`Get ${coin} from ${provider.url}`); } this._retrieve(provider, coin, (err, res) => { if (err) { log.warn('Error retrieving data for ' + provider.name + coin, err); return next2(); } this.storage.storeFiatRate(coin, res, err => { if (err) { log.warn('Error storing data for ' + provider.name, err); } return next2(); }); }); }, // next), cb ); } _retrieve(provider, coin, cb) { log.debug(`Fetching data for ${provider.name} / ${coin} `); const url = customCoins.includes(coin) ? provider.url : provider.url + coin.toUpperCase(); this.request.get( { url, json: true }, (err, res, body) => { if (err || !body) { return cb(err); } const customRates = []; if (customCoins.includes(coin)) { customRates.push({ code: 'USD', name: 'US Dollar', rate: body[coin.toUpperCase()].USD }); } const bodyRates = customCoins.includes(coin) ? customRates : body; log.debug(`Data for ${provider.name} / ${coin} fetched successfully`); if (!provider.parseFn) { return cb(new Error('No parse function for provider ' + provider.name)); } try { const rates = _.filter(provider.parseFn(bodyRates), x => fiatCodes[x.code]); return cb(null, rates); } catch (e) { return cb(e); } } ); } getRate(opts, cb) { $.shouldBeFunction(cb); opts = opts || {}; const now = Date.now(); const coin = opts.coin || 'btc'; // const provider = opts.provider || this.defaultProvider; const ts = _.isNumber(opts.ts) || _.isArray(opts.ts) ? opts.ts : now; async.map( [].concat(ts), (ts, cb) => { this.storage.fetchFiatRate(coin, opts.code, ts, (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 }); }); }, (err, res: any) => { if (err) return cb(err); if (!_.isArray(ts)) res = res[0]; return cb(null, res); } ); } async getHistoricalRates(opts, cb) { $.shouldBeFunction(cb); opts = opts || {}; const historicalRates = {}; // Oldest date in timestamp range in epoch number ex. 24 hours ago const now = Date.now() - Defaults.FIAT_RATE_FETCH_INTERVAL * 60 * 1000; const ts = _.isNumber(opts.ts) ? opts.ts : now; const coins = ['btc', 'bch', 'eth', 'xrp', 'duc', 'ducx']; const customCoins = ['duc', 'ducx']; async.map( coins, async (coin: string, cb) => { this.storage.fetchHistoricalRates(coin, opts.code, ts, (err, rates) => { if (err) return cb(err); if (!rates) return cb(); for (const rate of rates) { rate.rate = rate.value; rate.fetchedOn = rate.ts; } historicalRates[coin] = rates; return cb(null, historicalRates); }); }, (err, res: any) => { if (err) return cb(err); return cb(null, res[0]); } ); } }