From 6cf1073a3c0ea17186253cdc99e7974203e89e42 Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Wed, 11 Oct 2023 12:26:18 +0200 Subject: [PATCH] Add option to use cached results The cache will remain valid for 10s before it is refreshed with a "real" Get / Post / Patch call. --- src/macro-external/twitch/twitch-helpers.cpp | 111 +++++++++++++++++++ src/macro-external/twitch/twitch-helpers.hpp | 17 +++ 2 files changed, 128 insertions(+) diff --git a/src/macro-external/twitch/twitch-helpers.cpp b/src/macro-external/twitch/twitch-helpers.cpp index 6ed0f6fd..1a5391cb 100644 --- a/src/macro-external/twitch/twitch-helpers.cpp +++ b/src/macro-external/twitch/twitch-helpers.cpp @@ -4,6 +4,58 @@ namespace advss { static constexpr std::string_view clientID = "ds5tt4ogliifsqc04mz3d3etnck3e5"; +static const int cacheTimeoutSeconds = 10; + +class Args { +public: + Args(const std::string &uri, const std::string &path, + const std::string &data, httplib::Params params, + httplib::Headers headers) + : _uri(uri), + _path(path), + _data(data), + _params(params), + _headers(headers) + { + } + bool operator<(const Args &other) const + { + bool ret = true; + ret = ret && _uri < other._uri; + ret = ret && _path < other._path; + ret = ret && _params < other._params; + ret = ret && _data < other._data; + ret = ret && _headers < other._headers; + return ret; + } + +private: + std::string _uri; + std::string _path; + std::string _data; + httplib::Params _params; + httplib::Headers _headers; +}; + +struct CacheEntry { + RequestResult result; + std::chrono::system_clock::time_point cacheTime = + std::chrono::system_clock::now(); +}; + +static bool chacheIsTooOld(const CacheEntry &cache) +{ + auto currentTime = std::chrono::system_clock::now(); + auto diff = currentTime - cache.cacheTime; + return diff >= std::chrono::seconds(cacheTimeoutSeconds); +} + +static bool cacheIsValid(const std::map &cache, + const Args &args) +{ + auto it = cache.find(args); + return it != cache.end() && !chacheIsTooOld(it->second); +} static httplib::Headers getTokenRequestHeaders(const TwitchToken &token) { @@ -37,6 +89,25 @@ RequestResult SendGetRequest(const std::string &uri, const std::string &path, return result; } +RequestResult SendGetRequest(const std::string &uri, const std::string &path, + const TwitchToken &token, + const httplib::Params ¶ms, bool useCache) +{ + static std::map cache; + static std::mutex mtx; + std::lock_guard lock(mtx); + auto headers = getTokenRequestHeaders(token); + Args args(uri, path, "", params, headers); + if (useCache && cacheIsValid(cache, args)) { + auto it = cache.find(args); + return it->second.result; + } + + auto result = SendGetRequest(uri, path, token, params); + cache[args] = {result}; + return result; +} + RequestResult SendPostRequest(const std::string &uri, const std::string &path, const TwitchToken &token, const OBSData &data) { @@ -62,6 +133,26 @@ RequestResult SendPostRequest(const std::string &uri, const std::string &path, return result; } +RequestResult SendPostRequest(const std::string &uri, const std::string &path, + const TwitchToken &token, const OBSData &data, + bool useCache) +{ + static std::map cache; + static std::mutex mtx; + std::lock_guard lock(mtx); + auto headers = getTokenRequestHeaders(token); + auto jsonCstr = obs_data_get_json(data); + Args args(uri, path, jsonCstr ? jsonCstr : "", {}, headers); + if (useCache && cacheIsValid(cache, args)) { + auto it = cache.find(args); + return it->second.result; + } + + auto result = SendPostRequest(uri, path, token, data); + cache[args] = {result}; + return result; +} + RequestResult SendPatchRequest(const std::string &uri, const std::string &path, const TwitchToken &token, const OBSData &data) { @@ -87,6 +178,26 @@ RequestResult SendPatchRequest(const std::string &uri, const std::string &path, return result; } +RequestResult SendPatchRequest(const std::string &uri, const std::string &path, + const TwitchToken &token, const OBSData &data, + bool useCache) +{ + static std::map cache; + static std::mutex mtx; + std::lock_guard lock(mtx); + auto headers = getTokenRequestHeaders(token); + auto jsonCstr = obs_data_get_json(data); + Args args(uri, path, jsonCstr ? jsonCstr : "", {}, headers); + if (useCache && cacheIsValid(cache, args)) { + auto it = cache.find(args); + return it->second.result; + } + + auto result = SendPatchRequest(uri, path, token, data); + cache[args] = {result}; + return result; +} + const char *GetClientID() { return clientID.data(); diff --git a/src/macro-external/twitch/twitch-helpers.hpp b/src/macro-external/twitch/twitch-helpers.hpp index 7330b0ad..19c7a52e 100644 --- a/src/macro-external/twitch/twitch-helpers.hpp +++ b/src/macro-external/twitch/twitch-helpers.hpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace advss { @@ -12,6 +13,8 @@ struct RequestResult { OBSData data = nullptr; }; +// These functions do *not* use or create RequestResult cache entries + RequestResult SendGetRequest(const std::string &uri, const std::string &path, const TwitchToken &token, const httplib::Params & = {}); @@ -19,6 +22,20 @@ RequestResult SendPostRequest(const std::string &uri, const std::string &path, const TwitchToken &token, const OBSData &data); RequestResult SendPatchRequest(const std::string &uri, const std::string &path, const TwitchToken &token, const OBSData &data); + +// 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 std::string &uri, const std::string &path, + const TwitchToken &token, const httplib::Params &, + bool useCache); +RequestResult SendPostRequest(const std::string &uri, const std::string &path, + const TwitchToken &token, const OBSData &data, + bool useCache); +RequestResult SendPatchRequest(const std::string &uri, const std::string &path, + const TwitchToken &token, const OBSData &data, + bool useCache); + const char *GetClientID(); } // namespace advss