github.com/chnsz/golangsdk@v0.0.0-20240506093406-85a3fbfa605b/openstack/obs/progress.go (about)

     1  package obs
     2  
     3  import (
     4  	"io"
     5  )
     6  
     7  type ProgressEventType int
     8  
     9  type ProgressEvent struct {
    10  	ConsumedBytes int64
    11  	TotalBytes    int64
    12  	EventType     ProgressEventType
    13  }
    14  
    15  const (
    16  	TransferStartedEvent ProgressEventType = 1 + iota
    17  	TransferDataEvent
    18  	TransferCompletedEvent
    19  	TransferFailedEvent
    20  )
    21  
    22  func newProgressEvent(eventType ProgressEventType, consumed, total int64) *ProgressEvent {
    23  	return &ProgressEvent{
    24  		ConsumedBytes: consumed,
    25  		TotalBytes:    total,
    26  		EventType:     eventType,
    27  	}
    28  }
    29  
    30  type ProgressListener interface {
    31  	ProgressChanged(event *ProgressEvent)
    32  }
    33  
    34  type readerTracker struct {
    35  	completedBytes int64
    36  }
    37  
    38  // publishProgress
    39  func publishProgress(listener ProgressListener, event *ProgressEvent) {
    40  	if listener != nil && event != nil {
    41  		listener.ProgressChanged(event)
    42  	}
    43  }
    44  
    45  type teeReader struct {
    46  	reader        io.Reader
    47  	consumedBytes int64
    48  	totalBytes    int64
    49  	tracker       *readerTracker
    50  	listener      ProgressListener
    51  }
    52  
    53  func TeeReader(reader io.Reader, totalBytes int64, listener ProgressListener, tracker *readerTracker) io.ReadCloser {
    54  	return &teeReader{
    55  		reader:        reader,
    56  		consumedBytes: 0,
    57  		totalBytes:    totalBytes,
    58  		tracker:       tracker,
    59  		listener:      listener,
    60  	}
    61  }
    62  
    63  func (t *teeReader) Read(p []byte) (n int, err error) {
    64  	n, err = t.reader.Read(p)
    65  
    66  	if err != nil && err != io.EOF {
    67  		event := newProgressEvent(TransferFailedEvent, t.consumedBytes, t.totalBytes)
    68  		publishProgress(t.listener, event)
    69  	}
    70  
    71  	if n > 0 {
    72  		t.consumedBytes += int64(n)
    73  
    74  		if t.listener != nil {
    75  			event := newProgressEvent(TransferDataEvent, t.consumedBytes, t.totalBytes)
    76  			publishProgress(t.listener, event)
    77  		}
    78  
    79  		if t.tracker != nil {
    80  			t.tracker.completedBytes = t.consumedBytes
    81  		}
    82  	}
    83  
    84  	return
    85  }
    86  
    87  func (r *teeReader) Size() int64 {
    88  	return r.totalBytes
    89  }
    90  
    91  func (t *teeReader) Close() error {
    92  	if rc, ok := t.reader.(io.ReadCloser); ok {
    93  		return rc.Close()
    94  	}
    95  	return nil
    96  }