feat(updater): in-app dragonxd updater + browse-all-releases
Add a full-node daemon updater (util/DaemonUpdater + daemon_download_dialog) reachable from Settings -> NODE & SECURITY: downloads/verifies (SHA-256 + enforced ed25519 signature) and atomically installs the latest dragonxd from the project Gitea, with a "Restart daemon now" step. Add a shared "Browse all releases..." picker (release_list_view) to both the miner and daemon updaters so users can pin older/pre-release builds. Pure no-I/O cores (daemon_updater_core / xmrig_updater_core) are unit-tested; sign-daemon-release.sh signs release archives offline. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -38,7 +38,10 @@ struct XmrigReleaseAsset {
|
||||
struct XmrigRelease {
|
||||
bool ok = false;
|
||||
std::string tag; // e.g. "v1.0.0"
|
||||
std::string name; // human title (e.g. "DRG-XMRig v6.25.3")
|
||||
std::string body; // release notes markdown (holds the checksum blocks)
|
||||
bool prerelease = false; // marked pre-release on the Gitea release
|
||||
std::string publishedAt; // ISO-8601 publish timestamp (date shown in the UI)
|
||||
std::vector<XmrigReleaseAsset> assets;
|
||||
std::string error;
|
||||
};
|
||||
@@ -61,6 +64,10 @@ inline constexpr bool kXmrigRequireSignature = true; // enforced: refus
|
||||
// Parse the Gitea GET /releases/latest JSON into an XmrigRelease (ok=false + error on failure).
|
||||
XmrigRelease parseXmrigRelease(const std::string& json);
|
||||
|
||||
// Parse the Gitea GET /releases (array) JSON into the list of releases, newest first, skipping
|
||||
// drafts. Empty on parse failure. Lets the user browse + pin a specific (or pre-release) version.
|
||||
std::vector<XmrigRelease> parseXmrigReleaseList(const std::string& json);
|
||||
|
||||
// The asset-name token for the host platform: "linux-x64", "win-x64", "macos-x64",
|
||||
// "macos-arm64", or "" if unknown/unsupported.
|
||||
std::string currentXmrigPlatformToken();
|
||||
@@ -102,6 +109,8 @@ public:
|
||||
UpToDate,
|
||||
UpdateAvailable,
|
||||
Unavailable, // no miner build is published for this platform (terminal, not an error)
|
||||
Listing, // fetching the full release list (Browse all releases)
|
||||
ReleaseList, // release list fetched; awaiting the user's pick
|
||||
Downloading,
|
||||
Verifying,
|
||||
Extracting,
|
||||
@@ -124,6 +133,9 @@ public:
|
||||
// Gitea releases API for the DRG-XMRig fork.
|
||||
static constexpr const char* kApiUrl =
|
||||
"https://git.dragonx.is/api/v1/repos/DragonX/drg-xmrig/releases/latest";
|
||||
// Full release list (newest first, includes pre-releases) for the "Browse all releases" picker.
|
||||
static constexpr const char* kReleasesUrl =
|
||||
"https://git.dragonx.is/api/v1/repos/DragonX/drg-xmrig/releases?limit=50";
|
||||
|
||||
XmrigUpdater() = default;
|
||||
~XmrigUpdater();
|
||||
@@ -136,10 +148,21 @@ public:
|
||||
void startCheck(const std::string& installedTag);
|
||||
|
||||
// Download → verify archive → extract (flatten) → verify binary → install into `targetDir` on a
|
||||
// background thread. Re-fetches the release so it is self-contained. End state: Done / Failed.
|
||||
// On Done, getProgress().latest_tag is the version that should be persisted as the installed tag.
|
||||
// background thread. Re-fetches the latest release so it is self-contained. End state: Done /
|
||||
// Failed. On Done, getProgress().latest_tag is the version that should be persisted as installed.
|
||||
void startInstall(const std::string& targetDir);
|
||||
|
||||
// Fetch the full release list on a background thread (for "Browse all releases"). End state:
|
||||
// ReleaseList (then getReleases() holds the list, newest first) / Failed.
|
||||
void startListReleases();
|
||||
|
||||
// Snapshot of the release list fetched by startListReleases().
|
||||
std::vector<XmrigRelease> getReleases() const;
|
||||
|
||||
// Install a SPECIFIC release (chosen from the browse list) into `targetDir` — same verify/extract
|
||||
// path as startInstall, but pinned to `release` instead of latest. End state: Done / Failed.
|
||||
void startInstallRelease(const std::string& targetDir, XmrigRelease release);
|
||||
|
||||
void cancel();
|
||||
Progress getProgress() const;
|
||||
bool isDone() const; // true once the worker reached a terminal state (Done/Failed/Unavailable)
|
||||
@@ -151,13 +174,16 @@ public:
|
||||
|
||||
private:
|
||||
void runCheck(std::string installedTag);
|
||||
void runListReleases();
|
||||
void runInstall(std::string targetDir);
|
||||
void installResolved(const std::string& targetDir, const XmrigRelease& rel); // shared install body
|
||||
void setProgress(State state, const std::string& text, double done = 0, double total = 0);
|
||||
bool downloadToFile(const std::string& url, const std::string& destPath);
|
||||
std::string httpGet(const std::string& url);
|
||||
|
||||
mutable std::mutex mutex_;
|
||||
Progress progress_;
|
||||
std::vector<XmrigRelease> releases_;
|
||||
std::atomic<bool> cancel_requested_{false};
|
||||
std::atomic<bool> worker_running_{false};
|
||||
std::thread worker_;
|
||||
|
||||
Reference in New Issue
Block a user