diff --git a/bot/modules/price.js b/bot/modules/price.js new file mode 100644 index 0000000..2ddcbc4 --- /dev/null +++ b/bot/modules/price.js @@ -0,0 +1,203 @@ +'use strict'; +var jp = require('jsonpath'); +var moment = require('moment'); +var numeral = require('numeral'); +var request = require('request'); + + + +exports.commands = [ + "price" +] + +exports.price = { + usage: " ", + description: 'displays price of lbc', + process: function(bot,msg,suffix){ + + var ChannelID = '369896313082478594' + + var options = { + defaultCurrency: 'USD', + + // supported currencies and api steps to arrive at the final value + currencies: { + USD: { steps: ['LBCBTC', 'BTCUSD'], format: '$0,0.00', sign: 'USD ' }, + GBP: { steps: ['LBCBTC', 'BTCGBP'], format: '£0,0.00', sign: '£' }, + AUD: { steps: ['LBCBTC', 'BTCAUD'], format: '$0,0.00', sign: 'AUD ' }, + BRL: { steps: ['LBCBTC', 'BTCBRL'], format: 'R$0,0.00', sign: 'R$' }, + CAD: { steps: ['LBCBTC', 'BTCCAD'], format: '$0,0.00', sign: 'CAD ' }, + CHF: { steps: ['LBCBTC', 'BTCCHF'], format: 'CHF 0,0.00', sign: 'CHF' }, + CLP: { steps: ['LBCBTC', 'BTCCLP'], format: '$0,0.00', sign: 'CLP ' }, + CNY: { steps: ['LBCBTC', 'BTCCNY'], format: '¥0,0.00', sign: '¥' }, + DKK: { steps: ['LBCBTC', 'BTCDKK'], format: 'kr 0,0.00', sign: 'kr' }, + EUR: { steps: ['LBCBTC', 'BTCEUR'], format: '€0,0.00', sign: '€' }, + HKD: { steps: ['LBCBTC', 'BTCHKD'], format: '$0,0.00', sign: 'HKD ' }, + INR: { steps: ['LBCBTC', 'BTCINR'], format: '₹0,0.00', sign: '₹' }, + ISK: { steps: ['LBCBTC', 'BTCISK'], format: 'kr 0,0.00', sign: 'kr' }, + JPY: { steps: ['LBCBTC', 'BTCJPY'], format: '¥0,0.00', sign: '¥' }, + KRW: { steps: ['LBCBTC', 'BTCKRW'], format: '₩0,0.00', sign: '₩' }, + NZD: { steps: ['LBCBTC', 'BTCNZD'], format: '$0,0.00', sign: 'NZD ' }, + PLN: { steps: ['LBCBTC', 'BTCPLN'], format: 'zł 0,0.00', sign: 'zł' }, + RUB: { steps: ['LBCBTC', 'BTCRUB'], format: 'RUB 0,0.00', sign: 'RUB' }, + SEK: { steps: ['LBCBTC', 'BTCSEK'], format: 'kr 0,0.00', sign: 'kr' }, + SGD: { steps: ['LBCBTC', 'BTCSGD'], format: '$0,0.00', sign: 'SGD ' }, + THB: { steps: ['LBCBTC', 'BTCTHB'], format: '฿0,0.00', sign: '฿' }, + TWD: { steps: ['LBCBTC', 'BTCTWD'], format: 'NT$0,0.00', sign: 'NT$' }, + IDR: { steps: ['LBCBTC', 'BTCIDR'], format: 'Rp0,0.00', sign: 'Rp' }, + BTC: { steps: ['LBCBTC'], format: '0,0[.][00000000] BTC', sign: 'BTC' } + }, + + // api steps + api: { + LBCBTC: { url: 'https://bittrex.com/api/v1.1/public/getticker?market=BTC-LBC', path: '$.result.Bid' }, + BTCUSD: { url: 'https://blockchain.info/ticker', path: '$.USD.buy' }, + BTCGBP: { url: 'https://blockchain.info/ticker', path: '$.GBP.buy' }, + BTCAUD: { url: 'https://blockchain.info/ticker', path: '$.AUD.buy' }, + BTCBRL: { url: 'https://blockchain.info/ticker', path: '$.BRL.buy' }, + BTCCAD: { url: 'https://blockchain.info/ticker', path: '$.CAD.buy' }, + BTCCHF: { url: 'https://blockchain.info/ticker', path: '$.CHF.buy' }, + BTCCLP: { url: 'https://blockchain.info/ticker', path: '$.CLP.buy' }, + BTCCNY: { url: 'https://blockchain.info/ticker', path: '$.CNY.buy' }, + BTCDKK: { url: 'https://blockchain.info/ticker', path: '$.DKK.buy' }, + BTCEUR: { url: 'https://blockchain.info/ticker', path: '$.EUR.buy' }, + BTCHKD: { url: 'https://blockchain.info/ticker', path: '$.HKD.buy' }, + BTCINR: { url: 'https://blockchain.info/ticker', path: '$.INR.buy' }, + BTCISK: { url: 'https://blockchain.info/ticker', path: '$.ISK.buy' }, + BTCJPY: { url: 'https://blockchain.info/ticker', path: '$.JPY.buy' }, + BTCKRW: { url: 'https://blockchain.info/ticker', path: '$.KRW.buy' }, + BTCNZD: { url: 'https://blockchain.info/ticker', path: '$.NZD.buy' }, + BTCPLN: { url: 'https://blockchain.info/ticker', path: '$.PLN.buy' }, + BTCRUB: { url: 'https://blockchain.info/ticker', path: '$.RUB.buy' }, + BTCSEK: { url: 'https://blockchain.info/ticker', path: '$.SEK.buy' }, + BTCSGD: { url: 'https://blockchain.info/ticker', path: '$.SGD.buy' }, + BTCTHB: { url: 'https://blockchain.info/ticker', path: '$.THB.buy' }, + BTCTWD: { url: 'https://blockchain.info/ticker', path: '$.TWD.buy' }, + BTCIDR: { url: 'https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=IDR', path: '$.IDR'} + }, + + // display date/time format + dtFormat: 'Do MMM YYYY h:mma [UTC]', + + // refresh rate in milliseconds to retrieve a new price (default to 10 minutes) + refreshTime: 100000 +}; + var words = suffix.trim().split(' ').filter( function(n){return n !== "";} ); + + var currency = (words.length > 0) ? words[0].toUpperCase() : options.defaultCurrency; + var amount = (words.length > 1) ? parseFloat(words[1], 10) : 1; + var showHelp = (isNaN(amount)) || (Object.keys(options.currencies).indexOf(currency) === -1); +// store the last retrieved rate +var cachedRates = {}; +var command = "!price" + + var currencies = Object.keys(options.currencies); + for (var i = 0; i < currencies.length; i++) { + cachedRates[currencies[i]] = { rate: 0, time: null }; + } + if (showHelp) { + doHelp(bot,msg,suffix); + } else { + if(!inPrivateOrBotSandbox(msg)){ + msg.channel.send('Please use <#' + ChannelID + '> or DMs to talk to price bot.'); + return; + } + doSteps(bot, currency, amount); + } + +function doHelp(bot,msg,suffix) { + if(!inPrivateOrBotSandbox(msg)){ + msg.channel.send('Please use <#' + ChannelID + '> or DMs to talk to price bot.'); + return; + } + var message = + '**' + command + '**: show the price of 1 LBC in ' + options.defaultCurrency + '\n' + + '**' + command + ' help**: this message\n' + + '**' + command + ' CURRENCY**: show the price of 1 LBC in CURRENCY. Supported values for CURRENCY are Listed Below\n' + + '**' + command + ' CURRENCY AMOUNT**: show the price of AMOUNT LBC in CURRENCY\n' + + '**Supported Currencies:** *usd*, *gbp*, *eur*, *aud*, *brl*, *cad*, *chf*, *clp*, *cny*, *dkk*, *hkd*, *inr*, *isk*, *jpy*, *krw*, *nzd*, *pln* ,*rub*, *sek*, *sgd*, *thb*, *twd*, *idr* and *btc* (case-insensitive)'; + msg.channel.send(message); +} + +function formatMessage(amount, rate, option) { + var cur = option.sign; + var value = numeral(rate.rate * amount).format(option.format); + return '*' + numeral(amount).format('0,0[.][00000000]') + ' LBC = ' + cur +' ' + value + '*\n_last updated ' + rate.time.utc().format(options.dtFormat) + '_'; +} + +function doSteps(bot, currency, amount) { + var option = options.currencies[currency]; + var shouldReload = true; + if (cachedRates[currency]) { + var cache = cachedRates[currency]; + shouldReload = cache.time === null || moment().diff(cache.time) >= options.refreshTime; + if (!shouldReload) { + var message = formatMessage(amount, cache, option); + msg.channel.send(message); + } + } + + if (shouldReload) { + // copy the steps array + var steps = []; + for (var i = 0; i < option.steps.length; i++) { + steps.push(option.steps[i]); + } + + processSteps(bot, currency, 0, amount, steps, option); + } +} + +function processSteps(bot, currency, rate, amount, steps, option) { + if (steps.length > 0) { + var pairName = steps[0]; + if (!options.api[pairName]) { + msg.channel.send('There was a configuration error. ' + pairName + ' pair was not found.'); + return; + } + + var pair = options.api[pairName]; + request.get(pair.url, function(error, response, body) { + if (error) { + msg.channel.send( err.message ? err.message : 'The request could not be completed at this time. Please try again later.'); + return; + } + var pairRate = 0; + try { + pairRate = jp.query(JSON.parse(body), pair.path); + if (Array.isArray(pairRate) && pairRate.length > 0) { + pairRate = pairRate[0]; + } + } catch (ignored) { + // invalid response or pair rate + } + + if (pairRate > 0) { + rate = (rate === 0) ? pairRate : rate * pairRate; + steps.shift(); + if (steps.length > 0) { + processSteps(bot, currency, rate, amount, steps, option); + return; + } + + // final step, cache and then response + var result = { rate: rate, time: moment() }; + cachedRates[currency] = result; + msg.channel.send(formatMessage(amount, result, option)); + } else { + msg.channel.send('The rate returned for the ' + pairName + ' pair was invalid.'); + } + }); + } +} + +function inPrivateOrBotSandbox(msg){ + if((msg.channel.type == 'dm') || (msg.channel.id === ChannelID)){ + return true; + }else{ + return false; + } +} + +} +}