github.com/2lambda123/git-lfs@v2.5.2+incompatible/tools/copycallback.go (about)

     1  package tools
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  )
     7  
     8  type CopyCallback func(totalSize int64, readSoFar int64, readSinceLast int) error
     9  
    10  type BodyWithCallback struct {
    11  	c         CopyCallback
    12  	totalSize int64
    13  	readSize  int64
    14  	ReadSeekCloser
    15  }
    16  
    17  func NewByteBodyWithCallback(by []byte, totalSize int64, cb CopyCallback) *BodyWithCallback {
    18  	return NewBodyWithCallback(NewByteBody(by), totalSize, cb)
    19  }
    20  
    21  func NewBodyWithCallback(body ReadSeekCloser, totalSize int64, cb CopyCallback) *BodyWithCallback {
    22  	return &BodyWithCallback{
    23  		c:              cb,
    24  		totalSize:      totalSize,
    25  		ReadSeekCloser: body,
    26  	}
    27  }
    28  
    29  // Read wraps the underlying Reader's "Read" method. It also captures the number
    30  // of bytes read, and calls the callback.
    31  func (r *BodyWithCallback) Read(p []byte) (int, error) {
    32  	n, err := r.ReadSeekCloser.Read(p)
    33  
    34  	if n > 0 {
    35  		r.readSize += int64(n)
    36  
    37  		if (err == nil || err == io.EOF) && r.c != nil {
    38  			err = r.c(r.totalSize, r.readSize, n)
    39  		}
    40  	}
    41  	return n, err
    42  }
    43  
    44  // Seek wraps the underlying Seeker's "Seek" method, updating the number of
    45  // bytes that have been consumed by this reader.
    46  func (r *BodyWithCallback) Seek(offset int64, whence int) (int64, error) {
    47  	switch whence {
    48  	case io.SeekStart:
    49  		r.readSize = offset
    50  	case io.SeekCurrent:
    51  		r.readSize += offset
    52  	case io.SeekEnd:
    53  		r.readSize = r.totalSize + offset
    54  	}
    55  
    56  	return r.ReadSeekCloser.Seek(offset, whence)
    57  }
    58  
    59  // ResetProgress calls the callback with a negative read size equal to the
    60  // total number of bytes read so far, effectively "resetting" the progress.
    61  func (r *BodyWithCallback) ResetProgress() error {
    62  	return r.c(r.totalSize, r.readSize, -int(r.readSize))
    63  }
    64  
    65  type CallbackReader struct {
    66  	C         CopyCallback
    67  	TotalSize int64
    68  	ReadSize  int64
    69  	io.Reader
    70  }
    71  
    72  func (w *CallbackReader) Read(p []byte) (int, error) {
    73  	n, err := w.Reader.Read(p)
    74  
    75  	if n > 0 {
    76  		w.ReadSize += int64(n)
    77  
    78  		if (err == nil || err == io.EOF) && w.C != nil {
    79  			err = w.C(w.TotalSize, w.ReadSize, n)
    80  		}
    81  	}
    82  	return n, err
    83  }
    84  
    85  // prevent import cycle
    86  type ReadSeekCloser interface {
    87  	io.Seeker
    88  	io.ReadCloser
    89  }
    90  
    91  func NewByteBody(by []byte) ReadSeekCloser {
    92  	return &closingByteReader{Reader: bytes.NewReader(by)}
    93  }
    94  
    95  type closingByteReader struct {
    96  	*bytes.Reader
    97  }
    98  
    99  func (r *closingByteReader) Close() error {
   100  	return nil
   101  }