From f13beaead2ef4b5d43cdf1ae4c8069c307513a34 Mon Sep 17 00:00:00 2001 From: WarmUpTill <19472752+WarmUpTill@users.noreply.github.com> Date: Mon, 5 May 2025 21:55:38 +0200 Subject: [PATCH] Reduce log spam in case of invalid token The caching mechanism for the token validity checks did not have the desired effect, and the Twitch channel to user id mapping function was attempting to resolve names even with an invalid token. --- plugins/twitch/channel-selection.cpp | 14 ++++-- plugins/twitch/channel-selection.hpp | 4 +- plugins/twitch/token.cpp | 68 ++++++++++++++++++---------- plugins/twitch/token.hpp | 8 ++++ 4 files changed, 65 insertions(+), 29 deletions(-) diff --git a/plugins/twitch/channel-selection.cpp b/plugins/twitch/channel-selection.cpp index 598ce9d9..6d9f3187 100644 --- a/plugins/twitch/channel-selection.cpp +++ b/plugins/twitch/channel-selection.cpp @@ -31,6 +31,11 @@ void TwitchChannel::Save(obs_data_t *obj) const std::string TwitchChannel::GetUserID(const TwitchToken &token) const { static std::map userIDCache; + if (!token.IsValid()) { + vblog(LOG_INFO, "%s() failed: token invalid", __func__); + return "invalid"; + } + auto it = userIDCache.find(std::string(_name)); if (it != userIDCache.end()) { return it->second; @@ -47,7 +52,7 @@ std::string TwitchChannel::GetUserID(const TwitchToken &token) const } if (res.status != 200) { - blog(LOG_INFO, "failed to get Twitch user id from token! (%d)", + blog(LOG_INFO, "failed to get Twitch user id for channel! (%d)", res.status); return "invalid"; } @@ -90,7 +95,7 @@ getStringArrayHelper(const OBSDataAutoRelease &data, const std::string &value) } try { auto json = nlohmann::json::parse(jsonStr); - auto array = json[value]; + auto &array = json[value]; if (!array.is_array()) { return result; } @@ -104,7 +109,7 @@ getStringArrayHelper(const OBSDataAutoRelease &data, const std::string &value) } std::optional -TwitchChannel::GetLiveInfo(const TwitchToken &token) +TwitchChannel::GetLiveInfo(const TwitchToken &token) const { auto id = GetUserID(token); if (!IsValid(id)) { @@ -146,7 +151,8 @@ TwitchChannel::GetLiveInfo(const TwitchToken &token) return info; } -std::optional TwitchChannel::GetInfo(const TwitchToken &token) +std::optional +TwitchChannel::GetInfo(const TwitchToken &token) const { auto id = GetUserID(token); if (!IsValid(id)) { diff --git a/plugins/twitch/channel-selection.hpp b/plugins/twitch/channel-selection.hpp index 175b751d..87a46ca3 100644 --- a/plugins/twitch/channel-selection.hpp +++ b/plugins/twitch/channel-selection.hpp @@ -51,8 +51,8 @@ struct TwitchChannel { StringVariable GetName() const { return _name; } std::string GetUserID(const TwitchToken &token) const; bool IsValid(const std::string &id) const; - std::optional GetLiveInfo(const TwitchToken &); - std::optional GetInfo(const TwitchToken &); + std::optional GetLiveInfo(const TwitchToken &) const; + std::optional GetInfo(const TwitchToken &) const; void ResolveVariables(); private: diff --git a/plugins/twitch/token.cpp b/plugins/twitch/token.cpp index 1bf4bde2..6b8e5909 100644 --- a/plugins/twitch/token.cpp +++ b/plugins/twitch/token.cpp @@ -81,7 +81,7 @@ const std::unordered_map TokenOption::_apiIdToLocale{ static void saveConnections(obs_data_t *obj); static void loadConnections(obs_data_t *obj); -bool setupTwitchTokenSupport() +static bool setupTwitchTokenSupport() { AddSaveStep(saveConnections); AddLoadStep(loadConnections); @@ -153,6 +153,29 @@ bool TokenOption::operator<(const TokenOption &other) const return apiId < other.apiId; } +TwitchToken::TwitchToken(const TwitchToken &other) + : Item(other._name), + _token(other._token), + _lastValidityCheckTime(), + _lastValidityCheckValue(), + _lastValidityCheckResult(false), + _userID(other._userID), + _tokenOptions(other._tokenOptions), + _eventSub(), + _validateEventSubTimestamps(other._validateEventSubTimestamps) +{ +} + +TwitchToken &TwitchToken::operator=(const TwitchToken &other) +{ + _name = other._name; + _token = other._token; + _userID = other._userID; + _tokenOptions = other._tokenOptions; + _validateEventSubTimestamps = other._validateEventSubTimestamps; + return *this; +} + void TwitchToken::Load(obs_data_t *obj) { Item::Load(obj); @@ -273,39 +296,38 @@ std::shared_ptr TwitchToken::GetEventSub() bool TwitchToken::IsValid(bool forceUpdate) const { - static std::chrono::system_clock::time_point queryTime; - static std::string lastQueryToken; - static httplib::Result response; static httplib::Client cli("https://id.twitch.tv"); httplib::Headers headers{{"Authorization", "OAuth " + _token}}; + std::scoped_lock lock(_cacheMutex); + auto currentTime = std::chrono::system_clock::now(); - auto diff = currentTime - queryTime; + auto diff = currentTime - _lastValidityCheckTime; const bool cacheIsTooOld = diff >= std::chrono::hours(1); - const bool tokenChanged = lastQueryToken != _token; - if (tokenChanged) { - response = + const auto checkToken = [&]() -> bool { + const auto response = cli.Get("/oauth2/validate", httplib::Params{}, headers); - queryTime = std::chrono::system_clock::now(); - lastQueryToken = _token; - return response && response->status == 200; + _lastValidityCheckTime = std::chrono::system_clock::now(); + _lastValidityCheckValue = _token; + _lastValidityCheckResult = response && response->status == 200; + if (!_lastValidityCheckResult) { + blog(LOG_INFO, "Twitch token %s is not valid!", + _name.c_str()); + } + return _lastValidityCheckResult; + }; + + const bool tokenChanged = _lastValidityCheckValue != _token; + if (tokenChanged) { + return checkToken(); } - // No point in checking again as token will not become valid again - if (!forceUpdate && response && response->status != 200) { - blog(LOG_INFO, "Twitch token %s is not valid!", _name.c_str()); - return false; + if (!forceUpdate && !cacheIsTooOld) { + return _lastValidityCheckResult; } - if (!forceUpdate && !cacheIsTooOld && response) { - return response->status == 200; - } - - response = cli.Get("/oauth2/validate", httplib::Params{}, headers); - queryTime = std::chrono::system_clock::now(); - lastQueryToken = _token; - return response && response->status == 200; + return checkToken(); } TwitchToken *GetTwitchTokenByName(const QString &name) diff --git a/plugins/twitch/token.hpp b/plugins/twitch/token.hpp index 205455d6..b3763af4 100644 --- a/plugins/twitch/token.hpp +++ b/plugins/twitch/token.hpp @@ -33,6 +33,10 @@ private: class TwitchToken : public Item { public: + TwitchToken() = default; + TwitchToken(const TwitchToken &); + TwitchToken &operator=(const TwitchToken &); + static std::shared_ptr Create() { return std::make_shared(); @@ -55,6 +59,10 @@ public: private: std::string _token; + mutable std::mutex _cacheMutex; + mutable std::string _lastValidityCheckValue; + mutable bool _lastValidityCheckResult = false; + mutable std::chrono::system_clock::time_point _lastValidityCheckTime; std::string _userID; std::set _tokenOptions = TokenOption::GetAllTokenOptions(); std::shared_ptr _eventSub;