From 54dcde38af1df1e5c7430cfefa3d55532f1dc112 Mon Sep 17 00:00:00 2001 From: perennial Date: Thu, 17 Oct 2024 20:13:18 +1100 Subject: [PATCH] rework caching functions --- core/requests.go | 93 ++++++++++++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 34 deletions(-) diff --git a/core/requests.go b/core/requests.go index ad11d74..67cde11 100644 --- a/core/requests.go +++ b/core/requests.go @@ -42,6 +42,19 @@ type CachedItem struct { ExpiresAt time.Time } +// CachePolicy defines the caching behavior for a request. +type CachePolicy struct { + ShouldUseCached bool // whether to attempt fetching from the cache + ShouldStore bool // whether to store the API response in the cache after retrieval + CachedResponse *SimpleHTTPResponse // the cached response if available and valid +} + +// CachingResult encapsulates the response and whether it was retrieved from the cache. +type CachingResult struct { + Response *SimpleHTTPResponse + FromCache bool +} + var ( retryClient *retryablehttp.Client cacheSeed uint64 @@ -116,20 +129,17 @@ func generateCacheKey(url, userToken string) string { return fmt.Sprintf("%x", hash) } -// shouldUseCache determines the caching policy for a given request. -// -// It returns three values: -// - shouldFetch: whether to attempt fetching from the cache. -// - shouldStore: whether to store the response in the cache after retrieval. -// - cachedResponse: the cached response if available and valid. -func shouldUseCache(rawURL, userToken string, incomingHeaders http.Header) (shouldFetch bool, shouldStore bool, cachedResponse *SimpleHTTPResponse) { +// determineCachePolicy determines the caching policy for a given request. +// It returns a CachePolicy struct indicating whether to fetch from cache, +// whether to store the response in cache, and the cached response if available. +func determineCachePolicy(rawURL, userToken string, headers http.Header) CachePolicy { if !config.GlobalConfig.CacheEnabled { - return false, false, nil + return CachePolicy{} } parsedURL, err := url.Parse(rawURL) if err != nil { - return false, false, nil + return CachePolicy{} } urlPath := path.Clean(parsedURL.Path) @@ -137,49 +147,61 @@ func shouldUseCache(rawURL, userToken string, incomingHeaders http.Header) (shou // Check if the path is excluded from caching for _, exclPath := range excludedCachePaths { if strings.HasPrefix(urlPath, exclPath) { - return false, false, nil + return CachePolicy{} } } cacheKey := generateCacheKey(rawURL, userToken) // Check if cache invalidation is requested - redirectedHeader := incomingHeaders.Get("X-Handled-Redirected") + redirectedHeader := headers.Get("X-Handled-Redirected") if strings.Contains(strings.ToLower(redirectedHeader), "true") { cache.Remove(cacheKey) - return false, false, nil + return CachePolicy{} } // Attempt to fetch from cache if cachedItem, found := cache.Get(cacheKey); found { item := cachedItem.(CachedItem) if time.Now().Before(item.ExpiresAt) { - return false, false, item.Response + return CachePolicy{ + ShouldUseCached: false, + CachedResponse: item.Response, + } } // Cache expired cache.Remove(cacheKey) } // Determine if response should be cached based on headers - cacheControl := incomingHeaders.Get("Cache-Control") - shouldStore = cacheControl == "" || !strings.Contains(strings.ToLower(cacheControl), "no-cache") + cacheControl := headers.Get("Cache-Control") + shouldStore := cacheControl == "" || !strings.Contains(strings.ToLower(cacheControl), "no-store") - return true, shouldStore, nil + return CachePolicy{ + ShouldUseCached: shouldStore, // Use cached version if storage is allowed + ShouldStore: shouldStore, + } } -// handleCaching manages the caching logic during and after a request. +// manageCaching manages the caching logic during and after a request. // It either returns a cached response or allows the request to proceed and optionally caches the new response. -func handleCaching(rawURL, userToken string, incomingHeaders http.Header, resp *SimpleHTTPResponse) (*SimpleHTTPResponse, bool) { - shouldFetch, shouldStore, cachedResponse := shouldUseCache(rawURL, userToken, incomingHeaders) - if !shouldFetch && cachedResponse != nil { - return cachedResponse, true +func manageCaching(rawURL, userToken string, headers http.Header, response *SimpleHTTPResponse) CachingResult { + policy := determineCachePolicy(rawURL, userToken, headers) + if policy.ShouldUseCached && policy.CachedResponse != nil { + return CachingResult{ + Response: policy.CachedResponse, + FromCache: true, + } } - if shouldStore && resp != nil { + if policy.ShouldStore && response != nil { ttl := config.GlobalConfig.CacheTTL parsedURL, err := url.Parse(rawURL) if err != nil { - return resp, false + return CachingResult{ + Response: response, + FromCache: false, + } } urlPath := path.Clean(parsedURL.Path) for _, shortPath := range shortTTLPaths { @@ -190,12 +212,15 @@ func handleCaching(rawURL, userToken string, incomingHeaders http.Header, resp * } cache.Add(generateCacheKey(rawURL, userToken), CachedItem{ - Response: resp, + Response: response, ExpiresAt: time.Now().Add(ttl), }) } - return resp, false + return CachingResult{ + Response: response, + FromCache: false, + } } // makeRequest is a helper function that encapsulates the common logic for making HTTP requests. @@ -300,13 +325,13 @@ func executeGetWithRetries( if resp.StatusCode == http.StatusOK { tokenManager.MarkTokenStatus(token, token_manager.Good) - // Handle caching logic after we receieve an HTTP 200 response - cachedResp, isCached := handleCaching(url, userToken, incomingHeaders, resp) - if isCached { - return cachedResp, nil + // Handle caching logic after we receive an HTTP 200 response + cachingResult := manageCaching(url, userToken, incomingHeaders, resp) + if cachingResult.FromCache { + return cachingResult.Response, nil } - return resp, nil + return cachingResult.Response, nil } lastErr = i18n.Errorf("HTTP status code: %d", resp.StatusCode) @@ -336,10 +361,10 @@ func retryRequest( return executeSinglePostRequest(ctx, reqFunc, userToken, url) } - // Handle caching logic before we send a request - shouldFetch, _, cachedResponse := shouldUseCache(url, userToken, incomingHeaders) - if !shouldFetch && cachedResponse != nil { - return cachedResponse, nil + // Determine caching policy before we send a request + policy := determineCachePolicy(url, userToken, incomingHeaders) + if !policy.ShouldUseCached && policy.CachedResponse != nil { + return policy.CachedResponse, nil } return executeGetWithRetries(ctx, reqFunc, userToken, url, incomingHeaders)