github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/lib/readers/repeatable.go (about)

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