Skip to content

Instantly share code, notes, and snippets.

@klingtnet
Created July 18, 2020 10:21
Show Gist options
  • Save klingtnet/c5f55e5e851d12157aa902c2ba9a4f61 to your computer and use it in GitHub Desktop.
Save klingtnet/c5f55e5e851d12157aa902c2ba9a4f61 to your computer and use it in GitHub Desktop.
Progress Reader
package main
import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"time"
)
type fakeReader struct {
stopAfter time.Time
}
func newFakeReader(stopAfter time.Time) *fakeReader {
return &fakeReader{stopAfter}
}
func (fr *fakeReader) Read(p []byte) (n int, err error) {
if time.Now().After(fr.stopAfter) {
return 0, io.EOF
}
return len(p), nil
}
func main() {
fr := newFakeReader(time.Now().Add(10 * time.Second))
pr := newProgressReader(fr, os.Stdout)
io.Copy(ioutil.Discard, pr)
}
type progressReader struct {
in io.Reader
out io.Writer
cnt int
cntCh chan int
errCh chan error
}
func newProgressReader(in io.Reader, out io.Writer) *progressReader {
pr := &progressReader{
in: in,
out: out,
cnt: 0,
cntCh: make(chan int, 0),
errCh: make(chan error, 0),
}
go func() {
t := time.Tick(1 * time.Second)
for {
select {
case n := <-pr.cntCh:
pr.cnt += n
case err := <-pr.errCh:
if errors.Is(err, io.EOF) {
fmt.Fprintln(pr.out, "transfer finished")
}
return
case <-t:
fmt.Fprintf(pr.out, "wrote %d bytes\n", pr.cnt)
}
}
}()
return pr
}
func (pg *progressReader) Read(p []byte) (n int, err error) {
n, err = pg.in.Read(p)
if err != nil {
pg.errCh <- err
} else {
pg.cntCh <- n
}
return
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment