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:
@@ -80,6 +80,7 @@ Table of Contents
|
|||||||
- Chart.js v3.6.1
|
- Chart.js v3.6.1
|
||||||
- chartjs-plugin-crosshair v1.2.0 ([https://github.com/abelheinsbroek/chartjs-plugin-crosshair](https://github.com/abelheinsbroek/chartjs-plugin-crosshair))
|
- chartjs-plugin-crosshair v1.2.0 ([https://github.com/abelheinsbroek/chartjs-plugin-crosshair](https://github.com/abelheinsbroek/chartjs-plugin-crosshair))
|
||||||
- flag-icon-css v4.1.4 ([https://github.com/lipis/flag-icon-css](https://github.com/lipis/flag-icon-css))
|
- flag-icon-css v4.1.4 ([https://github.com/lipis/flag-icon-css](https://github.com/lipis/flag-icon-css))
|
||||||
|
- Platform independent (tested to run on Windows, MacOS and Linux) **NOTE:** Most of the instructions in this guide were written for use with Linux and may need to be modified when using another OS
|
||||||
- Mobile-friendly
|
- Mobile-friendly
|
||||||
- Sass support
|
- Sass support
|
||||||
- Pages/features:
|
- Pages/features:
|
||||||
@@ -291,7 +292,7 @@ npm start
|
|||||||
or (useful for crontab):
|
or (useful for crontab):
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run prestart && /path/to/node --stack-size=10000 ./bin/cluster
|
cd /path/to/explorer && /path/to/npm run prestart && /path/to/node --stack-size=10000 ./bin/cluster
|
||||||
```
|
```
|
||||||
|
|
||||||
**NOTE:** mongod must be running to start the explorer.
|
**NOTE:** mongod must be running to start the explorer.
|
||||||
@@ -305,7 +306,7 @@ npm run start-instance
|
|||||||
or (useful for crontab):
|
or (useful for crontab):
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run prestart && /path/to/node --stack-size=10000 ./bin/instance
|
cd /path/to/explorer && /path/to/npm run prestart && /path/to/node --stack-size=10000 ./bin/instance
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Stop Explorer (Use for Testing)
|
#### Stop Explorer (Use for Testing)
|
||||||
@@ -319,7 +320,7 @@ npm stop
|
|||||||
or (useful for crontab):
|
or (useful for crontab):
|
||||||
|
|
||||||
```
|
```
|
||||||
sh ./scripts/stop_explorer.sh
|
cd /path/to/explorer && /path/to/node ./scripts/stop_explorer.js
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Start Explorer Using PM2 (Recommended for Production)
|
#### Start Explorer Using PM2 (Recommended for Production)
|
||||||
@@ -335,10 +336,10 @@ npm run start-pm2
|
|||||||
or (useful for crontab):
|
or (useful for crontab):
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run prestart "pm2" && /path/to/pm2 start ./bin/instance -i 0 --node-args="--stack-size=10000"
|
cd /path/to/explorer && /path/to/npm run prestart "pm2" && /path/to/pm2 start ./bin/instance -i 0 --node-args="--stack-size=10000"
|
||||||
```
|
```
|
||||||
|
|
||||||
**NOTE:** Use the following cmd to find the install path for PM2:
|
**NOTE:** Use the following cmd to find the install path for PM2 (Linux only):
|
||||||
|
|
||||||
```
|
```
|
||||||
which pm2
|
which pm2
|
||||||
@@ -355,7 +356,7 @@ npm run start-pm2-debug
|
|||||||
or (useful for crontab):
|
or (useful for crontab):
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run prestart "pm2" && /path/to/pm2 start ./bin/instance -i 0 --node-args="--stack-size=10000" && /path/to/pm2 logs
|
cd /path/to/explorer && /path/to/npm run prestart "pm2" && /path/to/pm2 start ./bin/instance -i 0 --node-args="--stack-size=10000" && /path/to/pm2 logs
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Stop Explorer Using PM2 (Recommended for Production)
|
#### Stop Explorer Using PM2 (Recommended for Production)
|
||||||
@@ -369,7 +370,7 @@ npm run stop-pm2
|
|||||||
or (useful for crontab):
|
or (useful for crontab):
|
||||||
|
|
||||||
```
|
```
|
||||||
/path/to/pm2 stop ./bin/instance
|
cd /path/to/explorer && /path/to/pm2 stop ./bin/instance
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Start Explorer Using Forever (Alternate Production Option)
|
#### Start Explorer Using Forever (Alternate Production Option)
|
||||||
@@ -385,10 +386,10 @@ npm run start-forever
|
|||||||
or (useful for crontab):
|
or (useful for crontab):
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run prestart && /path/to/node /path/to/forever start ./bin/cluster
|
cd /path/to/explorer && /path/to/npm run prestart && /path/to/forever start ./bin/cluster
|
||||||
```
|
```
|
||||||
|
|
||||||
**NOTE:** Use the following cmd to find the install path for forever:
|
**NOTE:** Use the following cmd to find the install path for forever (Linux only):
|
||||||
|
|
||||||
```
|
```
|
||||||
which forever
|
which forever
|
||||||
@@ -405,15 +406,15 @@ npm run stop-forever
|
|||||||
or (useful for crontab):
|
or (useful for crontab):
|
||||||
|
|
||||||
```
|
```
|
||||||
/path/to/node /path/to/forever stop ./bin/cluster
|
cd /path/to/explorer && /path/to/forever stop ./bin/cluster
|
||||||
```
|
```
|
||||||
|
|
||||||
### Syncing Databases with the Blockchain
|
### Syncing Databases with the Blockchain
|
||||||
|
|
||||||
sync.sh (located in scripts/) is used for updating the local databases. This script must be called from the explorers root directory.
|
sync.js (located in scripts/) is used for updating the local databases. This script must be called from the explorers root directory.
|
||||||
|
|
||||||
```
|
```
|
||||||
Usage: scripts/sync.sh /path/to/node [mode]
|
Usage: /path/to/node scripts/sync.js [mode]
|
||||||
|
|
||||||
Mode: (required)
|
Mode: (required)
|
||||||
update Updates index from last sync to current block
|
update Updates index from last sync to current block
|
||||||
@@ -469,10 +470,10 @@ Easier crontab syntax using npm scripts, but may not work on some systems depend
|
|||||||
Or, run the crontab by calling the sync script directly, which should work better in the event you have problems running the npm scripts from a crontab:
|
Or, run the crontab by calling the sync script directly, which should work better in the event you have problems running the npm scripts from a crontab:
|
||||||
|
|
||||||
```
|
```
|
||||||
*/1 * * * * /path/to/explorer/scripts/sync.sh /path/to/node update > /dev/null 2>&1
|
*/1 * * * * cd /path/to/explorer && /path/to/node scripts/sync.js update > /dev/null 2>&1
|
||||||
*/2 * * * * /path/to/explorer/scripts/sync.sh /path/to/node market > /dev/null 2>&1
|
*/2 * * * * cd /path/to/explorer && /path/to/node scripts/sync.js market > /dev/null 2>&1
|
||||||
*/5 * * * * /path/to/explorer/scripts/sync.sh /path/to/node peers > /dev/null 2>&1
|
*/5 * * * * cd /path/to/explorer && /path/to/node scripts/sync.js peers > /dev/null 2>&1
|
||||||
*/5 * * * * /path/to/explorer/scripts/sync.sh /path/to/node masternodes > /dev/null 2>&1
|
*/5 * * * * cd /path/to/explorer && /path/to/node scripts/sync.js masternodes > /dev/null 2>&1
|
||||||
```
|
```
|
||||||
|
|
||||||
### Wallet Settings
|
### Wallet Settings
|
||||||
@@ -504,6 +505,8 @@ A typical webserver binds to port 80 to serve webpages over the http protocol, b
|
|||||||
|
|
||||||
#### Use Setcap to Safely Grant User Permissions
|
#### Use Setcap to Safely Grant User Permissions
|
||||||
|
|
||||||
|
**NOTE:** This option is only available to Linux users
|
||||||
|
|
||||||
1. You can use the `setcap` command to change the capabilities of the `node` binary file to specifically allow the Express webserver to bind to a port less than 1024 (this one-time cmd requires root privileges):
|
1. You can use the `setcap` command to change the capabilities of the `node` binary file to specifically allow the Express webserver to bind to a port less than 1024 (this one-time cmd requires root privileges):
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -516,6 +519,8 @@ You should now be able to browse to the explorer by IP address or domain name wi
|
|||||||
|
|
||||||
#### Use Another Webserver as a Reverse Proxy
|
#### Use Another Webserver as a Reverse Proxy
|
||||||
|
|
||||||
|
**NOTE:** The following instructions are for Linux users only, but installing and configuring another webserver should be possible on any OS
|
||||||
|
|
||||||
A few steps are involved in setting up another webserver that can bind to port 80 and forward all incoming traffic to the eIquidus node.js app. Any commercial webserver can be used to create the reverse proxy, but in this case, Nginx will be used as an example:
|
A few steps are involved in setting up another webserver that can bind to port 80 and forward all incoming traffic to the eIquidus node.js app. Any commercial webserver can be used to create the reverse proxy, but in this case, Nginx will be used as an example:
|
||||||
|
|
||||||
1. Install Nginx with the following terminal cmd:
|
1. Install Nginx with the following terminal cmd:
|
||||||
@@ -573,6 +578,8 @@ Similar to [the problem with binding to port 80](#run-express-webserver-on-port-
|
|||||||
|
|
||||||
#### Prerequisites
|
#### Prerequisites
|
||||||
|
|
||||||
|
**NOTE:** The following instructions are for Linux users only, but installing and configuring certbot should be possible on any OS
|
||||||
|
|
||||||
There are a few common steps that must be completed before TLS/SSL certificates can be generated:
|
There are a few common steps that must be completed before TLS/SSL certificates can be generated:
|
||||||
|
|
||||||
1. Install snapd:
|
1. Install snapd:
|
||||||
@@ -601,6 +608,8 @@ sudo ln -s /snap/bin/certbot /usr/bin/certbot
|
|||||||
|
|
||||||
#### Manually Link TLS/SSL Certificates to the Explorer
|
#### Manually Link TLS/SSL Certificates to the Explorer
|
||||||
|
|
||||||
|
**NOTE:** The following instructions are for Linux users only, but installing and configuring certbot should be possible on any OS
|
||||||
|
|
||||||
Follow the steps below to configure the Express webserver for use with TLS/SSL:
|
Follow the steps below to configure the Express webserver for use with TLS/SSL:
|
||||||
|
|
||||||
1. If you haven't already done so, run the `setcap` cmd from the [Use Setcap to Safely Grant User Permissions Instructions](#use-setcap-to-safely-grant-user-permissions) which will allow node.js to bind to port 443 without needing root permissions.
|
1. If you haven't already done so, run the `setcap` cmd from the [Use Setcap to Safely Grant User Permissions Instructions](#use-setcap-to-safely-grant-user-permissions) which will allow node.js to bind to port 443 without needing root permissions.
|
||||||
@@ -645,6 +654,8 @@ Ensure that `webserver.tls.enabled` = true and that you specify the exact path t
|
|||||||
|
|
||||||
#### Use Nginx as a Reverse Proxy
|
#### Use Nginx as a Reverse Proxy
|
||||||
|
|
||||||
|
**NOTE:** The following instructions are for Linux users only, but installing and configuring certbot and nginx should be possible on any OS
|
||||||
|
|
||||||
1. If you haven't already done so, first follow through the [Use Another Webserver as a Reverse Proxy Instructions](#use-another-webserver-as-a-reverse-proxy) and then continue with step #2 below.
|
1. If you haven't already done so, first follow through the [Use Another Webserver as a Reverse Proxy Instructions](#use-another-webserver-as-a-reverse-proxy) and then continue with step #2 below.
|
||||||
|
|
||||||
2. Generate a new TLS/SSL certificate via certbot which will automatically edit your Nginx configuration files and enable https at the same time:
|
2. Generate a new TLS/SSL certificate via certbot which will automatically edit your Nginx configuration files and enable https at the same time:
|
||||||
@@ -708,47 +719,51 @@ jQuery(document).ready(function($) {
|
|||||||
|
|
||||||
#### Backup Database Script
|
#### Backup Database Script
|
||||||
|
|
||||||
Make a complete backup of an eIquidus mongo database collection and save to compressed tar.gz file. Please note that you must ensure that the explorer is NOT running at the time of backup to prevent corrupting the backup data. The following backup scenarios are supported:
|
Make a complete backup of an eIquidus mongo database collection and save to compressed file. Please note that you must ensure that the explorer is NOT running at the time of backup to prevent corrupting the backup data. The following backup scenarios are supported:
|
||||||
|
|
||||||
**Backup Database (No filename specified)**
|
**Backup Database (No filename specified)**
|
||||||
|
|
||||||
`sh scripts/create_backup.sh`: Backs up to the explorer/backups directory by default with the current date as the filename in the format yyyy-MMM-dd.tar.gz
|
`npm run create-backup`: Backs up to the explorer/backups directory by default with the current date as the filename in the format yyyy-MMM-dd.bak
|
||||||
|
|
||||||
**Backup Database (Partial filename specified)**
|
**Backup Database (Partial filename specified)**
|
||||||
|
|
||||||
`sh scripts/create_backup.sh test`: Backs up the the explorer/backups directory by default with the filename test.tar.gz
|
`npm run create-backup test`: Backs up the the explorer/backups directory by default with the filename test.bak
|
||||||
|
|
||||||
**Backup Database (Full filename specified)**
|
**Backup Database (Full filename specified)**
|
||||||
|
|
||||||
`sh scripts/create_backup.sh today.tar.gz`: Backs up the the explorer/backups directory by default with the filename today.tar.gz
|
`npm run create-backup today.bak`: Backs up the the explorer/backups directory by default with the filename today.bak
|
||||||
|
|
||||||
**Backup Database (Full path with partial filename specified)**
|
**Backup Database (Full path with partial filename specified)**
|
||||||
|
|
||||||
`sh scripts/create_backup.sh /usr/local/bin/abc`: Backs up the the /usr/local/bin directory with the filename abc.tar.gz
|
`npm run create-backup /usr/local/bin/abc`: Backs up the the /usr/local/bin directory with the filename abc.bak
|
||||||
|
|
||||||
**Backup Database (Full path and filename specified)**
|
**Backup Database (Full path and filename specified)**
|
||||||
|
|
||||||
`sh scripts/create_backup.sh ~/new.tar.gz`: Backs up the the users home directory with the filename new.tar.gz
|
`npm run create-backup ~/new.bak`: Backs up the the users home directory with the filename new.bak
|
||||||
|
|
||||||
#### Restore Database Script
|
#### Restore Database Script
|
||||||
|
|
||||||
Restore a previously saved eIquidus mongo database collection backup. :warning: **WARNING:** This will completely overwrite your existing eIquidus mongo database, so be sure to make a full backup before proceeding. Please note that the explorer should NOT be running at the time of restore to prevent problems restoring the database. The following restore scenarios are supported:
|
Restore a previously saved eIquidus mongo database collection backup. :warning: **WARNING:** This will completely overwrite your existing eIquidus mongo database, so be sure to make a full backup before proceeding. Please note that the explorer should NOT be running at the time of restore to prevent problems restoring the database.
|
||||||
|
|
||||||
|
**NOTE:** Older v1.x eIquidus database backups were compressed into tar.gz files. These older tar.gz backups can still be restored, but you must specifically add the .tar.gz suffix. Example: `npm run restore-backup /path/to/old_backup.tar.gz`
|
||||||
|
|
||||||
|
The following restore scenarios are supported:
|
||||||
|
|
||||||
**Restore Database (Partial filename specified)**
|
**Restore Database (Partial filename specified)**
|
||||||
|
|
||||||
`sh scripts/restore_backup.sh old`: Restores the explorer/scripts/backups/old.tar.gz file
|
`npm run restore-backup old`: Restores the explorer/scripts/backups/old.bak file
|
||||||
|
|
||||||
**Restore Database (Full filename specified)**
|
**Restore Database (Full filename specified)**
|
||||||
|
|
||||||
`sh scripts/restore_backup.sh working.tar.gz`: Restores the explorer/scripts/backups/working.tar.gz file
|
`npm run restore-backup working.bak`: Restores the explorer/scripts/backups/working.bak file
|
||||||
|
|
||||||
**Restore Database (Full path with partial filename specified)**
|
**Restore Database (Full path with partial filename specified)**
|
||||||
|
|
||||||
`sh scripts/restore_backup.sh /home/explorer/backup`: Restores the /home/explorer/backup.tar.gz file
|
`npm run restore-backup /home/explorer/backup`: Restores the /home/explorer/backup.bak file
|
||||||
|
|
||||||
**Restore Database (Full path and filename specified)**
|
**Restore Database (Full path and filename specified)**
|
||||||
|
|
||||||
`sh scripts/restore_backup.sh ~/archive.tar.gz`: Restores the ~/archive.tar.gz file
|
`npm run restore-backup ~/archive.bak`: Restores the ~/archive.bak file
|
||||||
|
|
||||||
#### Delete Database Script
|
#### Delete Database Script
|
||||||
|
|
||||||
@@ -756,7 +771,7 @@ Completely wipe the eIquidus mongo database collection clean to start again from
|
|||||||
|
|
||||||
**Delete Database**
|
**Delete Database**
|
||||||
|
|
||||||
`sh scripts/delete_database.sh`
|
`npm run delete-database`
|
||||||
|
|
||||||
### Known Issues
|
### Known Issues
|
||||||
|
|
||||||
@@ -766,7 +781,7 @@ Completely wipe the eIquidus mongo database collection clean to start again from
|
|||||||
RangeError: Maximum call stack size exceeded
|
RangeError: Maximum call stack size exceeded
|
||||||
```
|
```
|
||||||
|
|
||||||
Nodes default stack size may be too small to index addresses with many tx's. If you experience the above error while running sync.sh the stack size needs to be increased.
|
Nodes default stack size may be too small to index addresses with many tx's. If you experience the above error while running sync.js the stack size needs to be increased.
|
||||||
|
|
||||||
To determine the default setting run:
|
To determine the default setting run:
|
||||||
|
|
||||||
|
|||||||
+14
-2
@@ -1,5 +1,6 @@
|
|||||||
var cluster = require('cluster');
|
var cluster = require('cluster');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
const isWinOS = process.platform == 'win32';
|
||||||
|
|
||||||
if (cluster.isMaster) {
|
if (cluster.isMaster) {
|
||||||
console.log('Starting cluster with pid: ' + process.pid);
|
console.log('Starting cluster with pid: ' + process.pid);
|
||||||
@@ -11,7 +12,11 @@ if (cluster.isMaster) {
|
|||||||
// send kill cmd to all workers
|
// send kill cmd to all workers
|
||||||
for (var id in cluster.workers) {
|
for (var id in cluster.workers) {
|
||||||
console.log('Worker (' + id + ') shutting down...');
|
console.log('Worker (' + id + ') shutting down...');
|
||||||
process.kill(cluster.workers[id]['process']['pid'], 'SIGINT');
|
|
||||||
|
if (!isWinOS) {
|
||||||
|
// only kill the worker if not on windows (otherwise an error is displayed)
|
||||||
|
process.kill(cluster.workers[id]['process']['pid'], 'SIGINT');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function waitForWorkerShutdown () {
|
function waitForWorkerShutdown () {
|
||||||
@@ -21,6 +26,13 @@ if (cluster.isMaster) {
|
|||||||
} else {
|
} else {
|
||||||
// all worker threads have closed
|
// all worker threads have closed
|
||||||
// now exit the master process
|
// now exit the master process
|
||||||
|
|
||||||
|
if (isWinOS) {
|
||||||
|
// command line in windows doesn't seem to release itself
|
||||||
|
// show a message that the app has finished
|
||||||
|
console.log('The application is now safe to close');
|
||||||
|
}
|
||||||
|
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,7 +51,7 @@ if (cluster.isMaster) {
|
|||||||
cluster.on('exit', function (worker, code, signal) {
|
cluster.on('exit', function (worker, code, signal) {
|
||||||
if (worker['process']['exitCode'] === 0) {
|
if (worker['process']['exitCode'] === 0) {
|
||||||
console.log('Worker (' + worker['id'] + ') shutdown complete');
|
console.log('Worker (' + worker['id'] + ') shutdown complete');
|
||||||
} else if ((signal != 'SIGINT') && (worker['process']['exitCode'] !== 0) && (worker.exitedAfterDisconnect !== true)) {
|
} else if (signal != 'SIGINT' && worker['process']['exitCode'] !== 0 && worker['process']['exitCode'] !== 999 && worker.exitedAfterDisconnect !== true) {
|
||||||
console.log('Cluster restarting...');
|
console.log('Cluster restarting...');
|
||||||
cluster.fork();
|
cluster.fork();
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -219,7 +219,7 @@ module.exports = {
|
|||||||
if (err) {
|
if (err) {
|
||||||
console.log('Unable to connect to database: %s', database);
|
console.log('Unable to connect to database: %s', database);
|
||||||
console.log('Aborting');
|
console.log('Aborting');
|
||||||
process.exit(1);
|
process.exit(999);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cb();
|
return cb();
|
||||||
|
|||||||
+2
-2
@@ -1088,9 +1088,9 @@ exports.sync = {
|
|||||||
// If you sync using more than 1 parallel task, then historical balance data for wallet addresses can possibly be saved out-of-order and there is currently no workaround for this.
|
// If you sync using more than 1 parallel task, then historical balance data for wallet addresses can possibly be saved out-of-order and there is currently no workaround for this.
|
||||||
// Therefore, it is recommended to keep this setting to 1 parallel task for now until a proper solution can be procured for the historical balance issue.
|
// Therefore, it is recommended to keep this setting to 1 parallel task for now until a proper solution can be procured for the historical balance issue.
|
||||||
"block_parallel_tasks": 1,
|
"block_parallel_tasks": 1,
|
||||||
// update_timeout: The amount of time to wait (in milliseconds) before moving to the next block or transaction during blockchain sync or reindex (scripts/sync.sh /path/to/node update or scripts/sync.sh /path/to/node reindex)
|
// update_timeout: The amount of time to wait (in milliseconds) before moving to the next block or transaction during blockchain sync or reindex (/path/to/node scripts/sync.js update or /path/to/node scripts/sync.js reindex)
|
||||||
"update_timeout": 10,
|
"update_timeout": 10,
|
||||||
// check_timeout: The amount of time to wait (in milliseconds) before moving to the next block or transaction during a check sync (scripts/sync.sh /path/to/node check)
|
// check_timeout: The amount of time to wait (in milliseconds) before moving to the next block or transaction during a check sync (/path/to/node scripts/sync.js check)
|
||||||
"check_timeout": 250,
|
"check_timeout": 250,
|
||||||
// save_stats_after_sync_blocks: During index syncronization, stats are saved after processing this many blocks to save time by not having to save after each block
|
// save_stats_after_sync_blocks: During index syncronization, stats are saved after processing this many blocks to save time by not having to save after each block
|
||||||
"save_stats_after_sync_blocks": 100,
|
"save_stats_after_sync_blocks": 100,
|
||||||
|
|||||||
+24
-22
@@ -3,25 +3,28 @@
|
|||||||
"version": "1.99.0",
|
"version": "1.99.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "npm run prestart && $(which node) --stack-size=10000 ./bin/cluster",
|
"start": "npm run prestart && node --stack-size=10000 ./bin/cluster",
|
||||||
"stop": "sh ./scripts/stop_explorer.sh",
|
"stop": "node ./scripts/stop_explorer.js",
|
||||||
"start-instance": "npm run prestart && $(which node) --stack-size=10000 ./bin/instance",
|
"start-instance": "npm run prestart && node --stack-size=10000 ./bin/instance",
|
||||||
"start-forever": "npm run prestart \"forever\" && $(which node) $(which forever) start ./bin/cluster",
|
"start-forever": "npm run prestart \"forever\" && forever start ./bin/cluster",
|
||||||
"stop-forever": "$(which node) $(which forever) stop ./bin/cluster",
|
"stop-forever": "forever stop ./bin/cluster",
|
||||||
"start-pm2": "npm run prestart \"pm2\" && $(which pm2) start ./bin/instance -i 0 --node-args=\"--stack-size=10000\"",
|
"start-pm2": "npm run prestart \"pm2\" && pm2 start ./bin/instance -i 0 --node-args=\"--stack-size=10000\"",
|
||||||
"start-pm2-debug": "npm run prestart \"pm2\" && $(which pm2) start ./bin/instance -i 0 --node-args=\"--stack-size=10000\" && $(which pm2) logs",
|
"start-pm2-debug": "npm run prestart \"pm2\" && pm2 start ./bin/instance -i 0 --node-args=\"--stack-size=10000\" && pm2 logs",
|
||||||
"stop-pm2": "$(which pm2) stop ./bin/instance",
|
"stop-pm2": "pm2 stop ./bin/instance",
|
||||||
"test": "$(which node) ./node_modules/jasmine/bin/jasmine.js test/*Spec.js",
|
"test": "node ./node_modules/jasmine/bin/jasmine.js test/*Spec.js",
|
||||||
"prestart": "sh ./scripts/prestart.sh",
|
"prestart": "node ./scripts/prestart.js",
|
||||||
"sync-blocks": "sh ./scripts/sync.sh $(which node) update",
|
"sync-blocks": "node ./scripts/sync.js index update",
|
||||||
"sync-markets": "sh ./scripts/sync.sh $(which node) market",
|
"sync-markets": "node ./scripts/sync.js market",
|
||||||
"sync-peers": "sh ./scripts/sync.sh $(which node) peers",
|
"sync-peers": "node ./scripts/sync.js peers",
|
||||||
"sync-masternodes": "sh ./scripts/sync.sh $(which node) masternodes",
|
"sync-masternodes": "node ./scripts/sync.js masternodes",
|
||||||
"check-blocks": "sh ./scripts/sync.sh $(which node) check",
|
"check-blocks": "node ./scripts/sync.js index check",
|
||||||
"reindex": "sh ./scripts/sync.sh $(which node) reindex",
|
"reindex": "node ./scripts/sync.js index reindex",
|
||||||
"reindex-rich": "sh ./scripts/sync.sh $(which node) reindex-rich",
|
"reindex-rich": "node ./scripts/sync.js index reindex-rich",
|
||||||
"reindex-txcount": "sh ./scripts/sync.sh $(which node) reindex-txcount",
|
"reindex-txcount": "node ./scripts/sync.js index reindex-txcount",
|
||||||
"reindex-last": "sh ./scripts/sync.sh $(which node) reindex-last"
|
"reindex-last": "node ./scripts/sync.js index reindex-last",
|
||||||
|
"create-backup": "node ./scripts/create_backup.js",
|
||||||
|
"restore-backup": "node ./scripts/restore_backup.js",
|
||||||
|
"delete-database": "node ./scripts/delete_database.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": ">=4.17.1",
|
"express": ">=4.17.1",
|
||||||
@@ -40,9 +43,8 @@
|
|||||||
"mongoose": "^6.0.14",
|
"mongoose": "^6.0.14",
|
||||||
"qr-image": "^3.2.0",
|
"qr-image": "^3.2.0",
|
||||||
"sass": "^1.44.0",
|
"sass": "^1.44.0",
|
||||||
"json": "^11.0.0",
|
"bad-words": "^3.0.4",
|
||||||
"strip-json-comments-cli": "^2.0.1",
|
"readline-sync": "^1.4.10"
|
||||||
"bad-words": "^3.0.4"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"jasmine": ">=3.6.3"
|
"jasmine": ">=3.6.3"
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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
|
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -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
|
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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.');
|
||||||
|
}
|
||||||
@@ -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
@@ -13,7 +13,7 @@ var block_start = 1;
|
|||||||
|
|
||||||
// displays usage and exits
|
// displays usage and exits
|
||||||
function usage() {
|
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('');
|
||||||
console.log('Mode: (required)');
|
console.log('Mode: (required)');
|
||||||
console.log('update Updates index from last sync to current block');
|
console.log('update Updates index from last sync to current block');
|
||||||
@@ -37,41 +37,109 @@ function usage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check options
|
// check options
|
||||||
if (process.argv[2] == 'index') {
|
if (process.argv[2] == null || process.argv[2] == 'index' || process.argv[2] == 'update') {
|
||||||
if (process.argv.length < 3)
|
mode = null;
|
||||||
usage();
|
|
||||||
else {
|
|
||||||
switch (process.argv[3]) {
|
|
||||||
case 'update':
|
|
||||||
mode = 'update';
|
|
||||||
break;
|
|
||||||
case 'check':
|
|
||||||
mode = 'check';
|
|
||||||
|
|
||||||
// check if the block start value was passed in and is an integer
|
switch (process.argv[3]) {
|
||||||
if (!isNaN(process.argv[4]) && Number.isInteger(parseFloat(process.argv[4]))) {
|
case undefined:
|
||||||
// Check if the block start value is less than 1
|
case null:
|
||||||
if (parseInt(process.argv[4]) < 1)
|
case 'update':
|
||||||
block_start = 1;
|
mode = 'update';
|
||||||
else
|
break;
|
||||||
block_start = parseInt(process.argv[4]);
|
case 'check':
|
||||||
}
|
mode = 'check';
|
||||||
|
|
||||||
break;
|
// check if the block start value was passed in and is an integer
|
||||||
case 'reindex':
|
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';
|
mode = 'reindex';
|
||||||
break;
|
} else {
|
||||||
case 'reindex-rich':
|
console.log('Process aborted. Nothing was deleted');
|
||||||
mode = 'reindex-rich';
|
process.exit(0);
|
||||||
break;
|
}
|
||||||
case 'reindex-txcount':
|
|
||||||
mode = 'reindex-txcount';
|
break;
|
||||||
break;
|
case 'reindex-rich':
|
||||||
case 'reindex-last':
|
mode = 'reindex-rich';
|
||||||
mode = 'reindex-last';
|
break;
|
||||||
break;
|
case 'reindex-txcount':
|
||||||
default:
|
mode = 'reindex-txcount';
|
||||||
usage();
|
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')
|
} else if (process.argv[2] == 'market')
|
||||||
|
|||||||
-161
@@ -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
|
|
||||||
@@ -1172,9 +1172,9 @@
|
|||||||
// If you sync using more than 1 parallel task, then historical balance data for wallet addresses can possibly be saved out-of-order and there is currently no workaround for this.
|
// If you sync using more than 1 parallel task, then historical balance data for wallet addresses can possibly be saved out-of-order and there is currently no workaround for this.
|
||||||
// Therefore, it is recommended to keep this setting to 1 parallel task for now until a proper solution can be procured for the historical balance issue.
|
// Therefore, it is recommended to keep this setting to 1 parallel task for now until a proper solution can be procured for the historical balance issue.
|
||||||
"block_parallel_tasks": 1,
|
"block_parallel_tasks": 1,
|
||||||
// update_timeout: The amount of time to wait (in milliseconds) before moving to the next block or transaction during blockchain sync or reindex (scripts/sync.sh /path/to/node update or scripts/sync.sh /path/to/node reindex)
|
// update_timeout: The amount of time to wait (in milliseconds) before moving to the next block or transaction during blockchain sync or reindex (/path/to/node scripts/sync.js update or /path/to/node scripts/sync.js reindex)
|
||||||
"update_timeout": 10,
|
"update_timeout": 10,
|
||||||
// check_timeout: The amount of time to wait (in milliseconds) before moving to the next block or transaction during a check sync (scripts/sync.sh /path/to/node check)
|
// check_timeout: The amount of time to wait (in milliseconds) before moving to the next block or transaction during a check sync (/path/to/node scripts/sync.js check)
|
||||||
"check_timeout": 250,
|
"check_timeout": 250,
|
||||||
// save_stats_after_sync_blocks: During index syncronization, stats are saved after processing this many blocks to save time by not having to save after each block
|
// save_stats_after_sync_blocks: During index syncronization, stats are saved after processing this many blocks to save time by not having to save after each block
|
||||||
"save_stats_after_sync_blocks": 100,
|
"save_stats_after_sync_blocks": 100,
|
||||||
|
|||||||
Reference in New Issue
Block a user