From 34e125f82d0f6a3d689f07445d3d52f0a6293edd Mon Sep 17 00:00:00 2001 From: WarmUpTill <19472752+WarmUpTill@users.noreply.github.com> Date: Thu, 13 Mar 2025 19:29:26 +0100 Subject: [PATCH] Rework chache handling * No longer provide multiple HTTP helper functions with the same name * Default to cache not being used * Explicitly use the cache for certain Twitch actions and conditions * Clear caches on shutdown to avoid leaks being reported --- plugins/twitch/category-selection.cpp | 8 +- plugins/twitch/channel-selection.cpp | 2 +- plugins/twitch/points-reward-selection.cpp | 2 +- plugins/twitch/twitch-helpers.cpp | 107 +++++++++++++++------ plugins/twitch/twitch-helpers.hpp | 37 +++---- 5 files changed, 95 insertions(+), 61 deletions(-) diff --git a/plugins/twitch/category-selection.cpp b/plugins/twitch/category-selection.cpp index af42d34b..0d28ced7 100644 --- a/plugins/twitch/category-selection.cpp +++ b/plugins/twitch/category-selection.cpp @@ -193,7 +193,7 @@ void CategoryGrabber::Search(const std::string &) httplib::Params params = {{"first", "100"}, {"after", cursor}, {"query", _searchString}}; - auto response = SendGetRequest(*_token, uri, path, params); + auto response = SendGetRequest(*_token, uri, path, params, true); while (response.status == 200 && !_stop) { cursor = ParseReply(response.data); @@ -203,7 +203,7 @@ void CategoryGrabber::Search(const std::string &) params = {{"first", "100"}, {"after", cursor}, {"query", _searchString}}; - response = SendGetRequest(*_token, uri, path, params); + response = SendGetRequest(*_token, uri, path, params, true); emit CategoryCountUpdated(_categoryMap.size() - startCount); } } @@ -217,7 +217,7 @@ void CategoryGrabber::GetAll() static std::string cursor; httplib::Params params = {{"first", "100"}, {"after", cursor}}; - auto response = SendGetRequest(*_token, uri, path, params); + auto response = SendGetRequest(*_token, uri, path, params, true); while (response.status == 200 && !_stop) { cursor = ParseReply(response.data); @@ -225,7 +225,7 @@ void CategoryGrabber::GetAll() break; // End of category list } params = {{"first", "100"}, {"after", cursor}}; - response = SendGetRequest(*_token, uri, path, params); + response = SendGetRequest(*_token, uri, path, params, true); emit CategoryCountUpdated(_categoryMap.size()); } } diff --git a/plugins/twitch/channel-selection.cpp b/plugins/twitch/channel-selection.cpp index 50752f14..598ce9d9 100644 --- a/plugins/twitch/channel-selection.cpp +++ b/plugins/twitch/channel-selection.cpp @@ -37,7 +37,7 @@ std::string TwitchChannel::GetUserID(const TwitchToken &token) const } auto res = SendGetRequest(token, "https://api.twitch.tv", - "/helix/users", {{"login", _name}}); + "/helix/users", {{"login", _name}}, true); if (res.status == 400) { userIDCache[_name] = "invalid"; diff --git a/plugins/twitch/points-reward-selection.cpp b/plugins/twitch/points-reward-selection.cpp index c81ef70f..226c2db6 100644 --- a/plugins/twitch/points-reward-selection.cpp +++ b/plugins/twitch/points-reward-selection.cpp @@ -136,7 +136,7 @@ TwitchPointsRewardSelection::GetPointsRewards( auto response = SendGetRequest(*token, "https://api.twitch.tv", "/helix/channel_points/custom_rewards", - params); + params, true); if (response.status != 200) { blog(LOG_WARNING, diff --git a/plugins/twitch/twitch-helpers.cpp b/plugins/twitch/twitch-helpers.cpp index ff9b6f11..eae7bd80 100644 --- a/plugins/twitch/twitch-helpers.cpp +++ b/plugins/twitch/twitch-helpers.cpp @@ -1,4 +1,5 @@ #include "twitch-helpers.hpp" +#include "plugin-state-helpers.hpp" #include "token.hpp" #include @@ -65,6 +66,12 @@ static bool cacheIsValid(const std::map &cache, return it != cache.end() && !cacheIsTooOld(it->second); } +static void cleanupCache(std::map &cache, std::mutex &mtx) +{ + std::lock_guard lock(mtx); + cache.clear(); +} + static httplib::Headers getTokenRequestHeaders(const std::string &token) { return { @@ -104,9 +111,10 @@ static RequestResult processResult(const httplib::Result &response, return result; } -RequestResult SendGetRequest(const TwitchToken &token, const std::string &uri, - const std::string &path, - const httplib::Params ¶ms) +static RequestResult sendGetRequest(const TwitchToken &token, + const std::string &uri, + const std::string &path, + const httplib::Params ¶ms) { httplib::Client cli(uri); auto tokenStr = token.GetToken(); @@ -130,7 +138,11 @@ RequestResult SendGetRequest(const TwitchToken &token, const std::string &uri, { static std::map cache; static std::mutex mtx; - std::lock_guard lock(mtx); + [[maybe_unused]] static bool _ = []() { + AddPluginCleanupStep([]() { cleanupCache(cache, mtx); }); + return true; + }(); + auto tokenStr = token.GetToken(); if (!tokenStr) { @@ -140,21 +152,27 @@ RequestResult SendGetRequest(const TwitchToken &token, const std::string &uri, auto headers = getTokenRequestHeaders(*tokenStr); Args args(uri, path, "", params, headers); - if (useCache && cacheIsValid(cache, args)) { + if (!useCache) { + return sendGetRequest(token, uri, path, params); + } + + std::lock_guard lock(mtx); + if (cacheIsValid(cache, args)) { auto it = cache.find(args); return it->second.result; } - auto result = SendGetRequest(token, uri, path, params); + auto result = sendGetRequest(token, uri, path, params); cache[args] = {result}; return result; } -RequestResult SendPostRequest(const TwitchToken &token, const std::string &uri, - const std::string &path, - const httplib::Params ¶ms, - const OBSData &data) +static RequestResult sendPostRequest(const TwitchToken &token, + const std::string &uri, + const std::string &path, + const httplib::Params ¶ms, + const OBSData &data) { httplib::Client cli(uri); auto tokenStr = token.GetToken(); @@ -182,7 +200,11 @@ RequestResult SendPostRequest(const TwitchToken &token, const std::string &uri, { static std::map cache; static std::mutex mtx; - std::lock_guard lock(mtx); + [[maybe_unused]] static bool _ = []() { + AddPluginCleanupStep([]() { cleanupCache(cache, mtx); }); + return true; + }(); + auto tokenStr = token.GetToken(); if (!tokenStr) { @@ -193,20 +215,27 @@ RequestResult SendPostRequest(const TwitchToken &token, const std::string &uri, auto body = getRequestBody(data); Args args(uri, path, body, params, headers); - if (useCache && cacheIsValid(cache, args)) { + if (!useCache) { + return sendPostRequest(token, uri, path, params, data); + } + + std::lock_guard lock(mtx); + if (cacheIsValid(cache, args)) { auto it = cache.find(args); return it->second.result; } - auto result = SendPostRequest(token, uri, path, params, data); + auto result = sendPostRequest(token, uri, path, params, data); cache[args] = {result}; return result; } -RequestResult SendPutRequest(const TwitchToken &token, const std::string &uri, - const std::string &path, - const httplib::Params ¶ms, const OBSData &data) +static RequestResult sendPutRequest(const TwitchToken &token, + const std::string &uri, + const std::string &path, + const httplib::Params ¶ms, + const OBSData &data) { httplib::Client cli(uri); auto tokenStr = token.GetToken(); @@ -234,7 +263,11 @@ RequestResult SendPutRequest(const TwitchToken &token, const std::string &uri, { static std::map cache; static std::mutex mtx; - std::lock_guard lock(mtx); + [[maybe_unused]] static bool _ = []() { + AddPluginCleanupStep([]() { cleanupCache(cache, mtx); }); + return true; + }(); + auto tokenStr = token.GetToken(); if (!tokenStr) { @@ -245,21 +278,27 @@ RequestResult SendPutRequest(const TwitchToken &token, const std::string &uri, auto body = getRequestBody(data); Args args(uri, path, body, params, headers); - if (useCache && cacheIsValid(cache, args)) { + if (!useCache) { + return sendPutRequest(token, uri, path, params, data); + } + + std::lock_guard lock(mtx); + if (cacheIsValid(cache, args)) { auto it = cache.find(args); return it->second.result; } - auto result = SendPutRequest(token, uri, path, params, data); + auto result = sendPutRequest(token, uri, path, params, data); cache[args] = {result}; return result; } -RequestResult SendPatchRequest(const TwitchToken &token, const std::string &uri, - const std::string &path, - const httplib::Params ¶ms, - const OBSData &data) +static RequestResult sendPatchRequest(const TwitchToken &token, + const std::string &uri, + const std::string &path, + const httplib::Params ¶ms, + const OBSData &data) { httplib::Client cli(uri); auto tokenStr = token.GetToken(); @@ -287,7 +326,11 @@ RequestResult SendPatchRequest(const TwitchToken &token, const std::string &uri, { static std::map cache; static std::mutex mtx; - std::lock_guard lock(mtx); + [[maybe_unused]] static bool _ = []() { + AddPluginCleanupStep([]() { cleanupCache(cache, mtx); }); + return true; + }(); + auto tokenStr = token.GetToken(); if (!tokenStr) { @@ -298,20 +341,26 @@ RequestResult SendPatchRequest(const TwitchToken &token, const std::string &uri, auto body = getRequestBody(data); Args args(uri, path, body, params, headers); - if (useCache && cacheIsValid(cache, args)) { + if (!useCache) { + return sendPatchRequest(token, uri, path, params, data); + } + + std::lock_guard lock(mtx); + if (cacheIsValid(cache, args)) { auto it = cache.find(args); return it->second.result; } - auto result = SendPatchRequest(token, uri, path, params, data); + auto result = sendPatchRequest(token, uri, path, params, data); cache[args] = {result}; return result; } -RequestResult SendDeleteRequest(const TwitchToken &token, - const std::string &uri, const std::string &path, - const httplib::Params ¶ms) +static RequestResult sendDeleteRequest(const TwitchToken &token, + const std::string &uri, + const std::string &path, + const httplib::Params ¶ms) { httplib::Client cli(uri); auto tokenStr = token.GetToken(); diff --git a/plugins/twitch/twitch-helpers.hpp b/plugins/twitch/twitch-helpers.hpp index eda748a8..6e53e8f0 100644 --- a/plugins/twitch/twitch-helpers.hpp +++ b/plugins/twitch/twitch-helpers.hpp @@ -15,45 +15,30 @@ struct RequestResult { const char *GetClientID(); -// These functions do *not* use or create RequestResult cache entries +// These functions can cache the RequestResult for 10s + RequestResult SendGetRequest(const TwitchToken &token, const std::string &uri, const std::string &path, - const httplib::Params ¶ms = {}); + const httplib::Params ¶ms = {}, + bool useCache = false); RequestResult SendPostRequest(const TwitchToken &token, const std::string &uri, const std::string &path, const httplib::Params ¶ms = {}, - const OBSData &data = nullptr); + const OBSData &data = nullptr, + bool useCache = false); RequestResult SendPutRequest(const TwitchToken &token, const std::string &uri, const std::string &path, const httplib::Params ¶ms = {}, - const OBSData &data = nullptr); + const OBSData &data = nullptr, + bool useCache = false); RequestResult SendPatchRequest(const TwitchToken &token, const std::string &uri, const std::string &path, const httplib::Params ¶ms = {}, - const OBSData &data = nullptr); -RequestResult SendDeleteRequest(const TwitchToken &token, - const std::string &uri, const std::string &path, - const httplib::Params ¶ms = {}); - -// These functions will cache the RequestResult for 10s -// Note that the cache will be reported as a "memory leak" on OBS shutdown -RequestResult SendGetRequest(const TwitchToken &token, const std::string &uri, - const std::string &path, - const httplib::Params ¶ms, bool useCache); -RequestResult SendPostRequest(const TwitchToken &token, const std::string &uri, - const std::string &path, - const httplib::Params ¶ms, - const OBSData &data, bool useCache); -RequestResult SendPutRequest(const TwitchToken &token, const std::string &uri, - const std::string &path, - const httplib::Params ¶ms, const OBSData &data, - bool useCache); -RequestResult SendPatchRequest(const TwitchToken &token, const std::string &uri, - const std::string &path, - const httplib::Params ¶ms, - const OBSData &data, bool useCache); + const OBSData &data = nullptr, + bool useCache = false); // Helper functions to set temp var values + void SetJsonTempVars(const std::string &jsonStr, std::function setVarFunc); void SetJsonTempVars(obs_data_t *data,