From 51e4324c7a00596a1ab0d62a22688d204384c6f1 Mon Sep 17 00:00:00 2001 From: rjp Date: Thu, 25 May 2023 08:05:58 +0100 Subject: [PATCH] Better handling of "save the JSON" As suggested by 'mattn, use a `TeeReader` with an `io.Writer` to keep the semantics of `json.NewDecoder().Decode()` whilst also being able to save the JSON if requested by the client. However we need to use our own interface (`WriteResetter`) in order to be able to call `Reset()` on the underlying buffer (which does somewhat limit the usage to buffers instead of generic `io.Writer` and may not be the 100% ideal solution.) --- mastodon.go | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/mastodon.go b/mastodon.go index 2bd61c3..309bac2 100644 --- a/mastodon.go +++ b/mastodon.go @@ -24,13 +24,17 @@ type Config struct { AccessToken string } +type WriteResetter interface { + io.Writer + Reset() +} + // Client is a API client for mastodon. type Client struct { http.Client - Config *Config - UserAgent string - SaveJSON bool - LastJSON []byte + Config *Config + UserAgent string + JSONWriter WriteResetter } func (c *Client) doAPI(ctx context.Context, method string, uri string, params interface{}, res interface{}, pg *Pagination) error { @@ -128,20 +132,10 @@ func (c *Client) doAPI(ctx context.Context, method string, uri string, params in } } - if c.SaveJSON { - // We want to store the JSON received -> we absolutely have to - // read all of it. But we restrict ourselves to a max of 100M. - safer := &io.LimitedReader{resp.Body, 100 * 1_048_576} - c.LastJSON, err = io.ReadAll(safer) - - if err != nil || c.LastJSON == nil { - return err - } - - // ...which means we can't use `NewDecoder.Decode` any more. - return json.Unmarshal(c.LastJSON, &res) + if c.JSONWriter != nil { + c.JSONWriter.Reset() + return json.NewDecoder(io.TeeReader(resp.Body, c.JSONWriter)).Decode(&res) } else { - // We don't want the JSON, just do the previous streaming decode. return json.NewDecoder(resp.Body).Decode(&res) } }