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
|
package progressreadseeker
import (
"io"
)
type ProgressFn func(approxReadBytes int64, totalSize int64)
type Reader struct {
rs io.ReadSeeker
pos int64
totalSize int64
partitionSize int64
partitions []bool
partitionsReadCount int64
progressFn ProgressFn
}
func New(rs io.ReadSeeker, precision int64, totalSize int64, fn ProgressFn) *Reader {
partitionSize := totalSize / precision
if totalSize%precision != 0 {
partitionSize++
}
return &Reader{
rs: rs,
totalSize: totalSize,
partitionSize: partitionSize,
partitions: make([]bool, precision),
progressFn: fn,
}
}
func (prs *Reader) Read(p []byte) (n int, err error) {
n, err = prs.rs.Read(p)
newPos := prs.pos + int64(n)
lastPartitionsReadCount := prs.partitionsReadCount
partStart := prs.pos / prs.partitionSize
partEnd := newPos / prs.partitionSize
for i := partStart; i < partEnd; i++ {
if prs.partitions[i] {
continue
}
prs.partitions[i] = true
prs.partitionsReadCount++
}
if lastPartitionsReadCount != prs.partitionsReadCount {
readBytes := prs.partitionSize * prs.partitionsReadCount
if readBytes > prs.totalSize {
readBytes = prs.totalSize
}
prs.progressFn(readBytes, prs.totalSize)
}
prs.pos = newPos
return n, err
}
func (prs *Reader) Seek(offset int64, whence int) (int64, error) {
pos, err := prs.rs.Seek(offset, whence)
prs.pos = pos
return pos, err
}
func (prs *Reader) Unwrap() any {
return prs.rs
}
|