4790764e2c
-Restructured the settings.json.template and settings.js files with better groupings -Added better comments for improved explanations of all settings -Better handling of page length options on all datatables; Page length options are now configurable and also only display options based on limits set by certain items_per_page and max_items_per_query settings -Markets have been extended to support unlimited trading pairs for each exchange -Added coin_symbol and pair_symbol to the markets schema to support multiple trading pairs -Added a burned field to the richlist schema for tracking burned coin addresses -Added a locale string for the new richlist wealth distribution "Top 1-100 Total" table row -Updated a couple locale strings that were incomplete or needed fixing (api_getblockhash and api_getnextrewardwhenstr) -Added a new css class to remove some redundant inline styles for the richlist wealth distribution color boxes -Richlist page now allows better separation of the top list(s) and the wealth distribution table and chart (you can now hide or show sections as desired) -Richlist page now allows for better burned coin support (Hide burned coin addresses from lists and totals even when the burned coin amounts are still included in the total coin supply value) -Block page now only displays the raw block link if the api_page.public_apis.rpc.getblock.enabled settings is set to true -Transaction page now only displays the raw tx link if the api_page.public_apis.rpc.getrawtransaction.enabled setting is set to true -Rate limiting class has been made global and is now used to limit market requests -getnetworkhashps rpc call now returns a '-' if shared_pages.show_hashrate is not set to true -Searching for unsycned blocks/txs no longer saves the data locally but instead still shows the data on screen. This helps prevent syncing data out-of-order (This eliminates the need for db_index.pid which has been removed) -Coin supply is now always taken from the stats collection database instead of from the wallet via rpc command in all cases except when syncing -Lots of misc fixes and code cleanup changes -List of changed settings: -title -> shared_pages.page_title -coin -> coin.name -symbol -> coin.symbol -logo -> shared_pages.logo -headerlogo -> shared_pages.page_header.home_link_logo -favicon -> shared_pages.favicon -homelink -> shared_pages.page_header.home_link -logoheight -> shared_pages.page_header.home_link_logo_height -sticky_header -> shared_pages.page_header.sticky_header -sticky_footer -> shared_pages.page_footer.sticky_footer -footer_height_desktop -> shared_pages.page_footer.footer_height_desktop -footer_height_tablet -> shared_pages.page_footer.footer_height_tablet -footer_height_mobile -> shared_pages.page_footer.footer_height_mobile -social_link_percent_height_desktop -> shared_pages.page_footer.social_link_percent_height_desktop -social_link_percent_height_tablet -> shared_pages.page_footer.social_link_percent_height_tablet -social_link_percent_height_mobile -> shared_pages.page_footer.social_link_percent_height_mobile -theme -> shared_pages.theme -port -> webserver.port -update_timeout -> sync.update_timeout -check_timeout -> sync.check_timeout -block_parallel_tasks -> sync.block_parallel_tasks -use_rpc -> api_cmds.use_rpc -confirmations -> shared_pages.confirmations -display.api -> api_page.enabled -display.markets -> markets_page.enabled -display.richlist -> richlist_page.enabled -display.search -> shared_pages.page_header.show_search -display.movement -> movement_page.enabled -display.network -> network_page.enabled -display.masternodes -> masternodes_page.enabled -display.claim_address -> claim_address_page.enabled -display.claim_address_header_menu -> claim_address_page.show_header_menu -display.page_header_bgcolor -> shared_pages.page_header.bgcolor -display.page_footer_bgcolor -> shared_pages.page_footer.bgcolor -display.table_header_bgcolor -> shared_pages.table_header_bgcolor -display.networkpnl -> shared_pages.page_header.panels.network_panel.display_order -display.difficultypnl -> shared_pages.page_header.panels.difficulty_panel.display_order -display.masternodespnl -> shared_pages.page_header.panels.masternodes_panel.display_order -display.coinsupplypnl -> shared_pages.page_header.panels.coin_supply_panel.display_order -display.pricepnl -> shared_pages.page_header.panels.price_panel.display_order -display.marketcappnl -> shared_pages.page_header.panels.market_cap_panel.display_order -display.logopnl -> shared_pages.page_header.panels.logo_panel.display_order -index.show_last_updated -> index_page.show_last_updated -index.show_hashrate -> shared_pages.show_hashrate -index.difficulty -> shared_pages.difficulty -index.last_txs -> api_page.public_apis.ext.getlasttxs.max_items_per_query -index.txs_per_page -> index_page.transaction_table.items_per_page (for index page) AND movement_page.movement_table.items_per_page (for movement page) -reward_page.show_last_updated -> blockchain_specific.heavycoin.reward_page.show_last_updated -api.blockindex -> api_page.sample_data.blockindex -api.blockhash -> api_page.sample_data.blockhash -api.txhash -> api_page.sample_data.txhash -api.address -> api_page.sample_data.address -markets.exchange -> markets_page.default_exchange.trading_pair -markets.default -> markets_page.default_exchange.exchange_name -markets.market_dropdown_menu -> markets_page.show_market_dropdown_menu -markets.market_select_visible -> markets_page.show_market_select -richlist.distribution -> richlist_page.wealth_distribution.show_distribution_chart -richlist.received -> richlist_page.show_received_coins -richlist.balance -> richlist_page.show_current_balance -movement.min_amount -> movement_page.movement_table.min_amount -movement.low_flag -> movement_page.movement_table.low_warning_flag -movement.high_flag -> movement_page.movement_table.high_warning_flag -social_links -> shared_pages.page_footer.social_links -social_links[x].image_url -> shared_pages.page_footer.social_links[x].image_path -genesis_tx -> transaction_page.genesis_tx -genesis_block -> block_page.genesis_block -heavy -> blockchain_specific.heavycoin.enabled -save_stats_after_sync_blocks -> sync.save_stats_after_sync_blocks -txcount -> api_page.public_apis.ext.getaddresstxs.max_items_per_query -txcount_per_page -> address_page.history_table.items_per_page -show_sent_received -> address_page.show_sent_received -supply -> sync.supply -nethash -> shared_pages.page_header.panels.network_panel.nethash -nethash_units -> shared_pages.page_header.panels.network_panel.nethash_units -usecors -> webserver.cors.enabled -corsorigin -> webserver.cors.corsorigin -burned_coins -> richlist_page.burned_coins.addresses -public_api.rpc.getdifficulty -> api_page.public_apis.rpc.getdifficulty.enabled -public_api.rpc.getconnectioncount -> api_page.public_apis.rpc.getconnectioncount.enabled -public_api.rpc.getblockcount -> api_page.public_apis.rpc.getblockcount.enabled -public_api.rpc.getblockhash -> api_page.public_apis.rpc.getblockhash.enabled -public_api.rpc.getblock -> api_page.public_apis.rpc.getblock.enabled -public_api.rpc.getrawtransaction -> api_page.public_apis.rpc.getrawtransaction.enabled -public_api.rpc.getnetworkhashps -> api_page.public_apis.rpc.getnetworkhashps.enabled -public_api.rpc.getvotelist -> api_page.public_apis.rpc.getvotelist.enabled -public_api.rpc.getmasternodecount -> api_page.public_apis.rpc.getmasternodecount.enabled -public_api.rpc.getmaxmoney -> blockchain_specific.heavycoin.public_apis.getmaxmoney.enabled -public_api.rpc.getmaxvote -> blockchain_specific.heavycoin.public_apis.getmaxvote.enabled -public_api.rpc.getvote -> blockchain_specific.heavycoin.public_apis.getvote.enabled -public_api.rpc.getphase -> blockchain_specific.heavycoin.public_apis.getphase.enabled -public_api.rpc.getreward -> blockchain_specific.heavycoin.public_apis.getreward.enabled -public_api.rpc.getsupply -> blockchain_specific.heavycoin.public_apis.getsupply.enabled -public_api.rpc.getnextrewardestimate -> blockchain_specific.heavycoin.public_apis.getnextrewardestimate.enabled -public_api.rpc.getnextrewardwhenstr -> blockchain_specific.heavycoin.public_apis.getnextrewardwhenstr.enabled -public_api.ext.getmoneysupply -> api_page.public_apis.ext.getmoneysupply.enabled -public_api.ext.getdistribution -> api_page.public_apis.ext.getdistribution.enabled -public_api.ext.getaddress -> api_page.public_apis.ext.getaddress.enabled -public_api.ext.getaddresstxs -> api_page.public_apis.ext.getaddresstxs.enabled -public_api.ext.gettx -> api_page.public_apis.ext.gettx.enabled -public_api.ext.getbalance -> api_page.public_apis.ext.getbalance.enabled -public_api.ext.getlasttxs -> api_page.public_apis.ext.getlasttxs.enabled -public_api.ext.getcurrentprice -> api_page.public_apis.ext.getcurrentprice.enabled -public_api.ext.getbasicstats -> api_page.public_apis.ext.getbasicstats.enabled -public_api.ext.getsummary -> api_page.public_apis.ext.getsummary.enabled -public_api.ext.getnetworkpeers -> api_page.public_apis.ext.getnetworkpeers.enabled -public_api.ext.getmasternodelist -> api_page.public_apis.ext.getmasternodelist.enabled -public_api.ext.getmasternoderewards -> api_page.public_apis.ext.getmasternoderewards.enabled -public_api.ext.getmasternoderewardstotal -> api_page.public_apis.ext.getmasternoderewardstotal.enabled -api_cmds.heavies.getmaxmoney -> blockchain_specific.heavycoin.api_cmds.getmaxmoney -api_cmds.heavies.getmaxvote -> blockchain_specific.heavycoin.api_cmds.getmaxvote -api_cmds.heavies.getvote -> blockchain_specific.heavycoin.api_cmds.getvote -api_cmds.heavies.getphase -> blockchain_specific.heavycoin.api_cmds.getphase -api_cmds.heavies.getreward -> blockchain_specific.heavycoin.api_cmds.getreward -api_cmds.heavies.getnextrewardestimate -> blockchain_specific.heavycoin.api_cmds.getnextrewardestimate -api_cmds.heavies.getnextrewardwhenstr -> blockchain_specific.heavycoin.api_cmds.getnextrewardwhenstr -api_cmds.heavies.getsupply -> blockchain_specific.heavycoin.api_cmds.getsupply -List of new settings: -shared_pages.page_header.panels.network_panel.enabled: allow enabling/disabling of the network panel -shared_pages.page_header.panels.difficulty_panel.enabled: allow enabling/disabling of the difficulty panel -shared_pages.page_header.panels.masternodes_panel.enabled: allow enabling/disabling of the masternodes panel -shared_pages.page_header.panels.coin_supply_panel.enabled: allow enabling/disabling of the coin supply panel -shared_pages.page_header.panels.price_panel.enabled: allow enabling/disabling of the price panel -shared_pages.page_header.panels.market_cap_panel.enabled: allow enabling/disabling of the market cap panel -shared_pages.page_header.panels.logo_panel.enabled: allow enabling/disabling of the logo panel -index_page.transaction_table.page_length_options: specify the page length options that determine how many items/records to display in the table at any given time -index_page.transaction_table.reload_table_seconds: the time in seconds to automatically reload the table data from the server -address_page.history_table.page_length_options: specify the page length options that determine how many items/records to display in the table at any given time -masternodes_page.masternode_table.page_length_options: specify the page length options that determine how many items/records to display in the table at any given time -masternodes_page.masternode_table.items_per_page: the default amount of items/records to display in the table at any given time -movement_page.movement_table.page_length_options: specify the page length options that determine how many items/records to display in the table at any given time -movement_page.movement_table.reload_table_seconds: the time in seconds to automatically reload the table data from the server -network_page.connections_table.page_length_options: specify the page length options that determine how many items/records to display in the table at any given time -network_page.connections_table.items_per_page: the default amount of items/records to display in the table at any given time -network_page.addnodes_table.page_length_options: specify the page length options that determine how many items/records to display in the table at any given time -network_page.addnodes_table.items_per_page: the default amount of items/records to display in the table at any given time -network_page.onetry_table.page_length_options: specify the page length options that determine how many items/records to display in the table at any given time -network_page.onetry_table.items_per_page: the default amount of items/records to display in the table at any given time -richlist_page.wealth_distribution.show_distribution_table: show/hide the wealth distribution summary table -richlist_page.wealth_distribution.colors: a list of html color codes to represent the top 100 groupings in the wealth distribution table and pie chart -richlist_page.burned_coins.include_burned_coins_in_distribution: determine whether to include burned coins in the wealth distribution section or not -markets_page.exchanges.altmarkets.enabled: enable/disable the altmarkets exchange -markets_page.exchanges.altmarkets.trading_pairs: a list of market trading pair symbols -markets_page.exchanges.bittrex.enabled: enable/disable the bittrex exchange -markets_page.exchanges.bittrex.trading_pairs: a list of market trading pair symbols -markets_page.exchanges.bleutrade.enabled: enable/disable the bleutrade exchange -markets_page.exchanges.bleutrade.trading_pairs: a list of market trading pair symbols -markets_page.exchanges.crex.enabled: enable/disable the crex exchange -markets_page.exchanges.crex.trading_pairs: a list of market trading pair symbols -markets_page.exchanges.poloniex.enabled: enable/disable the poloniex exchange -markets_page.exchanges.poloniex.trading_pairs: a list of market trading pair symbols -markets_page.exchanges.stex.enabled: enable/disable the stex exchange -markets_page.exchanges.stex.trading_pairs: a list of market trading pair symbols -markets_page.exchanges.yobit.enabled: enable/disable the yobit exchange -markets_page.exchanges.yobit.trading_pairs: a list of market trading pair symbols -claim_address_page.enable_bad_word_filter: enable/disable the "bad word" filter for claimed addresses, so that trying to claim an address with a bad word will fail -sync.show_sync_msg_when_syncing_more_than_blocks: show the sync msg at the top of all pages during index syncronization if there are more than this many blocks to process -labels[x].enabled: allow enabling/disabling of specific wallet address labels -blockchain_specific.heavycoin.reward_page.enabled: enable/disable the reward page -blockchain_specific.zksnarks.enabled: enable/disable Zcash zk-SNARKs private transaction support (WIP - 90% complete) -List of deleted settings -address: unnecessary setting has been replaced by dynamic values via http request -markets.coin: replaced by a richer set of settings that allow choosing the coin for each market -markets.enabled -> replaced by a richer set of settings that allow enabling/disabling each market specifically -lock_during_index: no longer possible to save unsynced blocks/txs via search so this settings is now obsolete/unused
731 lines
35 KiB
JavaScript
731 lines
35 KiB
JavaScript
var express = require('express')
|
|
, path = require('path')
|
|
, nodeapi = require('./lib/nodeapi')
|
|
, favicon = require('serve-favicon')
|
|
, logger = require('morgan')
|
|
, cookieParser = require('cookie-parser')
|
|
, bodyParser = require('body-parser')
|
|
, settings = require('./lib/settings')
|
|
, routes = require('./routes/index')
|
|
, lib = require('./lib/explorer')
|
|
, db = require('./lib/database')
|
|
, package_metadata = require('./package.json')
|
|
, locale = require('./lib/locale')
|
|
, request = require('postman-request');
|
|
|
|
var app = express();
|
|
var apiAccessList = [];
|
|
|
|
// pass wallet rpc connection info to nodeapi
|
|
nodeapi.setWalletDetails(settings.wallet);
|
|
// dynamically build the nodeapi cmd access list by adding all non-blockchain-specific api cmds that have a value
|
|
Object.keys(settings.api_cmds).forEach(function(key, index, map) {
|
|
if (key != 'use_rpc' && settings.api_cmds[key] != null && settings.api_cmds[key] != '')
|
|
apiAccessList.push(key);
|
|
});
|
|
// dynamically find and add additional blockchain_specific api cmds
|
|
Object.keys(settings.blockchain_specific).forEach(function(key, index, map) {
|
|
// check if this feature is enabled and has api cmds
|
|
if (settings.blockchain_specific[key].enabled == true && Object.keys(settings.blockchain_specific[key]).indexOf('api_cmds') > -1) {
|
|
// add all blockchain specific api cmds that have a value
|
|
Object.keys(settings.blockchain_specific[key]['api_cmds']).forEach(function(key2, index, map) {
|
|
if (settings.blockchain_specific[key]['api_cmds'][key2] != null && settings.blockchain_specific[key]['api_cmds'][key2] != '')
|
|
apiAccessList.push(key2);
|
|
});
|
|
}
|
|
});
|
|
// whitelist the cmds in the nodeapi access list
|
|
nodeapi.setAccess('only', apiAccessList);
|
|
// determine if cors should be enabled
|
|
if (settings.webserver.cors.enabled == true) {
|
|
app.use(function(req, res, next) {
|
|
res.header("Access-Control-Allow-Origin", settings.webserver.cors.corsorigin);
|
|
res.header('Access-Control-Allow-Methods', 'DELETE, PUT, GET, POST');
|
|
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
|
|
next();
|
|
});
|
|
}
|
|
// view engine setup
|
|
app.set('views', path.join(__dirname, 'views'));
|
|
app.set('view engine', 'pug');
|
|
|
|
app.use(favicon(path.join(__dirname, settings.shared_pages.favicon)));
|
|
app.use(logger('dev'));
|
|
app.use(bodyParser.json());
|
|
app.use(bodyParser.urlencoded({ extended: true }));
|
|
app.use(cookieParser());
|
|
app.use(express.static(path.join(__dirname, 'public')));
|
|
|
|
// routes
|
|
app.use('/api', nodeapi.app);
|
|
app.use('/', routes);
|
|
|
|
// post method to claim an address using verifymessage functionality
|
|
app.post('/claim', function(req, res) {
|
|
// check if the bad-words filter is enabled
|
|
if (settings.claim_address_page.enable_bad_word_filter == true) {
|
|
// initialize the bad-words filter
|
|
var bad_word_lib = require('bad-words');
|
|
var bad_word_filter = new bad_word_lib();
|
|
|
|
// clean the message (Display name) of bad words
|
|
var message = (req.body.message == null || req.body.message == '' ? '' : bad_word_filter.clean(req.body.message));
|
|
} else {
|
|
// Do not use the bad word filter
|
|
var message = (req.body.message == null || req.body.message == '' ? '' : req.body.message);
|
|
}
|
|
|
|
// check if the message was filtered
|
|
if (message == req.body.message) {
|
|
// call the verifymessage api
|
|
lib.verify_message(req.body.address, req.body.signature, req.body.message, function(body) {
|
|
if (body == false) {
|
|
res.json({'status': 'failed', 'error': true, 'message': 'Invalid signature'});
|
|
} else if (body == true) {
|
|
db.update_label(req.body.address, req.body.message, function(val) {
|
|
// check if the update was successful
|
|
if (val == '')
|
|
res.json({'status': 'success'});
|
|
else if (val == 'no_address')
|
|
res.json({'status': 'failed', 'error': true, 'message': 'Wallet address ' + req.body.address + ' is not valid or does not have any transactions'});
|
|
else
|
|
res.json({'status': 'failed', 'error': true, 'message': 'Wallet address or signature is invalid'});
|
|
});
|
|
} else
|
|
res.json({'status': 'failed', 'error': true, 'message': 'Wallet address or signature is invalid'});
|
|
});
|
|
} else {
|
|
// message was filtered which would change the signature
|
|
res.json({'status': 'failed', 'error': true, 'message': 'Display name contains bad words and cannot be saved: ' + message});
|
|
}
|
|
});
|
|
|
|
// extended apis
|
|
app.use('/ext/getmoneysupply', function(req, res) {
|
|
// check if the getmoneysupply api is enabled
|
|
if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.getmoneysupply.enabled == true) {
|
|
// lookup stats
|
|
db.get_stats(settings.coin.name, function (stats) {
|
|
res.setHeader('content-type', 'text/plain');
|
|
res.end((stats && stats.supply ? stats.supply.toString() : '0'));
|
|
});
|
|
} else
|
|
res.end('This method is disabled');
|
|
});
|
|
|
|
app.use('/ext/getaddress/:hash', function(req, res) {
|
|
// check if the getaddress api is enabled
|
|
if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.getaddress.enabled == true) {
|
|
db.get_address(req.params.hash, false, function(address) {
|
|
db.get_address_txs_ajax(req.params.hash, 0, settings.api_page.public_apis.ext.getaddresstxs.max_items_per_query, function(txs, count) {
|
|
if (address) {
|
|
var last_txs = [];
|
|
for (i = 0; i < txs.length; i++) {
|
|
if (typeof txs[i].txid !== "undefined") {
|
|
var out = 0,
|
|
vin = 0,
|
|
tx_type = 'vout',
|
|
row = {};
|
|
txs[i].vout.forEach(function (r) {
|
|
if (r.addresses == req.params.hash)
|
|
out += r.amount;
|
|
});
|
|
txs[i].vin.forEach(function (s) {
|
|
if (s.addresses == req.params.hash)
|
|
vin += s.amount;
|
|
});
|
|
if (vin > out)
|
|
tx_type = 'vin';
|
|
row['addresses'] = txs[i].txid;
|
|
row['type'] = tx_type;
|
|
last_txs.push(row);
|
|
}
|
|
}
|
|
var a_ext = {
|
|
address: address.a_id,
|
|
sent: (address.sent / 100000000),
|
|
received: (address.received / 100000000),
|
|
balance: (address.balance / 100000000).toString().replace(/(^-+)/mg, ''),
|
|
last_txs: last_txs
|
|
};
|
|
res.send(a_ext);
|
|
} else
|
|
res.send({ error: 'address not found.', hash: req.params.hash});
|
|
});
|
|
});
|
|
} else
|
|
res.end('This method is disabled');
|
|
});
|
|
|
|
app.use('/ext/gettx/:txid', function(req, res) {
|
|
// check if the gettx api is enabled
|
|
if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.gettx.enabled == true) {
|
|
var txid = req.params.txid;
|
|
db.get_tx(txid, function(tx) {
|
|
if (tx) {
|
|
lib.get_blockcount(function(blockcount) {
|
|
res.send({ active: 'tx', tx: tx, confirmations: settings.shared_pages.confirmations, blockcount: (blockcount ? blockcount : 0)});
|
|
});
|
|
}
|
|
else {
|
|
lib.get_rawtransaction(txid, function(rtx) {
|
|
if (rtx && rtx.txid) {
|
|
lib.prepare_vin(rtx, function(vin) {
|
|
lib.prepare_vout(rtx.vout, rtx.txid, vin, ((typeof rtx.vjoinsplit === 'undefined' || rtx.vjoinsplit == null) ? [] : rtx.vjoinsplit), function(rvout, rvin) {
|
|
lib.calculate_total(rvout, function(total) {
|
|
if (!rtx.confirmations > 0) {
|
|
var utx = {
|
|
txid: rtx.txid,
|
|
vin: rvin,
|
|
vout: rvout,
|
|
total: total.toFixed(8),
|
|
timestamp: rtx.time,
|
|
blockhash: '-',
|
|
blockindex: -1,
|
|
};
|
|
res.send({ active: 'tx', tx: utx, confirmations: settings.shared_pages.confirmations, blockcount:-1});
|
|
} else {
|
|
var utx = {
|
|
txid: rtx.txid,
|
|
vin: rvin,
|
|
vout: rvout,
|
|
total: total.toFixed(8),
|
|
timestamp: rtx.time,
|
|
blockhash: rtx.blockhash,
|
|
blockindex: rtx.blockheight,
|
|
};
|
|
lib.get_blockcount(function(blockcount) {
|
|
res.send({ active: 'tx', tx: utx, confirmations: settings.shared_pages.confirmations, blockcount: (blockcount ? blockcount : 0)});
|
|
});
|
|
}
|
|
});
|
|
});
|
|
});
|
|
} else {
|
|
res.send({ error: 'tx not found.', hash: txid});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
} else
|
|
res.end('This method is disabled');
|
|
});
|
|
|
|
app.use('/ext/getbalance/:hash', function(req, res) {
|
|
// check if the getbalance api is enabled
|
|
if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.getbalance.enabled == true) {
|
|
db.get_address(req.params.hash, false, function(address) {
|
|
if (address) {
|
|
res.setHeader('content-type', 'text/plain');
|
|
res.end((address.balance / 100000000).toString().replace(/(^-+)/mg, ''));
|
|
} else
|
|
res.send({ error: 'address not found.', hash: req.params.hash });
|
|
});
|
|
} else
|
|
res.end('This method is disabled');
|
|
});
|
|
|
|
app.use('/ext/getdistribution', function(req, res) {
|
|
// check if the getdistribution api is enabled
|
|
if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.getdistribution.enabled == true) {
|
|
db.get_richlist(settings.coin.name, function(richlist) {
|
|
db.get_stats(settings.coin.name, function(stats) {
|
|
db.get_distribution(richlist, stats, function(dist) {
|
|
res.send(dist);
|
|
});
|
|
});
|
|
});
|
|
} else
|
|
res.end('This method is disabled');
|
|
});
|
|
|
|
app.use('/ext/getcurrentprice', function(req, res) {
|
|
// check if the getcurrentprice api is enabled
|
|
if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.getcurrentprice.enabled == true) {
|
|
db.get_stats(settings.coin.name, function (stats) {
|
|
eval('var p_ext = { "last_price_' + settings.markets_page.default_exchange.trading_pair.split('/')[1].toLowerCase() + '": stats.last_price, "last_price_usd": stats.last_usd_price, }');
|
|
res.send(p_ext);
|
|
});
|
|
} else
|
|
res.end('This method is disabled');
|
|
});
|
|
|
|
app.use('/ext/getbasicstats', function(req, res) {
|
|
// check if the getbasicstats api is enabled
|
|
if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.getbasicstats.enabled == true) {
|
|
// lookup stats
|
|
db.get_stats(settings.coin.name, function (stats) {
|
|
// check if the masternode count api is enabled
|
|
if (settings.api_page.public_apis.rpc.getmasternodecount.enabled == true && settings.api_cmds['getmasternodecount'] != null && settings.api_cmds['getmasternodecount'] != '') {
|
|
// masternode count api is available
|
|
lib.get_masternodecount(function(masternodestotal) {
|
|
eval('var p_ext = { "block_count": (stats.count ? stats.count : 0), "money_supply": (stats.supply ? stats.supply : 0), "last_price_' + settings.markets_page.default_exchange.trading_pair.split('/')[1].toLowerCase() + '": stats.last_price, "last_price_usd": stats.last_usd_price, "masternode_count": masternodestotal.total }');
|
|
res.send(p_ext);
|
|
});
|
|
} else {
|
|
// masternode count api is not available
|
|
eval('var p_ext = { "block_count": (stats.count ? stats.count : 0), "money_supply": (stats.supply ? stats.supply : 0), "last_price_' + settings.markets_page.default_exchange.trading_pair.split('/')[1].toLowerCase() + '": stats.last_price, "last_price_usd": stats.last_usd_price }');
|
|
res.send(p_ext);
|
|
}
|
|
});
|
|
} else
|
|
res.end('This method is disabled');
|
|
});
|
|
|
|
app.use('/ext/getlasttxs/:min', function(req, res) {
|
|
// check if the getlasttxs api is enabled or else check the headers to see if it matches an internal ajax request from the explorer itself (TODO: come up with a more secure method of whitelisting ajax calls from the explorer)
|
|
if ((settings.api_page.enabled == true && settings.api_page.public_apis.ext.getlasttxs.enabled == true) || (req.headers['x-requested-with'] != null && req.headers['x-requested-with'].toLowerCase() == 'xmlhttprequest' && req.headers.referer != null && req.headers.accept.indexOf('text/javascript') > -1 && req.headers.accept.indexOf('application/json') > -1)) {
|
|
var min = req.params.min, start, length, internal = false;
|
|
// split url suffix by forward slash and remove blank entries
|
|
var split = req.url.split('/').filter(function(v) { return v; });
|
|
// determine how many parameters were passed
|
|
switch (split.length) {
|
|
case 2:
|
|
// capture start and length
|
|
start = split[0];
|
|
length = split[1];
|
|
break;
|
|
default:
|
|
if (split.length == 1) {
|
|
// capture start
|
|
start = split[0];
|
|
} else if (split.length >= 2) {
|
|
// capture start and length
|
|
start = split[0];
|
|
length = split[1];
|
|
// check if this is an internal request
|
|
if (split.length > 2 && split[2] == 'internal')
|
|
internal = true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// fix parameters
|
|
if (typeof length === 'undefined' || isNaN(length) || length > settings.api_page.public_apis.ext.getlasttxs.max_items_per_query)
|
|
length = settings.api_page.public_apis.ext.getlasttxs.max_items_per_query;
|
|
if (typeof start === 'undefined' || isNaN(start) || start < 0)
|
|
start = 0;
|
|
if (typeof min === 'undefined' || isNaN(min) || min < 0)
|
|
min = 0;
|
|
else
|
|
min = (min * 100000000);
|
|
|
|
db.get_last_txs(start, length, min, internal, function(data, count) {
|
|
// check if this is an internal request
|
|
if (internal) {
|
|
// display data formatted for internal datatable
|
|
res.json({"data": data, "recordsTotal": count, "recordsFiltered": count});
|
|
} else {
|
|
// display data in more readable format for public api
|
|
res.json(data);
|
|
}
|
|
});
|
|
} else
|
|
res.end('This method is disabled');
|
|
});
|
|
|
|
app.use('/ext/getaddresstxs/:address/:start/:length', function(req, res) {
|
|
// check if the getaddresstxs api is enabled or else check the headers to see if it matches an internal ajax request from the explorer itself (TODO: come up with a more secure method of whitelisting ajax calls from the explorer)
|
|
if ((settings.api_page.enabled == true && settings.api_page.public_apis.ext.getaddresstxs.enabled == true) || (req.headers['x-requested-with'] != null && req.headers['x-requested-with'].toLowerCase() == 'xmlhttprequest' && req.headers.referer != null && req.headers.accept.indexOf('text/javascript') > -1 && req.headers.accept.indexOf('application/json') > -1)) {
|
|
var internal = false;
|
|
// split url suffix by forward slash and remove blank entries
|
|
var split = req.url.split('/').filter(function(v) { return v; });
|
|
// check if this is an internal request
|
|
if (split.length > 0 && split[0] == 'internal')
|
|
internal = true;
|
|
// fix parameters
|
|
if (typeof req.params.length === 'undefined' || isNaN(req.params.length) || req.params.length > settings.api_page.public_apis.ext.getaddresstxs.max_items_per_query)
|
|
req.params.length = settings.api_page.public_apis.ext.getaddresstxs.max_items_per_query;
|
|
if (typeof req.params.start === 'undefined' || isNaN(req.params.start) || req.params.start < 0)
|
|
req.params.start = 0;
|
|
if (typeof req.params.min === 'undefined' || isNaN(req.params.min) || req.params.min < 0)
|
|
req.params.min = 0;
|
|
else
|
|
req.params.min = (req.params.min * 100000000);
|
|
|
|
db.get_address_txs_ajax(req.params.address, req.params.start, req.params.length, function(txs, count) {
|
|
var data = [];
|
|
|
|
for (i = 0; i < txs.length; i++) {
|
|
if (typeof txs[i].txid !== "undefined") {
|
|
var out = 0;
|
|
var vin = 0;
|
|
|
|
txs[i].vout.forEach(function(r) {
|
|
if (r.addresses == req.params.address)
|
|
out += r.amount;
|
|
});
|
|
|
|
txs[i].vin.forEach(function(s) {
|
|
if (s.addresses == req.params.address)
|
|
vin += s.amount;
|
|
});
|
|
|
|
if (internal) {
|
|
var row = [];
|
|
row.push(txs[i].timestamp);
|
|
row.push(txs[i].txid);
|
|
row.push(Number(out / 100000000));
|
|
row.push(Number(vin / 100000000));
|
|
row.push(Number(txs[i].balance / 100000000));
|
|
data.push(row);
|
|
} else {
|
|
data.push({
|
|
timestamp: txs[i].timestamp,
|
|
txid: txs[i].txid,
|
|
sent: Number(out / 100000000),
|
|
received: Number(vin / 100000000),
|
|
balance: Number(txs[i].balance / 100000000)
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
// check if this is an internal request
|
|
if (internal) {
|
|
// display data formatted for internal datatable
|
|
res.json({"data": data, "recordsTotal": count, "recordsFiltered": count});
|
|
} else {
|
|
// display data in more readable format for public api
|
|
res.json(data);
|
|
}
|
|
});
|
|
} else
|
|
res.end('This method is disabled');
|
|
});
|
|
|
|
app.use('/ext/getsummary', function(req, res) {
|
|
// check if the getsummary api is enabled or else check the headers to see if it matches an internal ajax request from the explorer itself (TODO: come up with a more secure method of whitelisting ajax calls from the explorer)
|
|
if ((settings.api_page.enabled == true && settings.api_page.public_apis.ext.getsummary.enabled == true) || (req.headers['x-requested-with'] != null && req.headers['x-requested-with'].toLowerCase() == 'xmlhttprequest' && req.headers.referer != null && req.headers.accept.indexOf('text/javascript') > -1 && req.headers.accept.indexOf('application/json') > -1)) {
|
|
lib.get_difficulty(function(difficulty) {
|
|
difficultyHybrid = '';
|
|
if (difficulty && difficulty['proof-of-work']) {
|
|
if (settings.shared_pages.difficulty == 'Hybrid') {
|
|
difficultyHybrid = 'POS: ' + difficulty['proof-of-stake'];
|
|
difficulty = 'POW: ' + difficulty['proof-of-work'];
|
|
} else if (settings.shared_pages.difficulty == 'POW')
|
|
difficulty = difficulty['proof-of-work'];
|
|
else
|
|
difficulty = difficulty['proof-of-stake'];
|
|
}
|
|
lib.get_hashrate(function(hashrate) {
|
|
lib.get_connectioncount(function(connections) {
|
|
lib.get_blockcount(function(blockcount) {
|
|
db.get_stats(settings.coin.name, function (stats) {
|
|
lib.get_masternodecount(function(masternodestotal) {
|
|
if (hashrate == 'There was an error. Check your console.')
|
|
hashrate = 0;
|
|
// check if the masternode count api is enabled
|
|
if (settings.api_page.public_apis.rpc.getmasternodecount.enabled == true && settings.api_cmds['getmasternodecount'] != null && settings.api_cmds['getmasternodecount'] != '') {
|
|
// masternode count api is available
|
|
var mn_total = 0;
|
|
var mn_enabled = 0;
|
|
|
|
if (masternodestotal) {
|
|
if (masternodestotal.total)
|
|
mn_total = masternodestotal.total;
|
|
if (masternodestotal.enabled)
|
|
mn_enabled = masternodestotal.enabled;
|
|
}
|
|
res.send({
|
|
difficulty: (difficulty ? difficulty : '-'),
|
|
difficultyHybrid: difficultyHybrid,
|
|
supply: (stats == null || stats.supply == null ? 0 : stats.supply),
|
|
hashrate: hashrate,
|
|
lastPrice: (stats == null || stats.last_price == null ? 0 : stats.last_price),
|
|
connections: (connections ? connections : '-'),
|
|
masternodeCountOnline: (masternodestotal ? mn_enabled : '-'),
|
|
masternodeCountOffline: (masternodestotal ? Math.floor(mn_total - mn_enabled) : '-'),
|
|
blockcount: (blockcount ? blockcount : '-')
|
|
});
|
|
} else {
|
|
// masternode count api is not available
|
|
res.send({
|
|
difficulty: (difficulty ? difficulty : '-'),
|
|
difficultyHybrid: difficultyHybrid,
|
|
supply: (stats == null || stats.supply == null ? 0 : stats.supply),
|
|
hashrate: hashrate,
|
|
lastPrice: (stats == null || stats.last_price == null ? 0 : stats.last_price),
|
|
connections: (connections ? connections : '-'),
|
|
blockcount: (blockcount ? blockcount : '-')
|
|
});
|
|
}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
} else
|
|
res.end('This method is disabled');
|
|
});
|
|
|
|
app.use('/ext/getnetworkpeers', function(req, res) {
|
|
// check if the getnetworkpeers api is enabled or else check the headers to see if it matches an internal ajax request from the explorer itself (TODO: come up with a more secure method of whitelisting ajax calls from the explorer)
|
|
if ((settings.api_page.enabled == true && settings.api_page.public_apis.ext.getnetworkpeers.enabled == true) || (req.headers['x-requested-with'] != null && req.headers['x-requested-with'].toLowerCase() == 'xmlhttprequest' && req.headers.referer != null && req.headers.accept.indexOf('text/javascript') > -1 && req.headers.accept.indexOf('application/json') > -1)) {
|
|
var internal = false;
|
|
// split url suffix by forward slash and remove blank entries
|
|
var split = req.url.split('/').filter(function(v) { return v; });
|
|
// check if this is an internal request
|
|
if (split.length > 0 && split[0].indexOf('internal') > -1)
|
|
internal = true;
|
|
|
|
// get list of peers
|
|
db.get_peers(function(peers) {
|
|
// loop through peers list and remove the mongo _id and __v keys
|
|
for (i = 0; i < peers.length; i++) {
|
|
delete peers[i]['_doc']['_id'];
|
|
delete peers[i]['_doc']['__v'];
|
|
}
|
|
// check if this is an internal request
|
|
if (internal) {
|
|
// display data formatted for internal datatable
|
|
res.json({"data": peers});
|
|
} else {
|
|
// display data in more readable format for public api
|
|
res.json(peers);
|
|
}
|
|
});
|
|
} else
|
|
res.end('This method is disabled');
|
|
});
|
|
|
|
// get the list of masternodes from local collection
|
|
app.use('/ext/getmasternodelist', function(req, res) {
|
|
// check if the getmasternodelist api is enabled or else check the headers to see if it matches an internal ajax request from the explorer itself (TODO: come up with a more secure method of whitelisting ajax calls from the explorer)
|
|
if ((settings.api_page.enabled == true && settings.api_page.public_apis.ext.getmasternodelist.enabled == true) || (req.headers['x-requested-with'] != null && req.headers['x-requested-with'].toLowerCase() == 'xmlhttprequest' && req.headers.referer != null && req.headers.accept.indexOf('text/javascript') > -1 && req.headers.accept.indexOf('application/json') > -1)) {
|
|
// get the masternode list from local collection
|
|
db.get_masternodes(function(masternodes) {
|
|
// loop through masternode list and remove the mongo _id and __v keys
|
|
for (i = 0; i < masternodes.length; i++) {
|
|
delete masternodes[i]['_doc']['_id'];
|
|
delete masternodes[i]['_doc']['__v'];
|
|
}
|
|
// return masternode list
|
|
res.send(masternodes);
|
|
});
|
|
} else
|
|
res.end('This method is disabled');
|
|
});
|
|
|
|
// returns a list of masternode reward txs for a single masternode address from a specific block height
|
|
app.use('/ext/getmasternoderewards/:hash/:since', function(req, res) {
|
|
// check if the getmasternoderewards api is enabled
|
|
if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.getmasternoderewards.enabled == true) {
|
|
db.get_masternode_rewards(req.params.hash, req.params.since, function(rewards) {
|
|
if (rewards != null) {
|
|
// loop through the tx list to fix vout values and remove unnecessary data such as the always empty vin array and the mongo _id and __v keys
|
|
for (i = 0; i < rewards.length; i++) {
|
|
// remove unnecessary data keys
|
|
delete rewards[i]['vin'];
|
|
delete rewards[i]['_id'];
|
|
delete rewards[i]['__v'];
|
|
// convert amounts from satoshis
|
|
rewards[i]['total'] = rewards[i]['total'] / 100000000;
|
|
rewards[i]['vout']['amount'] = rewards[i]['vout']['amount'] / 100000000;
|
|
}
|
|
// return list of masternode rewards
|
|
res.json(rewards);
|
|
} else
|
|
res.send({error: "failed to retrieve masternode rewards", hash: req.params.hash, since: req.params.since});
|
|
});
|
|
} else
|
|
res.end('This method is disabled');
|
|
});
|
|
|
|
// returns the total masternode rewards received for a single masternode address from a specific block height
|
|
app.use('/ext/getmasternoderewardstotal/:hash/:since', function(req, res) {
|
|
// check if the getmasternoderewardstotal api is enabled
|
|
if (settings.api_page.enabled == true && settings.api_page.public_apis.ext.getmasternoderewardstotal.enabled == true) {
|
|
db.get_masternode_rewards_totals(req.params.hash, req.params.since, function(total_rewards) {
|
|
if (total_rewards != null) {
|
|
// return the total of masternode rewards
|
|
res.json(total_rewards);
|
|
} else
|
|
res.send({error: "failed to retrieve masternode rewards", hash: req.params.hash, since: req.params.since});
|
|
});
|
|
} else
|
|
res.end('This method is disabled');
|
|
});
|
|
|
|
var market_data = [];
|
|
var market_count = 0;
|
|
|
|
// check if markets are enabled
|
|
if (settings.markets_page.enabled == true) {
|
|
// dynamically populate market data
|
|
Object.keys(settings.markets_page.exchanges).forEach(function (key, index, map) {
|
|
// check if market is enabled via settings
|
|
if (settings.markets_page.exchanges[key].enabled == true) {
|
|
// check if market is installed/supported
|
|
if (db.fs.existsSync('./lib/markets/' + key + '.js')) {
|
|
// load market file
|
|
var exMarket = require('./lib/markets/' + key);
|
|
// save market_name and market_logo from market file to settings
|
|
eval('market_data.push({id: "' + key + '", name: "' + (exMarket.market_name == null ? '' : exMarket.market_name) + '", logo: "' + (exMarket.market_logo == null ? '' : exMarket.market_logo) + '", trading_pairs: []});');
|
|
// loop through all trading pairs for this market
|
|
for (var i = 0; i < settings.markets_page.exchanges[key].trading_pairs.length; i++) {
|
|
// ensure trading pair setting is always uppercase
|
|
settings.markets_page.exchanges[key].trading_pairs[i] = settings.markets_page.exchanges[key].trading_pairs[i].toUpperCase();
|
|
// add trading pair to market_data
|
|
market_data[market_data.length - 1].trading_pairs.push(settings.markets_page.exchanges[key].trading_pairs[i]);
|
|
// increment the market count
|
|
market_count++;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// sort market data by market name
|
|
market_data.sort(function(a, b) {
|
|
var name1 = a.name.toLowerCase();
|
|
var name2 = b.name.toLowerCase();
|
|
|
|
if (name1 < name2)
|
|
return -1;
|
|
else if (name1 > name2)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
});
|
|
|
|
// Fix default exchange case
|
|
settings.markets_page.default_exchange.exchange_name = settings.markets_page.default_exchange.exchange_name.toLowerCase();
|
|
settings.markets_page.default_exchange.trading_pair = settings.markets_page.default_exchange.trading_pair.toUpperCase();
|
|
|
|
var ex = settings.markets_page.exchanges;
|
|
var ex_name = settings.markets_page.default_exchange.exchange_name;
|
|
var ex_pair = settings.markets_page.default_exchange.trading_pair;
|
|
var ex_keys = Object.keys(ex);
|
|
var ex_error = '';
|
|
|
|
// check to ensure default market and trading pair exist and are enabled
|
|
if (ex[ex_name] == null) {
|
|
// exchange name does not exist in exchanges list
|
|
ex_error = 'Default exchange name is not valid' + ': ' + ex_name;
|
|
} else if (!ex[ex_name].enabled) {
|
|
// exchange is not enabled
|
|
ex_error = 'Default exchange is disabled in settings' + ': ' + ex_name;
|
|
} else if (ex[ex_name].trading_pairs.findIndex(p => p.toLowerCase() == ex_pair.toLowerCase()) == -1) {
|
|
// invalid default exchange trading pair
|
|
ex_error = 'Default exchange trading pair is not valid' + ': ' + ex_pair;
|
|
}
|
|
|
|
// check if there was an error msg
|
|
if (ex_error != '') {
|
|
// there was an error, so find the next available market from settings.json
|
|
var new_default_index = -1;
|
|
|
|
// find the first enabled exchange with at least one trading pair
|
|
for (var i = 0; i < ex_keys.length; i++) {
|
|
if (ex[ex_keys[i]]['enabled'] === true && ex[ex_keys[i]]['trading_pairs'].length > 0) {
|
|
// found a match so save the index
|
|
new_default_index = i;
|
|
// stop looking for more matches
|
|
break;
|
|
}
|
|
}
|
|
|
|
// check if a valid and enabled market was found
|
|
if (new_default_index == -1) {
|
|
// no valid markets found
|
|
console.log('WARNING: ' + ex_error + '. ' + 'No valid or enabled markets found in settings.json. The markets feature will be temporarily disabled. To restore markets functionality, please enable at least 1 market and ensure at least 1 valid trading pair is added. Finally, restart the explorer to resolve the problem');
|
|
// disable the markets feature for this session
|
|
settings.markets_page.enabled = false;
|
|
} else {
|
|
// a valid and enabled market was found to replace the default
|
|
console.log('WARNING: ' + ex_error + '. ' + 'Default exchange will be set to' + ': ' + ex_keys[new_default_index] + ' (' + ex[ex_keys[new_default_index]].trading_pairs[0] + ')');
|
|
// set new default exchange data
|
|
settings.markets_page.default_exchange.exchange_name = ex_keys[new_default_index];
|
|
settings.markets_page.default_exchange.trading_pair = ex[ex_keys[new_default_index]].trading_pairs[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
// check if home_link_logo file exists
|
|
if (!db.fs.existsSync(path.join('./public', settings.shared_pages.page_header.home_link_logo)))
|
|
settings.shared_pages.page_header.home_link_logo = '';
|
|
|
|
// always disable the rpc masternode list cmd from public apis
|
|
settings.api_page.public_apis.rpc.getmasternodelist = { "enabled": false };
|
|
|
|
// locals
|
|
app.set('explorer_version', package_metadata.version);
|
|
app.set('locale', locale);
|
|
app.set('coin', settings.coin);
|
|
app.set('shared_pages', settings.shared_pages);
|
|
app.set('index_page', settings.index_page);
|
|
app.set('block_page', settings.block_page);
|
|
app.set('transaction_page', settings.transaction_page);
|
|
app.set('address_page', settings.address_page);
|
|
app.set('masternodes_page', settings.masternodes_page);
|
|
app.set('movement_page', settings.movement_page);
|
|
app.set('network_page', settings.network_page);
|
|
app.set('richlist_page', settings.richlist_page);
|
|
app.set('markets_page', settings.markets_page);
|
|
app.set('api_page', settings.api_page);
|
|
app.set('claim_address_page', settings.claim_address_page);
|
|
app.set('labels', settings.labels);
|
|
app.set('api_cmds', settings.api_cmds);
|
|
app.set('blockchain_specific', settings.blockchain_specific);
|
|
|
|
// determine panel offset based on which panels are enabled
|
|
var paneltotal = 5;
|
|
var panelcount = (settings.shared_pages.page_header.panels.network_panel.enabled == true && settings.shared_pages.page_header.panels.network_panel.display_order > 0 ? 1 : 0) +
|
|
(settings.shared_pages.page_header.panels.difficulty_panel.enabled == true && settings.shared_pages.page_header.panels.difficulty_panel.display_order > 0 ? 1 : 0) +
|
|
(settings.shared_pages.page_header.panels.masternodes_panel.enabled == true && settings.shared_pages.page_header.panels.masternodes_panel.display_order > 0 ? 1 : 0) +
|
|
(settings.shared_pages.page_header.panels.coin_supply_panel.enabled == true && settings.shared_pages.page_header.panels.coin_supply_panel.display_order > 0 ? 1 : 0) +
|
|
(settings.shared_pages.page_header.panels.price_panel.enabled == true && settings.shared_pages.page_header.panels.price_panel.display_order > 0 ? 1 : 0) +
|
|
(settings.shared_pages.page_header.panels.market_cap_panel.enabled == true && settings.shared_pages.page_header.panels.market_cap_panel.display_order > 0 ? 1 : 0) +
|
|
(settings.shared_pages.page_header.panels.logo_panel.enabled == true && settings.shared_pages.page_header.panels.logo_panel.display_order > 0 ? 1 : 0);
|
|
app.set('paneloffset', paneltotal + 1 - panelcount);
|
|
|
|
// determine panel order
|
|
var panel_order = new Array();
|
|
|
|
if (settings.shared_pages.page_header.panels.network_panel.enabled == true && settings.shared_pages.page_header.panels.network_panel.display_order > 0) panel_order.push({name: 'network_panel', val: settings.shared_pages.page_header.panels.network_panel.display_order});
|
|
if (settings.shared_pages.page_header.panels.difficulty_panel.enabled == true && settings.shared_pages.page_header.panels.difficulty_panel.display_order > 0) panel_order.push({name: 'difficulty_panel', val: settings.shared_pages.page_header.panels.difficulty_panel.display_order});
|
|
if (settings.shared_pages.page_header.panels.masternodes_panel.enabled == true && settings.shared_pages.page_header.panels.masternodes_panel.display_order > 0) panel_order.push({name: 'masternodes_panel', val: settings.shared_pages.page_header.panels.masternodes_panel.display_order});
|
|
if (settings.shared_pages.page_header.panels.coin_supply_panel.enabled == true && settings.shared_pages.page_header.panels.coin_supply_panel.display_order > 0) panel_order.push({name: 'coin_supply_panel', val: settings.shared_pages.page_header.panels.coin_supply_panel.display_order});
|
|
if (settings.shared_pages.page_header.panels.price_panel.enabled == true && settings.shared_pages.page_header.panels.price_panel.display_order > 0) panel_order.push({name: 'price_panel', val: settings.shared_pages.page_header.panels.price_panel.display_order});
|
|
if (settings.shared_pages.page_header.panels.market_cap_panel.enabled == true && settings.shared_pages.page_header.panels.market_cap_panel.display_order > 0) panel_order.push({name: 'market_cap_panel', val: settings.shared_pages.page_header.panels.market_cap_panel.display_order});
|
|
if (settings.shared_pages.page_header.panels.logo_panel.enabled == true && settings.shared_pages.page_header.panels.logo_panel.display_order > 0) panel_order.push({name: 'logo_panel', val: settings.shared_pages.page_header.panels.logo_panel.display_order});
|
|
|
|
panel_order.sort(function(a,b) { return a.val - b.val; });
|
|
|
|
for (var i=1; i<6; i++)
|
|
app.set('panel'+i.toString(), ((panel_order.length >= i) ? panel_order[i-1].name : ''));
|
|
|
|
app.set('market_data', market_data);
|
|
app.set('market_count', market_count);
|
|
|
|
// catch 404 and forward to error handler
|
|
app.use(function(req, res, next) {
|
|
var err = new Error('Not Found');
|
|
err.status = 404;
|
|
next(err);
|
|
});
|
|
|
|
// development error handler
|
|
// will print stacktrace
|
|
if (app.get('env') === 'development') {
|
|
app.use(function(err, req, res, next) {
|
|
res.status(err.status || 500);
|
|
res.render('error', {
|
|
message: err.message,
|
|
error: err
|
|
});
|
|
});
|
|
}
|
|
|
|
// production error handler
|
|
// no stacktraces leaked to user
|
|
app.use(function(err, req, res, next) {
|
|
res.status(err.status || 500);
|
|
res.render('error', {
|
|
message: err.message,
|
|
error: {}
|
|
});
|
|
});
|
|
|
|
module.exports = app; |