#pragma once #include #include #include #include #include #include "provision_state.h" namespace dragonx { namespace resources { // Embedded resource data (generated at build time) struct EmbeddedResource { const uint8_t* data; size_t size; const char* filename; }; // Check if embedded resources are available bool hasEmbeddedResources(); // Get embedded resource by name // Returns nullptr if not found or not embedded const EmbeddedResource* getEmbeddedResource(const std::string& name); using CancelFn = std::function; // polled between 4 MB chunks; true = stop now // Suffix of our own temp files in the daemon dir (".partial"). NOT ".tmp": the in-app miner/node // updaters stage ".tmp" in the same directory and must never have it deleted under them. inline constexpr const char* kPartialFileSuffix = ".partial"; // Extract all embedded resources to the daemon directory. Serialised with every other writer of that // directory by an internal mutex; atomic per file (temp + flush + rename), so a destination is either the old // complete file or the new one. `progress` (optional) receives bytes written; `cancelled` (optional) aborts // between chunks leaving no partial destination. Returns true if every needed file was written (false also on // cancel). Safe on any thread. bool extractEmbeddedResources(ProvisionProgress* progress = nullptr, const CancelFn& cancelled = {}); // Does `destPath` need (re)writing? Missing -> yes. Present: only when `refreshOnSizeMismatch` and the size // differs. embeddedSize == 0 -> never. (Pure apart from the stat; exposed for tests.) bool resourceNeedsWrite(std::uint64_t embeddedSize, bool refreshOnSizeMismatch, const std::string& destPath); // The bundled miner is placed only when MISSING: a present xmrig is never replaced by the bundled copy, even when // its size differs, so an "Update miner..." install survives a wallet restart or upgrade. inline constexpr bool kXmrigRefreshOnSizeMismatch = false; // the in-app updater owns the miner once placed // Write `data` to `destPath` via `destPath + kPartialFileSuffix`, flush it to disk, then move it into place // (POSIX rename; Windows MoveFileEx with retry and move-aside of a running .exe to ".old"). POSIX: chmod 0755 // first when `executable`. Returns false (temp removed, original kept) on any failure or on cancel. // Takes no lock itself (extractEmbeddedResources / copyBundledFiles / the on-demand extractors do). bool writeFileAtomic(const std::string& destPath, const std::uint8_t* data, std::size_t size, bool executable, ProvisionProgress* progress = nullptr, const CancelFn& cancelled = {}); // Same contract, streaming from a source file in 4 MB chunks; keeps the source's permissions. bool copyFileAtomic(const std::string& srcPath, const std::string& destPath, ProvisionProgress* progress = nullptr, const CancelFn& cancelled = {}); // Node files shipped NEXT TO the executable (zip / AppImage / .app; no embedded_data.h). struct BundleCopyItem { std::string name, src, dst; }; std::vector bundleSearchDirs(); // macOS: .app Contents/Resources first; then exe dir const std::vector& saplingParamFileNames(); // sapling-spend.params, sapling-output.params const std::vector& nodeBundleFileNames(); // params + asmap.dat + dragonxd + dragonx-cli + dragonx-tx // First search dir holding a name wins; names with no source are skipped (optional); names whose destination // exists are skipped unless replaceExisting. Stat-only. std::vector planBundleCopy(const std::vector& searchDirs, const std::string& destDir, const std::vector& names, bool replaceExisting); struct BundleCopyResult { bool ok = true; int copied = 0; std::string firstFailure; }; // Executes planBundleCopy under the provisioning lock (checks the plan lock-free first: the common // "nothing to copy" call never touches the lock). BundleCopyResult copyBundledFiles(const std::vector& searchDirs, const std::string& destDir, const std::vector& names, bool replaceExisting, ProvisionProgress* progress = nullptr, const CancelFn& cancelled = {}); // Check if params need to be extracted (not already present) bool needsParamsExtraction(); // Get the params directory path std::string getParamsDirectory(); // --- Daemon binary management (Settings → daemon binary panel) ------------------------------ // Info about the dragonxd binary currently installed in the dragonx/ extraction directory. struct DaemonBinaryInfo { bool exists = false; std::string path; std::uintmax_t size = 0; std::string version; // scanned from the binary ("vX.Y.Z-"), empty if not found std::int64_t modifiedEpoch = 0; // last-write time as unix epoch seconds, 0 if unknown }; // Info about the dragonxd binary bundled inside this wallet build. struct BundledDaemonInfo { bool available = false; // a daemon resource is embedded in this build std::uintmax_t size = 0; std::string version; }; // Read + scan the installed dragonxd (reads the file; call off the UI thread or cache the result). // scanVersion=false: stat only (exists / size / modifiedEpoch), no 16 MB read. DaemonBinaryInfo getInstalledDaemonInfo(bool scanVersion = true); // Info about the bundled daemon (scans the embedded bytes once, cached). BundledDaemonInfo getBundledDaemonInfo(); // Force-overwrite the installed dragonx binaries (dragonxd/cli/tx) with the bundled ones. The // caller should stop the daemon first. Returns true if all present resources were written. bool reextractBundledDaemon(); // Ensure the embedded offline wallet-rebuild recovery helper is extracted to the daemon dir, and // return its path ("" if not embedded in this build or extraction failed). Idempotent — extracts only // when missing. Unlike the first-run extractEmbeddedResources() (gated on needsParamsExtraction()), // this runs on demand so recovery works from a self-contained exe on ANY run, not just the first. std::string ensureWalletRebuildHelperExtracted(); // Resource names constexpr const char* RESOURCE_SAPLING_SPEND = "sapling-spend.params"; constexpr const char* RESOURCE_SAPLING_OUTPUT = "sapling-output.params"; constexpr const char* RESOURCE_ASMAP = "asmap.dat"; constexpr const char* RESOURCE_DRAGONXD = "dragonxd.exe"; // embedded-resource table key (Windows builds only) // The daemon binary's file name on THIS platform. Use it to build paths; RESOURCE_DRAGONXD is only the table key. #ifdef _WIN32 constexpr const char* DAEMON_BINARY_NAME = "dragonxd.exe"; #else constexpr const char* DAEMON_BINARY_NAME = "dragonxd"; #endif constexpr const char* RESOURCE_DRAGONX_CLI = "dragonx-cli.exe"; constexpr const char* RESOURCE_DRAGONX_TX = "dragonx-tx.exe"; constexpr const char* RESOURCE_DRAGONX_WALLET_REBUILD = "dragonx-wallet-rebuild.exe"; constexpr const char* RESOURCE_XMRIG = "xmrig.exe"; constexpr const char* RESOURCE_DARK_GRADIENT = "dark_gradient.png"; constexpr const char* RESOURCE_LOGO = "logo_ObsidianDragon_dark.png"; // Embedded theme overlay info (for iterating bundled themes) struct EmbeddedTheme { const uint8_t* data; size_t size; const char* filename; // e.g. "dark.toml" }; // Get array of embedded overlay themes (nullptr-terminated) const EmbeddedTheme* getEmbeddedThemes(); // Extract bundled overlay themes to the given directory // Returns number of themes extracted int extractBundledThemes(const std::string& destDir); // Write `size` bytes to `path` unless the file already holds exactly those bytes. // Returns 1 = written, 0 = already identical (untouched), -1 = write failed. int writeFileIfDifferent(const std::string& path, const uint8_t* data, size_t size); // Update stale bundled theme files in the given directory. // Compares on-disk file size to embedded size; overwrites on mismatch. // Returns number of themes updated. int updateBundledThemes(const std::string& dir); // Check if daemon needs to be extracted bool needsDaemonExtraction(); // Get daemon binary directory (/dragonx/) std::string getDaemonDirectory(); // Check if daemon is available (embedded or in app directory) bool hasDaemonAvailable(); // Get daemon executable path (extracts if needed) std::string getDaemonPath(); // Check if xmrig is available (embedded or in app directory) bool hasXmrigAvailable(); // Force re-extract xmrig binary from embedded resources // (bypasses exists-check; use when Defender deletes the file) bool forceExtractXmrig(); // Get xmrig executable path (extracts if needed) std::string getXmrigPath(); } // namespace resources } // namespace dragonx