From b6808da45499053f36e8a18b0960d5c9f962e541 Mon Sep 17 00:00:00 2001 From: joeuhren <46763106+joeuhren@users.noreply.github.com> Date: Fri, 4 Dec 2020 10:59:58 -0700 Subject: [PATCH] Improved syncing features --- README.md | 40 ++--- scripts/index.sh | 16 -- scripts/peers.js | 113 -------------- scripts/sync.js | 396 +++++++++++++++++++++++++++++------------------ scripts/sync.sh | 120 ++++++++++++++ 5 files changed, 385 insertions(+), 300 deletions(-) delete mode 100755 scripts/index.sh delete mode 100644 scripts/peers.js create mode 100644 scripts/sync.sh diff --git a/README.md b/README.md index 817a05c..5452f52 100644 --- a/README.md +++ b/README.md @@ -59,34 +59,34 @@ To stop the cluster you can use ### Syncing databases with the blockchain -sync.js (located in scripts/) is used for updating the local databases. This script must be called from the explorers root directory. +sync.sh (located in scripts/) is used for updating the local databases. This script must be called from the explorers root directory. - Usage: node scripts/sync.js [database] [mode] + Usage: scripts/sync.sh /path/to/nodejs [mode] - database: (required) - index [mode] Main index: coin info/stats, transactions & addresses - market Market data: summaries, orderbooks, trade history & chartdata + Mode: (required) + update Updates index from last sync to current block + check Checks index for (and adds) any missing transactions/addresses + reindex Clears index then resyncs from genesis to current block + reindex-rich Clears and recreates the richlist data + reindex-txcount Rescan and flatten the tx count value for faster access + market Updates market summaries, orderbooks, trade history + charts + peers Updates peer info based on local wallet connections - mode: (required for index database only) - update Updates index from last sync to current block - check checks index for (and adds) any missing transactions/addresses - reindex Clears index then resyncs from genesis to current block - - notes: - * 'current block' is the latest created block when script is executed. - * The market database only supports (& defaults to) reindex mode. - * If check mode finds missing data(ignoring new data since last sync), + Notes: + - 'current block' is the latest created block when script is executed. + - The market + peers databases only support (& defaults to) reindex mode. + - If check mode finds missing data(ignoring new data since last sync), index_timeout in settings.json is set too low. *It is recommended to have this script launched via a cronjob at 1+ min intervals.* **crontab** -*Example crontab; update index every minute and market data every 2 minutes* +*Example crontab; update index every minute, market data every 2 minutes and peers every 5 minutes* - */1 * * * * /path/to/explorer/scripts/index.sh /path/to/nodejs > /dev/null 2>&1 - */2 * * * * cd /path/to/explorer && /path/to/nodejs scripts/sync.js market > /dev/null 2>&1 - */5 * * * * cd /path/to/explorer && /path/to/nodejs scripts/peers.js > /dev/null 2>&1 + */1 * * * * /path/to/explorer/scripts/sync.sh /path/to/nodejs update > /dev/null 2>&1 + */2 * * * * /path/to/explorer/scripts/sync.sh /path/to/nodejs market > /dev/null 2>&1 + */5 * * * * /path/to/explorer/scripts/sync.sh /path/to/nodejs peers > /dev/null 2>&1 ### Wallet @@ -200,13 +200,13 @@ A pair of scripts to backup or restore the internal mongo database are included. RangeError: Maximum call stack size exceeded -Nodes default stack size may be too small to index addresses with many tx's. If you experience the above error while running sync.js the stack size needs to be increased. +Nodes default stack size may be too small to index addresses with many tx's. If you experience the above error while running sync.sh the stack size needs to be increased. To determine the default setting run node --v8-options | grep -B0 -A1 stack_size -To run sync.js with a larger stack size launch with +To run a sync with a larger stack size launch with node --stack-size=[SIZE] scripts/sync.js index update diff --git a/scripts/index.sh b/scripts/index.sh deleted file mode 100755 index 3da8371..0000000 --- a/scripts/index.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash -EXPLORER_PATH=$(dirname $(dirname $(readlink -f "$0"))) -if [ -f "${EXPLORER_PATH}/tmp/index.pid" ]; -then - ps -p `cat ${EXPLORER_PATH}/tmp/index.pid` > /dev/null - if [ $? -eq 0 ]; then - exit 1 - else - rm "${EXPLORER_PATH}/tmp/index.pid" - fi -fi -if [ -z "${1}" ]; then - eval "cd ${EXPLORER_PATH} && $(which node) scripts/sync.js index update" -else - eval "cd ${EXPLORER_PATH} && ${1} scripts/sync.js index update" -fi \ No newline at end of file diff --git a/scripts/peers.js b/scripts/peers.js deleted file mode 100644 index 9b96d48..0000000 --- a/scripts/peers.js +++ /dev/null @@ -1,113 +0,0 @@ -var mongoose = require('mongoose') - , lib = require('../lib/explorer') - , db = require('../lib/database') - , settings = require('../lib/settings') - , request = require('postman-request'); - -var COUNT = 5000; //number of blocks to index - -function exit() { - mongoose.disconnect(); - process.exit(0); -} - -var dbString = 'mongodb://' + settings.dbsettings.user; -dbString = dbString + ':' + settings.dbsettings.password; -dbString = dbString + '@' + settings.dbsettings.address; -dbString = dbString + ':' + settings.dbsettings.port; -dbString = dbString + '/' + settings.dbsettings.database; - -mongoose.connect(dbString, { useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true, useFindAndModify: false }, function(err) { - if (err) { - console.log('Unable to connect to database: %s', dbString); - console.log('Aborting'); - exit(); - } else { - request({uri: 'http://127.0.0.1:' + settings.port + '/api/getpeerinfo', json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) { - lib.syncLoop(body.length, function (loop) { - var i = loop.iteration(); - var address = body[i].addr.substring(0, body[i].addr.lastIndexOf(":")).replace("[","").replace("]",""); - var port = body[i].addr.substring(body[i].addr.lastIndexOf(":") + 1); - var rateLimit = new RateLimit(1, 2000, false); - db.find_peer(address, function(peer) { - if (peer) { - if (isNaN(peer['port']) || peer['port'].length < 2 || peer['country'].length < 1 || peer['country_code'].length < 1) { - db.drop_peers(function() { - console.log('Saved peers missing ports or country, dropping peers. Re-run this script afterwards.'); - exit(); - }); - } - // peer already exists - loop.next(); - } else { - rateLimit.schedule(function() { - request({uri: 'https://freegeoip.app/json/' + address, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, geo) { - db.create_peer({ - address: address, - port: port, - protocol: body[i].version, - version: body[i].subver.replace('/', '').replace('/', ''), - country: geo.country_name, - country_code: geo.country_code - }, function(){ - loop.next(); - }); - }); - }); - } - }); - }, function() { - exit(); - }); - }); - } -}); - -// rate limiting class from Matteo Agosti via https://www.matteoagosti.com/blog/2013/01/22/rate-limiting-function-calls-in-javascript/ -var RateLimit = (function() { - var RateLimit = function(maxOps, interval, allowBursts) { - this._maxRate = allowBursts ? maxOps : maxOps / interval; - this._interval = interval; - this._allowBursts = allowBursts; - - this._numOps = 0; - this._start = new Date().getTime(); - this._queue = []; - }; - - RateLimit.prototype.schedule = function(fn) { - var that = this, - rate = 0, - now = new Date().getTime(), - elapsed = now - this._start; - - if (elapsed > this._interval) { - this._numOps = 0; - this._start = now; - } - - rate = this._numOps / (this._allowBursts ? 1 : elapsed); - - if (rate < this._maxRate) { - if (this._queue.length === 0) { - this._numOps++; - fn(); - } - else { - if (fn) this._queue.push(fn); - - this._numOps++; - this._queue.shift()(); - } - } - else { - if (fn) this._queue.push(fn); - - setTimeout(function() { - that.schedule(); - }, 1 / this._maxRate); - } - }; - - return RateLimit; -})(); \ No newline at end of file diff --git a/scripts/sync.js b/scripts/sync.js index a302fc8..e796c77 100644 --- a/scripts/sync.js +++ b/scripts/sync.js @@ -1,4 +1,5 @@ var mongoose = require('mongoose') + , lib = require('../lib/explorer') , db = require('../lib/database') , Tx = require('../models/tx') , Address = require('../models/address') @@ -6,6 +7,7 @@ var mongoose = require('mongoose') , Richlist = require('../models/richlist') , Stats = require('../models/stats') , settings = require('../lib/settings') + , request = require('postman-request') , fs = require('fs'); var mode = 'update'; @@ -13,22 +15,21 @@ var database = 'index'; // displays usage and exits function usage() { - console.log('Usage: node scripts/sync.js [database] [mode]'); + console.log('Usage: scripts/sync.sh /path/to/nodejs [mode]'); console.log(''); - console.log('database: (required)'); - console.log('index [mode] Main index: coin info/stats, transactions & addresses'); - console.log('market Market data: summaries, orderbooks, trade history & chartdata') - console.log(''); - console.log('mode: (required for index database only)'); + console.log('Mode: (required)'); console.log('update Updates index from last sync to current block'); console.log('check Checks index for (and adds) any missing transactions/addresses'); console.log('reindex Clears index then resyncs from genesis to current block'); + console.log('reindex-rich Clears and recreates the richlist data'); console.log('reindex-txcount Rescan and flatten the tx count value for faster access'); + console.log('market Updates market summaries, orderbooks, trade history + charts'); + console.log('peers Updates peer info based on local wallet connections'); console.log(''); - console.log('notes:'); - console.log('* \'current block\' is the latest created block when script is executed.'); - console.log('* The market database only supports (& defaults to) reindex mode.'); - console.log('* If check mode finds missing data(ignoring new data since last sync),'); + console.log('Notes:'); + console.log('- \'current block\' is the latest created block when script is executed.'); + console.log('- The market + peers databases only support (& defaults to) reindex mode.'); + console.log('- If check mode finds missing data (ignoring new data since last sync),'); console.log(' index_timeout in settings.json is set too low.') console.log(''); process.exit(0); @@ -52,6 +53,7 @@ if (process.argv[2] == 'index') { break; case 'reindex-rich': mode = 'reindex-rich'; + break; case 'reindex-txcount': mode = 'reindex-txcount'; break; @@ -59,8 +61,10 @@ if (process.argv[2] == 'index') { usage(); } } -} else if (process.argv[2] == 'market'){ +} else if (process.argv[2] == 'market') { database = 'market'; +} else if (process.argv[2] == 'peers') { + database = 'peers'; } else { usage(); } @@ -125,54 +129,153 @@ dbString = dbString + '@' + settings.dbsettings.address; dbString = dbString + ':' + settings.dbsettings.port; dbString = dbString + '/' + settings.dbsettings.database; -is_locked(function (exists) { - if (exists) { - console.log("Script already running.."); - process.exit(0); - } else { - create_lock(function (){ - console.log("script launched with pid: " + process.pid); - mongoose.connect(dbString, { useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true, useFindAndModify: false }, function(err) { - if (err) { - console.log('Unable to connect to database: %s', dbString); - console.log('Aborting'); - exit(); - } else if (database == 'index') { - db.check_stats(settings.coin, function(exists) { - if (exists == false) { - console.log('Run \'npm start\' to create database structures before running this script.'); - exit(); - } else { - db.update_db(settings.coin, function(stats){ - if (settings.heavy == true) { - db.update_heavy(settings.coin, stats.count, 20, function(){ +if (database == 'peers') { + console.log('syncing peers.. please wait..'); + // Initialize the rate limiting class from Matteo Agosti via https://www.matteoagosti.com/blog/2013/01/22/rate-limiting-function-calls-in-javascript/ + var RateLimit = (function() { + var RateLimit = function(maxOps, interval, allowBursts) { + this._maxRate = allowBursts ? maxOps : maxOps / interval; + this._interval = interval; + this._allowBursts = allowBursts; - }); - } - if (mode == 'reindex') { - Tx.deleteMany({}, function(err) { - console.log('TXs cleared.'); - Address.deleteMany({}, function(err2) { - console.log('Addresses cleared.'); - AddressTx.deleteMany({}, function(err3) { - console.log('Address TXs cleared.'); - Richlist.updateOne({coin: settings.coin}, { - received: [], - balance: [], - }, function(err3) { - Stats.updateOne({coin: settings.coin}, { - last: 0, - count: 0, - supply: 0 - }, function() { - console.log('index cleared (reindex)'); - }); - db.update_tx_db(settings.coin, 1, stats.count, stats.txes, settings.update_timeout, function(){ - db.update_richlist('received', function(){ - db.update_richlist('balance', function(){ - db.get_stats(settings.coin, function(nstats){ - console.log('reindex complete (block: %s)', nstats.last); - exit(); + this._numOps = 0; + this._start = new Date().getTime(); + this._queue = []; + }; + + RateLimit.prototype.schedule = function(fn) { + var that = this, + rate = 0, + now = new Date().getTime(), + elapsed = now - this._start; + + if (elapsed > this._interval) { + this._numOps = 0; + this._start = now; + } + + rate = this._numOps / (this._allowBursts ? 1 : elapsed); + + if (rate < this._maxRate) { + if (this._queue.length === 0) { + this._numOps++; + fn(); + } + else { + if (fn) this._queue.push(fn); + + this._numOps++; + this._queue.shift()(); + } + } + else { + if (fn) this._queue.push(fn); + + setTimeout(function() { + that.schedule(); + }, 1 / this._maxRate); + } + }; + + return RateLimit; + })(); + // syncing peers does not require a lock + mongoose.connect(dbString, { useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true, useFindAndModify: false }, function(err) { + if (err) { + console.log('Unable to connect to database: %s', dbString); + console.log('Aborting'); + exit(); + } else { + request({uri: 'http://127.0.0.1:' + settings.port + '/api/getpeerinfo', json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, body) { + lib.syncLoop(body.length, function (loop) { + var i = loop.iteration(); + var address = body[i].addr.substring(0, body[i].addr.lastIndexOf(":")).replace("[","").replace("]",""); + var port = body[i].addr.substring(body[i].addr.lastIndexOf(":") + 1); + var rateLimit = new RateLimit(1, 2000, false); + db.find_peer(address, function(peer) { + if (peer) { + if (isNaN(peer['port']) || peer['port'].length < 2 || peer['country'].length < 1 || peer['country_code'].length < 1) { + db.drop_peers(function() { + console.log('Saved peers missing ports or country, dropping peers. Re-run this script afterwards.'); + exit(); + }); + } + // peer already exists + loop.next(); + } else { + rateLimit.schedule(function() { + request({uri: 'https://freegeoip.app/json/' + address, json: true, headers: {'User-Agent': 'eiquidus'}}, function (error, response, geo) { + db.create_peer({ + address: address, + port: port, + protocol: body[i].version, + version: body[i].subver.replace('/', '').replace('/', ''), + country: geo.country_name, + country_code: geo.country_code + }, function(){ + loop.next(); + }); + }); + }); + } + }); + }, function() { + console.log('peer sync complete'); + exit(); + }); + }); + } + }); +} else { + // index and market sync requires locking + is_locked(function (exists) { + if (exists) { + console.log("Script already running.."); + process.exit(0); + } else { + create_lock(function (){ + console.log("script launched with pid: " + process.pid); + mongoose.connect(dbString, { useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true, useFindAndModify: false }, function(err) { + if (err) { + console.log('Unable to connect to database: %s', dbString); + console.log('Aborting'); + exit(); + } else if (database == 'index') { + db.check_stats(settings.coin, function(exists) { + if (exists == false) { + console.log('Run \'npm start\' to create database structures before running this script.'); + exit(); + } else { + db.update_db(settings.coin, function(stats){ + if (settings.heavy == true) { + db.update_heavy(settings.coin, stats.count, 20, function(){ + }); + } + if (mode == 'reindex') { + Tx.deleteMany({}, function(err) { + console.log('TXs cleared.'); + Address.deleteMany({}, function(err2) { + console.log('Addresses cleared.'); + AddressTx.deleteMany({}, function(err3) { + console.log('Address TXs cleared.'); + Richlist.updateOne({coin: settings.coin}, { + received: [], + balance: [], + }, function(err3) { + Stats.updateOne({coin: settings.coin}, { + last: 0, + count: 0, + supply: 0 + }, function() { + console.log('index cleared (reindex)'); + }); + db.update_tx_db(settings.coin, 1, stats.count, stats.txes, settings.update_timeout, function(){ + db.update_richlist('received', function(){ + db.update_richlist('balance', function(){ + db.get_stats(settings.coin, function(nstats){ + console.log('reindex complete (block: %s)', nstats.last); + exit(); + }); }); }); }); @@ -180,112 +283,103 @@ is_locked(function (exists) { }); }); }); - }); - } else if (mode == 'check') { - db.update_tx_db(settings.coin, 1, stats.count, stats.txes, settings.check_timeout, function(){ - db.get_stats(settings.coin, function(nstats){ - console.log('check complete (block: %s)', nstats.last); - exit(); - }); - }); - } else if (mode == 'update') { - // Lookup the last block index - Tx.findOne({}, {blockindex:1}).sort({blockindex:-1}).limit(1).exec(function(err, data){ - var nLast = stats.last; - if (!err && data) { - // start from the last block index - nLast = data.blockindex; - } - - db.update_tx_db(settings.coin, nLast, stats.count, stats.txes, settings.update_timeout, function(){ - db.update_richlist('received', function(){ - db.update_richlist('balance', function(){ - db.get_stats(settings.coin, function(nstats){ - console.log('update complete (block: %s)', nstats.last); - exit(); - }); - }); + } else if (mode == 'check') { + console.log('starting check.. please wait..'); + db.update_tx_db(settings.coin, 1, stats.count, stats.txes, settings.check_timeout, function(){ + db.get_stats(settings.coin, function(nstats){ + console.log('check complete (block: %s)', nstats.last); + exit(); }); }); - }); - } else if (mode == 'reindex-rich') { - console.log('update started'); - db.update_tx_db(settings.coin, stats.last, stats.count, stats.txes, settings.check_timeout, function(){ - console.log('update finished'); - db.check_richlist(settings.coin, function(exists){ - if (exists == true) { - console.log('richlist entry found, deleting now..'); + } else if (mode == 'update') { + // Lookup the last block index + Tx.findOne({}, {blockindex:1}).sort({blockindex:-1}).limit(1).exec(function(err, data){ + var nLast = stats.last; + if (!err && data) { + // start from the last block index + nLast = data.blockindex; } - db.delete_richlist(settings.coin, function(deleted) { - if (deleted == true) { - console.log('richlist entry deleted'); - } - db.create_richlist(settings.coin, function() { - console.log('richlist created.'); - db.update_richlist('received', function(){ - console.log('richlist updated received.'); - db.update_richlist('balance', function(){ - console.log('richlist updated balance.'); - db.get_stats(settings.coin, function(nstats){ - console.log('update complete (block: %s)', nstats.last); - exit(); - }); + + db.update_tx_db(settings.coin, nLast, stats.count, stats.txes, settings.update_timeout, function(){ + db.update_richlist('received', function(){ + db.update_richlist('balance', function(){ + db.get_stats(settings.coin, function(nstats){ + console.log('update complete (block: %s)', nstats.last); + exit(); }); }); }); }); - }); - }); - } else if (mode == 'reindex-txcount') { - console.log('calculating tx count.. please wait..'); - // Resetting the transaction counter requires a single lookup on the txes collection to find all txes that have a positive or zero total and 1 or more vout - Tx.find({'total': {$gte: 0}, 'vout': { $gte: { $size: 1 }}}).countDocuments(function(err, count) { - console.log('found tx count: ' + count.toString()); - Stats.updateOne({coin: settings.coin}, { - txes: count - }, function() { - console.log('tx count update complete'); - exit(); }); - }); + } else if (mode == 'reindex-rich') { + console.log('check richlist'); + db.check_richlist(settings.coin, function(exists) { + if (exists) console.log('richlist entry found, deleting now..'); + db.delete_richlist(settings.coin, function(deleted) { + if (deleted) console.log('richlist entry deleted'); + db.create_richlist(settings.coin, function() { + console.log('richlist created.'); + db.update_richlist('received', function() { + console.log('richlist updated received.'); + db.update_richlist('balance', function() { + console.log('richlist update complete'); + exit(); + }); + }); + }); + }); + }); + } else if (mode == 'reindex-txcount') { + console.log('calculating tx count.. please wait..'); + // Resetting the transaction counter requires a single lookup on the txes collection to find all txes that have a positive or zero total and 1 or more vout + Tx.find({'total': {$gte: 0}, 'vout': { $gte: { $size: 1 }}}).countDocuments(function(err, count) { + console.log('found tx count: ' + count.toString()); + Stats.updateOne({coin: settings.coin}, { + txes: count + }, function() { + console.log('tx count update complete'); + exit(); + }); + }); + } + }); + } + }); + } else { + //update markets + var markets = settings.markets.enabled; + var complete = 0; + for (var x = 0; x < markets.length; x++) { + var market = markets[x]; + db.check_market(market, function(mkt, exists) { + if (exists) { + db.update_markets_db(mkt, function(err) { + if (!err) { + console.log('%s market data updated successfully.', mkt); + complete++; + if (complete == markets.length) + get_last_usd_price(); + } else { + console.log('%s: %s', mkt, err); + complete++; + if (complete == markets.length) + get_last_usd_price(); + } + }); + } else { + console.log('error: entry for %s does not exists in markets db.', mkt); + complete++; + if (complete == markets.length) + get_last_usd_price(); } }); } - }); - } else { - //update markets - var markets = settings.markets.enabled; - var complete = 0; - for (var x = 0; x < markets.length; x++) { - var market = markets[x]; - db.check_market(market, function(mkt, exists) { - if (exists) { - db.update_markets_db(mkt, function(err) { - if (!err) { - console.log('%s market data updated successfully.', mkt); - complete++; - if (complete == markets.length) - get_last_usd_price(); - } else { - console.log('%s: %s', mkt, err); - complete++; - if (complete == markets.length) - get_last_usd_price(); - } - }); - } else { - console.log('error: entry for %s does not exists in markets db.', mkt); - complete++; - if (complete == markets.length) - get_last_usd_price(); - } - }); } - } + }); }); - }); - } -}); + } + }); +} function get_last_usd_price() { // Get the last usd price for coinstats diff --git a/scripts/sync.sh b/scripts/sync.sh new file mode 100644 index 0000000..345a7f5 --- /dev/null +++ b/scripts/sync.sh @@ -0,0 +1,120 @@ +#!/bin/bash +readonly EXPLORER_PATH=$(dirname $(dirname $(readlink -f "$0"))) +NODE_PATH="" +MODE="" +# Check if parameters were passed into the script +if [ -n "${1}" ]; then + # At least one parameter has been passed in + case ${1} in + "update") + # Index update + MODE="index update" + ;; + "check") + # Index check + MODE="index check" + ;; + "reindex") + # Index reindex + MODE="index reindex" + ;; + "reindex-rich") + # Index reindex-rich + MODE="index reindex-rich" + ;; + "reindex-txcount") + # Index reindex-txcount + MODE="index reindex-txcount" + ;; + "market") + # Market update + MODE="market" + ;; + "peers") + # Peers update + MODE="peers" + ;; + *) + # Check if this is a file that exists on the filesystem + if [ -f ${1} ]; then + # The file exists. Assume this is the path to node + NODE_PATH="${1}" + fi + ;; + esac + # Check if the mode is already set + if [ -z "${MODE}" ]; then + # Mode is not set so check if the next parameter exists + if [ -n "${2}" ]; then + # Determine which mode this last parameter is + case ${2} in + "update") + # Index update + MODE="index update" + ;; + "check") + # Index check + MODE="index check" + ;; + "reindex") + # Index reindex + MODE="index reindex" + ;; + "reindex-rich") + # Index reindex-rich + MODE="index reindex-rich" + ;; + "reindex-txcount") + # Index reindex-txcount + MODE="index reindex-txcount" + ;; + "market") + # Market update + MODE="market" + ;; + "peers") + # Peers update + MODE="peers" + ;; + esac + elif [ -n "${NODE_PATH}" ]; then + # Node path was specified but no mode, so default to 'index update' mode + MODE="index update" + fi + fi +else + # No parameters specified so default to 'index update' mode + MODE="index update" +fi +# Check if the mode is set +if [ -n "${MODE}" ]; then + # Mode is set + # Check if the desired mode requires a lock + if [ "${MODE}" != "peers" ]; then + # A lock is required + # Check if the script is already running (tmp/index.pid file already exists) + if [ -f "${EXPLORER_PATH}/tmp/index.pid" ]; then + # The tmp/index.pid file exists. Check if the process is actually still running + ps -p `cat ${EXPLORER_PATH}/tmp/index.pid` > /dev/null + if [ $? -eq 0 ]; then + # Script is running so the data is locked and we must exit now and try again later + echo "Script already running.." + exit 1 + else + # Script is not actually running so we can delete the lock file + rm "${EXPLORER_PATH}/tmp/index.pid" + fi + fi + fi + # Check if the node path was specified + if [ -z "${NODE_PATH}" ]; then + # Node path not specified so lookup using the 'which' cmd + eval "cd ${EXPLORER_PATH} && $(which node) scripts/sync.js ${MODE}" + else + # Node path specified + eval "cd ${EXPLORER_PATH} && ${NODE_PATH} scripts/sync.js ${MODE}" + fi +else + # Mode not set so load the sync script without specifying the mode to return the usage options + eval "cd ${EXPLORER_PATH} && $(which node) scripts/sync.js" +fi \ No newline at end of file