github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/chat/attachments/progress/progress.go (about) 1 package progress 2 3 import ( 4 "time" 5 6 "github.com/keybase/client/go/chat/types" 7 ) 8 9 // desktop requested 1 update per second: 10 const durationBetweenUpdates = 1 * time.Second 11 const maxDurationBetweenUpdates = 1 * time.Second 12 13 type ProgressWriter struct { 14 complete int64 15 total int64 16 lastReport int64 17 lastReportTime time.Time 18 updateDuration time.Duration 19 progress types.ProgressReporter 20 } 21 22 func NewProgressWriter(p types.ProgressReporter, size int64) *ProgressWriter { 23 return NewProgressWriterWithUpdateDuration(p, size, durationBetweenUpdates) 24 } 25 26 func NewProgressWriterWithUpdateDuration(p types.ProgressReporter, size int64, ud time.Duration) *ProgressWriter { 27 pw := &ProgressWriter{progress: p, total: size, updateDuration: ud} 28 pw.initialReport() 29 return pw 30 } 31 32 func (p *ProgressWriter) Write(data []byte) (n int, err error) { 33 n = len(data) 34 p.complete += int64(n) 35 p.report() 36 return n, nil 37 } 38 39 func (p *ProgressWriter) Update(n int) { 40 p.complete += int64(n) 41 p.report() 42 } 43 44 func (p *ProgressWriter) report() { 45 now := time.Now() 46 dur := now.Sub(p.lastReportTime) 47 48 // if it has been longer than maxDurationBetweenUpdates, 49 // then send an update regardless 50 if dur >= maxDurationBetweenUpdates { 51 p.notify(now) 52 return 53 } 54 55 // if the percentage hasn't changed, then don't update. 56 if p.percent() <= p.lastReport { 57 return 58 } 59 60 // if it has been less than p.updateDuration since last 61 // report, then don't do anything. 62 if dur < p.updateDuration { 63 return 64 } 65 66 p.notify(now) 67 } 68 69 func (p *ProgressWriter) notify(now time.Time) { 70 if p.progress != nil { 71 p.progress(p.complete, p.total) 72 } 73 p.lastReport = p.percent() 74 p.lastReportTime = now 75 } 76 77 func (p *ProgressWriter) percent() int64 { 78 if p.total == 0 { 79 return 0 80 } 81 return (100 * p.complete) / p.total 82 } 83 84 // send 0% progress 85 func (p *ProgressWriter) initialReport() { 86 if p.progress == nil { 87 return 88 } 89 90 p.progress(0, p.total) 91 } 92 93 func (p *ProgressWriter) Finish() { 94 if p.progress == nil { 95 return 96 } 97 p.progress(p.total, p.total) 98 }