From 633292a82029fed626eae1e02567a1f70be5f81c Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Mon, 23 Oct 2023 00:08:25 +0200 Subject: [PATCH] Add comprehensive error logging for downloads and fix CPU in progress callback The game will now not be installed if the download fails (this should've never happened in the first place). The CPU usage fix should also fix download speed throttling. --- r5dev/netconsole/CMakeLists.txt | 2 +- r5dev/public/tier2/curlutils.h | 15 +++++--- r5dev/sdklauncher/CMakeLists.txt | 1 + r5dev/sdklauncher/base_surface.cpp | 16 +++++++-- r5dev/sdklauncher/sdklauncher_utils.cpp | 42 ++++++++++++++++------- r5dev/sdklauncher/sdklauncher_utils.h | 4 +-- r5dev/{netconsole => tier0}/plat_time.cpp | 0 r5dev/tier2/curlutils.cpp | 32 ++++++++++++----- 8 files changed, 80 insertions(+), 32 deletions(-) rename r5dev/{netconsole => tier0}/plat_time.cpp (100%) diff --git a/r5dev/netconsole/CMakeLists.txt b/r5dev/netconsole/CMakeLists.txt index bb951a54..69d3a74f 100644 --- a/r5dev/netconsole/CMakeLists.txt +++ b/r5dev/netconsole/CMakeLists.txt @@ -6,13 +6,13 @@ start_sources() add_sources( SOURCE_GROUP "Core" "netconsole.cpp" "netconsole.h" - "plat_time.cpp" "${ENGINE_SOURCE_DIR}/core/logdef.cpp" "${ENGINE_SOURCE_DIR}/core/logdef.h" "${ENGINE_SOURCE_DIR}/core/logger.cpp" "${ENGINE_SOURCE_DIR}/core/logger.h" "${ENGINE_SOURCE_DIR}/core/termutil.cpp" "${ENGINE_SOURCE_DIR}/core/termutil.h" + "${ENGINE_SOURCE_DIR}/tier0/plat_time.cpp" ) add_sources( SOURCE_GROUP "Engine" diff --git a/r5dev/public/tier2/curlutils.h b/r5dev/public/tier2/curlutils.h index 66419dd8..81b4f269 100644 --- a/r5dev/public/tier2/curlutils.h +++ b/r5dev/public/tier2/curlutils.h @@ -6,13 +6,13 @@ struct CURLProgress CURLProgress() : curl(nullptr) , name(nullptr) - , cust(nullptr) + , user(nullptr) , size(0) {} CURL* curl; const char* name; - void* cust; // custom pointer to anything. + void* user; // custom pointer to anything. size_t size; }; @@ -25,7 +25,10 @@ struct CURLParams , verifyPeer(false) , followRedirect(false) , verbose(false) - {} + , printError(false) + { + memset(errorBuffer, '\0', sizeof(errorBuffer)); + } void* writeFunction; void* statusFunction; @@ -34,16 +37,18 @@ struct CURLParams bool verifyPeer; bool followRedirect; bool verbose; + bool printError; + char errorBuffer[256]; }; size_t CURLWriteStringCallback(char* contents, const size_t size, const size_t nmemb, string* userp); size_t CURLWriteFileCallback(void* data, const size_t size, const size_t nmemb, FILE* userp); bool CURLDownloadFile(const char* remote, const char* savePath, const char* fileName, - const char* options, curl_off_t dataSize, void* customPointer, const CURLParams& params); + const char* options, curl_off_t dataSize, void* customPointer, CURLParams& params); CURL* CURLInitRequest(const char* remote, const char* request, string& outResponse, - curl_slist*& slist, const CURLParams& params); + curl_slist*& slist, CURLParams& params); CURLcode CURLSubmitRequest(CURL* curl, curl_slist*& slist); CURLINFO CURLRetrieveInfo(CURL* curl); diff --git a/r5dev/sdklauncher/CMakeLists.txt b/r5dev/sdklauncher/CMakeLists.txt index 44896673..89f42995 100644 --- a/r5dev/sdklauncher/CMakeLists.txt +++ b/r5dev/sdklauncher/CMakeLists.txt @@ -9,6 +9,7 @@ add_sources( SOURCE_GROUP "Core" "sdklauncher_const.h" "sdklauncher_utils.cpp" "sdklauncher_utils.h" + "${ENGINE_SOURCE_DIR}/tier0/plat_time.cpp" ) add_sources( SOURCE_GROUP "GUI" diff --git a/r5dev/sdklauncher/base_surface.cpp b/r5dev/sdklauncher/base_surface.cpp index 44ad9816..2076c19a 100644 --- a/r5dev/sdklauncher/base_surface.cpp +++ b/r5dev/sdklauncher/base_surface.cpp @@ -184,8 +184,14 @@ void CBaseSurface::OnUpdateClick(Forms::Control* Sender) } CUtlVector fileList; - if (SDKLauncher_BeginInstall(true, false, fileList, pProgress)) + CUtlString errorMessage; + + if (!SDKLauncher_BeginInstall(true, false, fileList, &errorMessage, pProgress)) { + Forms::MessageBox::Show(Format("Failed to install game: %s\n", errorMessage.String()).c_str(), + "Error", Forms::MessageBoxButtons::OK, Forms::MessageBoxIcon::Error); + + return; } // Close on finish. @@ -243,8 +249,14 @@ void CBaseSurface::OnInstallClick(Forms::Control* Sender) } CUtlVector fileList; - if (SDKLauncher_BeginInstall(true, false, fileList, pProgress)) + CUtlString errorMessage; + + if (!SDKLauncher_BeginInstall(true, false, fileList, &errorMessage, pProgress)) { + Forms::MessageBox::Show(Format("Failed to install game: %s\n", errorMessage.String()).c_str(), + "Error", Forms::MessageBoxButtons::OK, Forms::MessageBoxIcon::Error); + + return; } // Close on finish. diff --git a/r5dev/sdklauncher/sdklauncher_utils.cpp b/r5dev/sdklauncher/sdklauncher_utils.cpp index 98fff7d3..ff74f43a 100644 --- a/r5dev/sdklauncher/sdklauncher_utils.cpp +++ b/r5dev/sdklauncher/sdklauncher_utils.cpp @@ -362,7 +362,7 @@ bool SDKLauncher_AcquireReleaseManifest(const char* url, string& responseMessage int SDKLauncher_ProgressCallback(CURLProgress* progessData, double dltotal, double dlnow, double ultotal, double ulnow) { - CProgressPanel* pDownloadSurface = (CProgressPanel*)progessData->cust; + CProgressPanel* pDownloadSurface = (CProgressPanel*)progessData->user; if (pDownloadSurface->IsCanceled()) { @@ -371,12 +371,12 @@ int SDKLauncher_ProgressCallback(CURLProgress* progessData, double dltotal, } // This gets called often, prevent this callback from eating all CPU. - //const double curTime = Plat_FloatTime(); - //if ((curTime - s_flLastProgressUpdate) < PROGRESS_CALLBACK_UPDATE_DELTA) - //{ - // return 0; - //} - //s_flLastProgressUpdate = curTime; + const double curTime = Plat_FloatTime(); + if ((curTime - s_flLastProgressUpdate) < PROGRESS_CALLBACK_UPDATE_DELTA) + { + return 0; + } + s_flLastProgressUpdate = curTime; double downloaded; curl_easy_getinfo(progessData->curl, CURLINFO_SIZE_DOWNLOAD, &downloaded); @@ -394,7 +394,7 @@ int SDKLauncher_ProgressCallback(CURLProgress* progessData, double dltotal, // Purpose: //---------------------------------------------------------------------------- bool SDKLauncher_DownloadAsset(const char* url, const char* path, const char* fileName, - const size_t fileSize, const char* options, CProgressPanel* pProgress) + const size_t fileSize, const char* options, CUtlString* errorMessage, CProgressPanel* pProgress) { CURLParams params; @@ -402,7 +402,12 @@ bool SDKLauncher_DownloadAsset(const char* url, const char* path, const char* fi params.statusFunction = SDKLauncher_ProgressCallback; params.followRedirect = true; - return CURLDownloadFile(url, path, fileName, options, fileSize, pProgress, params); + bool ret = CURLDownloadFile(url, path, fileName, options, fileSize, pProgress, params); + + if (!ret && errorMessage) + errorMessage->Set(params.errorBuffer); + + return ret; } bool SDKLauncher_BuildUpdateList(const nlohmann::json& localManifest, @@ -503,7 +508,7 @@ bool SDKLauncher_BuildUpdateList(const nlohmann::json& localManifest, // Purpose: //---------------------------------------------------------------------------- bool SDKLauncher_BeginInstall(const bool bPreRelease, const bool bOptionalDepots, - CUtlVector& zipList, CProgressPanel* pProgress) + CUtlVector& zipList, CUtlString* errorMessage, CProgressPanel* pProgress) { string responseMessage; nlohmann::json remoteManifest; @@ -511,6 +516,9 @@ bool SDKLauncher_BeginInstall(const bool bPreRelease, const bool bOptionalDepots if (!SDKLauncher_GetRemoteManifest(XorStr(SDK_DEPOT_VENDOR), responseMessage, remoteManifest, bPreRelease)) { printf("%s: Failed! %s\n", "SDKLauncher_GetRemoteManifest", responseMessage.c_str()); + + // TODO: make more comprehensive... + errorMessage->Set("Failed to obtain remote manifest"); return false; } @@ -536,8 +544,9 @@ bool SDKLauncher_BeginInstall(const bool bPreRelease, const bool bOptionalDepots } if (!SDKLauncher_DownloadDepotList(remoteManifest, depotList, - zipList, pProgress, DEFAULT_DEPOT_DOWNLOAD_DIR, bOptionalDepots)) + zipList, errorMessage, pProgress, DEFAULT_DEPOT_DOWNLOAD_DIR, bOptionalDepots)) { + // Error message is set by previous function. return false; } @@ -564,12 +573,13 @@ bool SDKLauncher_BeginInstall(const bool bPreRelease, const bool bOptionalDepots // Purpose: //---------------------------------------------------------------------------- bool SDKLauncher_DownloadDepotList(nlohmann::json& manifest, CUtlVector& depotList, - CUtlVector& outZipList, CProgressPanel* pProgress, const char* pPath, + CUtlVector& outZipList, CUtlString* errorMessage, CProgressPanel* pProgress, const char* pPath, const bool bOptionalDepots) { if (!manifest.contains("depot")) { Assert(0); + errorMessage->Set("Invalid manifest"); return false; } @@ -577,6 +587,7 @@ bool SDKLauncher_DownloadDepotList(nlohmann::json& manifest, CUtlVectorSet("No depots found in manifest"); return false; } @@ -622,7 +633,11 @@ bool SDKLauncher_DownloadDepotList(nlohmann::json& manifest, CUtlVectorSetText(Format("Downloading package %i of %i...", i, !depotList.IsEmpty() ? depotList.Count() : (int)depotListArray.size()).c_str()); - SDKLauncher_DownloadAsset(downloadLink.c_str(), pPath, fileName.c_str(), fileSize, "wb+", pProgress); + if (!SDKLauncher_DownloadAsset(downloadLink.c_str(), pPath, fileName.c_str(), fileSize, "wb+", errorMessage, pProgress)) + { + // Error message is set by previous function. + return false; + } // Check if its a zip file, as these are // the only files that will be installed. @@ -657,6 +672,7 @@ bool SDKLauncher_InstallDepotList(nlohmann::json& manifest, CUtlVectorSetText(Format("Installing package %i of %i...", i + 1, depotList.Count()).c_str()); CUtlString& depotFilePath = depotList[i]; + // TODO[ AMOS ]: make the ZIP lib return error codes instead if (!SDKLauncher_ExtractZipFile(manifest, depotFilePath, fileList, pProgress)) return false; } diff --git a/r5dev/sdklauncher/sdklauncher_utils.h b/r5dev/sdklauncher/sdklauncher_utils.h index b9bbe32e..8e700967 100644 --- a/r5dev/sdklauncher/sdklauncher_utils.h +++ b/r5dev/sdklauncher/sdklauncher_utils.h @@ -12,13 +12,13 @@ bool SDKLauncher_ClearDepotDirectories(); bool SDKLauncher_ExtractZipFile(nlohmann::json& manifest, const CUtlString& filePath, DepotChangedList_t* changedList, CProgressPanel* pProgress); bool SDKLauncher_BeginInstall(const bool bPreRelease, const bool bOptionalDepots, - CUtlVector& zipList, CProgressPanel* pProgress); + CUtlVector& zipList, CUtlString* errorMessage, CProgressPanel* pProgress); bool SDKLauncher_IsManifestValid(const nlohmann::json& depotManifest); bool SDKLauncher_IsDepositoryValid(const nlohmann::json& depotAssetList); bool SDKLauncher_DownloadDepotList(nlohmann::json& manifest, CUtlVector& depotList, - CUtlVector& outZipList, CProgressPanel* pProgress, const char* pPath, + CUtlVector& outZipList, CUtlString* errorMessage, CProgressPanel* pProgress, const char* pPath, const bool bOptionalDepots); bool SDKLauncher_InstallDepotList(nlohmann::json& manifest, CUtlVector& depotList, diff --git a/r5dev/netconsole/plat_time.cpp b/r5dev/tier0/plat_time.cpp similarity index 100% rename from r5dev/netconsole/plat_time.cpp rename to r5dev/tier0/plat_time.cpp diff --git a/r5dev/tier2/curlutils.cpp b/r5dev/tier2/curlutils.cpp index fd6f08ca..a99c1a5a 100644 --- a/r5dev/tier2/curlutils.cpp +++ b/r5dev/tier2/curlutils.cpp @@ -34,12 +34,16 @@ void CURLInitCommonOptions(CURL* curl, const char* remote, } bool CURLDownloadFile(const char* remote, const char* savePath, const char* fileName, - const char* options, curl_off_t dataSize, void* customPointer, const CURLParams& params) + const char* options, curl_off_t dataSize, void* customPointer, CURLParams& params) { CURL* curl = curl_easy_init(); if (!curl) { - Error(eDLL_T::COMMON, NO_ERROR, "CURL: %s\n", "Easy init failed"); + V_snprintf(params.errorBuffer, sizeof(params.errorBuffer), "CURL: %s", "Easy init failed"); + + if (params.printError) + Error(eDLL_T::COMMON, NO_ERROR, "%s\n", params.errorBuffer); + return false; } @@ -51,9 +55,12 @@ bool CURLDownloadFile(const char* remote, const char* savePath, const char* file FILE* file = fopen(filePath.c_str(), options); if (!file) { - Error(eDLL_T::COMMON, NO_ERROR, "CURL: %s\n", "Open file failed"); - curl_easy_cleanup(curl); + V_snprintf(params.errorBuffer, sizeof(params.errorBuffer), "CURL: %s", "Open file failed"); + if (params.printError) + Error(eDLL_T::COMMON, NO_ERROR, "%s\n", params.errorBuffer); + + curl_easy_cleanup(curl); return false; } @@ -61,7 +68,7 @@ bool CURLDownloadFile(const char* remote, const char* savePath, const char* file progressData.curl = curl; progressData.name = fileName; - progressData.cust = customPointer; + progressData.user = customPointer; progressData.size = dataSize; CURLInitCommonOptions(curl, remote, file, params); @@ -77,8 +84,11 @@ bool CURLDownloadFile(const char* remote, const char* savePath, const char* file if (res != CURLE_OK) { - Error(eDLL_T::COMMON, NO_ERROR, "CURL: Download of file '%s' failed; %s\n", - fileName, curl_easy_strerror(res)); + V_snprintf(params.errorBuffer, sizeof(params.errorBuffer), + "CURL: Download of file '%s' failed; %s", fileName, curl_easy_strerror(res)); + + if (params.printError) + Error(eDLL_T::COMMON, NO_ERROR, "%s\n", params.errorBuffer); curl_easy_cleanup(curl); fclose(file); @@ -93,11 +103,15 @@ bool CURLDownloadFile(const char* remote, const char* savePath, const char* file } CURL* CURLInitRequest(const char* remote, const char* request, - string& outResponse, curl_slist*& slist, const CURLParams& params) + string& outResponse, curl_slist*& slist, CURLParams& params) { std::function fnError = [&](const char* errorMsg) { - Error(eDLL_T::COMMON, NO_ERROR, "CURL: %s\n", errorMsg); + V_snprintf(params.errorBuffer, sizeof(params.errorBuffer), "CURL: %s", errorMsg); + + if (params.printError) + Error(eDLL_T::COMMON, NO_ERROR, "%s\n", params.errorBuffer); + curl_slist_free_all(slist); };