...
1 package download
2
3 import (
4 "fmt"
5 "io"
6 "time"
7
8 "github.com/dustin/go-humanize"
9 "github.com/pkg/errors"
10 )
11
12 type Metadata struct {
13 Name string
14 Size int64
15 SupportsRange bool
16 }
17
18 type ByteRange struct {
19 Start int64
20 End int64
21 Wrote int64
22 Progress int64
23 LastWrote time.Time
24 }
25
26 func NewByteRange(start, end, wrote int64) *ByteRange {
27 return &ByteRange{Start: start, End: end, Wrote: wrote}
28 }
29
30 func (r *ByteRange) String() string {
31 return fmt.Sprintf("{%s - %s (%s / %s)}", humanize.Bytes(uint64(r.Start)), humanize.Bytes(uint64(r.End)), humanize.Bytes(uint64(r.Wrote)), humanize.Bytes(uint64(r.End-r.Start+1)))
32 }
33
34 type BytesWrote struct {
35 Wrote int
36 Duration time.Duration
37 }
38
39 type ControlWriter struct {
40 io.WriterAt
41 offset int64
42
43 Cancelled chan bool
44 }
45
46 func NewControlWriter(w io.WriterAt, offset int64) *ControlWriter {
47 return &ControlWriter{WriterAt: w, offset: offset, Cancelled: make(chan bool)}
48 }
49
50 func (w *ControlWriter) Write(b []byte) (n int, err error) {
51 return w.WriteAt(b, w.offset)
52 }
53
54 type DownloadWriter struct {
55 io.WriterAt
56 Range *ByteRange
57 Cancelled bool
58 }
59
60 func NewDownloadWriter(w io.WriterAt, r *ByteRange) *DownloadWriter {
61 return &DownloadWriter{WriterAt: w, Range: r}
62 }
63
64 func (w *DownloadWriter) Write(b []byte) (n int, err error) {
65 if w.Cancelled {
66 return 0, errors.New("cancelled")
67 }
68
69 r := w.Range
70 r.LastWrote = time.Now()
71
72 n, err = w.WriteAt(b, r.Start+r.Wrote)
73 if err != nil {
74 return n, errors.Wrap(err, "failed to write to disk")
75 }
76
77 r.Wrote += int64(n)
78 r.Progress += int64(n)
79
80 return
81 }
82
View as plain text