package cacheimport ("bufio""bytes""encoding/base64""encoding/json""io""net/http""strings""time""github.com/navidrome/navidrome/log")const cacheSizeLimit = 100type HTTPClient struct {cache SimpleCache[string, string]hc httpDoerttl time.Duration}type httpDoer interface {Do(req *http.Request) (*http.Response, error)}type requestData struct {Method stringHeader http.HeaderURL stringBody *string}func NewHTTPClient(wrapped httpDoer, ttl time.Duration) *HTTPClient {c := &HTTPClient{hc: wrapped, ttl: ttl}c.cache = NewSimpleCache[string, string](Options{SizeLimit: cacheSizeLimit,DefaultTTL: ttl,})return c}func (c *HTTPClient) Do(req *http.Request) (*http.Response, error) {key := c.serializeReq(req)cached := truestart := time.Now()respStr, err := c.cache.GetWithLoader(key, func(key string) (string, time.Duration, error) {cached = falsereq, err := c.deserializeReq(key)if err != nil {log.Trace(req.Context(), "CachedHTTPClient.Do", "key", key, err)return "", 0, err}resp, err := c.hc.Do(req)if err != nil {log.Trace(req.Context(), "CachedHTTPClient.Do", "req", req, err)return "", 0, err}defer resp.Body.Close()return c.serializeResponse(resp), c.ttl, nil})log.Trace(req.Context(), "CachedHTTPClient.Do", "key", key, "cached", cached, "elapsed", time.Since(start), err)if err != nil {return nil, err}return c.deserializeResponse(req, respStr)}func (c *HTTPClient) serializeReq(req *http.Request) string {data := requestData{Method: req.Method,Header: req.Header,URL: req.URL.String(),}if req.Body != nil {bodyData, _ := io.ReadAll(req.Body)data.Body = new(base64.StdEncoding.EncodeToString(bodyData))}j, _ := json.Marshal(&data)return string(j)}func (c *HTTPClient) deserializeReq(reqStr string) (*http.Request, error) {var data requestData_ = json.Unmarshal([]byte(reqStr), &data)var body io.Readerif data.Body != nil {bodyStr, _ := base64.StdEncoding.DecodeString(*data.Body)body = strings.NewReader(string(bodyStr))}req, err := http.NewRequest(data.Method, data.URL, body)if err != nil {return nil, err}req.Header = data.Headerreturn req, nil}func (c *HTTPClient) serializeResponse(resp *http.Response) string {var b = &bytes.Buffer{}_ = resp.Write(b)return b.String()}func (c *HTTPClient) deserializeResponse(req *http.Request, respStr string) (*http.Response, error) {r := bufio.NewReader(strings.NewReader(respStr))return http.ReadResponse(r, req)}