progresstracking.go 1002 B

123456789101112131415161718192021222324252627282930313233343536373839
  1. // Copyright (c) Tailscale Inc & contributors
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Package progresstracking provides wrappers around io.Reader and io.Writer
  4. // that track progress.
  5. package progresstracking
  6. import (
  7. "io"
  8. "time"
  9. )
  10. // NewReader wraps the given Reader with a progress tracking Reader that
  11. // reports progress at the following points:
  12. //
  13. // - First read
  14. // - Every read spaced at least interval since the prior read
  15. // - Last read
  16. func NewReader(r io.Reader, interval time.Duration, onProgress func(totalRead int, err error)) io.Reader {
  17. return &reader{Reader: r, interval: interval, onProgress: onProgress}
  18. }
  19. type reader struct {
  20. io.Reader
  21. interval time.Duration
  22. onProgress func(int, error)
  23. lastTracked time.Time
  24. totalRead int
  25. }
  26. func (r *reader) Read(p []byte) (int, error) {
  27. n, err := r.Reader.Read(p)
  28. r.totalRead += n
  29. if time.Since(r.lastTracked) > r.interval || err != nil {
  30. r.onProgress(r.totalRead, err)
  31. r.lastTracked = time.Now()
  32. }
  33. return n, err
  34. }