Files
ObsidianDragon/src/util/pool_stats_service.h
DanS d0586e5e75 feat(mining): pool registry, schema-aware stats fetcher, pool-select setting
Data + service layer for supporting multiple mining pools:
- pool_registry: KnownPool table (pool.dragonx.is + pool.dragonx.cc) carrying
  each pool's stratum host, xmrig algo, and stats-API schema; pure helpers
  findKnownPoolByUrl / resolvePoolAlgo / parsePoolHashrate / chooseWeightedPool
  (weighted-random by hashrate with incumbent stickiness).
- pool_stats_service: background, schema-aware hashrate fetcher (libcurl, TLS,
  browser UA for Cloudflare) modelled on XmrigUpdater.
- settings: pool_select_mode (manual | auto_balance), string-serialized.
- i18n strings + unit tests (both stats schemas, algo resolution, weighted pick).

Note: pool.dragonx.cc's stratum host is us.dragonx.cc:3333 — the .cc domain is
only the Cloudflare-proxied web/API host and does not accept stratum on :3333.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 14:35:13 -05:00

60 lines
1.8 KiB
C++

// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
//
// PoolStatsService — fetch every known pool's live total hashrate on a background
// thread and expose a thread-safe snapshot. Modelled on util/XmrigUpdater: a
// std::thread + atomics + a mutex-guarded result, polled once per frame by the UI /
// the auto-balance driver. Schema-aware parsing is delegated to pool_registry.
#pragma once
#include "pool_registry.h"
#include <atomic>
#include <map>
#include <mutex>
#include <string>
#include <thread>
#include <vector>
namespace dragonx {
namespace util {
class PoolStatsService {
public:
struct Snapshot {
std::map<std::string, PoolHashrate> byId; // keyed by KnownPool.id
bool ready = false; // at least one refresh completed
};
PoolStatsService() = default;
~PoolStatsService();
PoolStatsService(const PoolStatsService&) = delete;
PoolStatsService& operator=(const PoolStatsService&) = delete;
// Fetch every pool's hashrate on a background thread. No-op if a refresh is
// already in flight.
void refresh(const std::vector<KnownPool>& pools);
bool busy() const { return worker_running_.load(); }
Snapshot snapshot() const;
// Internal: consulted by the libcurl xferinfo callback so an in-flight fetch can
// abort promptly on shutdown. Public only so the C callback can reach it.
bool cancelRequested() const { return cancel_requested_.load(); }
private:
void run(std::vector<KnownPool> pools);
std::string httpGet(const std::string& url);
mutable std::mutex mutex_;
Snapshot snapshot_;
std::atomic<bool> worker_running_{false};
std::atomic<bool> cancel_requested_{false};
std::thread worker_;
};
} // namespace util
} // namespace dragonx