mirror of
https://github.com/Retropex/apolloapi-v2.git
synced 2025-06-02 23:42:30 +02:00
Added Ckpool stats
This commit is contained in:
parent
e1b6389a9c
commit
664d4a8ed4
@ -2,7 +2,6 @@ const path = require('path')
|
|||||||
const express = require('express')
|
const express = require('express')
|
||||||
const cors = require('cors');
|
const cors = require('cors');
|
||||||
const graphqlApp = require('./graphqlApp')
|
const graphqlApp = require('./graphqlApp')
|
||||||
const buildPath = path.join(__dirname, '../../apolloui/build');
|
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
|
|
||||||
@ -10,11 +9,4 @@ app.use(cors());
|
|||||||
|
|
||||||
app.use('/api/graphql', graphqlApp)
|
app.use('/api/graphql', graphqlApp)
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'production') app.use(express.static(buildPath));
|
|
||||||
|
|
||||||
app.get('*', function (req, res) {
|
|
||||||
if (process.env.NODE_ENV === 'production') res.sendFile(buildPath + '/index.html');
|
|
||||||
else res.json({ message: 'API DEV server running' })
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = app
|
module.exports = app
|
||||||
|
@ -23,6 +23,7 @@ module.exports.typeDefs = `
|
|||||||
temperature: MinerStatsTemperature
|
temperature: MinerStatsTemperature
|
||||||
slots: MinerStatsSlots
|
slots: MinerStatsSlots
|
||||||
slaves: [MinerStatsSlave]
|
slaves: [MinerStatsSlave]
|
||||||
|
ckpool: MinerStatsCkpool
|
||||||
}
|
}
|
||||||
|
|
||||||
type MinerStatsVersion {
|
type MinerStatsVersion {
|
||||||
@ -160,7 +161,7 @@ module.exports.typeDefs = `
|
|||||||
errorRate: Float
|
errorRate: Float
|
||||||
chipRestarts: Int
|
chipRestarts: Int
|
||||||
wattPerGHs: Float
|
wattPerGHs: Float
|
||||||
tmpAlert: [MinerStatsSlotAlert],
|
tmpAlert: [MinerStatsSlotAlert]
|
||||||
osc: Int
|
osc: Int
|
||||||
oscStopChip: String
|
oscStopChip: String
|
||||||
}
|
}
|
||||||
@ -181,12 +182,68 @@ module.exports.typeDefs = `
|
|||||||
ping: Int
|
ping: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
`
|
type MinerStatsCkpool {
|
||||||
|
pool: MinerStatsCkpoolPool
|
||||||
|
users: MinerStatsCkpoolUsers
|
||||||
|
}
|
||||||
|
|
||||||
|
type MinerStatsCkpoolPool {
|
||||||
|
runtime: Int
|
||||||
|
lastupdate: Int
|
||||||
|
Users: Int
|
||||||
|
Workers: Int
|
||||||
|
Idle: Int
|
||||||
|
Disconnected: Int
|
||||||
|
hashrate1m: String
|
||||||
|
hashrate5m: String
|
||||||
|
hashrate15m: String
|
||||||
|
hashrate1hr: String
|
||||||
|
hashrate6hr: String
|
||||||
|
hashrate1d: String
|
||||||
|
hashrate7d: String
|
||||||
|
diff: Int
|
||||||
|
accepted: Int
|
||||||
|
rejected: Int
|
||||||
|
bestshare: Int
|
||||||
|
SPS1m: Float
|
||||||
|
SPS5m: Float
|
||||||
|
SPS15m: Float
|
||||||
|
SPS1h: Float
|
||||||
|
}
|
||||||
|
|
||||||
|
type MinerStatsCkpoolUsers {
|
||||||
|
hashrate1m: String
|
||||||
|
hashrate5m: String
|
||||||
|
hashrate1hr: String
|
||||||
|
hashrate1d: String
|
||||||
|
hashrate7d: String
|
||||||
|
lastshare: Int
|
||||||
|
workers: Int
|
||||||
|
shares: Int
|
||||||
|
bestshare: Float
|
||||||
|
bestever: Int
|
||||||
|
authorised: Int
|
||||||
|
worker: [MinerStatsCkpoolWorker]
|
||||||
|
}
|
||||||
|
|
||||||
|
type MinerStatsCkpoolWorker {
|
||||||
|
workername: String,
|
||||||
|
hashrate1m: String,
|
||||||
|
hashrate5m: String,
|
||||||
|
hashrate1hr: String,
|
||||||
|
hashrate1d: String,
|
||||||
|
hashrate7d: String,
|
||||||
|
lastshare: Int,
|
||||||
|
shares: Int,
|
||||||
|
bestshare: Float,
|
||||||
|
bestever: Int
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
module.exports.resolvers = {
|
module.exports.resolvers = {
|
||||||
MinerActions: {
|
MinerActions: {
|
||||||
stats (root, args, { dispatch }) {
|
stats(root, args, { dispatch }) {
|
||||||
return dispatch('api/miner/stats')
|
return dispatch('api/miner/stats');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
@ -1,73 +1,169 @@
|
|||||||
const { join } = require('path')
|
const { join } = require('path');
|
||||||
const { exec } = require('child_process')
|
const { exec } = require('child_process');
|
||||||
const fs = require('fs').promises
|
const fs = require('fs').promises;
|
||||||
const path = require('path')
|
const path = require('path');
|
||||||
const _ = require('lodash')
|
const _ = require('lodash');
|
||||||
const moment = require('moment')
|
const moment = require('moment');
|
||||||
|
const { existsSync } = require('fs');
|
||||||
|
const c = require('config');
|
||||||
|
|
||||||
module.exports = ({ define }) => {
|
module.exports = ({ define }) => {
|
||||||
define('stats', async (payload, { knex, errors, utils }) => {
|
define(
|
||||||
const stats = await getMinerStats(errors)
|
'stats',
|
||||||
return { stats }
|
async (payload, { knex, errors, dispatch }) => {
|
||||||
}, {
|
const settings = await dispatch('api/settings/collection/read');
|
||||||
auth: true
|
const { items: pools } = await dispatch('api/pools/collection/read', {});
|
||||||
})
|
const stats = await getMinerStats(errors, settings, pools);
|
||||||
|
return { stats };
|
||||||
|
},
|
||||||
|
{
|
||||||
|
auth: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseFileToJsonArray = async (filePath) => {
|
||||||
|
try {
|
||||||
|
// Read the file content
|
||||||
|
const fileContent = await fs.readFile(filePath, 'utf8');
|
||||||
|
|
||||||
|
// Divide the file content into lines
|
||||||
|
const lines = fileContent.split('\n');
|
||||||
|
|
||||||
|
const allKeys = {};
|
||||||
|
|
||||||
|
// Analyze each line
|
||||||
|
lines.forEach(line => {
|
||||||
|
if (line.trim() !== '') {
|
||||||
|
try {
|
||||||
|
const jsonObject = JSON.parse(line);
|
||||||
|
|
||||||
|
// Add the keys to the allKeys object
|
||||||
|
Object.entries(jsonObject).forEach(([key, value]) => {
|
||||||
|
if (!allKeys[key]) {
|
||||||
|
allKeys[key] = null;
|
||||||
|
}
|
||||||
|
allKeys[key] = value;
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error during the parsing of the line: ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return allKeys;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error during the reading of the file: ${error.message}`);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getMinerStats (errors) {
|
const getMinerStats = async (errors, settings, pools) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
const statsDir = path.resolve(__dirname, '../../../../backend/apollo-miner/');
|
const statsDir = path.resolve(
|
||||||
|
__dirname,
|
||||||
|
'../../../../backend/apollo-miner/'
|
||||||
|
);
|
||||||
const statsFilePattern = 'apollo-miner.*';
|
const statsFilePattern = 'apollo-miner.*';
|
||||||
let statsFiles = await fs.readdir(statsDir);
|
let statsFiles = await fs.readdir(statsDir);
|
||||||
statsFiles = _.filter(statsFiles, (f) => { return f.match(statsFilePattern) })
|
statsFiles = _.filter(statsFiles, (f) => {
|
||||||
|
return f.match(statsFilePattern);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get ckpool data
|
||||||
|
let ckpoolData = null;
|
||||||
|
|
||||||
|
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(
|
||||||
|
__dirname,
|
||||||
|
`../../../../backend/ckpool/logs/users/${poolUsername}`
|
||||||
|
);
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
})(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let stats = [];
|
let stats = [];
|
||||||
|
|
||||||
await Promise.all(statsFiles.map(async (file) => {
|
await Promise.all(
|
||||||
const data = await fs.readFile(`${statsDir}/${file}`);
|
statsFiles.map(async (file) => {
|
||||||
let received = data.toString('utf8').trim();
|
const data = await fs.readFile(`${statsDir}/${file}`);
|
||||||
// JSON from miner is dirty, clean it
|
let received = data.toString('utf8').trim();
|
||||||
received = received
|
// JSON from miner is dirty, clean it
|
||||||
.replace(/\-nan/g, '0')
|
received = received
|
||||||
.replace(/[^\x00-\x7F]/g, '')
|
.replace(/\-nan/g, '0')
|
||||||
.replace('}{', '},{')
|
.replace(/[^\x00-\x7F]/g, '')
|
||||||
.replace(String.fromCharCode(0), '')
|
.replace('}{', '},{')
|
||||||
.replace(/[^\}]+$/, '')
|
.replace(String.fromCharCode(0), '')
|
||||||
|
.replace(/[^\}]+$/, '');
|
||||||
|
|
||||||
received = JSON.parse(received);
|
received = JSON.parse(received);
|
||||||
|
|
||||||
received.uuid = file.replace('apollo-miner.', '');
|
received.uuid = file.replace('apollo-miner.', '');
|
||||||
|
|
||||||
received.master.intervals = _.mapKeys(received.master.intervals, (value, name) => {
|
received.master.intervals = _.mapKeys(
|
||||||
return `int_${name}`
|
received.master.intervals,
|
||||||
});
|
(value, name) => {
|
||||||
|
return `int_${name}`;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
received.pool.intervals = _.mapKeys(received.pool.intervals, (value, name) => {
|
received.pool.intervals = _.mapKeys(
|
||||||
return `int_${name}`
|
received.pool.intervals,
|
||||||
});
|
(value, name) => {
|
||||||
|
return `int_${name}`;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
received.fans = _.mapKeys(received.fans, (value, name) => {
|
received.fans = _.mapKeys(received.fans, (value, name) => {
|
||||||
return `int_${name}`
|
return `int_${name}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
received.slots = _.mapKeys(received.slots, (value, name) => {
|
received.slots = _.mapKeys(received.slots, (value, name) => {
|
||||||
return `int_${name}`
|
return `int_${name}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Hack to add timezone to miner date
|
// Hack to add timezone to miner date
|
||||||
let offset = new Date().getTimezoneOffset();
|
let offset = new Date().getTimezoneOffset();
|
||||||
offset *= -1
|
offset *= -1;
|
||||||
received.date = moment(`${received.date}`, 'YYYY-MM-DD HH:mm:ss').utcOffset(offset).format();
|
received.date = moment(`${received.date}`, 'YYYY-MM-DD HH:mm:ss')
|
||||||
|
.utcOffset(offset)
|
||||||
|
.format();
|
||||||
|
|
||||||
stats.push(received);
|
if (ckpoolData) received.ckpool = ckpoolData;
|
||||||
}));
|
|
||||||
|
|
||||||
resolve(stats)
|
stats.push(received);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
resolve(stats);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
reject(new errors.InternalError(err.toString()));
|
reject(new errors.InternalError(err.toString()));
|
||||||
}
|
}
|
||||||
})()
|
})();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user