From ff5af54b07195046382f8d0c158d41fa96bf7eec Mon Sep 17 00:00:00 2001 From: HJfod <60038575+HJfod@users.noreply.github.com> Date: Sun, 10 Mar 2024 13:26:47 +0200 Subject: [PATCH] cache server icon results --- loader/src/server/Server.hpp | 136 +++++++++++++++++++++++++++++++++++ loader/src/ui/GeodeUI.cpp | 4 +- 2 files changed, 139 insertions(+), 1 deletion(-) diff --git a/loader/src/server/Server.hpp b/loader/src/server/Server.hpp index a2727a2a..907c029f 100644 --- a/loader/src/server/Server.hpp +++ b/loader/src/server/Server.hpp @@ -97,4 +97,140 @@ namespace server { ServerPromise getMods(ModsQuery const& query); ServerPromise getMod(std::string const& id); ServerPromise getModLogo(std::string const& id); + + // Caching for server endpoints + namespace impl_cache { + template + struct ExtractServerReqParams { + using Result = R; + using Query = Q; + ExtractServerReqParams(ServerPromise(*)(Q const&)) {} + }; + + template + class ServerResultCache final { + public: + using Extract = decltype(ExtractServerReqParams(F)); + using Result = Extract::Result; + using Query = Extract::Query; + + private: + std::mutex m_cachedMutex; + // The result and the query used for cached value + std::optional> m_cached; + + ServerPromise fetch(Query&& query) { + return ServerPromise([this, query = std::move(query)](auto resolve, auto reject, auto progress, auto cancelled) { + F(Query(query)) + .then([this, resolve, query = std::move(query)](auto res) { + std::unique_lock lock(m_cachedMutex); + m_cached = { res, query }; + lock.unlock(); + + resolve(res); + }) + .expect([reject](auto err) { + reject(err); + }) + .progress([progress](auto prog) { + progress(prog); + }) + .link(cancelled); + }); + } + + public: + ServerPromise get(Query&& query) { + std::unique_lock lock(m_cachedMutex); + // Return cached value if there is one and the query matches + if (m_cached && m_cached->second == query) { + auto cached = m_cached->first; + lock.unlock(); + return ServerPromise([cached = std::move(cached)](auto resolve, auto) { + resolve(std::move(cached)); + }); + } + lock.unlock(); + return this->fetch(std::move(query)); + } + + ServerPromise refetch(Query&& query) { + // Clear cache + std::unique_lock lock(m_cachedMutex); + m_cached.reset(); + lock.unlock(); + + // Fetch new value + return this->fetch(std::move(query)); + } + }; + + template + class ServerMultiResultCache final { + public: + using Extract = decltype(ExtractServerReqParams(F)); + using Result = Extract::Result; + using Query = Extract::Query; + + private: + std::mutex m_queriesMutex; + std::map m_queries; + + ServerPromise fetch(Query const& query) { + return ServerPromise([this, query = Query(query)](auto resolve, auto reject, auto progress, auto cancelled) { + F(Query(query)) + .then([this, resolve, query = std::move(query)](auto res) { + std::unique_lock lock(m_queriesMutex); + m_queries[std::move(query)] = res; + lock.unlock(); + + resolve(res); + }) + .expect([reject](auto err) { + reject(err); + }) + .progress([progress](auto prog) { + progress(prog); + }) + .link(cancelled); + }); + } + + public: + ServerPromise get(Query const& query) { + std::unique_lock lock(m_queriesMutex); + // Return cached value if there is one and the query matches + if (m_queries.contains(query)) { + auto cached = m_queries.at(query); + lock.unlock(); + return ServerPromise([cached = std::move(cached)](auto resolve, auto) { + resolve(std::move(cached)); + }); + } + lock.unlock(); + return this->fetch(std::move(query)); + } + + ServerPromise refetch(Query const& query) { + // Clear cache for this query only + std::unique_lock lock (m_queriesMutex); + m_queries.erase(query); + lock.unlock(); + + // Fetch new value + return this->fetch(std::move(query)); + } + + // Clear all caches + void invalidateAll() { + std::unique_lock _(m_queriesMutex); + m_queries.clear(); + } + }; + } + + // todo: default shared caching for endpoints for all users + // todo: (so it can be automatically cleared for example after leaving the geode layer) + // template + // impl_cache::ServerResultCache sharedCache() {} } diff --git a/loader/src/ui/GeodeUI.cpp b/loader/src/ui/GeodeUI.cpp index 49ad84ca..274259a7 100644 --- a/loader/src/ui/GeodeUI.cpp +++ b/loader/src/ui/GeodeUI.cpp @@ -70,6 +70,8 @@ protected: std::string m_modID; CCNode* m_sprite = nullptr; EventListener> m_listener; + // todo: use shared cache once impl'd + static inline server::impl_cache::ServerMultiResultCache<&server::getModLogo> s_cache = {}; bool init(std::string const& id, bool fetch) { if (!CCNode::init()) @@ -93,7 +95,7 @@ protected: this->setSprite(CCSprite::create("loadingCircle.png")); static_cast(m_sprite)->setBlendFunc({ GL_ONE, GL_ONE }); m_sprite->runAction(CCRepeatForever::create(CCRotateBy::create(1.f, 360.f))); - m_listener.setFilter(server::getModLogo(id).listen()); + m_listener.setFilter(s_cache.get(id).listen()); } return true;