Improved (sync/backup) scripts + misc updates
-Added locks to all sync processes (blocks, markets, peers, masternodes) as well as "create backup", "restore backup" and "delete database" functions. This helps prevent problems with syncing data while a backup is in progress for example -The code to initialize certain database collections on startup was moved into database.js and is now called from restore_backup.js and delete_database.js. This effectively allows the database to be deleted or restored to a completely different backup while the explorer is still running -Lock functions (create_lock, remove_lock, is_locked) were moved into explorer.js for better reusability and rewriten to be synchronous -is_locked function now accepts an array of lock files to be able to check for multiple locks in a single call -remove_sync_message() function was moved into database.js so that restore_backup.js and delete_database.js can also check for and remove the sync msg if it exists -Useful Scripts section updated in the README to make it clear that the explorer no longer needs to be stopped for these scripts to be run -Most if not all log messages now start with a capitlal letter
This commit is contained in:
+201
-42
@@ -212,13 +212,102 @@ function hex_to_ascii(hex) {
|
||||
return str;
|
||||
}
|
||||
|
||||
function init_markets(cb) {
|
||||
// check if markets/exchanges feature is enabled
|
||||
if (settings.markets_page.enabled == true) {
|
||||
var marketCounter = 0;
|
||||
|
||||
// loop through and test all exchanges defined in the settings.json file
|
||||
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 exchange is installed/supported
|
||||
if (module.exports.fs.existsSync('./lib/markets/' + key + '.js')) {
|
||||
var pairCounter = 0;
|
||||
|
||||
// loop through all trading pairs
|
||||
settings.markets_page.exchanges[key].trading_pairs.forEach(function (pair_key, pair_index, pair_map) {
|
||||
// split the pair data
|
||||
var split_pair = pair_key.split('/');
|
||||
// check if this is a valid trading pair
|
||||
if (split_pair.length == 2) {
|
||||
// lookup the exchange in the market collection
|
||||
module.exports.check_market(key, split_pair[0], split_pair[1], function(market, exists) {
|
||||
// check if exchange trading pair exists in the market collection
|
||||
if (!exists) {
|
||||
// exchange doesn't exist in the market collection so add a default definition now
|
||||
console.log('No %s: %s entry found. Creating new entry now..', market, pair_key);
|
||||
module.exports.create_market(split_pair[0], split_pair[1], market, function() {
|
||||
pairCounter++;
|
||||
|
||||
// check if all pairs have been tested
|
||||
if (pairCounter == settings.markets_page.exchanges[key].trading_pairs.length)
|
||||
marketCounter++;
|
||||
|
||||
// check if all exchanges have been tested
|
||||
if (marketCounter == Object.keys(settings.markets_page.exchanges).length) {
|
||||
// finished initializing markets
|
||||
return cb();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
pairCounter++;
|
||||
|
||||
// check if all pairs have been tested
|
||||
if (pairCounter == settings.markets_page.exchanges[key].trading_pairs.length)
|
||||
marketCounter++;
|
||||
}
|
||||
|
||||
// check if all exchanges have been tested
|
||||
if (marketCounter == Object.keys(settings.markets_page.exchanges).length) {
|
||||
// finished initializing markets
|
||||
return cb();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
pairCounter++;
|
||||
|
||||
// check if all pairs have been tested
|
||||
if (pairCounter == settings.markets_page.exchanges[key].trading_pairs.length)
|
||||
marketCounter++;
|
||||
}
|
||||
});
|
||||
} else
|
||||
marketCounter++;
|
||||
} else
|
||||
marketCounter++;
|
||||
});
|
||||
|
||||
// check if all exchanges have been tested
|
||||
if (marketCounter == Object.keys(settings.markets_page.exchanges).length) {
|
||||
// finished initializing markets
|
||||
return cb();
|
||||
}
|
||||
} else
|
||||
return cb();
|
||||
}
|
||||
|
||||
function init_heavy(cb) {
|
||||
if (settings.blockchain_specific.heavycoin.enabled == true) {
|
||||
module.exports.check_heavy(settings.coin.name, function(exists) {
|
||||
if (exists == false) {
|
||||
console.log('No heavycoin entry found. Creating new entry now..');
|
||||
module.exports.create_heavy(settings.coin.name, function() {
|
||||
return cb();
|
||||
});
|
||||
} else
|
||||
return cb();
|
||||
});
|
||||
} else
|
||||
return cb();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
// initialize DB
|
||||
connect: function(database, cb) {
|
||||
mongoose.connect(database, function(err) {
|
||||
if (err) {
|
||||
console.log('Unable to connect to database: %s', database);
|
||||
console.log('Aborting');
|
||||
console.log('Error: Unable to connect to database: %s', database);
|
||||
process.exit(999);
|
||||
}
|
||||
|
||||
@@ -377,21 +466,25 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
create_stats: function(coin, cb) {
|
||||
var newStats = new Stats({
|
||||
coin: coin,
|
||||
last: 0
|
||||
});
|
||||
create_stats: function(coin, skip, cb) {
|
||||
// check if stats need to be created
|
||||
if (!skip) {
|
||||
var newStats = new Stats({
|
||||
coin: coin,
|
||||
last: 0
|
||||
});
|
||||
|
||||
newStats.save(function(err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return cb();
|
||||
} else {
|
||||
console.log("initial stats entry created for %s", coin);
|
||||
return cb();
|
||||
}
|
||||
});
|
||||
newStats.save(function(err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return cb();
|
||||
} else {
|
||||
console.log("Initial stats entry created for %s", coin);
|
||||
return cb();
|
||||
}
|
||||
});
|
||||
} else
|
||||
return cb();
|
||||
},
|
||||
|
||||
get_address: function(hash, caseSensitive, cb) {
|
||||
@@ -630,7 +723,7 @@ module.exports = {
|
||||
console.log(err);
|
||||
return cb();
|
||||
} else {
|
||||
console.log("initial market entry created for %s: %s", market, coin_symbol +'/' + pair_symbol);
|
||||
console.log("Initial market entry created for %s: %s", market, coin_symbol +'/' + pair_symbol);
|
||||
return cb();
|
||||
}
|
||||
});
|
||||
@@ -653,21 +746,25 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
// creates initial richlist entry in database; called on first launch of explorer
|
||||
create_richlist: function(coin, cb) {
|
||||
var newRichlist = new Richlist({
|
||||
coin: coin
|
||||
});
|
||||
// creates initial richlist entry in database; called on first launch of explorer + after restore or delete database
|
||||
create_richlist: function(coin, skip, cb) {
|
||||
// check if stats need to be created
|
||||
if (!skip) {
|
||||
var newRichlist = new Richlist({
|
||||
coin: coin
|
||||
});
|
||||
|
||||
newRichlist.save(function(err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return cb();
|
||||
} else {
|
||||
console.log("initial richlist entry created for %s", coin);
|
||||
return cb();
|
||||
}
|
||||
});
|
||||
newRichlist.save(function(err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return cb();
|
||||
} else {
|
||||
console.log("Initial richlist entry created for %s", coin);
|
||||
return cb();
|
||||
}
|
||||
});
|
||||
} else
|
||||
return cb();
|
||||
},
|
||||
|
||||
// drops richlist data for given coin
|
||||
@@ -700,7 +797,7 @@ module.exports = {
|
||||
console.log(err);
|
||||
return cb();
|
||||
} else {
|
||||
console.log("initial heavycoin entry created for %s", coin);
|
||||
console.log("Initial heavycoin entry created for %s", coin);
|
||||
return cb();
|
||||
}
|
||||
});
|
||||
@@ -812,7 +909,7 @@ module.exports = {
|
||||
}, function() {
|
||||
// update reward_last_updated value
|
||||
module.exports.update_last_updated_stats(settings.coin.name, { reward_last_updated: Math.floor(new Date() / 1000) }, function (new_cb) {
|
||||
console.log('heavycoin update complete');
|
||||
console.log('Heavycoin update complete');
|
||||
return cb();
|
||||
});
|
||||
});
|
||||
@@ -849,7 +946,7 @@ module.exports = {
|
||||
newNetworkHistory.save(function(err) {
|
||||
// check for errors
|
||||
if (err) {
|
||||
console.log('error updating network history: ' + err);
|
||||
console.log('Error updating network history: ' + err);
|
||||
return cb();
|
||||
} else {
|
||||
// get the count of network history records
|
||||
@@ -866,12 +963,12 @@ module.exports = {
|
||||
|
||||
// delete old network history records
|
||||
NetworkHistory.deleteMany({blockindex: {$in: ids}}, function(err) {
|
||||
console.log('network history update complete');
|
||||
console.log('Network history update complete');
|
||||
return cb();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
console.log('network history update complete');
|
||||
console.log('Network history update complete');
|
||||
return cb();
|
||||
}
|
||||
});
|
||||
@@ -977,7 +1074,7 @@ module.exports = {
|
||||
lib.get_blockcount( function (count) {
|
||||
// check to ensure count is a positive number
|
||||
if (!count || (count != null && typeof count === 'number' && count < 0)) {
|
||||
console.log('Unable to connect to explorer API');
|
||||
console.log('Error: Unable to connect to explorer API');
|
||||
|
||||
return cb(false);
|
||||
}
|
||||
@@ -993,7 +1090,7 @@ module.exports = {
|
||||
connections: (connections ? connections : 0)
|
||||
}, function(err) {
|
||||
if (err)
|
||||
console.log("Error during Stats Update: ", err);
|
||||
console.log("Error during stats update: %s", err);
|
||||
|
||||
return cb({
|
||||
coin: coin,
|
||||
@@ -1005,7 +1102,7 @@ module.exports = {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
console.log("Error during Stats Update: ", (err ? err : 'cannot find stats collection'));
|
||||
console.log("Error during stats update: %s", (err ? err : 'Cannot find stats collection'));
|
||||
return cb(false);
|
||||
}
|
||||
});
|
||||
@@ -1038,7 +1135,7 @@ module.exports = {
|
||||
txes: txes
|
||||
}, function() {});
|
||||
} else if (check_only) {
|
||||
console.log('checking block ' + block_height + '...');
|
||||
console.log('Checking block ' + block_height + '...');
|
||||
}
|
||||
|
||||
lib.get_blockhash(block_height, function(blockhash) {
|
||||
@@ -1077,7 +1174,7 @@ module.exports = {
|
||||
}, timeout);
|
||||
});
|
||||
} else {
|
||||
console.log('block not found: %s', blockhash);
|
||||
console.log('Block not found: %s', blockhash);
|
||||
|
||||
setTimeout( function() {
|
||||
next_block();
|
||||
@@ -1203,7 +1300,7 @@ module.exports = {
|
||||
// add or update a single masternode
|
||||
add_update_masternode(masternode, add, cb) {
|
||||
if (masternode.proTxHash == null && masternode.txhash == null) {
|
||||
console.log('Masternode Update - TXid is missing');
|
||||
console.log('Masternode update error: TXid is missing');
|
||||
|
||||
return cb(false);
|
||||
} else {
|
||||
@@ -1444,5 +1541,67 @@ module.exports = {
|
||||
});
|
||||
},
|
||||
|
||||
initialize_data_startup: function(cb) {
|
||||
console.log('Initializing database.. Please wait...');
|
||||
|
||||
// check if stats collection is initialized
|
||||
module.exports.check_stats(settings.coin.name, function(stats_exists) {
|
||||
var skip = true;
|
||||
|
||||
// determine if stats collection already exists
|
||||
if (stats_exists == false) {
|
||||
console.log('No stats entry found. Creating new entry now..');
|
||||
skip = false;
|
||||
}
|
||||
|
||||
// initialize the stats collection
|
||||
module.exports.create_stats(settings.coin.name, skip, function() {
|
||||
// check and initialize the markets collection
|
||||
init_markets(function() {
|
||||
// add new field(s) to tx collection if missing
|
||||
module.exports.check_txes(function(txes_exists) {
|
||||
// add new field(s) to masternode collection if missing
|
||||
module.exports.check_masternodes(function(masternodes_exists) {
|
||||
// check if richlist collection is initialized
|
||||
module.exports.check_richlist(settings.coin.name, function(richlist_exists) {
|
||||
skip = true;
|
||||
|
||||
// determine if richlist collection already exists
|
||||
if (richlist_exists == false) {
|
||||
console.log('No richlist entry found. Creating new entry now..');
|
||||
skip = false;
|
||||
}
|
||||
|
||||
// initialize the richlist collection
|
||||
module.exports.create_richlist(settings.coin.name, skip, function() {
|
||||
// check and initialize the heavycoin collection
|
||||
init_heavy(function() {
|
||||
// finished initializing startup data
|
||||
console.log('Database initialization complete');
|
||||
return cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
remove_sync_message: function() {
|
||||
var filePath = './tmp/show_sync_message.tmp';
|
||||
|
||||
// Check if the show sync stub file exists
|
||||
if (fs.existsSync(filePath)) {
|
||||
// File exists, so delete it now
|
||||
try {
|
||||
fs.unlinkSync(filePath);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
fs: fs
|
||||
};
|
||||
@@ -1315,5 +1315,93 @@ module.exports = {
|
||||
}, function() {
|
||||
return cb(arr_vin, tx_type);
|
||||
});
|
||||
},
|
||||
|
||||
create_lock: function(lock) {
|
||||
const fs = require('fs');
|
||||
var fname = './tmp/' + lock + '.pid';
|
||||
|
||||
try {
|
||||
fs.appendFileSync(fname, process.pid.toString());
|
||||
return true;
|
||||
} catch(err) {
|
||||
console.log("Error: Unable to remove lock: %s", fname);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
remove_lock: function(lock) {
|
||||
const fs = require('fs');
|
||||
var fname = './tmp/' + lock + '.pid';
|
||||
|
||||
try {
|
||||
fs.unlinkSync(fname);
|
||||
return true;
|
||||
} catch(err) {
|
||||
console.log("Error: Unable to remove lock: %s", fname);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
is_locked: function(lock_array) {
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
var retVal = false;
|
||||
|
||||
// loop through all lock files that need to be checked
|
||||
for (var i = 0; i < lock_array.length; i++) {
|
||||
var pidFile = path.join(path.dirname(__dirname), 'tmp', `${lock_array[i]}.pid`);
|
||||
|
||||
// check if the script is already running (tmp/file.pid file already exists)
|
||||
if (fs.existsSync(pidFile)) {
|
||||
const { execSync } = require('child_process');
|
||||
var deactivateLock = false;
|
||||
|
||||
// the pid file exists
|
||||
// determine the operating system
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
// windows
|
||||
// run a cmd that will determine if the lock should still be active
|
||||
var cmdResult = execSync(`tasklist /FI "PID eq ${fs.readFileSync(pidFile).toString()}"`);
|
||||
|
||||
// check if the process that created the lock is actually still running (crude check by testing for # of carriage returns or node.exe process running, but should work universally across different systems and languages)
|
||||
if (cmdResult.toString().split('\n').length < 4 || cmdResult.toString().toLowerCase().indexOf('\nnode.exe') == -1) {
|
||||
// lock should be deactivated
|
||||
deactivateLock = true;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
// linux or other
|
||||
// run a cmd that will determine if the lock should still be active
|
||||
|
||||
try {
|
||||
var cmdResult = execSync('ps -p `cat ' + pidFile + '` > /dev/null');
|
||||
} catch (err) {
|
||||
// if an error occurs, the process is NOT running and therefore the lock should be deactivated
|
||||
deactivateLock = true;
|
||||
}
|
||||
}
|
||||
|
||||
// check if the lock should be deactivated
|
||||
if (deactivateLock) {
|
||||
// script is not actually running so the lock file can be deleted
|
||||
try {
|
||||
fs.rmSync(pidFile);
|
||||
} catch(err) {
|
||||
console.log(`Failed to delete lock file ${pidFile}: ${err}`);
|
||||
}
|
||||
} else {
|
||||
// script is running
|
||||
console.log(`${lock_array[i]} script is running..`);
|
||||
retVal = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user