github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/lib/readers/repeatable.go (about) 1 package readers 2 3 import ( 4 "errors" 5 "io" 6 "sync" 7 ) 8 9 // A RepeatableReader implements the io.ReadSeeker it allow to seek cached data 10 // back and forth within the reader but will only read data from the internal Reader as necessary 11 // and will play nicely with the Account and io.LimitedReader to reflect current speed 12 type RepeatableReader struct { 13 mu sync.Mutex // protect against concurrent use 14 in io.Reader // Input reader 15 i int64 // current reading index 16 b []byte // internal cache buffer 17 } 18 19 var _ io.ReadSeeker = (*RepeatableReader)(nil) 20 21 // Seek implements the io.Seeker interface. 22 // If seek position is passed the cache buffer length the function will return 23 // the maximum offset that can be used and "fs.RepeatableReader.Seek: offset is unavailable" Error 24 func (r *RepeatableReader) Seek(offset int64, whence int) (int64, error) { 25 r.mu.Lock() 26 defer r.mu.Unlock() 27 28 var abs int64 29 cacheLen := int64(len(r.b)) 30 switch whence { 31 case io.SeekStart: 32 abs = offset 33 case io.SeekCurrent: 34 abs = r.i + offset 35 case io.SeekEnd: 36 abs = cacheLen + offset 37 default: 38 return 0, errors.New("fs.RepeatableReader.Seek: invalid whence") 39 } 40 if abs < 0 { 41 return 0, errors.New("fs.RepeatableReader.Seek: negative position") 42 } 43 if abs > cacheLen { 44 return offset - (abs - cacheLen), errors.New("fs.RepeatableReader.Seek: offset is unavailable") 45 } 46 r.i = abs 47 return abs, nil 48 } 49 50 // Read data from original Reader into bytes 51 // Data is either served from the underlying Reader or from cache if was already read 52 func (r *RepeatableReader) Read(b []byte) (n int, err error) { 53 r.mu.Lock() 54 defer r.mu.Unlock() 55 56 cacheLen := int64(len(r.b)) 57 if r.i == cacheLen { 58 n, err = r.in.Read(b) 59 if n > 0 { 60 r.b = append(r.b, b[:n]...) 61 } 62 } else { 63 n = copy(b, r.b[r.i:]) 64 } 65 r.i += int64(n) 66 return n, err 67 } 68 69 // NewRepeatableReader create new repeatable reader from Reader r 70 func NewRepeatableReader(r io.Reader) *RepeatableReader { 71 return &RepeatableReader{in: r} 72 } 73 74 // NewRepeatableReaderSized create new repeatable reader from Reader r 75 // with an initial buffer of size. 76 func NewRepeatableReaderSized(r io.Reader, size int) *RepeatableReader { 77 return &RepeatableReader{ 78 in: r, 79 b: make([]byte, 0, size), 80 } 81 } 82 83 // NewRepeatableLimitReader create new repeatable reader from Reader r 84 // with an initial buffer of size wrapped in an io.LimitReader to read 85 // only size. 86 func NewRepeatableLimitReader(r io.Reader, size int) *RepeatableReader { 87 return NewRepeatableReaderSized(io.LimitReader(r, int64(size)), size) 88 } 89 90 // NewRepeatableReaderBuffer create new repeatable reader from Reader r 91 // using the buffer passed in. 92 func NewRepeatableReaderBuffer(r io.Reader, buf []byte) *RepeatableReader { 93 return &RepeatableReader{ 94 in: r, 95 b: buf[:0], 96 } 97 } 98 99 // NewRepeatableLimitReaderBuffer create new repeatable reader from 100 // Reader r and buf wrapped in an io.LimitReader to read only size. 101 func NewRepeatableLimitReaderBuffer(r io.Reader, buf []byte, size int64) *RepeatableReader { 102 return NewRepeatableReaderBuffer(io.LimitReader(r, size), buf) 103 }