package metadata import ( "fmt" "git.gammaspectra.live/S.O.N.G/METANOIA/utilities" "net/http" "runtime" "time" ) //DefaultUserAgent Follows most identification rules (Like for Musicbrainz, or Discogs) var DefaultUserAgent = fmt.Sprintf("Mozilla/5.0 (compatible; METANOIA/%s; +https://git.gammaspectra.live/S.O.N.G/METANOIA) golang/%s (%s; %s; net/http; %s)", utilities.Version, runtime.Version(), runtime.GOOS, runtime.GOARCH, runtime.Compiler) var defaultCacheStore CacheStore type CachingClient struct { context string client *http.Client throttler <-chan time.Time } type CacheStore interface { Get(request *http.Request) (*http.Response, error) Set(request *http.Request, response *http.Response) (*http.Response, error) } func SetCacheStore(store CacheStore) { defaultCacheStore = store } func NewCachingClient(context string, rateLimit time.Duration) *CachingClient { return &CachingClient{ context: context, client: http.DefaultClient, throttler: time.Tick(rateLimit), } } func (c *CachingClient) Request(req *http.Request, lifetime time.Duration) (*http.Response, error) { if req.Header == nil || req.UserAgent() == "" { if req.Header == nil { req.Header = make(http.Header) } req.Header.Set("User-Agent", DefaultUserAgent) } if defaultCacheStore != nil { response, err := defaultCacheStore.Get(req) if err == nil && response != nil { timestamp, _ := time.ParseInLocation(time.UnixDate, response.Request.Header.Get("X-Fetched-At"), time.UTC) if timestamp.Add(lifetime).After(time.Now()) { return response, nil } } } <-c.throttler response, err := c.client.Do(req) if defaultCacheStore != nil && err == nil { req.Header.Set("X-Fetched-At", time.Now().UTC().Format(time.UnixDate)) response, err = defaultCacheStore.Set(req, response) } return response, err }