// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include #include #include #include #include #include #include #include #include #include #include struct ZenCacheValue; namespace cpr { class Session; } namespace zen { namespace detail { struct CloudCacheSessionState; } class CbObjectView; class CloudCacheClient; class IoBuffer; struct IoHash; /** * Cached access token, for use with `Authorization:` header */ struct CloudCacheAccessToken { using Clock = std::chrono::system_clock; using TimePoint = Clock::time_point; static constexpr int64_t ExpireMarginInSeconds = 30; std::string Value; TimePoint ExpireTime; bool IsValid() const { return Value.empty() == false && ExpireMarginInSeconds < std::chrono::duration_cast(ExpireTime - Clock::now()).count(); } }; struct CloudCacheResult { IoBuffer Response; int64_t Bytes{}; double ElapsedSeconds{}; int32_t ErrorCode{}; std::string Reason; bool Success = false; }; struct PutRefResult : CloudCacheResult { std::vector Needs; }; struct FinalizeRefResult : CloudCacheResult { std::vector Needs; }; struct CloudCacheExistsResult : CloudCacheResult { std::set Have; }; /** * Context for performing Jupiter operations * * Maintains an HTTP connection so that subsequent operations don't need to go * through the whole connection setup process * */ class CloudCacheSession { public: CloudCacheSession(CloudCacheClient* CacheClient); ~CloudCacheSession(); CloudCacheResult Authenticate(); CloudCacheResult GetDerivedData(std::string_view BucketId, std::string_view Key); CloudCacheResult GetDerivedData(std::string_view BucketId, const IoHash& Key); CloudCacheResult GetRef(std::string_view BucketId, const IoHash& Key, ZenContentType RefType); CloudCacheResult GetBlob(const IoHash& Key); CloudCacheResult GetCompressedBlob(const IoHash& Key); CloudCacheResult GetObject(const IoHash& Key); CloudCacheResult PutDerivedData(std::string_view BucketId, std::string_view Key, IoBuffer DerivedData); CloudCacheResult PutDerivedData(std::string_view BucketId, const IoHash& Key, IoBuffer DerivedData); PutRefResult PutRef(std::string_view BucketId, const IoHash& Key, IoBuffer Ref, ZenContentType RefType); CloudCacheResult PutBlob(const IoHash& Key, IoBuffer Blob); CloudCacheResult PutCompressedBlob(const IoHash& Key, IoBuffer Blob); CloudCacheResult PutObject(const IoHash& Key, IoBuffer Object); FinalizeRefResult FinalizeRef(std::string_view BucketId, const IoHash& Key, const IoHash& RefHah); CloudCacheResult RefExists(std::string_view BucketId, const IoHash& Key); CloudCacheResult BlobExists(const IoHash& Key); CloudCacheResult CompressedBlobExists(const IoHash& Key); CloudCacheResult ObjectExists(const IoHash& Key); CloudCacheExistsResult BlobExists(const std::set& Keys); CloudCacheExistsResult CompressedBlobExists(const std::set& Keys); CloudCacheExistsResult ObjectExists(const std::set& Keys); CloudCacheResult PostComputeTasks(IoBuffer TasksData); CloudCacheResult GetComputeUpdates(std::string_view ChannelId, const uint32_t WaitSeconds = 0); CloudCacheResult GetObjectTree(const IoHash& Key); std::vector Filter(std::string_view BucketId, const std::vector& ChunkHashes); private: inline spdlog::logger& Log() { return m_Log; } cpr::Session& GetSession(); CloudCacheAccessToken GetAccessToken(bool RefreshToken = false); bool VerifyAccessToken(long StatusCode); CloudCacheResult CacheTypeExists(std::string_view TypeId, const IoHash& Key); CloudCacheExistsResult CacheTypeExists(std::string_view TypeId, const std::set& Keys); spdlog::logger& m_Log; RefPtr m_CacheClient; detail::CloudCacheSessionState* m_SessionState; }; /** * Access token provider interface */ class CloudCacheTokenProvider { public: virtual ~CloudCacheTokenProvider() = default; virtual CloudCacheAccessToken AcquireAccessToken() = 0; static std::unique_ptr CreateFromStaticToken(CloudCacheAccessToken Token); struct OAuthClientCredentialsParams { std::string_view Url; std::string_view ClientId; std::string_view ClientSecret; }; static std::unique_ptr CreateFromOAuthClientCredentials(const OAuthClientCredentialsParams& Params); static std::unique_ptr CreateFromCallback(std::function&& Callback); }; struct CloudCacheClientOptions { std::string_view Name; std::string_view ServiceUrl; std::string_view DdcNamespace; std::string_view BlobStoreNamespace; std::string_view ComputeCluster; std::chrono::milliseconds ConnectTimeout{5000}; std::chrono::milliseconds Timeout{}; bool UseLegacyDdc = false; }; /** * Jupiter upstream cache client */ class CloudCacheClient : public RefCounted { public: CloudCacheClient(const CloudCacheClientOptions& Options, std::unique_ptr TokenProvider); ~CloudCacheClient(); CloudCacheAccessToken AcquireAccessToken(); std::string_view DdcNamespace() const { return m_DdcNamespace; } std::string_view BlobStoreNamespace() const { return m_BlobStoreNamespace; } std::string_view ComputeCluster() const { return m_ComputeCluster; } std::string_view ServiceUrl() const { return m_ServiceUrl; } spdlog::logger& Logger() { return m_Log; } private: spdlog::logger& m_Log; std::string m_ServiceUrl; std::string m_DdcNamespace; std::string m_BlobStoreNamespace; std::string m_ComputeCluster; std::chrono::milliseconds m_ConnectTimeout{}; std::chrono::milliseconds m_Timeout{}; std::unique_ptr m_TokenProvider; RwLock m_SessionStateLock; std::list m_SessionStateCache; detail::CloudCacheSessionState* AllocSessionState(); void FreeSessionState(detail::CloudCacheSessionState*); friend class CloudCacheSession; }; } // namespace zen