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  }