From d6185a60996d7004a086acccee6e955a9a3a626f Mon Sep 17 00:00:00 2001 From: WarmUpTill <19472752+WarmUpTill@users.noreply.github.com> Date: Sat, 8 Mar 2025 19:39:16 +0100 Subject: [PATCH] Add handling for Twitch API throttling --- plugins/twitch/twitch-helpers.cpp | 73 +++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/plugins/twitch/twitch-helpers.cpp b/plugins/twitch/twitch-helpers.cpp index eae7bd80..4295b7bf 100644 --- a/plugins/twitch/twitch-helpers.cpp +++ b/plugins/twitch/twitch-helpers.cpp @@ -4,11 +4,13 @@ #include #include +#include namespace advss { static constexpr std::string_view clientID = "ds5tt4ogliifsqc04mz3d3etnck3e5"; static const int cacheTimeoutSeconds = 10; +static std::atomic_bool apiIsThrottling = {false}; const char *GetClientID() { @@ -86,6 +88,37 @@ static std::string getRequestBody(const OBSData &data) return json ? json : ""; } +static void handleThrottling(const httplib::Result &response) +{ + const auto &headers = response.value().headers; + const auto rateLimitResetTimeStr = headers.find("Ratelimit-Reset"); + if (rateLimitResetTimeStr == headers.end()) { + return; + } + + std::time_t rateLimitResetTime = + std::stoll(rateLimitResetTimeStr->second); + auto resetTimePoint = + std::chrono::system_clock::from_time_t(rateLimitResetTime); + auto sleepDuration = resetTimePoint - std::chrono::system_clock::now(); + if (sleepDuration.count() < 0) { + return; + } + + blog(LOG_WARNING, "Twitch API access is throttled for %lld seconds!", + static_cast( + std::chrono::duration_cast( + sleepDuration) + .count())); + apiIsThrottling = true; + + auto resetThread = std::thread([sleepDuration]() { + std::this_thread::sleep_for(sleepDuration); + apiIsThrottling = false; + }); + resetThread.detach(); +} + static RequestResult processResult(const httplib::Result &response, const char *funcName) { @@ -97,6 +130,10 @@ static RequestResult processResult(const httplib::Result &response, return {}; } + if (response->status == 429) { + handleThrottling(response); + } + RequestResult result; result.status = response->status; @@ -116,6 +153,10 @@ static RequestResult sendGetRequest(const TwitchToken &token, const std::string &path, const httplib::Params ¶ms) { + if (apiIsThrottling) { + return {}; + } + httplib::Client cli(uri); auto tokenStr = token.GetToken(); @@ -136,6 +177,10 @@ RequestResult SendGetRequest(const TwitchToken &token, const std::string &uri, const std::string &path, const httplib::Params ¶ms, bool useCache) { + if (apiIsThrottling) { + return {}; + } + static std::map cache; static std::mutex mtx; [[maybe_unused]] static bool _ = []() { @@ -174,6 +219,10 @@ static RequestResult sendPostRequest(const TwitchToken &token, const httplib::Params ¶ms, const OBSData &data) { + if (apiIsThrottling) { + return {}; + } + httplib::Client cli(uri); auto tokenStr = token.GetToken(); @@ -198,6 +247,10 @@ RequestResult SendPostRequest(const TwitchToken &token, const std::string &uri, const httplib::Params ¶ms, const OBSData &data, bool useCache) { + if (apiIsThrottling) { + return {}; + } + static std::map cache; static std::mutex mtx; [[maybe_unused]] static bool _ = []() { @@ -237,6 +290,10 @@ static RequestResult sendPutRequest(const TwitchToken &token, const httplib::Params ¶ms, const OBSData &data) { + if (apiIsThrottling) { + return {}; + } + httplib::Client cli(uri); auto tokenStr = token.GetToken(); @@ -261,6 +318,10 @@ RequestResult SendPutRequest(const TwitchToken &token, const std::string &uri, const httplib::Params ¶ms, const OBSData &data, bool useCache) { + if (apiIsThrottling) { + return {}; + } + static std::map cache; static std::mutex mtx; [[maybe_unused]] static bool _ = []() { @@ -300,6 +361,10 @@ static RequestResult sendPatchRequest(const TwitchToken &token, const httplib::Params ¶ms, const OBSData &data) { + if (apiIsThrottling) { + return {}; + } + httplib::Client cli(uri); auto tokenStr = token.GetToken(); @@ -324,6 +389,10 @@ RequestResult SendPatchRequest(const TwitchToken &token, const std::string &uri, const httplib::Params ¶ms, const OBSData &data, bool useCache) { + if (apiIsThrottling) { + return {}; + } + static std::map cache; static std::mutex mtx; [[maybe_unused]] static bool _ = []() { @@ -362,6 +431,10 @@ static RequestResult sendDeleteRequest(const TwitchToken &token, const std::string &path, const httplib::Params ¶ms) { + if (apiIsThrottling) { + return {}; + } + httplib::Client cli(uri); auto tokenStr = token.GetToken();