summaryrefslogtreecommitdiff
path: root/vendor/github.com/dsoprea/go-utility/v2/filesystem/progress_wrapper.go
blob: 0a064c53d1e872660f7782c3042970871b6a5249 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package rifs

import (
	"io"
	"time"

	"github.com/dsoprea/go-logging"
)

// ProgressFunc receives progress updates.
type ProgressFunc func(n int, duration time.Duration, isEof bool) error

// WriteProgressWrapper wraps a reader and calls a callback after each read with
// count and duration info.
type WriteProgressWrapper struct {
	w          io.Writer
	progressCb ProgressFunc
}

// NewWriteProgressWrapper returns a new WPW instance.
func NewWriteProgressWrapper(w io.Writer, progressCb ProgressFunc) io.Writer {
	return &WriteProgressWrapper{
		w:          w,
		progressCb: progressCb,
	}
}

// Write does a write and calls the callback.
func (wpw *WriteProgressWrapper) Write(buffer []byte) (n int, err error) {
	defer func() {
		if state := recover(); state != nil {
			err = log.Wrap(state.(error))
		}
	}()

	startAt := time.Now()

	n, err = wpw.w.Write(buffer)
	log.PanicIf(err)

	duration := time.Since(startAt)

	err = wpw.progressCb(n, duration, false)
	log.PanicIf(err)

	return n, nil
}

// ReadProgressWrapper wraps a reader and calls a callback after each read with
// count and duration info.
type ReadProgressWrapper struct {
	r          io.Reader
	progressCb ProgressFunc
}

// NewReadProgressWrapper returns a new RPW instance.
func NewReadProgressWrapper(r io.Reader, progressCb ProgressFunc) io.Reader {
	return &ReadProgressWrapper{
		r:          r,
		progressCb: progressCb,
	}
}

// Read reads data and calls the callback.
func (rpw *ReadProgressWrapper) Read(buffer []byte) (n int, err error) {
	defer func() {
		if state := recover(); state != nil {
			err = log.Wrap(state.(error))
		}
	}()

	startAt := time.Now()

	n, err = rpw.r.Read(buffer)

	duration := time.Since(startAt)

	if err != nil {
		if err == io.EOF {
			errInner := rpw.progressCb(n, duration, true)
			log.PanicIf(errInner)

			return n, err
		}

		log.Panic(err)
	}

	err = rpw.progressCb(n, duration, false)
	log.PanicIf(err)

	return n, nil
}