// DragonX Wallet - ImGui Edition // Copyright 2024-2026 The Hush Developers // Released under the GPLv3 #pragma once #include #include #include #include #include #include #ifdef _WIN32 #include #include #else #include #endif namespace dragonx { namespace daemon { /** * @brief Manages the xmrig pool mining process * * Handles starting/stopping xmrig for pool mining, polling stats via its * HTTP API, and capturing stdout for the log panel. Modelled on * EmbeddedDaemon (same fork/pipe/monitor pattern, same #ifdef split). */ class XmrigManager { public: enum class State { Stopped, Starting, Running, Stopping, Error }; /// Live stats polled from xmrig HTTP API (/2/summary) struct PoolStats { double hashrate_10s = 0; double hashrate_60s = 0; double hashrate_15m = 0; int64_t accepted = 0; int64_t rejected = 0; int64_t uptime_sec = 0; double pool_diff = 0; std::string pool_url; std::string algo; bool connected = false; // Memory usage int64_t memory_free = 0; // bytes int64_t memory_total = 0; // bytes int64_t memory_used = 0; // bytes (resident set size) int threads_active = 0; // actual mining threads // Pool-side hashrate (from pool stats API, not xmrig) double pool_hashrate = 0; }; /// User-facing config (maps 1:1 to UI fields / Settings) struct Config { std::string pool_url = "pool.dragonx.is:3433"; std::string wallet_address; std::string worker_name = "x"; std::string algo = "rx/hush"; int threads = 0; // 0 = xmrig auto bool tls = false; bool hugepages = true; }; XmrigManager(); ~XmrigManager(); // Non-copyable XmrigManager(const XmrigManager&) = delete; XmrigManager& operator=(const XmrigManager&) = delete; /** * @brief Start xmrig with the given config. * Generates a JSON config file, finds the binary, and spawns the process. */ bool start(const Config& cfg); /** * @brief Stop xmrig gracefully (SIGTERM → wait → SIGKILL). */ void stop(int wait_ms = 5000); bool isRunning() const; State getState() const { return state_.load(std::memory_order_relaxed); } const PoolStats& getStats() const { return stats_; } const std::string& getLastError() const { return last_error_; } /// Thread count requested at start() — available immediately, unlike /// PoolStats::threads_active which requires an API response. int getRequestedThreads() const { return threads_; } /** * @brief Get last N lines of xmrig stdout (thread-safe snapshot). */ std::vector getRecentLines(int maxLines = 30) const; /** * @brief Get new output since a given offset (thread-safe). * Returns the new text and updates offset to the current size. */ std::string getOutputSince(size_t& offset) const { std::lock_guard lk(output_mutex_); if (offset >= process_output_.size()) { offset = process_output_.size(); return {}; } std::string result = process_output_.substr(offset); offset = process_output_.size(); return result; } /** * @brief Get current output size (thread-safe, no copy) */ size_t getOutputSize() const { std::lock_guard lk(output_mutex_); return process_output_.size(); } /** * @brief Poll the xmrig HTTP API for live stats. * Lightweight — reads cached stats updated by the monitor thread. * Called from App::update() every ~2 s while running. */ void pollStats(); /** * @brief Get xmrig process memory usage in MB (from OS, not API). */ double getMemoryUsageMB() const; /** * @brief Find xmrig binary in standard locations. */ static std::string findXmrigBinary(); private: bool generateConfig(const Config& cfg, const std::string& outPath); bool startProcess(const std::string& xmrigPath, const std::string& cfgPath, int threads); void monitorProcess(); void drainOutput(); void appendOutput(const char* data, size_t len); void fetchStatsHttp(); // Blocking HTTP call — runs on monitor thread only void fetchPoolApiStats(); // Fetch pool-side stats (hashrate) from pool HTTP API std::atomic state_{State::Stopped}; std::string last_error_; mutable std::mutex output_mutex_; std::string process_output_; // xmrig HTTP API credentials (random per session) int api_port_ = 0; std::string api_token_; int threads_ = 0; // Thread count for mining std::string pool_host_; // Pool hostname for stats API PoolStats stats_; mutable std::mutex stats_mutex_; // Process handles #ifdef _WIN32 HANDLE process_handle_ = nullptr; HANDLE stdout_read_ = nullptr; #else pid_t process_pid_ = 0; int stdout_fd_ = -1; #endif std::thread monitor_thread_; std::atomic should_stop_{false}; }; } // namespace daemon } // namespace dragonx