mirror of
https://github.com/Retropex/apolloapi-v2.git
synced 2025-05-28 04:52:34 +02:00
commit
538da8ac95
3
.gitignore
vendored
3
.gitignore
vendored
@ -60,6 +60,7 @@ typings/
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.staging
|
||||
.env*.local
|
||||
|
||||
# next.js build output
|
||||
@ -67,6 +68,7 @@ typings/
|
||||
|
||||
# sqlite
|
||||
*.sqlite
|
||||
*.sqlite.*
|
||||
|
||||
#backed
|
||||
backend/apollo-miner/apollo-miner*
|
||||
@ -77,3 +79,4 @@ backend/node/bitcoind
|
||||
backend/node/bitcoin.conf
|
||||
backend/ckpool/ckpool.conf
|
||||
backend/start_swap.sh
|
||||
backend/apollo-miner/mode
|
||||
|
@ -2,7 +2,8 @@ server=1
|
||||
rpcuser=futurebit
|
||||
rpcpassword=
|
||||
daemon=0
|
||||
maxconnections=32
|
||||
upnp=1
|
||||
uacomment=FutureBit-Apollo-Node
|
||||
zmqpubhashblock=tcp://127.0.0.1:28332
|
||||
#SOLO_START
|
||||
zmqpubhashblock=tcp://127.0.0.1:28332
|
||||
#SOLO_END
|
@ -2,6 +2,5 @@ server=1
|
||||
rpcuser=futurebit
|
||||
rpcpassword=futurebit
|
||||
daemon=0
|
||||
maxconnections=32
|
||||
upnp=1
|
||||
uacomment=FutureBit-Apollo-Node
|
||||
|
@ -50,12 +50,47 @@ then
|
||||
MINER_FAN_SPEED=$(cat /var/local/apollo/hwmon/fan_rpm)
|
||||
fi
|
||||
|
||||
#Network
|
||||
# Function to check if an interface is up or down
|
||||
get_interface_status() {
|
||||
local interface=$1
|
||||
ip link show "$interface" | grep -q "state UP"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "true"
|
||||
else
|
||||
echo "false"
|
||||
fi
|
||||
}
|
||||
|
||||
# Retrieve IP, MAC and status of eth0 and wlan0 interfaces
|
||||
ETH_IP=$(ip addr show eth0 | awk '/inet / {print $2}' | cut -d/ -f 1)
|
||||
ETH_MAC=$(ip link show eth0 | awk '/ether/ {print $2}')
|
||||
ETH_STATUS=$(get_interface_status eth0)
|
||||
|
||||
WLAN_IP=$(ip addr show wlan0 | awk '/inet / {print $2}' | cut -d/ -f 1)
|
||||
WLAN_MAC=$(ip link show wlan0 | awk '/ether/ {print $2}')
|
||||
|
||||
WLAN_STATUS=$(get_interface_status wlan0)
|
||||
|
||||
# Variable to track the first IP of wlx interfaces
|
||||
FIRST_WLX_IP=""
|
||||
FIRST_WLX_MAC=""
|
||||
FIRST_WLX_STATUS=""
|
||||
|
||||
# Retrieve IP, MAC and status of WiFi interfaces starting with wlx
|
||||
for interface in $(ip -o link show | awk -F': ' '{print $2}' | grep ^wlx); do
|
||||
WLX_IP=$(ip addr show "$interface" | awk '/inet / {print $2}' | cut -d/ -f 1)
|
||||
WLX_MAC=$(ip link show "$interface" | awk '/ether/ {print $2}')
|
||||
WLX_STATUS=$(get_interface_status "$interface")
|
||||
|
||||
# If WLAN_IP is empty and FIRST_WLX_IP is not yet assigned, use WLX_IP
|
||||
if [ -z "$WLAN_IP" ] && [ -z "$FIRST_WLX_IP" ] && [ -n "$WLX_IP" ]; then
|
||||
FIRST_WLX_IP=$WLX_IP
|
||||
FIRST_WLX_MAC=$WLX_MAC
|
||||
FIRST_WLX_STATUS=$WLX_STATUS
|
||||
WLAN_IP=$WLX_IP
|
||||
WLAN_MAC=$WLX_MAC
|
||||
WLAN_STATUS=$WLX_STATUS
|
||||
fi
|
||||
done
|
||||
|
||||
# Memory
|
||||
memTotal=$(egrep '^MemTotal:' /proc/meminfo | awk '{print $2}')
|
||||
@ -98,11 +133,13 @@ JSON="{
|
||||
\"network\": [{
|
||||
\"name\": \"eth0\",
|
||||
\"address\": \"$ETH_IP\",
|
||||
\"mac\": \"$ETH_MAC\"
|
||||
\"mac\": \"$ETH_MAC\",
|
||||
\"status\": \"$ETH_STATUS\"
|
||||
}, {
|
||||
\"name\": \"wlan0\",
|
||||
\"address\": \"$WLAN_IP\",
|
||||
\"mac\": \"$WLAN_MAC\"
|
||||
\"mac\": \"$WLAN_MAC\",
|
||||
\"status\": \"$WLAN_STATUS\"
|
||||
}],
|
||||
\"memory\":
|
||||
{
|
||||
|
13
migrations/20240415123117_node_extra_options.js
Normal file
13
migrations/20240415123117_node_extra_options.js
Normal file
@ -0,0 +1,13 @@
|
||||
exports.up = function (knex, Promise) {
|
||||
return knex.schema.table('settings', function (t) {
|
||||
t.integer('node_max_connections').defaultTo(32);
|
||||
t.boolean('node_allow_lan').defaultTo(false);
|
||||
});
|
||||
};
|
||||
|
||||
exports.down = function (knex, Promise) {
|
||||
return knex.schema.table('settings', function (t) {
|
||||
t.dropColumn('node_max_connections');
|
||||
t.dropColumn('node_allow_lan');
|
||||
});
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "apolloapi-v2",
|
||||
"version": "2.0.4",
|
||||
"version": "2.0.5",
|
||||
"main": "index.js",
|
||||
"repository": "https://github.com/jstefanop/apolloapi-v2.git",
|
||||
"author": "FutureBit LLC",
|
||||
|
@ -17,6 +17,7 @@ module.exports.typeDefs = `
|
||||
uuid: String
|
||||
version: String
|
||||
date: String
|
||||
comport: String
|
||||
statVersion: String
|
||||
versions: MinerStatsVersion
|
||||
master: MinerStatsMaster
|
||||
@ -62,7 +63,7 @@ module.exports.typeDefs = `
|
||||
byDiff: Float
|
||||
byPool: Float
|
||||
byJobs: Float
|
||||
solutions: Int
|
||||
solutions: Float
|
||||
errors: Int
|
||||
errorRate: Float
|
||||
chipSpeed: Float
|
||||
@ -156,8 +157,8 @@ module.exports.typeDefs = `
|
||||
lowCurrRst: Int
|
||||
currents: [Int]
|
||||
brokenPwc: Int
|
||||
solutions: Int
|
||||
errors: Int
|
||||
solutions: Float
|
||||
errors: Float
|
||||
ghs: Float
|
||||
errorRate: Float
|
||||
chipRestarts: Int
|
||||
@ -185,11 +186,11 @@ module.exports.typeDefs = `
|
||||
|
||||
type MinerStatsCkpool {
|
||||
pool: MinerStatsCkpoolPool
|
||||
users: MinerStatsCkpoolUsers
|
||||
users: [MinerStatsCkpoolUsers]
|
||||
}
|
||||
|
||||
type MinerStatsCkpoolPool {
|
||||
runtime: Int
|
||||
runtime: Float
|
||||
lastupdate: Int
|
||||
Users: Int
|
||||
Workers: Int
|
||||
|
@ -23,11 +23,13 @@ module.exports.typeDefs = `
|
||||
leftSidebarExtended: Boolean!
|
||||
rightSidebarVisibility: Boolean!
|
||||
temperatureUnit: TemperatureUnit!
|
||||
powerLedOff: Boolean
|
||||
nodeRpcPassword: String
|
||||
nodeEnableTor: Boolean
|
||||
nodeUserConf: String
|
||||
nodeEnableSoloMining: Boolean
|
||||
powerLedOff: Boolean
|
||||
nodeMaxConnections: Int
|
||||
nodeAllowLan: Boolean
|
||||
}
|
||||
`
|
||||
|
||||
|
@ -18,11 +18,13 @@ module.exports.typeDefs = `
|
||||
leftSidebarExtended: Boolean
|
||||
rightSidebarVisibility: Boolean
|
||||
temperatureUnit: TemperatureUnit
|
||||
powerLedOff: Boolean
|
||||
nodeRpcPassword: String
|
||||
nodeEnableTor: Boolean
|
||||
nodeUserConf: String
|
||||
nodeEnableSoloMining: Boolean
|
||||
powerLedOff: Boolean
|
||||
nodeMaxConnections: Int
|
||||
nodeAllowLan: Boolean
|
||||
}
|
||||
|
||||
type SettingsUpdateOutput {
|
||||
|
111
src/init.js
111
src/init.js
@ -1,12 +1,8 @@
|
||||
const { writeFileSync, readFileSync, existsSync } = require('fs');
|
||||
const { writeFileSync, existsSync } = require('fs');
|
||||
const { join } = require('path');
|
||||
const crypto = require('crypto');
|
||||
const { exec } = require('child_process');
|
||||
const generator = require('generate-password');
|
||||
const utils = require('./utils');
|
||||
const { knex } = require('./db');
|
||||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
|
||||
const initEnvFile = async () => {
|
||||
const envPath = join(__dirname, '..', '.env');
|
||||
@ -30,109 +26,38 @@ const initEnvFile = async () => {
|
||||
const runMigrations = async () => {
|
||||
try {
|
||||
console.log('Run migrations');
|
||||
const resp = await knex.migrate.latest();
|
||||
await createCkpoolConfigFile();
|
||||
await createBitcoinConfigFile();
|
||||
await runGenerateBitcoinPassword();
|
||||
await knex.migrate.latest();
|
||||
const [settings] = await knex('settings')
|
||||
.select([
|
||||
'node_rpc_password as nodeRpcPassword',
|
||||
'node_enable_tor as nodeEnableTor',
|
||||
'node_user_conf as nodeUserConf',
|
||||
'node_enable_solo_mining as nodeEnableSoloMining',
|
||||
'node_max_connections as nodeMaxConnections',
|
||||
'node_allow_lan as nodeAllowLan',
|
||||
])
|
||||
.orderBy('created_at', 'desc')
|
||||
.orderBy('id', 'desc')
|
||||
.limit(1);
|
||||
await utils.auth.manageBitcoinConf(settings);
|
||||
await runGenerateBitcoinPassword(settings);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
|
||||
const runGenerateBitcoinPassword = async () => {
|
||||
const runGenerateBitcoinPassword = async (settings) => {
|
||||
try {
|
||||
console.log('Checking bitcoin password existence');
|
||||
const [settings] = await knex('settings')
|
||||
.select(['node_rpc_password as nodeRpcPassword'])
|
||||
.orderBy('created_at', 'desc')
|
||||
.orderBy('id', 'desc')
|
||||
.limit(1);
|
||||
|
||||
if (settings && settings.nodeRpcPassword)
|
||||
return console.log('Bitcoin password found');
|
||||
else await utils.auth.changeNodeRpcPassword();
|
||||
else await utils.auth.changeNodeRpcPassword(settings);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
|
||||
const createCkpoolConfigFile = async () => {
|
||||
const configFilePath = path.resolve(
|
||||
__dirname,
|
||||
'../backend/ckpool/ckpool.conf'
|
||||
);
|
||||
const configContent = `{
|
||||
"btcd": [
|
||||
{
|
||||
"url": "127.0.0.1:8332",
|
||||
"auth": "futurebit",
|
||||
"pass": "",
|
||||
"notify": true
|
||||
}
|
||||
],
|
||||
"logdir": "/opt/apolloapi/backend/ckpool/logs"
|
||||
}`;
|
||||
|
||||
try {
|
||||
// Check if the file exists
|
||||
await fs.access(configFilePath);
|
||||
console.log('File ckpool.conf already exists.');
|
||||
} catch (error) {
|
||||
try {
|
||||
// Create the file
|
||||
await fs.writeFile(configFilePath, configContent, 'utf-8');
|
||||
console.log('File ckpool.conf created.');
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Error during the creation of the file ckpool.conf: ${error.message}`
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
const [settings] = await knex('settings')
|
||||
.select(['node_rpc_password as nodeRpcPassword'])
|
||||
.orderBy('created_at', 'desc')
|
||||
.orderBy('id', 'desc')
|
||||
.limit(1);
|
||||
|
||||
if (settings && settings.nodeRpcPassword) {
|
||||
exec(
|
||||
`sudo sed -i 's#"pass":.*#"pass": "${settings.nodeRpcPassword}",#g' ${configFilePath}`
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const createBitcoinConfigFile = async () => {
|
||||
const configFilePath = path.resolve(
|
||||
__dirname,
|
||||
'../backend/node/bitcoin.conf'
|
||||
);
|
||||
const configContent = `server=1
|
||||
rpcuser=futurebit
|
||||
rpcpassword=
|
||||
daemon=0
|
||||
maxconnections=32
|
||||
upnp=1
|
||||
uacomment=FutureBit-Apollo-Node`;
|
||||
|
||||
try {
|
||||
// Check if the file exists
|
||||
await fs.access(configFilePath);
|
||||
console.log('File bitcoin.conf already exists.');
|
||||
} catch (error) {
|
||||
try {
|
||||
// Create the file
|
||||
await fs.writeFile(configFilePath, configContent, 'utf-8');
|
||||
console.log('File bitcoin.conf created.');
|
||||
await utils.auth.changeNodeRpcPassword();
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Error during the creation of the file bitcoin.conf: ${error.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
initEnvFile();
|
||||
runMigrations().then(startServer);
|
||||
|
||||
|
@ -11,7 +11,6 @@ module.exports = ({ define }) => {
|
||||
})
|
||||
|
||||
utils.auth.changeSystemPassword(password)
|
||||
await utils.auth.changeNodeRpcPassword()
|
||||
} catch (err) {
|
||||
console.log('ERROR', err);
|
||||
}
|
||||
|
@ -1,15 +1,30 @@
|
||||
const { join } = require('path');
|
||||
const { exec } = require('child_process');
|
||||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
const _ = require('lodash');
|
||||
|
||||
module.exports = ({ define }) => {
|
||||
define(
|
||||
'updateProgress',
|
||||
async (payload, { knex, errors, utils }) => {
|
||||
try {
|
||||
const data = await fs.readFile(`/tmp/update_progress`);
|
||||
// 1. Check if the file exists
|
||||
const filePath = '/tmp/update_progress';
|
||||
let fileExists = true;
|
||||
try {
|
||||
await fs.access(filePath, fs.constants.F_OK);
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
// File doesn't exist
|
||||
console.log('update_progress file not found. Returning default progress.');
|
||||
fileExists = false;
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fileExists) {
|
||||
return { value: 0 };
|
||||
}
|
||||
|
||||
const data = await fs.readFile(filePath);
|
||||
const progress = parseInt(data.toString());
|
||||
return { value: progress };
|
||||
} catch (error) {
|
||||
|
@ -1,10 +1,7 @@
|
||||
const { join } = require('path');
|
||||
const { exec } = require('child_process');
|
||||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
const _ = require('lodash');
|
||||
const moment = require('moment');
|
||||
const { existsSync } = require('fs');
|
||||
const c = require('config');
|
||||
|
||||
module.exports = ({ define }) => {
|
||||
@ -69,40 +66,48 @@ const getCkpoolStats = async (errors, settings, pools) => {
|
||||
|
||||
try {
|
||||
if (settings?.nodeEnableSoloMining) {
|
||||
const poolUsername = pools[0] && pools[0].username;
|
||||
const ckpoolPoolStatsFile = path.resolve(
|
||||
__dirname,
|
||||
'../../../../backend/ckpool/logs/pool/pool.status'
|
||||
);
|
||||
|
||||
const ckpoolUsersStatsFile = path.resolve(
|
||||
const ckpoolUsersStatsDir = path.resolve(
|
||||
__dirname,
|
||||
`../../../../backend/ckpool/logs/users/${poolUsername}`
|
||||
'../../../../backend/ckpool/logs/users/'
|
||||
);
|
||||
|
||||
if (
|
||||
existsSync(ckpoolPoolStatsFile) &&
|
||||
existsSync(ckpoolUsersStatsFile)
|
||||
) {
|
||||
await Promise.all([
|
||||
(async () => {
|
||||
let ckpoolPoolData = await parseFileToJsonArray(
|
||||
ckpoolPoolStatsFile
|
||||
);
|
||||
let ckpoolUsersData = await fs.readFile(
|
||||
ckpoolUsersStatsFile,
|
||||
'utf8'
|
||||
);
|
||||
|
||||
ckpoolUsersData = JSON.parse(ckpoolUsersData);
|
||||
|
||||
ckpoolData = {
|
||||
pool: ckpoolPoolData,
|
||||
users: ckpoolUsersData,
|
||||
};
|
||||
})(),
|
||||
]);
|
||||
try {
|
||||
// Check if the directory exists
|
||||
await fs.stat(ckpoolUsersStatsDir);
|
||||
} catch (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
// Directory does not exist
|
||||
resolve(ckpoolData); // Resolve with null data
|
||||
return;
|
||||
}
|
||||
throw err; // Re-throw other errors
|
||||
}
|
||||
|
||||
const filenames = await fs.readdir(ckpoolUsersStatsDir);
|
||||
|
||||
const usersDataPromises = filenames.map(async (filename) => {
|
||||
const ckpoolUsersStatsFile = path.resolve(
|
||||
ckpoolUsersStatsDir,
|
||||
filename
|
||||
);
|
||||
const ckpoolUsersData = await fs.readFile(
|
||||
ckpoolUsersStatsFile,
|
||||
'utf8'
|
||||
);
|
||||
return JSON.parse(ckpoolUsersData);
|
||||
});
|
||||
|
||||
const usersData = await Promise.all(usersDataPromises);
|
||||
|
||||
ckpoolData = {
|
||||
pool: await parseFileToJsonArray(ckpoolPoolStatsFile),
|
||||
users: usersData,
|
||||
};
|
||||
}
|
||||
|
||||
resolve(ckpoolData);
|
||||
|
@ -28,11 +28,13 @@ module.exports = ({ define }) => {
|
||||
'left_sidebar_extended as leftSidebarExtended',
|
||||
'right_sidebar_visibility as rightSidebarVisibility',
|
||||
'temperature_unit as temperatureUnit',
|
||||
'power_led_off as powerLedOff',
|
||||
'node_rpc_password as nodeRpcPassword',
|
||||
'node_enable_tor as nodeEnableTor',
|
||||
'node_user_conf as nodeUserConf',
|
||||
'node_enable_solo_mining as nodeEnableSoloMining',
|
||||
'power_led_off as powerLedOff',
|
||||
'node_max_connections as nodeMaxConnections',
|
||||
'node_allow_lan as nodeAllowLan',
|
||||
)
|
||||
|
||||
readQ.orderBy('created_at', 'desc')
|
||||
|
@ -13,11 +13,13 @@ module.exports = ({ define }) => {
|
||||
'left_sidebar_extended as leftSidebarExtended',
|
||||
'right_sidebar_visibility as rightSidebarVisibility',
|
||||
'temperature_unit as temperatureUnit',
|
||||
'power_led_off as powerLedOff',
|
||||
'node_rpc_password as nodeRpcPassword',
|
||||
'node_enable_tor as nodeEnableTor',
|
||||
'node_user_conf as nodeUserConf',
|
||||
'node_enable_solo_mining as nodeEnableSoloMining',
|
||||
'power_led_off as powerLedOff',
|
||||
'node_max_connections as nodeMaxConnections',
|
||||
'node_allow_lan as nodeAllowLan',
|
||||
])
|
||||
.orderBy('created_at', 'desc')
|
||||
.orderBy('id', 'desc')
|
||||
|
@ -12,11 +12,13 @@ const updateFields = {
|
||||
leftSidebarExtended: 'left_sidebar_extended',
|
||||
rightSidebarVisibility: 'right_sidebar_visibility',
|
||||
temperatureUnit: 'temperature_unit',
|
||||
powerLedOff: 'power_led_off',
|
||||
nodeRpcPassword: 'node_rpc_password',
|
||||
nodeEnableTor: 'node_enable_tor',
|
||||
nodeUserConf: 'node_user_conf',
|
||||
nodeEnableSoloMining: 'node_enable_solo_mining',
|
||||
powerLedOff: 'power_led_off'
|
||||
nodeMaxConnections: 'node_max_connections',
|
||||
nodeAllowLan: 'node_allow_lan'
|
||||
}
|
||||
|
||||
module.exports = ({ define }) => {
|
||||
|
@ -11,7 +11,10 @@ module.exports = ({ define }) => {
|
||||
if (
|
||||
oldSettings.nodeEnableTor !== newSettings.nodeEnableTor ||
|
||||
oldSettings.nodeUserConf !== newSettings.nodeUserConf ||
|
||||
oldSettings.nodeEnableSoloMining !== newSettings.nodeEnableSoloMining
|
||||
oldSettings.nodeEnableSoloMining !== newSettings.nodeEnableSoloMining ||
|
||||
oldSettings.nodeRpcPassword !== newSettings.nodeRpcPassword ||
|
||||
oldSettings.nodeAllowLan !== newSettings.nodeAllowLan ||
|
||||
oldSettings.nodeMaxConnections !== newSettings.nodeMaxConnections
|
||||
)
|
||||
await utils.auth.manageBitcoinConf(newSettings);
|
||||
|
||||
|
@ -20,7 +20,7 @@ const store = loadStore({
|
||||
return !['index.js', 'store.js'].includes(relativePath) && relativePath.match(/\.js$/)
|
||||
}
|
||||
},
|
||||
logger: logger,
|
||||
logger: process.env.NODE_ENV !== 'development' && logger,
|
||||
methodContext: {
|
||||
knex,
|
||||
utils
|
||||
|
244
src/utils.js
244
src/utils.js
@ -6,6 +6,22 @@ const config = require('config');
|
||||
const { knex } = require('./db');
|
||||
const fsPromises = require('fs').promises;
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
|
||||
const configBitcoinFilePath = path.resolve(
|
||||
__dirname,
|
||||
'../backend/node/bitcoin.conf'
|
||||
);
|
||||
|
||||
const configCkpoolFilePath = path.resolve(
|
||||
__dirname,
|
||||
'../backend/ckpool/ckpool.conf'
|
||||
);
|
||||
|
||||
const configCkpoolServiceFilePath = path.resolve(
|
||||
__dirname,
|
||||
'../backend/systemd/ckpool.service'
|
||||
);
|
||||
|
||||
module.exports.auth = {
|
||||
hashPassword(password) {
|
||||
@ -23,7 +39,7 @@ module.exports.auth = {
|
||||
exec(`echo 'futurebit:${password}' | sudo chpasswd`);
|
||||
},
|
||||
|
||||
async changeNodeRpcPassword() {
|
||||
async changeNodeRpcPassword(settings) {
|
||||
try {
|
||||
console.log('Generating and saving bitcoin password');
|
||||
|
||||
@ -36,28 +52,20 @@ module.exports.auth = {
|
||||
node_rpc_password: password,
|
||||
});
|
||||
|
||||
const configFilePath = path.resolve(
|
||||
__dirname,
|
||||
'../backend/node/bitcoin.conf'
|
||||
);
|
||||
await fsPromises.access(configBitcoinFilePath);
|
||||
await fsPromises.access(configCkpoolFilePath);
|
||||
|
||||
const configCkpoolFilePath = path.resolve(
|
||||
__dirname,
|
||||
'../backend/ckpool/ckpool.conf'
|
||||
exec(
|
||||
`sudo sed -i 's/rpcpassword.*/rpcpassword=${password}/g' ${configBitcoinFilePath}`
|
||||
);
|
||||
|
||||
exec(
|
||||
`sudo sed -i s/rpcpassword.*/rpcpassword=${password}/g ${configFilePath}`
|
||||
`sudo sed -i 's#"pass":.*#"pass": "${password}",#g' ${configCkpoolFilePath}`
|
||||
);
|
||||
|
||||
exec(
|
||||
`sudo sed -i 's#"pass": ""#"pass": "${password}"#g' ${configCkpoolFilePath}`
|
||||
);
|
||||
|
||||
console.log(password, configFilePath);
|
||||
|
||||
exec('sudo systemctl restart node');
|
||||
exec('sudo systemctl restart ckpool');
|
||||
|
||||
if (settings?.nodeEnableSoloMining) exec('sudo systemctl restart ckpool');
|
||||
} catch (err) {
|
||||
console.log('ERR changeNodeRpcPassword', err);
|
||||
}
|
||||
@ -73,13 +81,83 @@ module.exports.auth = {
|
||||
};
|
||||
},
|
||||
|
||||
async manageBitcoinConf(settings) {
|
||||
const defaultConf = `server=1\nrpcuser=futurebit\nrpcpassword=${settings.nodeRpcPassword}\ndaemon=0\nmaxconnections=32\nupnp=1\nuacomment=FutureBit-Apollo-Node`;
|
||||
let conf = defaultConf;
|
||||
networkAddressWithCIDR(ipAddress, netmask) {
|
||||
// Converti l'indirizzo IP e la netmask in forma binaria
|
||||
const ipBinary = ipAddress
|
||||
.split('.')
|
||||
.map((part) => parseInt(part, 10).toString(2).padStart(8, '0'))
|
||||
.join('');
|
||||
const netmaskBinary = netmask
|
||||
.split('.')
|
||||
.map((part) => parseInt(part, 10).toString(2).padStart(8, '0'))
|
||||
.join('');
|
||||
|
||||
if (settings.nodeEnableSoloMining) {
|
||||
conf += `\n#SOLO_START\nzmqpubhashblock=tcp://127.0.0.1:28332\n#SOLO_END`;
|
||||
// Applica l'operazione bitwise AND
|
||||
const networkBinary = ipBinary
|
||||
.split('')
|
||||
.map((bit, index) => bit & netmaskBinary[index])
|
||||
.join('');
|
||||
|
||||
// Converti il risultato in forma di stringa
|
||||
const networkAddress = networkBinary
|
||||
.match(/.{1,8}/g)
|
||||
.map((byte) => parseInt(byte, 2))
|
||||
.join('.');
|
||||
|
||||
// Calcola il numero di bit della netmask
|
||||
const cidrPrefix = netmask
|
||||
.split('.')
|
||||
.reduce(
|
||||
(acc, byte) =>
|
||||
acc + (parseInt(byte, 10).toString(2).match(/1/g) || '').length,
|
||||
0
|
||||
);
|
||||
|
||||
return `${networkAddress}/${cidrPrefix}`;
|
||||
},
|
||||
|
||||
getSystemNetwork() {
|
||||
// Get network interface information
|
||||
const interfaces = os.networkInterfaces();
|
||||
let address = null;
|
||||
let netmask = null;
|
||||
let network = null;
|
||||
|
||||
// Check if wlan0 has an associated IP address
|
||||
if (
|
||||
interfaces['wlan0'] &&
|
||||
interfaces['wlan0'].some((info) => info.family === 'IPv4')
|
||||
) {
|
||||
// If wlan0 has an associated IP address, use wlan0
|
||||
address = interfaces['wlan0'].find(
|
||||
(info) => info.family === 'IPv4'
|
||||
).address;
|
||||
netmask = interfaces['wlan0'].find(
|
||||
(info) => info.family === 'IPv4'
|
||||
).netmask;
|
||||
} else if (
|
||||
interfaces['eth0'] &&
|
||||
interfaces['eth0'].some((info) => info.family === 'IPv4')
|
||||
) {
|
||||
// If wlan0 doesn't have an associated IP address but eth0 does, use eth0
|
||||
address = interfaces['eth0'].find(
|
||||
(info) => info.family === 'IPv4'
|
||||
).address;
|
||||
netmask = interfaces['eth0'].find(
|
||||
(info) => info.family === 'IPv4'
|
||||
).netmask;
|
||||
} else {
|
||||
console.log('No IP address associated with wlan0 or eth0');
|
||||
}
|
||||
|
||||
if (address && netmask)
|
||||
network = this.networkAddressWithCIDR(address, netmask);
|
||||
|
||||
return network;
|
||||
},
|
||||
|
||||
async manageCkpoolConf(settings) {
|
||||
try {
|
||||
const ckpoolConf = {
|
||||
btcd: [
|
||||
{
|
||||
@ -95,37 +173,107 @@ module.exports.auth = {
|
||||
};
|
||||
|
||||
await fsPromises.writeFile(
|
||||
'/opt/apolloapi/backend/ckpool/ckpool.conf',
|
||||
configCkpoolFilePath,
|
||||
JSON.stringify(ckpoolConf, null, 2)
|
||||
);
|
||||
|
||||
exec(
|
||||
'sudo cp /opt/app/backend/systemd/ckpool.service /etc/systemd/system/ckpool.service'
|
||||
);
|
||||
exec('sudo systemctl daemon-reload');
|
||||
exec('sudo systemctl enable ckpool');
|
||||
exec('sudo systemctl restart ckpool');
|
||||
} else {
|
||||
exec('sudo systemctl stop ckpool');
|
||||
exec('sudo systemctl disable ckpool');
|
||||
} catch (err) {
|
||||
console.log('ERR manageCkpoolConf', err);
|
||||
}
|
||||
},
|
||||
|
||||
if (settings.nodeEnableTor) {
|
||||
conf += `\n#TOR_START\nproxy=127.0.0.1:9050\nlisten=1\nbind=127.0.0.1\nonlynet=onion\ndnsseed=0\ndns=0\n#TOR_END`;
|
||||
exec('sudo systemctl enable tor');
|
||||
exec('sudo systemctl restart tor');
|
||||
} else {
|
||||
exec('sudo systemctl stop tor');
|
||||
exec('sudo systemctl disable tor');
|
||||
async manageBitcoinConf(settings) {
|
||||
try {
|
||||
// CHecking current conf file
|
||||
const currentConf = await fsPromises.readFile(configBitcoinFilePath, 'utf8');
|
||||
const currentConfBase64 = Buffer.from(currentConf).toString('base64');
|
||||
|
||||
const defaultConf = `server=1\nrpcuser=futurebit\nrpcpassword=${settings.nodeRpcPassword}\ndaemon=0\nupnp=1\nuacomment=FutureBit-Apollo-Node`;
|
||||
let conf = defaultConf;
|
||||
conf += `\n#SOLO_START\nzmqpubhashblock=tcp://127.0.0.1:28332\n#SOLO_END`;
|
||||
|
||||
this.manageCkpoolConf(settings);
|
||||
|
||||
if (settings.nodeEnableSoloMining) {
|
||||
exec(
|
||||
`sudo cp ${configCkpoolServiceFilePath} /etc/systemd/system/ckpool.service`
|
||||
);
|
||||
exec('sudo systemctl daemon-reload');
|
||||
exec('sudo systemctl enable ckpool');
|
||||
exec('sudo systemctl restart ckpool');
|
||||
} else {
|
||||
exec('sudo systemctl stop ckpool');
|
||||
exec('sudo systemctl disable ckpool');
|
||||
}
|
||||
|
||||
if (settings.nodeEnableTor) {
|
||||
conf += `\n#TOR_START\nproxy=127.0.0.1:9050\nlisten=1\nbind=127.0.0.1\nonlynet=onion\ndnsseed=0\ndns=0\n#TOR_END`;
|
||||
exec('sudo systemctl enable tor');
|
||||
exec('sudo systemctl restart tor');
|
||||
} else {
|
||||
exec('sudo systemctl stop tor');
|
||||
exec('sudo systemctl disable tor');
|
||||
}
|
||||
|
||||
if (settings.nodeMaxConnections)
|
||||
conf += `\nmaxconnections=${settings.nodeMaxConnections}`;
|
||||
else conf += '\nmaxconnections=32';
|
||||
|
||||
if (settings.nodeAllowLan) {
|
||||
const lanNetwork = this.getSystemNetwork();
|
||||
conf += `\nrpcbind=0.0.0.0\nrpcallowip=0.0.0.0/0`;
|
||||
}
|
||||
|
||||
if (settings.nodeUserConf) {
|
||||
// Extract variable names from settings.nodeUserConf using regex
|
||||
const userConfVariables = settings.nodeUserConf.match(/^[^=\r\n]+/gm);
|
||||
|
||||
// Extract variable names from defaultConf using regex
|
||||
const defaultConfVariables = defaultConf.match(/^[^=\r\n]+/gm);
|
||||
|
||||
// Remove variables from settings.nodeUserConf that are also present in defaultConf
|
||||
const filteredUserConfVariables = userConfVariables.filter(
|
||||
(variable) => !defaultConfVariables.includes(variable)
|
||||
);
|
||||
|
||||
if (filteredUserConfVariables.length) {
|
||||
// Initialize an empty array to store formatted user configurations
|
||||
const formattedUserConf = [];
|
||||
|
||||
// Iterate through filtered variables and format them
|
||||
filteredUserConfVariables.forEach((variable) => {
|
||||
// If the variable has a value, format it as "variable=value"
|
||||
// Otherwise, format it as "variable"
|
||||
const formattedVariable = settings.nodeUserConf.includes(
|
||||
`${variable}=`
|
||||
)
|
||||
? `${variable}=${
|
||||
settings.nodeUserConf.match(new RegExp(`${variable}=(.*)`))[1]
|
||||
}`
|
||||
: variable;
|
||||
|
||||
// Push the formatted variable to the array
|
||||
formattedUserConf.push(formattedVariable);
|
||||
});
|
||||
|
||||
// Join the formatted variables into a single string with newlines
|
||||
const filteredUserConf = formattedUserConf.join('\n');
|
||||
|
||||
// Append the filtered user configuration to the overall configuration
|
||||
conf += `\n#USER_INPUT_START\n${filteredUserConf}\n#USER_INPUT_END`;
|
||||
}
|
||||
}
|
||||
|
||||
const confBase64 = Buffer.from(conf).toString('base64');
|
||||
|
||||
if (currentConfBase64 === confBase64) return console.log('No changes to bitcoin.conf file');
|
||||
|
||||
console.log('Writing Bitcoin conf file', conf);
|
||||
|
||||
await fsPromises.writeFile(configBitcoinFilePath, conf);
|
||||
|
||||
exec('sleep 3 && sudo systemctl restart node');
|
||||
} catch (err) {
|
||||
console.log('ERR manageBitcoinConf', err);
|
||||
}
|
||||
|
||||
if (settings.nodeUserConf)
|
||||
conf += `\n#USER_INPUT_START\n${settings.nodeUserConf}\n#USER_INPUT_END`;
|
||||
|
||||
console.log('Writing Bitcoin conf file', conf);
|
||||
|
||||
exec(`echo "${conf}" | sudo tee /opt/apolloapi/backend/node/bitcoin.conf`);
|
||||
|
||||
exec('sudo systemctl restart node');
|
||||
},
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user