-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathcopy.go
90 lines (68 loc) · 1.43 KB
/
copy.go
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
package savior
import (
"io"
"github.com/pkg/errors"
)
// ErrStop is returned when decompression has been stopped by a SaveConsumer returning
// AfterActionStop.
var ErrStop = errors.New("copy was stopped after save!")
type EmitProgressFunc func()
type Savable interface {
WantSave()
}
type CopyParams struct {
Src io.Reader
Dst io.Writer
Entry *Entry
Savable Savable
EmitProgress EmitProgressFunc
}
const progressThreshold = 512 * 1024
type Copier struct {
// params
SaveConsumer SaveConsumer
// internal
buf []byte
stop bool
}
func NewCopier(SaveConsumer SaveConsumer) *Copier {
return &Copier{
SaveConsumer: SaveConsumer,
buf: make([]byte, 32*1024),
}
}
func (c *Copier) Do(params *CopyParams) error {
if params == nil {
return errors.New("CopyWithSaver called with nil params")
}
c.stop = false
var progressCounter int64
for !c.stop {
n, readErr := params.Src.Read(c.buf)
m, err := params.Dst.Write(c.buf[:n])
if err != nil {
return errors.WithStack(err)
}
progressCounter += int64(m)
if progressCounter > progressThreshold {
progressCounter = 0
if params.EmitProgress != nil {
params.EmitProgress()
}
}
if readErr != nil {
if readErr == io.EOF {
// cool, we're done!
return nil
}
return errors.WithStack(readErr)
}
if c.SaveConsumer.ShouldSave(int64(n)) {
params.Savable.WantSave()
}
}
return nil
}
func (c *Copier) Stop() {
c.stop = true
}