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 }