aboutsummaryrefslogtreecommitdiffstats
path: root/drive/progress.go
blob: ee63b6c04818332591b697797f95333902f6bbdf (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
package drive

import (
    "io"
    "fmt"
    "time"
)

type Progress struct {
    Writer io.Writer
    Reader io.Reader
    Size int64
    progress int64
    rate int64
    rateProgress int64
    rateUpdated time.Time
    updated time.Time
    done bool
}

func (self *Progress) Read(p []byte) (int, error) {
    // Read
    n, err := self.Reader.Read(p)

    now := time.Now()
    isLast := err != nil

    // Increment progress
    newProgress := self.progress + int64(n)
    self.progress = newProgress

    // Initialize rate state
    if self.rateUpdated.IsZero() {
        self.rateUpdated = now
        self.rateProgress = newProgress
    }

    // Update rate every 3 seconds
    if self.rateUpdated.Add(time.Second * 3).Before(now) {
        self.rate = calcRate(newProgress - self.rateProgress, self.rateUpdated, now)
        self.rateUpdated = now
        self.rateProgress = newProgress
    }

    // Draw progress every second
    if self.updated.Add(time.Second).Before(now) || isLast {
        self.Draw(isLast)
    }

    // Update last draw time
    self.updated = now

    // Mark as done if error occurs
    self.done = isLast

    return n, err
}

func (self *Progress) Draw(isLast bool) {
    if self.done {
        return
    }

    // Clear line
    fmt.Fprintf(self.Writer, "\r%50s", "")

    // Print progress
    fmt.Fprintf(self.Writer, "\r%s/%s", formatSize(self.progress, false), formatSize(self.Size, false))

    // Print rate
    if self.rate > 0 {
        fmt.Fprintf(self.Writer, ", Rate: %s/s", formatSize(self.rate, false))
    }

    if isLast {
        fmt.Fprintf(self.Writer, "\n")
    }
}