github.com/lukasheimann/cloudfoundrycli@v7.1.0+incompatible/cf/net/progress_reader.go (about) 1 package net 2 3 import ( 4 "io" 5 "os" 6 "sync" 7 "time" 8 9 "code.cloudfoundry.org/cli/cf/formatters" 10 "code.cloudfoundry.org/cli/cf/terminal" 11 ) 12 13 type ProgressReader struct { 14 ioReadSeeker io.ReadSeeker 15 bytesRead int64 16 total int64 17 quit chan bool 18 ui terminal.UI 19 outputInterval time.Duration 20 mutex sync.RWMutex 21 } 22 23 func NewProgressReader(readSeeker io.ReadSeeker, ui terminal.UI, outputInterval time.Duration) *ProgressReader { 24 return &ProgressReader{ 25 ioReadSeeker: readSeeker, 26 ui: ui, 27 outputInterval: outputInterval, 28 mutex: sync.RWMutex{}, 29 } 30 } 31 32 func (progressReader *ProgressReader) Read(p []byte) (int, error) { 33 if progressReader.ioReadSeeker == nil { 34 return 0, os.ErrInvalid 35 } 36 37 n, err := progressReader.ioReadSeeker.Read(p) 38 39 if progressReader.total > int64(0) { 40 if n > 0 { 41 if progressReader.quit == nil { 42 progressReader.quit = make(chan bool) 43 go progressReader.printProgress(progressReader.quit) 44 } 45 46 progressReader.mutex.Lock() 47 progressReader.bytesRead += int64(n) 48 progressReader.mutex.Unlock() 49 50 if progressReader.total == progressReader.bytesRead { 51 progressReader.quit <- true 52 return n, err 53 } 54 } 55 } 56 57 return n, err 58 } 59 60 func (progressReader *ProgressReader) Seek(offset int64, whence int) (int64, error) { 61 return progressReader.ioReadSeeker.Seek(offset, whence) 62 } 63 64 func (progressReader *ProgressReader) printProgress(quit chan bool) { 65 timer := time.NewTicker(progressReader.outputInterval) 66 67 for { 68 select { 69 case <-quit: 70 //The spaces are there to ensure we overwrite the entire line 71 //before using the terminal printer to output Done Uploading 72 progressReader.ui.PrintCapturingNoOutput("\r ") 73 progressReader.ui.Say("\rDone uploading") 74 return 75 case <-timer.C: 76 progressReader.mutex.RLock() 77 progressReader.ui.PrintCapturingNoOutput("\r%s uploaded...", formatters.ByteSize(progressReader.bytesRead)) 78 progressReader.mutex.RUnlock() 79 } 80 } 81 } 82 83 func (progressReader *ProgressReader) SetTotalSize(size int64) { 84 progressReader.total = size 85 }