diff options
author | Meway <mewaysid92@gmail.com> | 2025-07-13 11:47:06 -0500 |
---|---|---|
committer | Meway <mewaysid92@gmail.com> | 2025-07-13 11:47:06 -0500 |
commit | b16d9d652296e7252de8223be20efced1e9bac7e (patch) | |
tree | e4b1f363d806c67d0bc759be578342a300b1a6ca | |
parent | f36f0bc8fd28d84ae40e5e3eff2c2ba8a1b769b0 (diff) | |
download | mana-b16d9d652296e7252de8223be20efced1e9bac7e.tar.gz mana-b16d9d652296e7252de8223be20efced1e9bac7e.tar.bz2 mana-b16d9d652296e7252de8223be20efced1e9bac7e.tar.xz mana-b16d9d652296e7252de8223be20efced1e9bac7e.zip |
Updated logic to be more informative to users with throttled internet connections
-rw-r--r-- | src/gui/updaterwindow.cpp | 6 | ||||
-rw-r--r-- | src/gui/updaterwindow.h | 2 | ||||
-rw-r--r-- | src/net/download.cpp | 112 | ||||
-rw-r--r-- | src/net/download.h | 1 |
4 files changed, 75 insertions, 46 deletions
diff --git a/src/gui/updaterwindow.cpp b/src/gui/updaterwindow.cpp index 5cfb45cd..646f0cb5 100644 --- a/src/gui/updaterwindow.cpp +++ b/src/gui/updaterwindow.cpp @@ -318,6 +318,12 @@ void UpdaterWindow::logic() mProgressBar->setProgress(progress); } +void UpdaterWindow::cancelDownloads() { + // Assuming UpdaterWindow has a Download* member (e.g., mDownload) + if (mDownload) { + mDownload->cancel(); + } +} void UpdaterWindow::downloadCompleted() { diff --git a/src/gui/updaterwindow.h b/src/gui/updaterwindow.h index dd1400ba..f87c6924 100644 --- a/src/gui/updaterwindow.h +++ b/src/gui/updaterwindow.h @@ -76,6 +76,8 @@ class UpdaterWindow : public Window, public gcn::ActionListener, void keyPressed(gcn::KeyEvent &keyEvent) override; void logic() override; + + void cancelDownloads(); private: bool cancel(); diff --git a/src/net/download.cpp b/src/net/download.cpp index 7aab3b2f..f96ae600 100644 --- a/src/net/download.cpp +++ b/src/net/download.cpp @@ -19,6 +19,8 @@ */ #include "net/download.h" +#include "client.h" +#include "main.h" #include "configuration.h" #include "log.h" @@ -35,9 +37,6 @@ constexpr char DOWNLOAD_ERROR_MESSAGE_THREAD[] = "Could not create download thre namespace Net { -/** - * Calculates the Alder-32 checksum for the given file. - */ unsigned long Download::fadler32(FILE *file) { if (!file || fseek(file, 0, SEEK_END) != 0) @@ -49,7 +48,6 @@ unsigned long Download::fadler32(FILE *file) rewind(file); - // Calculate Adler-32 checksum void *buffer = malloc(fileSize); const size_t read = fread(buffer, 1, fileSize, file); unsigned long adler = adler32_z(0L, Z_NULL, 0); @@ -76,8 +74,7 @@ Download::~Download() void Download::addHeader(const char *header) { - assert(!mThread); // Cannot add headers after starting download - + assert(!mThread); mHeaders = curl_slist_append(mHeaders, header); } @@ -90,8 +87,7 @@ void Download::noCache() void Download::setFile(const std::string &filename, std::optional<unsigned long> adler32) { - assert(!mThread); // Cannot set file after starting download - + assert(!mThread); mMemoryWrite = false; mFileName = filename; mAdler = adler32; @@ -99,15 +95,13 @@ void Download::setFile(const std::string &filename, void Download::setUseBuffer() { - assert(!mThread); // Cannot set write function after starting download - + assert(!mThread); mMemoryWrite = true; } bool Download::start() { - assert(!mThread); // Download already started - + assert(!mThread); logger->log("Starting download: %s", mUrl.c_str()); mThread = SDL_CreateThread(downloadThread, "Download", this); @@ -131,13 +125,10 @@ void Download::cancel() std::string_view Download::getBuffer() const { - assert(mMemoryWrite); // Buffer not used + assert(mMemoryWrite); return std::string_view(mBuffer, mDownloadedBytes); } -/** - * A libcurl callback for reporting progress. - */ int Download::downloadProgress(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) @@ -153,9 +144,6 @@ int Download::downloadProgress(void *clientp, return d->mCancel; } -/** - * A libcurl callback for writing to memory. - */ size_t Download::writeBuffer(char *ptr, size_t size, size_t nmemb, void *stream) { auto *d = reinterpret_cast<Download *>(stream); @@ -176,12 +164,18 @@ int Download::downloadThread(void *ptr) auto *d = reinterpret_cast<Download*>(ptr); bool complete = false; std::string outFilename; + curl_off_t resumeOffset = 0; if (!d->mMemoryWrite) outFilename = d->mFileName + ".part"; - for (int attempts = 0; attempts < 3 && !complete && !d->mCancel; ++attempts) + for (int attempts = 0; attempts < 5 && !complete && !d->mCancel; ++attempts) { + if (attempts > 0) { + SDL_Delay(2000 * (1 << attempts)); // 2s, 4s, 8s, 16s + logger->log("Retry attempt %d for %s at offset %lld", attempts + 1, d->mUrl.c_str(), resumeOffset); + } + CURL *curl = curl_easy_init(); if (!curl) break; @@ -201,8 +195,16 @@ int Download::downloadThread(void *ptr) } else { - file = fopen(outFilename.c_str(), "w+b"); + file = fopen(outFilename.c_str(), resumeOffset ? "ab" : "wb"); // Append if resuming + if (!file) { + logger->log("Failed to open file %s", outFilename.c_str()); + curl_easy_cleanup(curl); + break; + } curl_easy_setopt(curl, CURLOPT_WRITEDATA, file); + if (resumeOffset) { + curl_easy_setopt(curl, CURLOPT_RANGE, (std::to_string(resumeOffset) + "-").c_str()); + } } const std::string appShort = branding.getStringValue("appShort"); @@ -216,70 +218,84 @@ int Download::downloadThread(void *ptr) curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, &Download::downloadProgress); curl_easy_setopt(curl, CURLOPT_XFERINFODATA, ptr); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30); // 30s for connection + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 2100); // 30 for total download + curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 100); // 100 bytes/s + curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 60); // 60s low speed timeout const CURLcode res = curl_easy_perform(curl); + + if (!d->mMemoryWrite && file) { + // Update resume offset + resumeOffset = ftell(file); + logger->log("Download attempt %d progress: %lld bytes", attempts + 1, resumeOffset); + fclose(file); + file = nullptr; + } + curl_easy_cleanup(curl); if (res == CURLE_ABORTED_BY_CALLBACK) { d->mCancel = true; - if (file) { fclose(file); ::remove(outFilename.c_str()); } - break; } if (res != CURLE_OK) { - logger->log("curl error %d: %s host: %s", - res, d->mError, d->mUrl.c_str()); - - if (file) - { + logger->log("curl error %d: %s host: %s", res, d->mError, d->mUrl.c_str()); + if (file) { fclose(file); + file = nullptr; + } + auto state = d->mState.lock(); + state->status = DownloadStatus::Error; + snprintf(d->mError, CURL_ERROR_SIZE, "Failed to download %s: %s", d->mUrl.c_str(), curl_easy_strerror(res)); + if (res == CURLE_URL_MALFORMAT || res == CURLE_COULDNT_RESOLVE_HOST || res == CURLE_HTTP_RETURNED_ERROR) + { + extern std::string errorMessage; + ::errorMessage = d->mError; + Client::instance()->showErrorDialog(::errorMessage, STATE_CHOOSE_SERVER); + break; + } + if (!d->mMemoryWrite && resumeOffset > 0) { + logger->log("Resumable progress: %lld bytes", resumeOffset); + } else { ::remove(outFilename.c_str()); + resumeOffset = 0; // Reset if not resumable } - - break; + continue; } if (!d->mMemoryWrite) { - // Check the checksum if available if (d->mAdler) { + file = fopen(outFilename.c_str(), "rb"); unsigned long adler = fadler32(file); - if (d->mAdler != adler) { if (file) fclose(file); - - // Remove the corrupted file ::remove(outFilename.c_str()); logger->log("Checksum for file %s failed: (%lx/%lx)", - d->mFileName.c_str(), - adler, *d->mAdler); - - continue; // Bail out here to avoid the renaming + d->mFileName.c_str(), adler, *d->mAdler); + resumeOffset = 0; // Reset on checksum failure + continue; } } if (file) fclose(file); - // Any existing file with this name is deleted first, otherwise - // the rename will fail on Windows. ::remove(d->mFileName.c_str()); ::rename(outFilename.c_str(), d->mFileName.c_str()); - // Check if we can open it and no errors were encountered - // during renaming file = fopen(d->mFileName.c_str(), "rb"); if (file) { @@ -290,7 +306,6 @@ int Download::downloadThread(void *ptr) } else { - // It's stored in memory, we're done complete = true; } @@ -303,10 +318,15 @@ int Download::downloadThread(void *ptr) state->status = DownloadStatus::Canceled; else if (complete) state->status = DownloadStatus::Complete; - else + else { state->status = DownloadStatus::Error; + snprintf(d->mError, CURL_ERROR_SIZE, "Download failed after %d attempts: %s", 5, d->mUrl.c_str()); + extern std::string errorMessage; + ::errorMessage = d->mError; + Client::instance()->showErrorDialog(::errorMessage, STATE_CHOOSE_SERVER); + } return 0; } -} // namespace Net +} // namespace Net
\ No newline at end of file diff --git a/src/net/download.h b/src/net/download.h index e9483fa5..f7021ab3 100644 --- a/src/net/download.h +++ b/src/net/download.h @@ -20,6 +20,7 @@ #include "utils/mutex.h" + #include <cstdio> #include <optional> #include <string> |