Add mine-when-idle, default banlist, and console parsing improvements

Mine-when-idle:
- Auto-start/stop mining based on system idle time detection
- Platform::getSystemIdleSeconds() via XScreenSaver (Linux) / GetLastInputInfo (Win)
- Settings: mine_when_idle toggle + configurable delay (30s–10m)
- Settings page UI with checkbox and delay combo

Console tab:
- Shell-like argument parsing with quote and JSON bracket support
- Pass JSON objects/arrays directly as RPC params
- Fix selection indices when lines are evicted from buffer

Connection & status bar:
- Reduce RPC connect timeout to 1s for localhost fast-fail
- Fast retry timer on daemon startup and external daemon detection
- Show pool mining hashrate in status bar; sidebar badge reflects pool state

UI polish:
- Add logo to About card in settings; expose logo dimensions on App
- Header title offset-y support; adjust content-area margins
- Fix banned peers row cursor position (rawRowPosB.x)

Branding:
- Update copyright to "DragonX Developers" in RC and About section
- Replace logo/icon assets with updated versions

Misc:
- setup.sh: checkout dragonx branch before pulling
- Remove stale prebuilt-binaries/xmrig/.gitkeep
This commit is contained in:
dan_s
2026-03-07 13:42:31 -06:00
parent 653a90de62
commit cc617dd5be
22 changed files with 431 additions and 41 deletions

View File

@@ -13,6 +13,7 @@
#include "daemon/embedded_daemon.h"
#include "daemon/xmrig_manager.h"
#include "ui/notifications.h"
#include "default_banlist_embedded.h"
#include "util/platform.h"
#include "util/perf_log.h"
@@ -52,6 +53,7 @@ void App::tryConnect()
if (embedded_daemon_ && embedded_daemon_->externalDaemonDetected()) {
connection_status_ = "Waiting for daemon config...";
VERBOSE_LOGF("[connect #%d] External daemon detected on port, waiting for config file to appear\n", connect_attempt);
refresh_timer_ = REFRESH_INTERVAL - 1.0f;
return;
}
@@ -63,9 +65,11 @@ void App::tryConnect()
if (startEmbeddedDaemon()) {
// Will retry connection after daemon starts
VERBOSE_LOGF("[connect #%d] Embedded daemon starting, will retry connection...\n", connect_attempt);
refresh_timer_ = REFRESH_INTERVAL - 1.0f;
} else if (embedded_daemon_ && embedded_daemon_->externalDaemonDetected()) {
connection_status_ = "Waiting for daemon config...";
VERBOSE_LOGF("[connect #%d] External daemon detected but no config yet, will retry...\n", connect_attempt);
refresh_timer_ = REFRESH_INTERVAL - 1.0f;
} else {
VERBOSE_LOGF("[connect #%d] startEmbeddedDaemon() failed — lastError: %s, binary: %s\n",
connect_attempt,
@@ -148,10 +152,14 @@ void App::tryConnect()
state_.connected = false;
connection_status_ = "Waiting for dragonxd to start...";
VERBOSE_LOGF("[connect #%d] RPC connection failed — daemon still starting, will retry...\n", attempt);
// Fast retry: force the refresh timer to fire on the next cycle
// instead of waiting the full 5-second REFRESH_INTERVAL.
refresh_timer_ = REFRESH_INTERVAL - 1.0f;
} else if (externalDetected) {
state_.connected = false;
connection_status_ = "Connecting to daemon...";
VERBOSE_LOGF("[connect #%d] RPC connection failed — external daemon on port but RPC not ready yet, will retry...\n", attempt);
refresh_timer_ = REFRESH_INTERVAL - 1.0f;
} else {
onDisconnected("Connection failed");
VERBOSE_LOGF("[connect #%d] RPC connection failed — no daemon starting, no external detected\n", attempt);
@@ -286,6 +294,9 @@ void App::onConnected()
// Initial data refresh
refreshData();
refreshMarketData();
// Apply compiled-in default ban list
applyDefaultBanlist();
}
void App::onDisconnected(const std::string& reason)
@@ -1403,6 +1414,57 @@ void App::clearBans()
});
}
void App::applyDefaultBanlist()
{
if (!state_.connected || !rpc_ || !worker_) return;
// Parse the embedded default_banlist.txt (compiled from res/default_banlist.txt)
std::string data(reinterpret_cast<const char*>(embedded::default_banlist_data),
embedded::default_banlist_size);
std::vector<std::string> ips;
size_t pos = 0;
while (pos < data.size()) {
size_t eol = data.find('\n', pos);
if (eol == std::string::npos) eol = data.size();
std::string line = data.substr(pos, eol - pos);
pos = eol + 1;
// Strip carriage return (Windows line endings)
if (!line.empty() && line.back() == '\r') line.pop_back();
// Strip leading/trailing whitespace
size_t start = line.find_first_not_of(" \t");
if (start == std::string::npos) continue;
line = line.substr(start, line.find_last_not_of(" \t") - start + 1);
// Skip empty lines and comments
if (line.empty() || line[0] == '#') continue;
ips.push_back(line);
}
if (ips.empty()) return;
// Apply bans on the worker thread to avoid blocking the UI
worker_->post([this, ips]() -> rpc::RPCWorker::MainCb {
int applied = 0;
for (const auto& ip : ips) {
try {
// 0 = permanent ban (until node restart or manual unban)
// Using a very long duration (10 years) for effectively permanent bans
rpc_->call("setban", {ip, "add", 315360000});
applied++;
} catch (...) {
// Already banned or invalid — skip silently
}
}
return [applied]() {
if (applied > 0) {
DEBUG_LOGF("[Banlist] Applied %d default bans\n", applied);
}
};
});
}
// ============================================================================
// Address Operations
// ============================================================================