Introduce the QML mining interface

This commit is contained in:
dsc
2022-03-22 16:01:33 +02:00
parent 917f8b5812
commit 6b2f8f847e
41 changed files with 1222 additions and 370 deletions
+86 -23
View File
@@ -15,16 +15,16 @@ XmRig::XmRig(const QString &configDir, QObject *parent) :
{
m_statusTimer->setInterval(5000);
connect(m_statusTimer, &QTimer::timeout, [this]{
if(mining_started && m_process.state() == QProcess::Running)
if(daemonMiningState == DaemonMiningState::mining && m_process.state() == QProcess::Running)
m_process.write("status\n");
});
}
void XmRig::prepare() {
m_process.setProcessChannelMode(QProcess::MergedChannels);
connect(&m_process, &QProcess::readyReadStandardOutput, this, &XmRig::handleProcessOutput);
connect(&m_process, &QProcess::errorOccurred, this, &XmRig::handleProcessError);
connect(&m_process, &QProcess::stateChanged, this, &XmRig::stateChanged);
connect(&m_process, &QProcess::readyReadStandardOutput, this, &XmRig::onHandleProcessOutput);
connect(&m_process, &QProcess::errorOccurred, this, &XmRig::onHandleProcessError);
connect(&m_process, &QProcess::stateChanged, this, &XmRig::onProcessStateChanged);
}
void XmRig::stop() {
@@ -42,7 +42,9 @@ bool XmRig::start(const QString &path, int threads) {
m_ctx = MainWindow::getContext();
auto state = m_process.state();
if (state == QProcess::ProcessState::Running || state == QProcess::ProcessState::Starting) {
if (state == QProcess::ProcessState::Running ||
state == QProcess::ProcessState::Starting ||
daemonMiningState != DaemonMiningState::idle) {
emit error("Can't start wownerod, already running or starting");
return false;
}
@@ -72,45 +74,106 @@ bool XmRig::start(const QString &path, int threads) {
return true;
}
void XmRig::stateChanged(QProcess::ProcessState state) {
if(state == QProcess::ProcessState::Running)
void XmRig::onProcessStateChanged(QProcess::ProcessState state) {
if(state == QProcess::ProcessState::Running) {
emit output("wownerod started");
changeDaemonState(DaemonMiningState::startup);
}
else if (state == QProcess::ProcessState::NotRunning) {
emit output("wownerod stopped");
this->mining_started = false;
emit stopped();
changeDaemonState(DaemonMiningState::idle);
}
}
void XmRig::handleProcessOutput() {
void XmRig::onHandleProcessOutput() {
QByteArray data = m_process.readAllStandardOutput();
for(auto &line: data.split('\n')) {
// remove timestamp
if(line.indexOf("\tI") >= 20)
line = line.remove(0, line.indexOf("\tI") + 2);
if(line.trimmed().isEmpty() || line.startsWith("status")) continue;
if(line.contains("Mining started. Good luck"))
this->mining_started = true;
else if(line.contains("you won a block reward"))
line = line.trimmed();
// sad attempt at removing ANSI color codes
// yes this is stupid, no i dont care
// works remarkably well so far lmao
auto ansi_start = QByteArray("\x1b\x5b");
line = line.replace(ansi_start, "");
line = line.replace("0;36m", "");
line = line.replace("0;35m", "");
line = line.replace("0;34m", "");
line = line.replace("0;33m", "");
line = line.replace("0;32m", "");
line = line.replace("1;32m", "");
line = line.replace("1;33m", "");
line = line.replace("1;34m", "");
line = line.replace("1;35m", "");
line = line.replace("1;36m", "");
if(line.startsWith("0m")) continue;
auto lower = line.toLower();
if(lower.isEmpty() || lower.startsWith("status")) continue;
if(lower.startsWith("the daemon will start synchronizing")) {
changeDaemonState(DaemonMiningState::startup);
} else if(lower.startsWith("synchronization started")) {
changeDaemonState(DaemonMiningState::syncing);
} else if(lower.startsWith("synced") && lower.contains("left")) {
if(daemonMiningState < DaemonMiningState::syncing) changeDaemonState(DaemonMiningState::syncing);
QRegularExpression re("synced (\\d+)\\/(\\d+) \\((\\d+)%, (\\d+) left");
QRegularExpressionMatch match = re.match(lower);
if (match.hasMatch()) {
auto from = match.captured(1);
auto to = match.captured(2);
auto pct = match.captured(3);
m_from = from.toUInt();
m_to = to.toUInt();
emit syncStatus(m_from, m_to, pct.toInt());
}
} else if(lower.contains("mining started. good luck")) {
emit syncStatus(m_to, m_to, 100);
changeDaemonState(DaemonMiningState::mining);
}
else if(lower.contains("you won a block reward"))
emit blockReward();
else if(line.contains("mining at")) {
auto rate = line.remove(0, line.indexOf("mining at"));
rate = rate.remove(rate.indexOf(","), rate.length());
rate = rate.remove(0, 9);
rate = rate.trimmed();
emit hashrate(rate);
else if(lower.contains("mining at")) {
QRegularExpression re("Height\\: (\\d+)\\/(\\d+) \\((.*)\\) on mainnet, mining at (.*), net hash .*, uptime (.*)");
QRegularExpressionMatch match = re.match(line);
if (match.hasMatch()) {
m_from = match.captured(1).toUInt();
m_to = match.captured(2).toUInt();
unsigned int pct = match.captured(3).replace("%", "").toDouble();
auto rate = match.captured(4);
auto uptime = match.captured(5).replace(" ", "");
emit uptimeChanged(uptime);
emit syncStatus(m_to, m_to, pct);
emit hashrate(rate);
line = line.remove(0, line.indexOf("mining at"));
}
}
emit output(line);
emit output(line.trimmed());
}
}
void XmRig::handleProcessError(QProcess::ProcessError err) {
void XmRig::changeDaemonState(const DaemonMiningState state) {
if(daemonMiningState == state) return;
daemonMiningState = state;
emit daemonStateChanged(daemonMiningState);
}
void XmRig::onHandleProcessError(QProcess::ProcessError err) {
if (err == QProcess::ProcessError::Crashed)
emit error("wownerod crashed or killed");
else if (err == QProcess::ProcessError::FailedToStart) {
auto path = config()->get(Config::wownerodPath).toString();
emit error(QString("wownerod binary failed to start: %1").arg(path));
}
this->mining_started = false;
changeDaemonState(DaemonMiningState::idle);
}