Cross-platform support (Win, MacOS, Linux)

-All shell scripts have been removed and replaced with javascript equivalents which allows for better platform independence
-All scripts have been improved over the older shell scripts to be more functional and dynamic
-Updated all applicable cmds in the package.json to target the new js scripts + added the backup, restore and delete database functions to the list
-Removed the json and strip-json-comments-cli packages as they are no longer needed
-Added a new package realine-sync
-Updated cluster code with better Windows support when shutting down the explorer
-Backup and Restore scripts now use mongo's own encryption instead of tar.gz by default. Older tar.gz backups can still be restored as long as the tar.gz suffix is explicitly added
-Backup and Restore scripts now support connecting to remote database based on the mongo details in settings.json
-Updated README to include a new line for the 'platform independence' feature, updated script cmds and notes about certain steps being Linux only
This commit is contained in:
Joe Uhren
2022-04-23 11:28:32 -06:00
parent 5eeb6ed0c0
commit 8e32e294b7
21 changed files with 777 additions and 557 deletions
+76
View File
@@ -0,0 +1,76 @@
const fs = require('fs');
const path = require('path');
const archiveSuffix = '.bak';
var backupPath = path.join(path.dirname(__dirname), 'backups');
var backupFilename;
// 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 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}`))) {
const { exec } = require('child_process');
const settings = require('../lib/settings');
const randomDirectoryName = Math.random().toString(36).substring(2, 15) + Math.random().toString(23).substring(2, 5);
// 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`);
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}`);
process.exit(1);
} else if (signal) {
console.log(`Process killed with signal: ${signal}`);
process.exit(1);
} else {
console.log(`Backup saved successfully to ${path.join(backupPath, backupFilename + archiveSuffix)}`);
process.exit(0);
}
});
} else {
// backup already exists
console.log(`A backup named ${backupFilename}${archiveSuffix} already exists`);
process.exit(1);
}
-41
View File
@@ -1,41 +0,0 @@
#!/bin/bash
ends_with() { case $2 in *"$1") true;; *) false;; esac; }
BACKUP_PATH="$(dirname $(dirname $(readlink -f "$0")))/backups"
ARCHIVE_SUFFIX=".tar.gz"
if [ -n "${1}" ]; then
# use the backup filename passed into this script
BACKUP_FILENAME="${1}"
else
# no backup filename passed in, use todays date as the backup filename
BACKUP_FILENAME=$(date +"%Y-%b-%d")
fi
if ends_with "${ARCHIVE_SUFFIX}" "${BACKUP_FILENAME}"; then
# remove the archive suffix from the backup filename
BACKUP_FILENAME=${BACKUP_FILENAME%"${ARCHIVE_SUFFIX}"}
fi
if [ $(dirname "${BACKUP_FILENAME}") != "." ]; then
# The backup filename is a full path
# Split out the path and filename
BACKUP_DIR="$(dirname ${BACKUP_FILENAME})"
TEMP_FILENAME=${BACKUP_FILENAME#"${BACKUP_DIR}/"}
BACKUP_PATH=${BACKUP_FILENAME%"/${TEMP_FILENAME}"}
BACKUP_FILENAME="${TEMP_FILENAME}"
fi
if [ ! -f "${BACKUP_PATH}/${BACKUP_FILENAME}${ARCHIVE_SUFFIX}" ]; then
# execute backup
eval "mongodump -d explorerdb -o ${BACKUP_PATH}/${BACKUP_FILENAME}"
# archive the backup
cd "${BACKUP_PATH}" && tar -cvzf "${BACKUP_PATH}/${BACKUP_FILENAME}${ARCHIVE_SUFFIX}" "${BACKUP_FILENAME}"
# delete the uncompressed backup directory
rm -rf "${BACKUP_PATH}/${BACKUP_FILENAME}"
# finished msg
echo "Backup saved successfully to ${BACKUP_PATH}/${BACKUP_FILENAME}${ARCHIVE_SUFFIX}."
else
# backup already exists
echo "A backup named ${BACKUP_FILENAME}${ARCHIVE_SUFFIX} already exists."
fi
+101
View File
@@ -0,0 +1,101 @@
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
function drop_collection(mongoose, colName, cb) {
// attempt to delete the collection
mongoose.connection.db.dropCollection(colName, function(err, result) {
if (err || !result) {
console.log(`Unable to delete the ${colName} collection`);
console.log('Aborting');
process.exit(1);
} else
return cb(true);
});
}
function finished_deleting(mongoose) {
console.log('Finished deleting database');
// disconnect from mongo database
mongoose.disconnect();
// delete database complete
process.exit(0);
}
console.log('You are about to delete the entire eIquidus database.');
// prompt for deleting explorer database
rl.question('Are you sure you want to do this? [y/n]: ', function (deleteAnswer) {
// stop prompting
rl.close();
// determine if the explorer database should be deleted
switch (deleteAnswer) {
case 'y':
case 'Y':
case 'yes':
case 'YES':
case 'Yes':
const settings = require('../lib/settings');
const mongoose = require('mongoose');
const dbString = `mongodb://${settings.dbsettings.user}:${settings.dbsettings.password}@${settings.dbsettings.address}:${settings.dbsettings.port}/${settings.dbsettings.database}`;
console.log('Connecting to database..');
// connect to mongo database
mongoose.connect(dbString, function(err) {
if (err) {
console.log('Unable to connect to database: %s', dbString);
console.log('Aborting');
process.exit(1);
} else {
// get the list of collections
mongoose.connection.db.listCollections().toArray(function (err, collections) {
if (err) {
console.log('Unable to list collections in database: %s', err);
console.log('Aborting');
process.exit(1);
} else {
// check if there are any collections
if (collections.length > 0) {
var 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) {
// finish the delete process
finished_deleting(mongoose);
}
});
});
} else {
// nothing to delete
console.log('Nothing to delete, the database is already empty..');
// finish the delete process
finished_deleting(mongoose);
}
}
});
}
});
break;
default:
console.log('Process aborted. Nothing was deleted.');
process.exit(1);
}
});
-40
View File
@@ -1,40 +0,0 @@
#!/bin/bash
# Find the absolute path to this script file
SCRIPT_PATH=`dirname "$0"`
SCRIPT_PATH=`( cd "$SCRIPT_PATH" && pwd )`
# Remove temp file if it exists from last time
if [ -f "${SCRIPT_PATH}/del.tmp" ]; then
rm -f "${SCRIPT_PATH}/del.tmp"
fi
# Prompt for deleting database
echo "You are about to delete the entire eIquidus database."
echo "Are you sure you want to do this? [y/n]: ";
read -p "" DELETE_ANSWER
# Determine if the database should be deleted
case "$DELETE_ANSWER" in
y|Y|yes|Yes|YES) ;;
*) echo "Process aborted. Nothing was deleted." && exit ;;
esac
# Erase entire database
sudo touch "${SCRIPT_PATH}/del.tmp" && mongo <<EOF
use explorerdb
db.addresses.drop()
db.addresstxes.drop()
db.networkhistories.drop()
db.coinstats.drop()
db.heavies.drop()
db.markets.drop()
db.masternodes.drop()
db.peers.drop()
db.richlists.drop()
db.txes.drop()
exit
EOF
# Check if the temp file exists to determine if the delete was successful or not
if [ -f "${SCRIPT_PATH}/del.tmp" ]; then
rm -f "${SCRIPT_PATH}/del.tmp"
echo "Finished deleting database."
else
echo "Process aborted. Nothing was deleted."
fi
-27
View File
@@ -1,27 +0,0 @@
#!/bin/sh
# this super hack will sync the explorer within the specified block height range
forcesync() {
blockcount=$1
echo "╒══════════════════<<"
echo "| height : $blockcount"
blockhash=`curl -s https://explorer.exor.io/api/getblockhash?height=$blockcount`
echo "| ଓ hash : $blockhash"
curl -s https://explorer.exor.io/block/$blockhash > /dev/null
echo "╘═══════════════════════════════>>"
}
main() {
if [ $currentblockcount -ne $endingblockcount ]; then
forcesync $currentblockcount
currentblockcount=$((currentblockcount + 1))
else
exit;
fi
main
}
startingblockcount=1213133
endingblockcount=1213143
echo "Syncing..."
currentblockcount=$startingblockcount
main
-28
View File
@@ -1,28 +0,0 @@
#!/bin/sh
# this super hack will sync the explorer from the newest block as they occur
forcesync() {
blockcount=$1
echo "╒══════════════════<<"
echo "| height : $blockcount"
blockhash=`curl -s https://explorer.exor.io/api/getblockhash?height=$blockcount`
echo "| ଓ hash : $blockhash"
curl -s https://explorer.exor.io/block/$blockhash > /dev/null
echo "╘═══════════════════════════════>>"
}
main() {
echo "Checking for new block..."
previousblockcount=$currentblockcount
currentblockcount=`curl -s https://explorer.exor.io/api/getblockcount`
if [ $currentblockcount -ne $previousblockcount ]; then
echo "New block found. Syncing..."
forcesync $currentblockcount
else
echo "No new block found. Sleeping...";
fi
sleep 20
main
}
currentblockcount=0
main
+108
View File
@@ -0,0 +1,108 @@
const minNodeVersionMajor = '14';
const minNodeVersionMinor = '13';
const minNodeVersionRevision = '1';
// get the nodejs version
var nodeVersion = process.version;
var nodeVersionMajor = '0';
var nodeVersionMinor = '0';
var 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
var 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(0);
}
function check_argument_passed(cb) {
// check 1st argument
if (process.argv[2] != null) {
const { exec } = require('child_process');
// determine which argument was passed
switch (process.argv[2]) {
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).split('\n').filter(element => element);
// check if the cmd result contains an @ symbol
if (splitResponse[splitResponse.length - 1].indexOf('@') == -1) {
console.log('Installing pm2 module.. Please wait..');
// install pm2
exec(`npm install pm2@latest${(isWinOS ? ' -g' : '')}`, (err, stdout, stderr) => {
// always return true for now without checking results
return cb(true);
});
} else
return cb(true);
});
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).split('\n').filter(element => element);
// check if the cmd result contains an @ symbol
if (splitResponse[splitResponse.length - 1].indexOf('@') == -1) {
console.log('Installing forever module.. Please wait..');
// install forever
exec('npm install forever', (err, stdout, stderr) => {
// always return true for now without checking results
return cb(true);
});
} else
return cb(true);
});
break;
default:
// argument not passed or unknown argument
return cb(true);
}
} else
return cb(true);
}
// check if an argument was passed into this script
check_argument_passed(function(retVal) {
const fs = require('fs');
const settings = require('../lib/settings');
// ensure the selected theme is properly installed
fs.writeFile('./public/css/_theme-selector.scss', `$theme-name: "${settings.shared_pages.theme}";`, function (err) {
const sass = require('sass');
// generate minified css from scss file
const minified = sass.compile('./public/css/style.scss', {style: 'compressed'});
// save the minified css to file
fs.writeFile('./public/css/style.min.css', minified.css, function (err) {
// Finished pre-loading
});
});
});
-67
View File
@@ -1,67 +0,0 @@
#!/bin/bash
readonly MIN_NODE_VERSION_MAJOR="14"
readonly MIN_NODE_VERSION_MINOR="13"
readonly MIN_NODE_VERSION_REVISION="1"
readonly NONE="\033[00m"
readonly RED="\033[01;31m"
begins_with() { case $2 in "$1"*) true;; *) false;; esac; }
error_message() { echo "${RED}Error:${NONE} $1" && echo && exit 1; }
# Get the nodejs version
NODE_VERSION="$(node -v)"
NODE_VERSION_MAJOR="0"
NODE_VERSION_MINOR="0"
NODE_VERSION_REVISION="0"
# Check if the nodejs version # is blank or a very long string as that would usually indicate a problem
if [ "${#NODE_VERSION}" -gt 0 ] && [ "${#NODE_VERSION}" -lt 16 ]; then
# Remove the 'v' from the beginning of the version string
if begins_with "v" "${NODE_VERSION}"; then
NODE_VERSION=$(echo "${NODE_VERSION}" | cut -c2-${#NODE_VERSION})
fi
# Split node version string into major, minor and revision
NODE_VERSION_MAJOR="$(echo $NODE_VERSION | cut -d'.' -f1)"
NODE_VERSION_MINOR="$(echo $NODE_VERSION | cut -d'.' -f2)"
NODE_VERSION_REVISION="$(echo $NODE_VERSION | cut -d'.' -f3)"
fi
# Check if the installed nodejs is an older version than supported by the explorer
if !([ "${NODE_VERSION_MAJOR}" -gt "${MIN_NODE_VERSION_MAJOR}" ] || ([ "${NODE_VERSION_MAJOR}" -eq "${MIN_NODE_VERSION_MAJOR}" ] && ([ "${NODE_VERSION_MINOR}" -gt "${MIN_NODE_VERSION_MINOR}" ] || ([ "${NODE_VERSION_MINOR}" -eq "${MIN_NODE_VERSION_MINOR}" ] && [ "${NODE_VERSION_REVISION}" -ge "${MIN_NODE_VERSION_REVISION}" ])))); then
error_message "Please install an updated version of nodejs.\n\nInstalled: $NODE_VERSION\nRequired: $MIN_NODE_VERSION_MAJOR.$MIN_NODE_VERSION_MINOR.$MIN_NODE_VERSION_REVISION"
fi
## Check if new module directory exists
#if [ ! -d ./node_modules/change_to_module_dir_name ]; then
# # Install updated packages
# npm update
#fi
# Check if an argument was passed into this script
if [ -n "${1}" ]; then
# Determine which argument was passed
case "${1}" in
"pm2")
# Check if pm2 is installed
if [ -z "$(which pm2)" ]; then
# Install pm2
npm install pm2@latest -g
fi
;;
"forever")
# Check if forever is installed
if [ -z "$(which forever)" ]; then
# Install forever
npm install forever -g
fi
;;
esac
fi
# Ensure that selected theme is properly installed
sh ./scripts/sass_theme_reader.sh
# Run sass module to generate minified css from scss file
./node_modules/.bin/sass --no-source-map --style=compressed ./public/css/style.scss ./public/css/style.min.css
+244
View File
@@ -0,0 +1,244 @@
const fs = require('fs');
const path = require('path');
const archiveSuffix = '.bak';
const oldArchiveSuffix = '.tar.gz';
const defaultBackupPath = path.join(path.dirname(__dirname), 'backups');
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('Installing tar package.. Please wait..');
// install tar module
exec('npm install tar', (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, function(err, result) {
if (err || !result) {
console.log(`Unable to delete the ${colName} collection`);
console.log('Aborting');
process.exit(1);
} else
return cb(true);
});
}
function delete_database(settings, cb) {
const mongoose = require('mongoose');
const dbString = `mongodb://${settings.dbsettings.user}:${settings.dbsettings.password}@${settings.dbsettings.address}:${settings.dbsettings.port}/${settings.dbsettings.database}`;
console.log('Connecting to database..');
// connect to mongo database
mongoose.connect(dbString, function(err) {
if (err) {
console.log('Unable to connect to database: %s', dbString);
console.log('Aborting');
process.exit(1);
} else {
// get the list of collections
mongoose.connection.db.listCollections().toArray(function (err, collections) {
if (err) {
console.log('Unable to list collections in database: %s', err);
console.log('Aborting');
process.exit(1);
} else {
// check if there are any collections
if (collections.length > 0) {
var 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) {
// disconnect from mongo database
mongoose.disconnect();
// finished the delete process
return cb(true);
}
});
});
} else {
// nothing to delete
// disconnect from mongo database
mongoose.disconnect();
return cb(true);
}
}
});
}
});
}
function restore_backup(settings, backupPath, extractedPath, gZip) {
const { exec } = require('child_process');
console.log('Restoring backup.. 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}"`)}`);
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}`);
process.exit(1);
} else if (signal) {
console.log(`Process killed with signal: ${signal}`);
process.exit(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`);
process.exit(0);
}
});
}
// check if a backup filename was passed into the script
if (process.argv[2] != null && process.argv[2] != '') {
var backupPath = process.argv[2];
// 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 readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
console.log('You are about to delete the current eIquidus database and restore from backup.');
// prompt for restoring explorer database
rl.question('Are you sure you want to do this? [y/n]: ', function (restoreAnswer) {
// stop prompting
rl.close();
// determine if the explorer database should be restored
switch (restoreAnswer) {
case 'y':
case 'Y':
case 'yes':
case 'YES':
case 'Yes':
const settings = require('../lib/settings');
// check if this is a tar.gz (older explorer backup format)
if (!backupPath.endsWith(oldArchiveSuffix)) {
// newer backup format (.bak)
// delete all collections from existing database
delete_database(settings, function(retVal) {
if (retVal) {
// move on to the restore process
restore_backup(settings, backupPath, backupPath, true);
}
});
} else {
// older backup format (.tar.gz)
// check if the tar module is already installed
check_module_directory_exists('tar', function(retVal) {
const tar = require('tar');
console.log('Extracting backup files.. 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(settings, function(retVal) {
if (retVal) {
// move on to the restore process
restore_backup(settings, 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`);
process.exit(1);
}
}
});
});
}
break;
default:
console.log('Process aborted. Nothing was restored.');
process.exit(1);
}
});
} else {
// backup does not exist
console.log(`${backupPath} cannot be found`);
process.exit(1);
}
} else {
console.log('No backup file specified');
process.exit(1);
}
-63
View File
@@ -1,63 +0,0 @@
#!/bin/bash
ARCHIVE_SUFFIX=".tar.gz"
# Check if a backup file was specified
if [ -n "${1}" ]; then
BACKUP_PATH="${1}"
# Check if the backup file exists as a full path
if [ ! -f "${BACKUP_PATH}" ]; then
# Check if the backup is valid by adding the archive suffix
if [ -f "${BACKUP_PATH}${ARCHIVE_SUFFIX}" ]; then
# The backup file is valid after adding the archive suffix
BACKUP_PATH="${BACKUP_PATH}${ARCHIVE_SUFFIX}"
else
# Prepend the default backup path
BACKUP_PATH="$(dirname $(dirname $(readlink -f "$0")))/backups/${BACKUP_PATH}"
fi
fi
# Check for the backup file (again)
if [ ! -f "${BACKUP_PATH}" ]; then
# Append the default archive suffix
BACKUP_PATH="${BACKUP_PATH}${ARCHIVE_SUFFIX}"
fi
# Check for the backup file (last time)
if [ -f "${BACKUP_PATH}" ]; then
# Extract the backup archive
DIR_NAME=$(dirname "${BACKUP_PATH}")
tar -zxvf "${BACKUP_PATH}" -C "${DIR_NAME}"
# Check if this is a valid backup archive now that the files have been extracted
if [ -d ${BACKUP_PATH%"${ARCHIVE_SUFFIX}"}/explorerdb ]; then
BACKUP_DIR=${BACKUP_PATH%"${ARCHIVE_SUFFIX}"}
# Erase entire database
sudo mongo <<EOF
use explorerdb
db.addresses.drop()
db.addresstxes.drop()
db.networkhistories.drop()
db.coinstats.drop()
db.heavies.drop()
db.markets.drop()
db.masternodes.drop()
db.peers.drop()
db.richlists.drop()
db.txes.drop()
exit
EOF
# Restore mongo database from the backup directory
eval "mongorestore -d explorerdb ${BACKUP_DIR}/explorerdb"
# Remove the backup directory
rm -rf "${BACKUP_DIR}"
# Finished msg
echo "Backup restored from ${BACKUP_PATH} successfully."
else
# Backup file is not a valid mongo database backup
echo "${BACKUP_PATH} is not a valid backup file."
fi
else
# Backup does not exist
echo "${BACKUP_PATH} cannot be found."
fi
else
echo "no backup file specified."
fi
-7
View File
@@ -1,7 +0,0 @@
#!/bin/bash
if [ -f ./settings.json ]; then
echo "\$theme-name: \"$(./node_modules/.bin/strip-json-comments settings.json | ./node_modules/.bin/json shared_pages.theme)\";" > ./public/css/_theme-selector.scss
else
echo "\$theme-name: \"Exor\";" > ./public/css/_theme-selector.scss
fi
+60
View File
@@ -0,0 +1,60 @@
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('Explorer shutting down... Please wait...');
});
} else {
// webserver is not running
console.log('Error: Cannot stop explorer because it is not currently running');
}
});
} else {
// invalid port number
console.log('Error: webserver.port value not found in settings.json.');
}
-32
View File
@@ -1,32 +0,0 @@
#!/bin/bash
validate_port() {
if [ -z "$1" ] || ([ -n "$1" ] && ((echo $1 | egrep -q '^[0-9]+$' && ([ $1 -lt 1 ] || [ $1 -gt 65535 ])) || ! test "$1" -gt 0 2> /dev/null)); then
echo "err"
fi
}
# Check if the settings.json file exists
if [ -f ./settings.json ]; then
# Read the webserver.port value from settings.json file
readonly SERVER_PORT="$(./node_modules/.bin/strip-json-comments settings.json | ./node_modules/.bin/json -q webserver.port)"
# Check if the webserver.port value is a valid port #
if [ -z "$(validate_port $SERVER_PORT)" ]; then
# Check if the server is currently running
if [ -n "$(lsof -t -i:${SERVER_PORT} 2> /dev/null)" ]; then
# Send a SIGINT kill signal to the process that is currently using the explorer's server port
kill -2 $(lsof -t -i:${SERVER_PORT})
# Show shutdown msg
echo "Explorer shutting down... Please wait..."
else
# Webserver is not running
echo "Error: Cannot stop explorer because it is not currently running"
fi
else
# Invalid port number
echo "Error: webserver.port value not found in settings.json. webserver.port value is missing or file is not valid json."
fi
else
# Missing settings file
echo "Error: Cannot find settings.json"
fi
+101 -33
View File
@@ -13,7 +13,7 @@ var block_start = 1;
// displays usage and exits
function usage() {
console.log('Usage: scripts/sync.sh /path/to/node [mode]');
console.log('Usage: /path/to/node scripts/sync.js [mode]');
console.log('');
console.log('Mode: (required)');
console.log('update Updates index from last sync to current block');
@@ -37,41 +37,109 @@ function usage() {
}
// check options
if (process.argv[2] == 'index') {
if (process.argv.length < 3)
usage();
else {
switch (process.argv[3]) {
case 'update':
mode = 'update';
break;
case 'check':
mode = 'check';
if (process.argv[2] == null || process.argv[2] == 'index' || process.argv[2] == 'update') {
mode = null;
// check if the block start value was passed in and is an integer
if (!isNaN(process.argv[4]) && Number.isInteger(parseFloat(process.argv[4]))) {
// Check if the block start value is less than 1
if (parseInt(process.argv[4]) < 1)
block_start = 1;
else
block_start = parseInt(process.argv[4]);
}
switch (process.argv[3]) {
case undefined:
case null:
case 'update':
mode = 'update';
break;
case 'check':
mode = 'check';
break;
case 'reindex':
// check if the block start value was passed in and is an integer
if (!isNaN(process.argv[4]) && Number.isInteger(parseFloat(process.argv[4]))) {
// Check if the block start value is less than 1
if (parseInt(process.argv[4]) < 1)
block_start = 1;
else
block_start = parseInt(process.argv[4]);
}
break;
case 'reindex':
// check if readlinesync module is installed
if (!db.fs.existsSync('./node_modules/readline-sync')) {
const { execSync } = require('child_process');
console.log('Installing missing packages.. Please wait..');
// install updated packages
execSync('npm update');
}
const readlineSync = require('readline-sync');
console.log('You are about to delete all blockchain data (transactions and addresses)');
console.log('and resync from the genesis block.');
// prompt for the reindex
if (readlineSync.keyInYN('Are you sure you want to do this? ')) {
// set mode to 'reindex'
mode = 'reindex';
break;
case 'reindex-rich':
mode = 'reindex-rich';
break;
case 'reindex-txcount':
mode = 'reindex-txcount';
break;
case 'reindex-last':
mode = 'reindex-last';
break;
default:
usage();
} else {
console.log('Process aborted. Nothing was deleted');
process.exit(0);
}
break;
case 'reindex-rich':
mode = 'reindex-rich';
break;
case 'reindex-txcount':
mode = 'reindex-txcount';
break;
case 'reindex-last':
mode = 'reindex-last';
break;
default:
usage();
}
// check if mode is set
if (mode != null) {
const path = require('path');
const pidFile = path.join(path.dirname(__dirname), 'tmp', `${database}.pid`);
// check if the script is already running (tmp/index.pid file already exists)
if (db.fs.existsSync(pidFile)) {
const { execSync } = require('child_process');
var deactivateLock = false;
// the tmp/index.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 ${db.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
db.fs.rmSync(pidFile);
}
}
}
} else if (process.argv[2] == 'market')
-161
View File
@@ -1,161 +0,0 @@
#!/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"
# Check if the next parameter exists
if [ -n "${2}" ]; then
# Add onto the check cmd
MODE="${MODE} ${2}"
fi
;;
"reindex")
# Index reindex
MODE="index reindex"
;;
"reindex-rich")
# Index reindex-rich
MODE="index reindex-rich"
;;
"reindex-txcount")
# Index reindex-txcount
MODE="index reindex-txcount"
;;
"reindex-last")
# Index reindex-last
MODE="index reindex-last"
;;
"market")
# Market update
MODE="market"
;;
"peers")
# Peers update
MODE="peers"
;;
"masternodes")
# Masternodes update
MODE="masternodes"
;;
*)
# 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"
# Check if the next parameter exists
if [ -n "${3}" ]; then
# Add onto the check cmd
MODE="${MODE} ${3}"
fi
;;
"reindex")
# Index reindex
MODE="index reindex"
;;
"reindex-rich")
# Index reindex-rich
MODE="index reindex-rich"
;;
"reindex-txcount")
# Index reindex-txcount
MODE="index reindex-txcount"
;;
"reindex-last")
# Index reindex-last
MODE="index reindex-last"
;;
"market")
# Market update
MODE="market"
;;
"peers")
# Peers update
MODE="peers"
;;
"masternodes")
# Masternodes update
MODE="masternodes"
;;
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" ] && [ "${MODE}" != "masternodes" ]; then
# A lock is required
# Check if this is a reindex
if [ "${MODE}" = "index reindex" ]; then
# Prompt for the reindex
echo "You are about to delete all blockchain data (transactions and addresses)"
echo "and resync from the genesis block."
echo "Are you sure you want to do this? [y/n]: ";
read -p "" REINDEX_ANSWER
# Determine if the reindex should proceed
case "$REINDEX_ANSWER" in
y|Y|yes|Yes|YES) ;;
*) echo "Process aborted. Nothing was deleted." && exit ;;
esac
fi
# 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