non-blocking status() method
Vladimir Bauer
9 years ago
| 7 | 7 | |
| 8 | 8 | // Bar represents a progress Bar |
| 9 | 9 | type Bar struct { |
| 10 | total int | |
| 10 | // total int | |
| 11 | 11 | width int |
| 12 | 12 | alpha float64 |
| 13 | 13 | |
| 17 | 17 | leftEnd byte |
| 18 | 18 | rightEnd byte |
| 19 | 19 | |
| 20 | lastFrame []byte | |
| 20 | lastFrame []byte | |
| 21 | lastStatus int | |
| 21 | 22 | |
| 22 | 23 | incrCh chan int |
| 23 | 24 | redrawReqCh chan chan []byte |
| 40 | 41 | |
| 41 | 42 | func newBar(total, width int, wg *sync.WaitGroup) *Bar { |
| 42 | 43 | b := &Bar{ |
| 43 | fill: '=', | |
| 44 | empty: '-', | |
| 45 | tip: '>', | |
| 46 | leftEnd: '[', | |
| 47 | rightEnd: ']', | |
| 48 | alpha: 0.25, | |
| 49 | total: total, | |
| 44 | fill: '=', | |
| 45 | empty: '-', | |
| 46 | tip: '>', | |
| 47 | leftEnd: '[', | |
| 48 | rightEnd: ']', | |
| 49 | alpha: 0.25, | |
| 50 | // total: total, | |
| 50 | 51 | width: width, |
| 51 | 52 | incrCh: make(chan int), |
| 52 | 53 | redrawReqCh: make(chan chan []byte), |
| 57 | 58 | stopCh: make(chan struct{}), |
| 58 | 59 | done: make(chan struct{}), |
| 59 | 60 | } |
| 60 | go b.server(wg) | |
| 61 | go b.server(wg, total) | |
| 61 | 62 | return b |
| 62 | 63 | } |
| 63 | 64 | |
| 166 | 167 | return string(b.lastFrame) |
| 167 | 168 | } |
| 168 | 169 | |
| 169 | func (b *Bar) server(wg *sync.WaitGroup) { | |
| 170 | func (b *Bar) server(wg *sync.WaitGroup, total int) { | |
| 170 | 171 | timeStarted := time.Now() |
| 171 | 172 | blockStartTime := timeStarted |
| 172 | 173 | buf := make([]byte, b.width, b.width+24) |
| 180 | 181 | select { |
| 181 | 182 | case i := <-b.incrCh: |
| 182 | 183 | n := current + i |
| 183 | if n > b.total { | |
| 184 | current = b.total | |
| 184 | if n > total { | |
| 185 | current = total | |
| 185 | 186 | completed = true |
| 186 | 187 | break |
| 187 | 188 | } |
| 189 | 190 | tpie = calcTimePerItemEstimate(tpie, blockStartTime, b.alpha, i) |
| 190 | 191 | blockStartTime = time.Now() |
| 191 | 192 | current = n |
| 192 | if current == b.total && !completed { | |
| 193 | if current == total && !completed { | |
| 193 | 194 | completed = true |
| 194 | 195 | } |
| 195 | 196 | case d := <-b.decoratorCh: |
| 202 | 203 | case respCh := <-b.currentReqCh: |
| 203 | 204 | respCh <- current |
| 204 | 205 | case respCh := <-b.redrawReqCh: |
| 205 | stat := &Statistics{b.total, current, timeElapsed, tpie} | |
| 206 | stat := &Statistics{total, current, timeElapsed, tpie} | |
| 206 | 207 | respCh <- b.draw(stat, buf, appendFuncs, prependFuncs) |
| 207 | 208 | case respCh := <-b.statusReqCh: |
| 208 | respCh <- int(100 * float64(current) / float64(b.total)) | |
| 209 | respCh <- percentage(total, current, 100) | |
| 209 | 210 | case <-b.flushedCh: |
| 210 | 211 | if completed && !b.isDone() { |
| 211 | stat := &Statistics{b.total, current, timeElapsed, tpie} | |
| 212 | stat := &Statistics{total, current, timeElapsed, tpie} | |
| 212 | 213 | b.lastFrame = b.draw(stat, buf, appendFuncs, prependFuncs) |
| 214 | b.lastStatus = percentage(total, current, 100) | |
| 213 | 215 | close(b.done) |
| 214 | 216 | wg.Done() |
| 215 | 217 | return |
| 225 | 227 | } |
| 226 | 228 | |
| 227 | 229 | func (b *Bar) draw(stat *Statistics, buf []byte, appendFuncs, prependFuncs []DecoratorFunc) []byte { |
| 228 | completedWidth := stat.Current * b.width / b.total | |
| 230 | completedWidth := percentage(stat.Total, stat.Current, b.width) | |
| 229 | 231 | |
| 230 | 232 | for i := 0; i < completedWidth; i++ { |
| 231 | 233 | buf[i] = b.fill |
| 266 | 268 | } |
| 267 | 269 | |
| 268 | 270 | func (b *Bar) status() int { |
| 269 | respCh := make(chan int) | |
| 270 | b.statusReqCh <- respCh | |
| 271 | return <-respCh | |
| 271 | if !b.isDone() { | |
| 272 | respCh := make(chan int) | |
| 273 | b.statusReqCh <- respCh | |
| 274 | return <-respCh | |
| 275 | } | |
| 276 | return b.lastStatus | |
| 272 | 277 | } |
| 273 | 278 | |
| 274 | 279 | // SortableBarSlice satisfies sort interface |
| 285 | 290 | lastItemEstimate := float64(lastBlockTime) / float64(items) |
| 286 | 291 | return time.Duration((alpha * lastItemEstimate) + (1-alpha)*float64(tpie)) |
| 287 | 292 | } |
| 293 | ||
| 294 | func percentage(total, current, ratio int) int { | |
| 295 | if total == 0 { | |
| 296 | return 0 | |
| 297 | } | |
| 298 | return int(float64(ratio) * float64(current) / float64(total)) | |
| 299 | } | |