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.)
pull/183/head
rjp 2023-05-25 08:05:58 +01:00
parent 333d71452a
commit 51e4324c7a
1 changed files with 11 additions and 17 deletions

View File

@ -24,13 +24,17 @@ type Config struct {
AccessToken string AccessToken string
} }
type WriteResetter interface {
io.Writer
Reset()
}
// Client is a API client for mastodon. // Client is a API client for mastodon.
type Client struct { type Client struct {
http.Client http.Client
Config *Config Config *Config
UserAgent string UserAgent string
SaveJSON bool JSONWriter WriteResetter
LastJSON []byte
} }
func (c *Client) doAPI(ctx context.Context, method string, uri string, params interface{}, res interface{}, pg *Pagination) error { 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 { if c.JSONWriter != nil {
// We want to store the JSON received -> we absolutely have to c.JSONWriter.Reset()
// read all of it. But we restrict ourselves to a max of 100M. return json.NewDecoder(io.TeeReader(resp.Body, c.JSONWriter)).Decode(&res)
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)
} else { } else {
// We don't want the JSON, just do the previous streaming decode.
return json.NewDecoder(resp.Body).Decode(&res) return json.NewDecoder(resp.Body).Decode(&res)
} }
} }