Added support to the scraper for automatically retrying on errors.

This commit is contained in:
Leon Styhre 2023-02-10 17:24:50 +01:00
parent 07951d8d21
commit e663a717f0
4 changed files with 35 additions and 45 deletions

View file

@ -942,30 +942,19 @@ void GuiScraperMenu::openOtherOptions()
->setOpacity(DISABLED_OPACITY); ->setOpacity(DISABLED_OPACITY);
} }
// Retry search on peer verification errors (TLS/certificate issues). // Automatic retry on error.
auto scraperRetryPeerVerification = std::make_shared<SwitchComponent>(); auto scraperRetryOnError = std::make_shared<SwitchComponent>();
scraperRetryPeerVerification->setState( scraperRetryOnError->setState(Settings::getInstance()->getBool("ScraperRetryOnError"));
Settings::getInstance()->getBool("ScraperRetryPeerVerification")); s->addWithLabel("AUTOMATIC RETRY ON ERROR", scraperRetryOnError);
s->addWithLabel("AUTO-RETRY ON PEER VERIFICATION ERRORS", scraperRetryPeerVerification); s->addSaveFunc([scraperRetryOnError, s] {
s->addSaveFunc([scraperRetryPeerVerification, s] { if (scraperRetryOnError->getState() !=
if (scraperRetryPeerVerification->getState() != Settings::getInstance()->getBool("ScraperRetryOnError")) {
Settings::getInstance()->getBool("ScraperRetryPeerVerification")) { Settings::getInstance()->setBool("ScraperRetryOnError",
Settings::getInstance()->setBool("ScraperRetryPeerVerification", scraperRetryOnError->getState());
scraperRetryPeerVerification->getState());
s->setNeedsSaving(); s->setNeedsSaving();
} }
}); });
// The TLS/certificate issue is not present for TheGamesDB, so gray out the option if this
// scraper is selected.
if (Settings::getInstance()->getString("Scraper") == "thegamesdb") {
scraperRetryPeerVerification->setEnabled(false);
scraperRetryPeerVerification->setOpacity(DISABLED_OPACITY);
scraperRetryPeerVerification->getParent()
->getChild(scraperRetryPeerVerification->getChildIndex() - 1)
->setOpacity(DISABLED_OPACITY);
}
// Switch callbacks. // Switch callbacks.
auto interactiveToggleFunc = [scraperSemiautomatic]() { auto interactiveToggleFunc = [scraperSemiautomatic]() {
if (scraperSemiautomatic->getEnabled()) { if (scraperSemiautomatic->getEnabled()) {

View file

@ -34,24 +34,24 @@
#include "resources/Font.h" #include "resources/Font.h"
#include "utils/StringUtil.h" #include "utils/StringUtil.h"
#define FAILED_VERIFICATION_RETRIES 8
GuiScraperSearch::GuiScraperSearch(SearchType type, unsigned int scrapeCount) GuiScraperSearch::GuiScraperSearch(SearchType type, unsigned int scrapeCount)
: mRenderer {Renderer::getInstance()} : mRenderer {Renderer::getInstance()}
, mGrid {glm::ivec2 {5, 3}} , mGrid {glm::ivec2 {5, 3}}
, mSearchType {type} , mSearchType {type}
, mScrapeCount {scrapeCount} , mScrapeCount {scrapeCount}
, mRefinedSearch {false} , mRefinedSearch {false}
, mBlockAccept {false}
, mAcceptedResult {false}
, mFoundGame {false} , mFoundGame {false}
, mScrapeRatings {false} , mScrapeRatings {false}
, mRetrySearch {false}
, mRetryCount {0}
, mRetryTimer {glm::clamp(
Settings::getInstance()->getInt("ScraperRetryOnErrorTimer") * 1000, 1000, 60000)}
, mRetryAccumulator {0}
{ {
addChild(&mGrid); addChild(&mGrid);
mBlockAccept = false;
mAcceptedResult = false;
mRetrySearch = false;
mRetryCount = 0;
mWindow->setAllowTextScrolling(true); mWindow->setAllowTextScrolling(true);
// Left spacer (empty component, needed for borders). // Left spacer (empty component, needed for borders).
@ -498,21 +498,14 @@ void GuiScraperSearch::onSearchDone(std::vector<ScraperSearchResult>& results)
void GuiScraperSearch::onSearchError(const std::string& error, HttpReq::Status status) void GuiScraperSearch::onSearchError(const std::string& error, HttpReq::Status status)
{ {
// This is a workaround for a somehow frequently recurring issue with screenscraper.fr const int retries {
// where requests to download the thumbnails are randomly met with TLS verification errors. glm::clamp(Settings::getInstance()->getInt("ScraperRetryOnErrorCount"), 1, 20)};
// It's unclear why it only happens to the thumbnail requests, but it usually goes away if (Settings::getInstance()->getBool("ScraperRetryOnError") && mRetryCount < retries) {
// after a few days or so. If this issue occurs and the corresponding setting has been
// enabled, we'll retry the search automatically up to FAILED_VERIFICATION_RETRIES number
// of times. Usually a few retries is enough to get the thumbnail to download. If not,
// the error dialog will be presented to the user, and if the "Retry" button is pressed,
// a new round of retries will take place.
if (status == HttpReq::REQ_FAILED_VERIFICATION && mRetryCount < FAILED_VERIFICATION_RETRIES &&
Settings::getInstance()->getBool("ScraperRetryPeerVerification")) {
LOG(LogError) << "GuiScraperSearch: " << Utils::String::replace(error, "\n", ""); LOG(LogError) << "GuiScraperSearch: " << Utils::String::replace(error, "\n", "");
mRetrySearch = true; mRetrySearch = true;
++mRetryCount; ++mRetryCount;
LOG(LogError) << "GuiScraperSearch: Attempting automatic retry " << mRetryCount << " of " LOG(LogError) << "GuiScraperSearch: Attempting automatic retry " << mRetryCount << " of "
<< FAILED_VERIFICATION_RETRIES; << retries;
return; return;
} }
else { else {
@ -688,17 +681,21 @@ void GuiScraperSearch::update(int deltaTime)
{ {
GuiComponent::update(deltaTime); GuiComponent::update(deltaTime);
// There was a failure and we're attempting an automatic retry. if (mBlockAccept)
mBusyAnim.update(deltaTime);
if (mRetrySearch) { if (mRetrySearch) {
// There was an error and we're attempting an automatic retry.
mRetryAccumulator += deltaTime;
if (mRetryAccumulator < mRetryTimer)
return;
mRetrySearch = false; mRetrySearch = false;
mRetryAccumulator = 0;
stop(); stop();
search(mLastSearch); search(mLastSearch);
return; return;
} }
if (mBlockAccept)
mBusyAnim.update(deltaTime);
// Check if the thumbnail for the currently selected game has finished downloading. // Check if the thumbnail for the currently selected game has finished downloading.
if (mScraperResults.size() > 0) { if (mScraperResults.size() > 0) {
auto it = auto it =

View file

@ -171,7 +171,9 @@ private:
bool mScrapeRatings; bool mScrapeRatings;
bool mRetrySearch; bool mRetrySearch;
unsigned int mRetryCount; int mRetryCount;
int mRetryTimer;
int mRetryAccumulator;
std::unique_ptr<ScraperSearchHandle> mSearchHandle; std::unique_ptr<ScraperSearchHandle> mSearchHandle;
std::unique_ptr<ScraperSearchHandle> mMDRetrieveURLsHandle; std::unique_ptr<ScraperSearchHandle> mMDRetrieveURLsHandle;

View file

@ -148,7 +148,7 @@ void Settings::setDefaults()
mBoolMap["ScraperConvertUnderscores"] = {true, true}; mBoolMap["ScraperConvertUnderscores"] = {true, true};
mBoolMap["ScraperAutomaticRemoveDots"] = {true, true}; mBoolMap["ScraperAutomaticRemoveDots"] = {true, true};
mBoolMap["ScraperRegionFallback"] = {true, true}; mBoolMap["ScraperRegionFallback"] = {true, true};
mBoolMap["ScraperRetryPeerVerification"] = {false, false}; mBoolMap["ScraperRetryOnError"] = {true, true};
// UI settings. // UI settings.
mStringMap["ThemeSet"] = {"slate-es-de", "slate-es-de"}; mStringMap["ThemeSet"] = {"slate-es-de", "slate-es-de"};
@ -319,8 +319,10 @@ void Settings::setDefaults()
mStringMap["UIMode_passkey"] = {"uuddlrlrba", "uuddlrlrba"}; mStringMap["UIMode_passkey"] = {"uuddlrlrba", "uuddlrlrba"};
mIntMap["LottieMaxFileCache"] = {150, 150}; mIntMap["LottieMaxFileCache"] = {150, 150};
mIntMap["LottieMaxTotalCache"] = {1024, 1024}; mIntMap["LottieMaxTotalCache"] = {1024, 1024};
mIntMap["ScraperConnectionTimeout"] = {60, 60}; mIntMap["ScraperConnectionTimeout"] = {30, 30};
mIntMap["ScraperTransferTimeout"] = {120, 120}; mIntMap["ScraperTransferTimeout"] = {120, 120};
mIntMap["ScraperRetryOnErrorCount"] = {5, 5};
mIntMap["ScraperRetryOnErrorTimer"] = {5, 5};
// //
// Hardcoded or program-internal settings. // Hardcoded or program-internal settings.