Publish Nerbus source snapshot and build documentation
This commit is contained in:
commit
76cccceca7
198 files changed
+338574
No files matched your search
@@ -0,0 +1,235 @@
|
||||
const mongoose = require('mongoose');
|
||||
const Address = require('../models/address');
|
||||
const Tx = require('../models/tx');
|
||||
const blkSync = require('../lib/block_sync');
|
||||
const settings = require('../lib/settings');
|
||||
const resumeSync = process.argv[2] == '1';
|
||||
|
||||
let dbString = `mongodb://${settings.benchmark.address}:${settings.benchmark.port}/admin`
|
||||
|
||||
// prevent stopping of the sync script to be able to gracefully shut down
|
||||
process.on('SIGINT', () => {
|
||||
if (!blkSync.getStackSizeErrorId())
|
||||
console.log(`${settings.localization.stopping_sync_process}.. ${settings.localization.please_wait}..`);
|
||||
|
||||
blkSync.setStopSync(true);
|
||||
});
|
||||
|
||||
// prevent killing of the sync script to be able to gracefully shut down
|
||||
process.on('SIGTERM', () => {
|
||||
if (!blkSync.getStackSizeErrorId())
|
||||
console.log(`${settings.localization.stopping_sync_process}.. ${settings.localization.please_wait}..`);
|
||||
|
||||
blkSync.setStopSync(true);
|
||||
});
|
||||
|
||||
function exit(exitCode) {
|
||||
mongoose.disconnect();
|
||||
process.exit(exitCode);
|
||||
}
|
||||
|
||||
function check_user_exists(exists, cb) {
|
||||
// check if the user exists
|
||||
if (exists) {
|
||||
// user already exists
|
||||
return cb();
|
||||
} else {
|
||||
// user does not exist so create it now
|
||||
mongoose.connection.client.db(settings.benchmark.database).command({
|
||||
createUser: settings.benchmark.user,
|
||||
pwd: settings.benchmark.password,
|
||||
roles: [
|
||||
{
|
||||
role: 'readWrite',
|
||||
db: settings.benchmark.database
|
||||
}
|
||||
]
|
||||
})
|
||||
.then(() => {
|
||||
console.log('User created successfully');
|
||||
return cb();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error creating new user:', error);
|
||||
exit(2);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function check_create_user(cb) {
|
||||
// check if the benchmark database should be checked for the correct user
|
||||
if (settings.benchmark.auto_add_user) {
|
||||
// connect to the admin database without a username/password
|
||||
mongoose.connect(dbString).then(() => {
|
||||
// determine if the user already exists in the target database
|
||||
mongoose.connection.db
|
||||
.command({
|
||||
usersInfo: {
|
||||
user: settings.benchmark.user,
|
||||
db: settings.benchmark.database
|
||||
}
|
||||
})
|
||||
.then((userInfo) => {
|
||||
// check if the user already exists
|
||||
check_user_exists(userInfo.users.length > 0, function() {
|
||||
// disconnect the current database connection
|
||||
mongoose.disconnect().then(() => {
|
||||
// finished checking the benchmark database user
|
||||
return cb();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Error disconnecting from database:', err);
|
||||
exit(2);
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Error checking if user exists:', err);
|
||||
exit(2);
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('Error: Unable to connect to database: %s', dbString);
|
||||
exit(999);
|
||||
});
|
||||
} else
|
||||
return cb();
|
||||
}
|
||||
|
||||
function initialize_data_startup(cb) {
|
||||
console.log(`${settings.localization.initializing_database}.. ${settings.localization.please_wait}..`);
|
||||
|
||||
const db = require('../lib/database');
|
||||
|
||||
// check if stats collection is initialized
|
||||
db.check_stats(settings.coin.name, function(stats_exists) {
|
||||
let skip = true;
|
||||
|
||||
// determine if stats collection already exists
|
||||
if (stats_exists == false) {
|
||||
console.log(`${settings.localization.creating_initial_entry.replace('{1}', 'stats')}.. ${settings.localization.please_wait}..`);
|
||||
skip = false;
|
||||
}
|
||||
|
||||
// initialize the stats collection
|
||||
db.create_stats(settings.coin.name, skip, function() {
|
||||
// get the stats object from the database
|
||||
db.get_stats(settings.coin.name, function(stats) {
|
||||
// finished initializing startup data
|
||||
console.log('Database initialization complete');
|
||||
return cb(stats);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function delete_txes(cb) {
|
||||
// check if the benchmark sync is being resumed
|
||||
if (resumeSync) {
|
||||
// do not delete the list of txes for a resume sync
|
||||
return cb();
|
||||
} else {
|
||||
// delete all previous transaction records from the benchmark database
|
||||
Tx.deleteMany({}).then(() => {
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function delete_addresses(cb) {
|
||||
// check if the benchmark sync is being resumed
|
||||
if (resumeSync) {
|
||||
// do not delete the list of addresses for a resume sync
|
||||
return cb();
|
||||
} else {
|
||||
// delete all previous address records from the benchmark database
|
||||
Address.deleteMany({}).then(() => {
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function delete_stats(cb) {
|
||||
// check if the benchmark sync is being resumed
|
||||
if (resumeSync) {
|
||||
// do not delete the database stats for a resume sync
|
||||
return cb();
|
||||
} else {
|
||||
const Stats = require('../models/stats');
|
||||
|
||||
// delete all previous stat records from the benchmark database
|
||||
Stats.deleteMany({}).then(() => {
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`${settings.localization.script_launched}: ${process.pid}`);
|
||||
|
||||
mongoose.set('strictQuery', true);
|
||||
mongoose.set('updatePipeline', true);
|
||||
|
||||
// ensure the benchmark database user exists
|
||||
check_create_user(function() {
|
||||
// update db string to connect to benchmark database
|
||||
dbString = 'mongodb://' + encodeURIComponent(settings.benchmark.user);
|
||||
dbString = dbString + ':' + encodeURIComponent(settings.benchmark.password);
|
||||
dbString = dbString + '@' + settings.benchmark.address;
|
||||
dbString = dbString + ':' + settings.benchmark.port;
|
||||
dbString = dbString + '/' + settings.benchmark.database;
|
||||
|
||||
// connect to the benchmark database
|
||||
mongoose.connect(dbString).then(() => {
|
||||
// delete all previous transaction records from the benchmark database
|
||||
delete_txes(function() {
|
||||
// delete all previous address records from the benchmark database
|
||||
delete_addresses(function() {
|
||||
// delete all previous stat records from the benchmark database
|
||||
delete_stats(function() {
|
||||
// initialize the benchmark database
|
||||
initialize_data_startup(function(stats) {
|
||||
// get the last synced block index value
|
||||
const last = (stats.last ? stats.last : 0);
|
||||
|
||||
// get starting timestamp
|
||||
const s_timer = new Date().getTime();
|
||||
|
||||
// start the block sync
|
||||
blkSync.update_tx_db(settings.coin.name, last, settings.benchmark.block_to_sync, stats.txes, settings.sync.update_timeout, false, function() {
|
||||
// get ending timestamp
|
||||
const e_timer = new Date().getTime();
|
||||
|
||||
// get count of transactions
|
||||
Tx.countDocuments({}).then((txcount) => {
|
||||
// get count of addresses
|
||||
Address.countDocuments({}).then((acount) => {
|
||||
// check if the script stopped prematurely
|
||||
if (blkSync.getStopSync())
|
||||
console.log('Block sync was stopped prematurely');
|
||||
|
||||
// output final benchmark stats
|
||||
console.log({
|
||||
tx_count: txcount,
|
||||
address_count: acount,
|
||||
seconds: (e_timer - s_timer) / 1000,
|
||||
});
|
||||
|
||||
// check if the sync needed to be resumed
|
||||
if (resumeSync) {
|
||||
// output a warning msg
|
||||
console.log(`\n${settings.localization.ex_warning}: The sync ran out of memory during processing and therefore the run time was affected. It is recommended to re-run the benchmark again using a larger stack size such as 25000 or higher with the cmd "node --stack-size=25000 scripts/benchmark.js" to help ensure an accurate benchmark time.`);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}).catch((err) => {
|
||||
console.log('Error: Unable to connect to database: %s', dbString);
|
||||
exit(999);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,86 @@
|
||||
const fs = require('fs');
|
||||
const css_path = './public/css/';
|
||||
const theme_selector_filename = '_theme-selector.scss';
|
||||
const style_filename = 'style.scss';
|
||||
const style_min_filename = 'style.min.css'
|
||||
const custom_filename = 'custom.scss';
|
||||
const custom_min_filename = 'custom.min.css'
|
||||
const theme_selector_template_text = `$theme-name: "replace";`;
|
||||
const settings = require('../lib/settings');
|
||||
let compile_theme_css = false;
|
||||
let compile_custom_css = false;
|
||||
let theme_name = '';
|
||||
|
||||
// check if the theme selector file exists
|
||||
if (!fs.existsSync(`${css_path}${theme_selector_filename}`)) {
|
||||
// theme file doesn't exist, so it is necessary to compile the css
|
||||
compile_theme_css = true;
|
||||
} else {
|
||||
const last_theme = fs.readFileSync(`${css_path}${theme_selector_filename}`, 'utf-8');
|
||||
|
||||
theme_name = settings.shared_pages.theme;
|
||||
|
||||
// check if the theme name has changed since last run
|
||||
if (theme_selector_template_text.replace('replace', theme_name) != last_theme) {
|
||||
// theme name has changed, so it is necessary to compile the css
|
||||
compile_theme_css = true;
|
||||
} else if (!fs.existsSync(`${css_path}${style_min_filename}`)) {
|
||||
// the minified style file does not exist, so it is necessary to compile the css
|
||||
compile_theme_css = true;
|
||||
} else {
|
||||
const style_stats = fs.statSync(`${css_path}${style_filename}`);
|
||||
const style_min_stats = fs.statSync(`${css_path}${style_min_filename}`);
|
||||
|
||||
// check if the style file was last modified after the minified style file
|
||||
if (style_stats.mtime > style_min_stats.mtime) {
|
||||
// style file was modified since the style min file was created, so it is necessary to compile the css
|
||||
compile_theme_css = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if the minified custom file exists
|
||||
if (!fs.existsSync(`${css_path}${custom_min_filename}`)) {
|
||||
// the minified custom file does not exist, so it is necessary to compile the css
|
||||
compile_custom_css = true;
|
||||
} else {
|
||||
const custom_stats = fs.statSync(`${css_path}${custom_filename}`);
|
||||
const custom_min_stats = fs.statSync(`${css_path}${custom_min_filename}`);
|
||||
|
||||
// check if the custom file was last modified after the minified custom file
|
||||
if (custom_stats.mtime > custom_min_stats.mtime) {
|
||||
// custom file was modified since the custom min file was created, so it is necessary to compile the css
|
||||
compile_custom_css = true;
|
||||
}
|
||||
}
|
||||
|
||||
// check if it necessary to compile any css files
|
||||
if (compile_theme_css || compile_custom_css) {
|
||||
console.log(`${settings.localization.compiling_css}.. ${settings.localization.please_wait}..`);
|
||||
|
||||
const sass = require('sass');
|
||||
|
||||
// check if the theme css should be compiled
|
||||
if (compile_theme_css) {
|
||||
// ensure the selected theme is properly installed
|
||||
fs.writeFileSync(`${css_path}${theme_selector_filename}`, `$theme-name: "${theme_name}";`, 'utf-8');
|
||||
|
||||
// generate minified css from style.scss file
|
||||
const minified = sass.compile(`${css_path}${style_filename}`, {style: 'compressed'});
|
||||
|
||||
// save the minified css to file
|
||||
fs.writeFileSync(`${css_path}${style_min_filename}`, minified.css, 'utf-8');
|
||||
}
|
||||
|
||||
// check if the custom css should be compiled
|
||||
if (compile_custom_css) {
|
||||
// generate minified css from custom.scss file
|
||||
const custom_minified = sass.compile(`${css_path}${custom_filename}`, {style: 'compressed'});
|
||||
|
||||
// save the minified css to file
|
||||
fs.writeFileSync(`${css_path}${custom_min_filename}`, custom_minified.css, 'utf-8');
|
||||
}
|
||||
}
|
||||
|
||||
// finished compiling css
|
||||
process.exit(0);
|
||||
@@ -0,0 +1,167 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const lib = require('../lib/explorer');
|
||||
const archiveSuffix = '.bak';
|
||||
const backupLockName = 'backup';
|
||||
const settings = require('../lib/settings');
|
||||
let backupPath = path.join(path.dirname(__dirname), 'backups');
|
||||
let backupFilename;
|
||||
let singleCollection = '';
|
||||
let lockCreated = false;
|
||||
|
||||
// exit function used to cleanup lock before finishing script
|
||||
function exit(exitCode) {
|
||||
// only remove backup lock if it was created in this session
|
||||
if (!lockCreated || lib.remove_lock(backupLockName) == true) {
|
||||
// clean exit with previous exit code
|
||||
process.exit(exitCode);
|
||||
} else {
|
||||
// error removing lock
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// verify that the collection exists
|
||||
function verify_collection_exists(cb) {
|
||||
// check if the backup will be for a single collection
|
||||
if (singleCollection != null && singleCollection != '') {
|
||||
const mongoose = require('mongoose');
|
||||
const dbString = `mongodb://${encodeURIComponent(settings.dbsettings.user)}:${encodeURIComponent(settings.dbsettings.password)}@${settings.dbsettings.address}:${settings.dbsettings.port}/${settings.dbsettings.database}`;
|
||||
|
||||
console.log('Connecting to database..');
|
||||
|
||||
mongoose.set('strictQuery', true);
|
||||
mongoose.set('updatePipeline', true);
|
||||
|
||||
// connect to mongo database
|
||||
mongoose.connect(dbString).then(() => {
|
||||
// lookup the collection in the list of collections
|
||||
mongoose.connection.db.listCollections({ name: singleCollection }).toArray().then((collections) => {
|
||||
// check if the collection exists
|
||||
if (collections.length > 0) {
|
||||
// collection exists
|
||||
return cb(false);
|
||||
} else {
|
||||
// collection not found
|
||||
return cb(true);
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
return cb(true);
|
||||
});
|
||||
}).catch((err) => {
|
||||
console.log('Error: Unable to connect to database: %s', err);
|
||||
exit(999);
|
||||
return cb(true);
|
||||
});
|
||||
} else
|
||||
return cb(false);
|
||||
}
|
||||
|
||||
// check if a backup filename was passed into the script
|
||||
if (process.argv[2] != null && process.argv[2] != '') {
|
||||
// use the backup filename passed into this script
|
||||
backupFilename = process.argv[2];
|
||||
} else {
|
||||
const systemDate = new Date();
|
||||
const monthName = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
||||
|
||||
// no backup filename passed in. use todays date as the backup filename
|
||||
backupFilename = `${systemDate.getFullYear()}-${monthName[systemDate.getMonth()]}-${systemDate.getDate()}`;
|
||||
}
|
||||
|
||||
// check if a collection name was passed into the script
|
||||
if (process.argv[3] != null && process.argv[3] != '') {
|
||||
// save the collection name to a variable for later use
|
||||
singleCollection = process.argv[3];
|
||||
}
|
||||
|
||||
// check if backup filename has the archive suffix already
|
||||
if (backupFilename.endsWith(archiveSuffix)) {
|
||||
// remove the archive suffix from the backup filename
|
||||
backupFilename = backupFilename.substring(0, backupFilename.length - archiveSuffix.length);
|
||||
}
|
||||
|
||||
// check if the backup filename already has a path
|
||||
if (path.isAbsolute(backupFilename)) {
|
||||
// the backup filename is a full path
|
||||
// split out the path and filename
|
||||
backupPath = path.dirname(backupFilename);
|
||||
backupFilename = path.basename(backupFilename);
|
||||
}
|
||||
|
||||
// check if the backup directory exists
|
||||
if (!fs.existsSync(backupPath)) {
|
||||
// attempt to create the directory
|
||||
fs.mkdirSync(backupPath);
|
||||
}
|
||||
|
||||
// check if backup file already exists
|
||||
if (!fs.existsSync(path.join(backupPath, `${backupFilename}${archiveSuffix}`))) {
|
||||
// check if the "create backup" process is already running
|
||||
if (lib.is_locked([backupLockName]) == false) {
|
||||
// create a new backup lock before checking the rest of the locks to minimize problems with running scripts at the same time
|
||||
lib.create_lock(backupLockName);
|
||||
|
||||
// ensure the lock will be deleted on exit
|
||||
lockCreated = true;
|
||||
|
||||
// check all other possible locks since backups should not run at the same time that data is being changed
|
||||
if (lib.is_locked(['restore', 'delete', 'index', 'markets', 'peers', 'masternodes', 'plugin']) == false) {
|
||||
// check if the collection name exists
|
||||
verify_collection_exists(function(collection_error) {
|
||||
// check if there was an error finding the collection by name
|
||||
if (!collection_error) {
|
||||
// all tests passed. OK to run backup
|
||||
console.log(`${settings.localization.script_launched }: ${process.pid}`);
|
||||
|
||||
const { exec } = require('child_process');
|
||||
|
||||
// execute backup
|
||||
const backupProcess = exec(`mongodump --host="${settings.dbsettings.address}" --port="${settings.dbsettings.port}" --username="${settings.dbsettings.user}" --password="${settings.dbsettings.password}" --db="${settings.dbsettings.database}" --archive="${path.join(backupPath, backupFilename + archiveSuffix)}" --gzip${singleCollection == null || singleCollection == '' ? '' : ` --collection ${singleCollection}`}`);
|
||||
|
||||
backupProcess.stdout.on('data', (data) => {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
backupProcess.stderr.on('data', (data) => {
|
||||
console.log(Buffer.from(data).toString());
|
||||
});
|
||||
|
||||
backupProcess.on('error', (error) => {
|
||||
console.log(error);
|
||||
});
|
||||
|
||||
backupProcess.on('exit', (code, signal) => {
|
||||
if (code) {
|
||||
console.log(`Process exit with code: ${code}`);
|
||||
exit(code);
|
||||
} else if (signal) {
|
||||
console.log(`Process killed with signal: ${signal}`);
|
||||
exit(1);
|
||||
} else {
|
||||
console.log(`Backup saved successfully to ${path.join(backupPath, backupFilename + archiveSuffix)}`);
|
||||
exit(0);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// the collection does not exist
|
||||
console.log(`Collection "${singleCollection}" does not exist`);
|
||||
exit(2);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// another script process is currently running
|
||||
console.log("Backup aborted");
|
||||
exit(2);
|
||||
}
|
||||
} else {
|
||||
// backup process is already running
|
||||
console.log("Backup aborted");
|
||||
exit(2);
|
||||
}
|
||||
} else {
|
||||
// backup already exists
|
||||
console.log(`A backup named ${backupFilename}${archiveSuffix} already exists`);
|
||||
exit(2);
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
const lib = require('../lib/explorer');
|
||||
const readline = require('readline');
|
||||
const deleteLockName = 'delete';
|
||||
const settings = require('../lib/settings');
|
||||
let lockCreated = false;
|
||||
let preserveClaimAddressNames = false;
|
||||
|
||||
// exit function used to cleanup lock before finishing script
|
||||
function exit(mongoose, exitCode) {
|
||||
const db = require('../lib/database');
|
||||
|
||||
// check if mongo was connected
|
||||
if (mongoose != null) {
|
||||
// check if this is a clean exit
|
||||
if (exitCode == 0) {
|
||||
// initialize the database
|
||||
db.initialize_data_startup(function() {
|
||||
// disconnect mongo connection
|
||||
mongoose.disconnect();
|
||||
|
||||
// finish exit cleanup
|
||||
finishExit(db, exitCode);
|
||||
});
|
||||
} else {
|
||||
// disconnect mongo connection
|
||||
mongoose.disconnect();
|
||||
|
||||
// finish exit cleanup
|
||||
finishExit(db, exitCode);
|
||||
}
|
||||
} else {
|
||||
// finish exit cleanup
|
||||
finishExit(db, exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
function finishExit(db, exitCode) {
|
||||
// always check for and remove the sync msg if exists
|
||||
db.remove_sync_message();
|
||||
|
||||
// only remove delete lock if it was created in this session
|
||||
if (!lockCreated || lib.remove_lock(deleteLockName) == true) {
|
||||
// clean exit with previous exit code
|
||||
process.exit(exitCode);
|
||||
} else {
|
||||
// error removing lock
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function drop_collection(mongoose, colName, cb) {
|
||||
// attempt to delete the collection
|
||||
mongoose.connection.db.dropCollection(colName).then((result) => {
|
||||
if (!result) {
|
||||
console.log(`Error: Unable to delete the ${colName} collection`);
|
||||
exit(mongoose, 1);
|
||||
} else
|
||||
return cb(true);
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
exit(mongoose, 1);
|
||||
});
|
||||
}
|
||||
|
||||
function delete_prompt(cb) {
|
||||
preserve_claimaddress_prompt(function() {
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
// Change the delete prompt based on whether this is a reindex or regular delete
|
||||
if (process.argv[2] != null && process.argv[2] == 'reindex') {
|
||||
console.log('You are about to delete all data from the entire eIquidus database');
|
||||
|
||||
if (preserveClaimAddressNames)
|
||||
console.log('(claim address name data will not be deleted)');
|
||||
|
||||
console.log('and resync from the genesis block.');
|
||||
} else {
|
||||
console.log('You are about to delete all data from the entire eIquidus database.');
|
||||
|
||||
if (preserveClaimAddressNames)
|
||||
console.log('(claim address name data will not be deleted)');
|
||||
}
|
||||
|
||||
// prompt for deleting explorer database
|
||||
rl.question(`${settings.localization.are_you_sure}: `, function (deleteAnswer) {
|
||||
// stop prompting
|
||||
rl.close();
|
||||
|
||||
// determine if the explorer database should be deleted
|
||||
switch ((deleteAnswer == null ? '' : deleteAnswer).toLowerCase()) {
|
||||
case settings.localization.short_yes:
|
||||
case settings.localization.long_yes:
|
||||
return cb(true);
|
||||
break;
|
||||
default:
|
||||
return cb(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function preserve_claimaddress_prompt(cb) {
|
||||
const ClaimAddress = require('../models/claimaddress');
|
||||
|
||||
// check how many claim address records there are
|
||||
ClaimAddress.find({}).countDocuments().then((count) => {
|
||||
// display an additional prompt in the event the claimaddress collection has data
|
||||
if (count > 0) {
|
||||
console.log(`The current database has ${count} custom claim address names`);
|
||||
console.log('Would you like to preserve this data?');
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
// prompt for deleting claim address data
|
||||
rl.question('y = keep claim address data, n = delete claim address data [y/n]: ', function (preserveClaimAddresses) {
|
||||
// stop prompting
|
||||
rl.close();
|
||||
|
||||
// determine if the claim address data should be preserved
|
||||
switch (preserveClaimAddresses) {
|
||||
case 'y':
|
||||
case 'Y':
|
||||
case 'yes':
|
||||
case 'YES':
|
||||
case 'Yes':
|
||||
preserveClaimAddressNames = true;
|
||||
console.log('Claim address name data will be saved' + '\n');
|
||||
break;
|
||||
default:
|
||||
console.log('Claim address name data will be deleted' + '\n');
|
||||
}
|
||||
|
||||
return cb();
|
||||
});
|
||||
} else
|
||||
return cb();
|
||||
});
|
||||
}
|
||||
|
||||
// check if the "delete database" process is already running
|
||||
if (lib.is_locked([deleteLockName]) == false) {
|
||||
// create a new delete lock before checking the rest of the locks to minimize problems with running scripts at the same time
|
||||
lib.create_lock(deleteLockName);
|
||||
// ensure the lock will be deleted on exit
|
||||
lockCreated = true;
|
||||
|
||||
var lock_list = ['backup', 'restore', 'markets', 'peers', 'masternodes', 'plugin'];
|
||||
|
||||
// do not check the index lock if this is called from the reindex process
|
||||
if (process.argv[2] == null || process.argv[2] != 'reindex') {
|
||||
lock_list.push('index');
|
||||
}
|
||||
|
||||
// check all other possible locks since database deletion should not run at the same time that data is being changed
|
||||
if (lib.is_locked(lock_list) == false) {
|
||||
// all tests passed. OK to run delete
|
||||
|
||||
// suppress the pid message when doing a reindex
|
||||
if (process.argv[2] == null || process.argv[2] != 'reindex')
|
||||
console.log(`${settings.localization.script_launched }: ${process.pid}`);
|
||||
|
||||
const mongoose = require('mongoose');
|
||||
const dbString = `mongodb://${encodeURIComponent(settings.dbsettings.user)}:${encodeURIComponent(settings.dbsettings.password)}@${settings.dbsettings.address}:${settings.dbsettings.port}/${settings.dbsettings.database}`;
|
||||
|
||||
console.log('Connecting to database..');
|
||||
|
||||
mongoose.set('strictQuery', true);
|
||||
mongoose.set('updatePipeline', true);
|
||||
|
||||
// connect to mongo database
|
||||
mongoose.connect(dbString).then(() => {
|
||||
console.log('Database connection successful' + '\n');
|
||||
|
||||
// prompt for database delete
|
||||
delete_prompt(function(continue_process) {
|
||||
if (continue_process) {
|
||||
// get the list of collections
|
||||
mongoose.connection.db.listCollections().toArray().then((collections) => {
|
||||
// check if there are any collections
|
||||
if (collections.length > 0) {
|
||||
var counter = 0;
|
||||
|
||||
// loop through all collections
|
||||
collections.forEach((collection) => {
|
||||
// check if this is the claim addres collection and that data is being preserved
|
||||
if (!preserveClaimAddressNames || collection.name != 'claimaddresses') {
|
||||
console.log(`Deleting ${collection.name}..`);
|
||||
|
||||
// delete this collection
|
||||
drop_collection(mongoose, collection.name, function(retVal) {
|
||||
// check if the collection was successfully deleted
|
||||
if (retVal)
|
||||
counter++;
|
||||
|
||||
// check if the last collection was deleted
|
||||
if (counter == collections.length) {
|
||||
// finish the delete process
|
||||
console.log('Finished deleting database');
|
||||
exit(mongoose, 0);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// skipped deleting of the claimaddresses collection
|
||||
counter++;
|
||||
|
||||
// check if the last collection was deleted
|
||||
if (counter == collections.length) {
|
||||
// finish the delete process
|
||||
console.log('Finished deleting database');
|
||||
exit(mongoose, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// nothing to delete
|
||||
console.log('Nothing to delete, the database is already empty..');
|
||||
|
||||
// finish the delete process
|
||||
exit(mongoose, 0);
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.log('Error: Unable to list collections in database: %s', err);
|
||||
exit(mongoose, 1);
|
||||
});
|
||||
} else {
|
||||
console.log(`${settings.localization.process_aborted}. ${settings.localization.nothing_was_deleted}.`);
|
||||
exit(null, 2);
|
||||
}
|
||||
});
|
||||
}).catch((err) => {
|
||||
console.log('Error: Unable to connect to database: %s', err);
|
||||
exit(mongoose, 999);
|
||||
});
|
||||
} else {
|
||||
// another script process is currently running
|
||||
console.log("Delete aborted");
|
||||
exit(null, 2);
|
||||
}
|
||||
} else {
|
||||
// delete process is already running
|
||||
console.log("Delete aborted");
|
||||
exit(null, 2);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Read-only preflight: indexing never starts a coin daemon or mines blocks.
|
||||
const settings = require('../lib/settings');
|
||||
const Client = require('../lib/node').Client;
|
||||
const client = new Client({...settings.wallet,timeout:3000});
|
||||
client.cmd([{method:'getblockhash',params:[0]}], (err, genesis)=>{
|
||||
if(err) { console.log('NRB node offline; index remains idle'); process.exit(0); }
|
||||
if(genesis !== settings.block_page.genesis_block) {
|
||||
console.error('Refusing to index an unexpected blockchain'); process.exit(1);
|
||||
}
|
||||
const child=require('child_process').spawn(process.execPath,['scripts/sync.js','index','update'],{stdio:'inherit'});
|
||||
child.on('error',()=>process.exit(1));
|
||||
child.on('exit',code=>process.exit(code==null?1:code));
|
||||
});
|
||||
@@ -0,0 +1,157 @@
|
||||
const settings = require('../lib/settings');
|
||||
const minNodeVersionMajor = '20';
|
||||
const minNodeVersionMinor = '19';
|
||||
const minNodeVersionRevision = '0';
|
||||
|
||||
// get the nodejs version
|
||||
let nodeVersion = process.version;
|
||||
let nodeVersionMajor = '0';
|
||||
let nodeVersionMinor = '0';
|
||||
let nodeVersionRevision = '0';
|
||||
|
||||
// check if the nodejs version # is blank or a very long string as that would usually indicate a problem
|
||||
if (nodeVersion != null && nodeVersion != '' && nodeVersion.length < 16) {
|
||||
// remove the 'v' from the beginning of the version string
|
||||
if (nodeVersion.indexOf('v') == 0)
|
||||
nodeVersion = nodeVersion.slice(1);
|
||||
|
||||
// split node version string into major, minor and revision
|
||||
const splitVersion = nodeVersion.split('.');
|
||||
|
||||
nodeVersionMajor = splitVersion[0];
|
||||
|
||||
if (splitVersion.length > 1)
|
||||
nodeVersionMinor = splitVersion[1];
|
||||
|
||||
if (splitVersion.length > 2)
|
||||
nodeVersionRevision = splitVersion[2];
|
||||
}
|
||||
|
||||
// check if the installed nodejs is an older version than supported by the explorer
|
||||
if (!(nodeVersionMajor > minNodeVersionMajor || (nodeVersionMajor == minNodeVersionMajor && (nodeVersionMinor > minNodeVersionMinor || (nodeVersionMinor == minNodeVersionMinor && nodeVersionRevision >= minNodeVersionRevision))))) {
|
||||
console.log(`Please install an updated version of nodejs.\n\nInstalled: ${nodeVersion}\nRequired: ${minNodeVersionMajor}.${minNodeVersionMinor}.${minNodeVersionRevision}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function check_arguments_passed(cb) {
|
||||
const arguments = (process.argv[2] == null ? '' : process.argv[2]).split(' ');
|
||||
const pidName = (arguments != null && arguments.length > 0 && arguments[0] != null && arguments[0] != '' && (arguments[0] == 'pm2' || arguments[0] == 'forever') ? arguments[0] : 'node');
|
||||
const node_env = (arguments != null && arguments.length > 1 && arguments[1] != null && arguments[1] != '' ? arguments[1] : 'development');
|
||||
const reload = ((arguments != null && arguments.length > 2 && arguments[2] != null && arguments[2] != '' ? arguments[2] : '') == 'reload');
|
||||
|
||||
// check 1st argument
|
||||
if (pidName != null) {
|
||||
const { exec } = require('child_process');
|
||||
|
||||
// determine which argument was passed
|
||||
switch (pidName) {
|
||||
case 'pm2':
|
||||
// windows pm2 has problem loading locally, but other os's should work fine
|
||||
const isWinOS = process.platform == 'win32';
|
||||
|
||||
// run a cmd to check if pm2 is installed
|
||||
exec(`npm list${(isWinOS ? ' -g' : '')} pm2`, (err, stdout, stderr) => {
|
||||
// split stdout string by new line
|
||||
var splitResponse = (stdout == null ? '' : stdout.trim()).split('\n').filter(element => element);
|
||||
|
||||
// check if the cmd result contains an @ symbol
|
||||
if (splitResponse[1].indexOf('@') == -1) {
|
||||
console.log(`${settings.localization.installing_module.replace('{1}', 'pm2')}.. ${settings.localization.please_wait}..`);
|
||||
|
||||
// install pm2
|
||||
exec(`npm install pm2@latest${(isWinOS ? ' -g' : '')}`, (err, stdout, stderr) => {
|
||||
// always return the pidName and node_env value for now without checking results
|
||||
return cb(pidName, node_env, reload);
|
||||
});
|
||||
} else
|
||||
return cb(pidName, node_env, reload);
|
||||
});
|
||||
break;
|
||||
case 'forever':
|
||||
// run a cmd to check if forever is installed
|
||||
exec('npm list forever', (err, stdout, stderr) => {
|
||||
// split stdout string by new line
|
||||
var splitResponse = (stdout == null ? '' : stdout.trim()).split('\n').filter(element => element);
|
||||
|
||||
// check if the cmd result contains an @ symbol
|
||||
if (splitResponse[1].indexOf('@') == -1) {
|
||||
console.log(`${settings.localization.installing_module.replace('{1}', 'forever')}.. ${settings.localization.please_wait}..`);
|
||||
|
||||
// install forever
|
||||
exec('npm install forever', (err, stdout, stderr) => {
|
||||
// always return the pidName and node_env value for now without checking results
|
||||
return cb(pidName, node_env, reload);
|
||||
});
|
||||
} else
|
||||
return cb(pidName, node_env, reload);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
// argument not passed or unknown argument
|
||||
return cb(pidName, node_env, reload);
|
||||
}
|
||||
} else
|
||||
return cb(pidName, node_env, reload);
|
||||
}
|
||||
|
||||
// check if arguments were passed into this script
|
||||
check_arguments_passed(function(pidName, node_env, reload) {
|
||||
const execSync = require('child_process').execSync;
|
||||
|
||||
// compile scss to css
|
||||
execSync('node ./scripts/compile_css.js', {stdio : 'inherit'});
|
||||
|
||||
const db = require('../lib/database');
|
||||
|
||||
// connect to the mongo database
|
||||
db.connect(null, function() {
|
||||
// initialize the database
|
||||
db.initialize_data_startup(function() {
|
||||
// check if the webserver should be started from here based on the pidName
|
||||
switch (pidName) {
|
||||
case 'pm2':
|
||||
let startOrReloadPm2 = (reload ? 'reload' : 'start');
|
||||
|
||||
// get a json list of pm2 processes
|
||||
let result = execSync(`pm2 jlist`);
|
||||
|
||||
// check if the result is null
|
||||
if (result != null) {
|
||||
try {
|
||||
// convert return result to JSON
|
||||
result = JSON.parse(result);
|
||||
|
||||
// loop through the results
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
// check if this is an explorer process
|
||||
if (result[i].name == 'explorer') {
|
||||
// explorer process exists, so reload the process
|
||||
startOrReloadPm2 = 'reload';
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
// setting the NODE_ENV variable is more easily done from here seeing at the syntax changes slightly depending on operating system
|
||||
execSync(`${(process.platform == 'win32' ? 'set' : 'export')} NODE_ENV=${node_env} && pm2 ${startOrReloadPm2} ./bin/instance -i 0 -n explorer -p "./tmp/pm2.pid" --node-args="--stack-size=10000" --update-env`, {stdio : 'inherit'});
|
||||
break;
|
||||
case 'forever':
|
||||
const path = require('path');
|
||||
const startOrReloadForever = (reload ? 'restart' : 'start');
|
||||
|
||||
// there is a long-time bug or shortcoming in forever that still exists in the latest version which requires the absolute path to the pid file option
|
||||
// more info: https://github.com/foreversd/forever/issues/421
|
||||
// forever is therefore started from here to be able to more easily resolve the absolute path
|
||||
// also, setting the NODE_ENV variable is more easily done from here as well seeing at the syntax changes slightly depending on operating system
|
||||
execSync(`${(process.platform == 'win32' ? 'set' : 'export')} NODE_ENV=${node_env} && forever ${startOrReloadForever} --append --uid "explorer" --pidFile "${path.resolve('./tmp/forever.pid')}" ./bin/cluster`, {stdio : 'inherit'});
|
||||
break;
|
||||
}
|
||||
|
||||
// finished pre-loading
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,364 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const lib = require('../lib/explorer');
|
||||
const archiveSuffix = '.bak';
|
||||
const oldArchiveSuffix = '.tar.gz';
|
||||
const restoreLockName = 'restore';
|
||||
const tarModule = 'tar';
|
||||
const defaultBackupPath = path.join(path.dirname(__dirname), 'backups');
|
||||
const settings = require('../lib/settings');
|
||||
let singleCollection = '';
|
||||
let lockCreated = false;
|
||||
|
||||
// exit function used to cleanup lock before finishing script
|
||||
function exit(mongoose, exitCode) {
|
||||
const db = require('../lib/database');
|
||||
|
||||
// check if mongo was connected
|
||||
if (mongoose != null) {
|
||||
// check if this is a clean exit
|
||||
if (exitCode == 0) {
|
||||
// initialize the database
|
||||
db.initialize_data_startup(function() {
|
||||
// disconnect mongo connection
|
||||
mongoose.disconnect();
|
||||
|
||||
// finish exit cleanup
|
||||
finishExit(db, exitCode);
|
||||
});
|
||||
} else {
|
||||
// disconnect mongo connection
|
||||
mongoose.disconnect();
|
||||
|
||||
// finish exit cleanup
|
||||
finishExit(db, exitCode);
|
||||
}
|
||||
} else {
|
||||
// finish exit cleanup
|
||||
finishExit(db, exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
function finishExit(db, exitCode) {
|
||||
// always check for and remove the sync msg if exists
|
||||
db.remove_sync_message();
|
||||
|
||||
// only remove restore lock if it was created in this session
|
||||
if (!lockCreated || lib.remove_lock(restoreLockName) == true) {
|
||||
// clean exit with previous exit code
|
||||
process.exit(exitCode);
|
||||
} else {
|
||||
// error removing lock
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function check_module_directory_exists(dirName, cb) {
|
||||
// check if module directory exists
|
||||
if (!fs.existsSync(`./node_modules/${dirName}`)) {
|
||||
const { exec } = require('child_process');
|
||||
|
||||
console.log(`${settings.localization.installing_module.replace('{1}', tarModule)}.. ${settings.localization.please_wait}..`);
|
||||
|
||||
// install tar module
|
||||
exec(`npm install ${tarModule}`, (err, stdout, stderr) => {
|
||||
// always return true for now without checking results
|
||||
return cb(true);
|
||||
});
|
||||
} else
|
||||
return cb(true);
|
||||
}
|
||||
|
||||
function drop_collection(mongoose, colName, cb) {
|
||||
// attempt to delete the collection
|
||||
mongoose.connection.db.dropCollection(colName).then((result) => {
|
||||
if (!result) {
|
||||
console.log(`Error: Unable to delete the ${colName} collection`);
|
||||
exit(mongoose, 1);
|
||||
} else
|
||||
return cb(true);
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
exit(mongoose, 1);
|
||||
});
|
||||
}
|
||||
|
||||
function delete_database(mongoose, cb) {
|
||||
// check if a single collection is being restored
|
||||
if (singleCollection != null && singleCollection == '') {
|
||||
// get the list of collections
|
||||
mongoose.connection.db.listCollections().toArray().then((collections) => {
|
||||
// check if there are any collections
|
||||
if (collections.length > 0) {
|
||||
let counter = 0;
|
||||
|
||||
// loop through all collections
|
||||
collections.forEach((collection) => {
|
||||
console.log(`Deleting ${collection.name}..`);
|
||||
|
||||
// delete this collection
|
||||
drop_collection(mongoose, collection.name, function(retVal) {
|
||||
// check if the collection was successfully deleted
|
||||
if (retVal)
|
||||
counter++;
|
||||
|
||||
// check if the last collection was deleted
|
||||
if (counter == collections.length) {
|
||||
// finished the delete process
|
||||
return cb(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// nothing to delete
|
||||
return cb(true);
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
return cb(true);
|
||||
});
|
||||
} else {
|
||||
// do not delete any collections since mongorestore will drop the collection automatically
|
||||
return cb(true);
|
||||
}
|
||||
}
|
||||
|
||||
function restore_backup(mongoose, backupPath, extractedPath, gZip) {
|
||||
const { exec } = require('child_process');
|
||||
|
||||
console.log(`${settings.localization.restoring_backup}.. ${settings.localization.please_wait}..`);
|
||||
|
||||
// restore mongo database from backup
|
||||
const restoreProcess = exec(`mongorestore --host="${settings.dbsettings.address}" --port="${settings.dbsettings.port}" --username="${settings.dbsettings.user}" --password="${settings.dbsettings.password}" --authenticationDatabase="${settings.dbsettings.database}" ${(gZip ? `--gzip --archive="${backupPath}"` : `"${extractedPath}"`)}${singleCollection == null || singleCollection == '' ? '' : ` --drop --db explorerdb --collection ${singleCollection}`}`);
|
||||
|
||||
restoreProcess.stdout.on('data', (data) => {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
restoreProcess.stderr.on('data', (data) => {
|
||||
console.log(Buffer.from(data).toString());
|
||||
});
|
||||
|
||||
restoreProcess.on('error', (error) => {
|
||||
console.log(error);
|
||||
});
|
||||
|
||||
restoreProcess.on('exit', (code, signal) => {
|
||||
if (code) {
|
||||
console.log(`Process exit with code: ${code}`);
|
||||
exit(mongoose, code);
|
||||
} else if (signal) {
|
||||
console.log(`Process killed with signal: ${signal}`);
|
||||
exit(mongoose, 1);
|
||||
} else {
|
||||
// check if gZip is enabled
|
||||
if (!gZip) {
|
||||
// try to remove the backup directory
|
||||
try {
|
||||
fs.rmSync(extractedPath, { recursive: true });
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
// restore backup complete
|
||||
console.log(`Backup restored from ${path.basename(backupPath)} successfully`);
|
||||
exit(mongoose, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function delete_prompt(cb) {
|
||||
const readline = require('readline');
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
// check if a single collection is being restored
|
||||
if (singleCollection != null && singleCollection != '')
|
||||
console.log(`You are about to delete and restore the "${singleCollection}" collection from backup.`);
|
||||
else
|
||||
console.log('You are about to delete the current eIquidus database and restore from backup.');
|
||||
|
||||
// prompt for restoring explorer database
|
||||
rl.question(`${settings.localization.are_you_sure}: `, function (restoreAnswer) {
|
||||
// stop prompting
|
||||
rl.close();
|
||||
|
||||
// return the answer
|
||||
return cb(restoreAnswer);
|
||||
});
|
||||
}
|
||||
|
||||
// verify that the collection exists
|
||||
function verify_collection_exists(mongoose, cb) {
|
||||
const dbString = `mongodb://${encodeURIComponent(settings.dbsettings.user)}:${encodeURIComponent(settings.dbsettings.password)}@${settings.dbsettings.address}:${settings.dbsettings.port}/${settings.dbsettings.database}`;
|
||||
|
||||
console.log('Connecting to database..');
|
||||
|
||||
mongoose.set('strictQuery', true);
|
||||
mongoose.set('updatePipeline', true);
|
||||
|
||||
// connect to mongo database
|
||||
mongoose.connect(dbString).then(() => {
|
||||
// check if the restore will be for a single collection
|
||||
if (singleCollection != null && singleCollection != '') {
|
||||
// lookup the collection in the list of collections
|
||||
mongoose.connection.db.listCollections({ name: singleCollection }).toArray().then((collections) => {
|
||||
// check if the collection exists
|
||||
if (collections.length > 0) {
|
||||
// collection exists
|
||||
return cb(false);
|
||||
} else {
|
||||
// collection not found
|
||||
return cb(true);
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
return cb(true);
|
||||
});
|
||||
} else
|
||||
return cb(false);
|
||||
}).catch((err) => {
|
||||
console.log('Error: Unable to connect to database: %s', err);
|
||||
exit(999);
|
||||
return cb(true);
|
||||
});
|
||||
}
|
||||
|
||||
// check if a backup filename was passed into the script
|
||||
if (process.argv[2] != null && process.argv[2] != '') {
|
||||
let backupPath = process.argv[2];
|
||||
|
||||
// check if a collection name was passed into the script
|
||||
if (process.argv[3] != null && process.argv[3] != '') {
|
||||
// save the collection name to a variable for later use
|
||||
singleCollection = process.argv[3];
|
||||
}
|
||||
|
||||
// check if the backup filename already has a path
|
||||
if (!fs.existsSync(`${backupPath}`)) {
|
||||
// check if the backup is valid by adding the archive suffix
|
||||
if (fs.existsSync(`${backupPath}${archiveSuffix}`)) {
|
||||
// the backup file is valid after adding the archive suffix
|
||||
backupPath = `${backupPath}${archiveSuffix}`;
|
||||
} else {
|
||||
// prepend the default backup path
|
||||
backupPath = path.join(defaultBackupPath, backupPath);
|
||||
}
|
||||
}
|
||||
|
||||
// check for the backup file (again)
|
||||
if (!fs.existsSync(`${backupPath}`)) {
|
||||
// append the default archive suffix
|
||||
backupPath = `${backupPath}${archiveSuffix}`;
|
||||
}
|
||||
|
||||
// check for the backup file (last time)
|
||||
if (fs.existsSync(`${backupPath}`)) {
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
// check if the collection name exists
|
||||
verify_collection_exists(mongoose, function(collection_error) {
|
||||
// check if there was an error finding the collection by name
|
||||
if (!collection_error) {
|
||||
// prompt for deleting and restoring the database
|
||||
delete_prompt(function(restoreAnswer) {
|
||||
// determine if the explorer database should be restored
|
||||
switch ((restoreAnswer == null ? '' : restoreAnswer).toLowerCase()) {
|
||||
case settings.localization.short_yes:
|
||||
case settings.localization.long_yes:
|
||||
// check if the "restore backup" process is already running
|
||||
if (lib.is_locked([restoreLockName]) == false) {
|
||||
// create a new restore lock before checking the rest of the locks to minimize problems with running scripts at the same time
|
||||
lib.create_lock(restoreLockName);
|
||||
|
||||
// ensure the lock will be deleted on exit
|
||||
lockCreated = true;
|
||||
|
||||
// check all other possible locks since restoring backups should not run at the same time that data is being changed
|
||||
if (lib.is_locked(['backup', 'delete', 'index', 'markets', 'peers', 'masternodes', 'plugin']) == false) {
|
||||
// all tests passed. OK to run restore
|
||||
console.log(`${settings.localization.script_launched }: ${process.pid}`);
|
||||
|
||||
// check if this is a tar.gz (older explorer backup format)
|
||||
if (!backupPath.endsWith(oldArchiveSuffix)) {
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
// newer backup format (.bak)
|
||||
// delete all collections from existing database
|
||||
delete_database(mongoose, function(retVal) {
|
||||
if (retVal) {
|
||||
// move on to the restore process
|
||||
restore_backup(mongoose, backupPath, backupPath, true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// older backup format (.tar.gz)
|
||||
// check if the tar module is already installed
|
||||
check_module_directory_exists(tarModule, function(retVal) {
|
||||
const tar = require(tarModule);
|
||||
|
||||
console.log(`${settings.localization.extracting_backup_files}.. ${settings.localization.please_wait}..`);
|
||||
|
||||
// extract the backup archive
|
||||
tar.x({ file: backupPath, cwd: defaultBackupPath, gzip: true }, function() {
|
||||
var extractedPath = path.join(defaultBackupPath, path.basename(backupPath).replace(oldArchiveSuffix, ''));
|
||||
|
||||
// check if this is a valid backup archive now that the files have been extracted
|
||||
if (fs.existsSync(`${path.join(extractedPath, settings.dbsettings.database)}`)) {
|
||||
// delete all collections from existing database
|
||||
delete_database(mongoose, function(retVal) {
|
||||
if (retVal) {
|
||||
// move on to the restore process
|
||||
restore_backup(mongoose, backupPath, extractedPath, false);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// backup file is not a valid mongo database backup
|
||||
// try to remove the backup directory
|
||||
try {
|
||||
fs.rmSync(extractedPath, { recursive: true });
|
||||
} catch {
|
||||
// do nothing
|
||||
} finally {
|
||||
console.log(`${path.basename(backupPath)} is not a valid backup file`);
|
||||
exit(mongoose, 1);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// another script process is currently running
|
||||
console.log("Restore aborted");
|
||||
exit(mongoose, 2);
|
||||
}
|
||||
} else {
|
||||
// restore process is already running
|
||||
console.log("Restore aborted");
|
||||
exit(mongoose, 2);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
console.log(`${settings.localization.process_aborted}. ${settings.localization.nothing_was_restored}.`);
|
||||
exit(mongoose, 2);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// the collection does not exist
|
||||
console.log(`Collection "${singleCollection}" does not exist`);
|
||||
exit(mongoose, 2);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// backup does not exist
|
||||
console.log(settings.localization.path_cannot_be_found.replace('{1}', backupPath));
|
||||
exit(null, 2);
|
||||
}
|
||||
} else {
|
||||
console.log('No backup file specified');
|
||||
exit(null, 2);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
const settings = require('../lib/settings');
|
||||
const { exec } = require('child_process');
|
||||
|
||||
function validate_port(port) {
|
||||
if (port == null || typeof port !== 'number' || port < 1 || port > 65535)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
function check_webserver_running(cb) {
|
||||
// determine operating system
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
// windows
|
||||
exec(`for /f "tokens=5" %a in ('netstat -aon ^| findstr :${settings.webserver.port} ^| findstr LISTENING') do @echo %~nxa`, (err, stdout, stderr) => {
|
||||
// check if the port is open
|
||||
if (stdout != null && stdout != '') {
|
||||
// split the results in case there are multiple (usually because of ipv4 and ipv6)
|
||||
split = stdout.split('\n');
|
||||
|
||||
// return the kill cmd
|
||||
return cb(`taskkill /f /pid ${split[0]}`);
|
||||
} else
|
||||
return cb(null);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
// linux, macos, etc.
|
||||
exec(`lsof -t -i:${settings.webserver.port}`, (err, stdout, stderr) => {
|
||||
// check if the port is open
|
||||
if (stdout != null && stdout != '') {
|
||||
// return the kill cmd
|
||||
return cb(`kill -2 ${stdout.trim()}`);
|
||||
} else
|
||||
return cb(null);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// check if the webserver.port value is a valid port #
|
||||
if (validate_port(settings.webserver.port) == true) {
|
||||
// check if the server is currently running
|
||||
check_webserver_running(function(killcmd) {
|
||||
// check return value
|
||||
if (killcmd != null) {
|
||||
// send a kill signal to the process that is currently using the explorer's server port
|
||||
exec(killcmd, (err, stdout, stderr) => {
|
||||
// show shutdown msg
|
||||
console.log(`${settings.localization.explorer_shutting_down}.. ${settings.localization.please_wait}..`);
|
||||
process.exit(0);
|
||||
});
|
||||
} else {
|
||||
// webserver is not running
|
||||
console.log('Error: Cannot stop explorer because it is not currently running');
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// invalid port number
|
||||
console.log('Error: webserver.port value not found in settings.json.');
|
||||
process.exit(1);
|
||||
}
|
||||
+1715
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,198 @@
|
||||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const argument = (process.argv[2] != null && process.argv[2] != '' && (process.argv[2] == 'explorer-only' || process.argv[2] == 'dependencies-only') ? process.argv[2] : '');
|
||||
const settings = require('../lib/settings');
|
||||
let reloadWebserver = false;
|
||||
|
||||
function exit() {
|
||||
console.log('Explorer update complete');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
function init_database(cb) {
|
||||
// compile scss to css
|
||||
execSync('node ./scripts/compile_css.js', {stdio : 'inherit'});
|
||||
|
||||
const db = require('../lib/database');
|
||||
|
||||
// connect to mongo database
|
||||
db.connect(null, function() {
|
||||
// initialize the database
|
||||
db.initialize_data_startup(function() {
|
||||
// finish the database init
|
||||
return cb(null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// check if the script should check for code updates
|
||||
if (argument == '' || argument == 'explorer-only') {
|
||||
// check if the .git directory and .git/refs/heads/master file exist
|
||||
if (fs.existsSync('./.git') && fs.existsSync('./.git/refs/heads/master')) {
|
||||
// get the current commit hash
|
||||
var commit = fs.readFileSync('./.git/refs/heads/master');
|
||||
|
||||
// update to newest explorer source
|
||||
console.log(`${settings.localization.downloading_newest_explorer_code}.. ${settings.localization.please_wait}..\n`);
|
||||
|
||||
try {
|
||||
console.log('Git response:');
|
||||
execSync('git pull', {stdio : 'inherit'});
|
||||
|
||||
// get the current commit hash to see if it has changed
|
||||
var new_commit = fs.readFileSync('./.git/refs/heads/master');
|
||||
|
||||
// check if the commit values are the same
|
||||
if (new_commit.toString() == commit.toString()) {
|
||||
// explorer code was already up-to-date
|
||||
console.log('\nExplorer code is already up-to-date');
|
||||
} else {
|
||||
console.log('\nExplorer code successfully updated');
|
||||
reloadWebserver = true;
|
||||
}
|
||||
} catch(err) {
|
||||
console.log('\nError updating explorer code. Maybe git is not installed globally or you made some custom changes to the explorer code?');
|
||||
}
|
||||
} else {
|
||||
console.log('WARNING: Explorer code not cloned from github and cannot be automatically updated!');
|
||||
console.log('Skipping explorer code update');
|
||||
}
|
||||
|
||||
// check if this was an explorer-only update
|
||||
if (argument == 'explorer-only') {
|
||||
// add a new line for better spacing
|
||||
console.log('');
|
||||
}
|
||||
}
|
||||
|
||||
// check if the script should check for outdated dependencies
|
||||
if (argument == '' || argument == 'dependencies-only') {
|
||||
var outdatedPkgs = null;
|
||||
|
||||
// check for outdated packages
|
||||
try {
|
||||
console.log(`${(argument == 'dependencies-only' ? '' : '\n')}${settings.localization.check_outdated_packages}.. ${settings.localization.please_wait}..`);
|
||||
execSync('npm outdated');
|
||||
|
||||
// all packages are up-to-date
|
||||
console.log('\nAll explorer packages are up-to-date');
|
||||
} catch (err) {
|
||||
outdatedPkgs = err.stdout.toString().trim();
|
||||
}
|
||||
|
||||
// add a new line for better spacing
|
||||
console.log('');
|
||||
|
||||
// check if there were any outdated packages
|
||||
if (outdatedPkgs != null) {
|
||||
// update npm modules to latest versions according to package.json rules
|
||||
console.log(`${settings.localization.updating_explorer_packages}.. ${settings.localization.please_wait}..\n`);
|
||||
execSync('npm update');
|
||||
|
||||
// check for outdated packages (again)
|
||||
try {
|
||||
execSync('npm outdated');
|
||||
|
||||
// all packages are up-to-date
|
||||
console.log('All explorer packages are up-to-date\n');
|
||||
reloadWebserver = true;
|
||||
} catch (err) {
|
||||
console.log(`The following packages are still out-of-date:\n${err.stdout.toString().trim()}\n`);
|
||||
|
||||
// check if any of the packages were updated
|
||||
if (err.stdout.toString().trim() == outdatedPkgs)
|
||||
reloadWebserver = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if the web server should be reloaded
|
||||
if (reloadWebserver == true) {
|
||||
console.log(`${settings.localization.checking_webserver_running}.. ${settings.localization.please_wait}..\n`);
|
||||
|
||||
const path = require('path');
|
||||
const lib = require('../lib/explorer');
|
||||
var pidActive = false;
|
||||
|
||||
// get a list of all files in the tmp directory
|
||||
var tmpFiles = fs.readdirSync('./tmp');
|
||||
|
||||
// get a list of all pm2 pid files
|
||||
var pm2Files = tmpFiles
|
||||
.filter(file => file.startsWith('pm2') && file.endsWith('.pid'))
|
||||
.map(file => path.basename(file, '.pid'));
|
||||
|
||||
// loop through the pm2 pid files and check if at least one is valid/active by testing the pid to see if it is running
|
||||
for (var i = 0; i < pm2Files.length; i++) {
|
||||
// check if the current pm2.pid file is valid
|
||||
if (lib.is_locked([pm2Files[i]], true) == true) {
|
||||
// this pid is active so stop checking
|
||||
pidActive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check if any pm2 pids were active
|
||||
if (pidActive == true) {
|
||||
// compile css and initialize database
|
||||
init_database(function() {
|
||||
console.log(`\n${settings.localization.reloading_explorer}.. ${settings.localization.please_wait}..\n`);
|
||||
|
||||
// reload pm2 using the zero-downtime reload function
|
||||
execSync(`pm2 reload explorer`, {stdio : 'inherit'});
|
||||
|
||||
// add a new line for better spacing
|
||||
console.log('');
|
||||
|
||||
// finish the script
|
||||
exit();
|
||||
});
|
||||
} else {
|
||||
// check if the forever pid file exists and is valid
|
||||
if (fs.existsSync('./tmp/forever.pid') && lib.is_locked(['forever'], true) == true) {
|
||||
// this pid is active
|
||||
pidActive = true;
|
||||
}
|
||||
|
||||
// check if the forever.pid is active
|
||||
if (pidActive == true) {
|
||||
// compile css and initialize database
|
||||
init_database(function() {
|
||||
console.log(`\n${settings.localization.reloading_explorer}.. ${settings.localization.please_wait}..\n`);
|
||||
|
||||
// reload forever using the restart function
|
||||
execSync(`forever restart explorer`, {stdio : 'inherit'});
|
||||
|
||||
// add a new line for better spacing
|
||||
console.log('');
|
||||
|
||||
// finish the script
|
||||
exit();
|
||||
});
|
||||
} else {
|
||||
const request = require('postman-request');
|
||||
|
||||
// try executing the restart explorer api
|
||||
request({uri: `http://localhost:${settings.webserver.port}/system/restartexplorer`, timeout: 1000}, function (error, response, summary) {
|
||||
// check if there was an error
|
||||
if (error != null) {
|
||||
console.log('Webserver is not runnning\n');
|
||||
|
||||
// finish the script
|
||||
exit();
|
||||
} else {
|
||||
// compile css and initialize database
|
||||
init_database(function() {
|
||||
console.log(`\n${settings.localization.reloading_explorer}.. ${settings.localization.please_wait}..\n`);
|
||||
|
||||
// finish the script
|
||||
exit();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// finish the script
|
||||
exit();
|
||||
}
|
||||
Reference in new issue
Block a user