Refactor bar.go
Vladimir Bauer
9 years ago
| 27 | 27 | |
| 28 | 28 | // Bar represents a progress Bar |
| 29 | 29 | type Bar struct { |
| 30 | completeReqCh chan struct{} | |
| 31 | done chan struct{} | |
| 32 | inProgress chan struct{} | |
| 33 | ops chan func(*state) | |
| 34 | ||
| 35 | // following are used after (*Bar.done) is closed | |
| 36 | width int | |
| 37 | state state | |
| 30 | // quit channel to request b.server to quit | |
| 31 | quit chan struct{} | |
| 32 | // done channel is receiveable after b.server has been quit | |
| 33 | done chan struct{} | |
| 34 | ops chan func(*state) | |
| 35 | ||
| 36 | // following are used after b.done is receiveable | |
| 37 | cacheState state | |
| 38 | 38 | } |
| 39 | 39 | |
| 40 | 40 | type ( |
| 79 | 79 | } |
| 80 | 80 | |
| 81 | 81 | b := &Bar{ |
| 82 | completeReqCh: make(chan struct{}), | |
| 83 | done: make(chan struct{}), | |
| 84 | inProgress: make(chan struct{}), | |
| 85 | ops: make(chan func(*state)), | |
| 86 | } | |
| 87 | b.width = s.width | |
| 82 | quit: make(chan struct{}), | |
| 83 | done: make(chan struct{}), | |
| 84 | ops: make(chan func(*state)), | |
| 85 | } | |
| 88 | 86 | |
| 89 | 87 | go b.server(s, wg, cancel) |
| 90 | 88 | return b |
| 96 | 94 | case b.ops <- func(s *state) { |
| 97 | 95 | s.prependFuncs = nil |
| 98 | 96 | }: |
| 99 | case <-b.done: | |
| 97 | case <-b.quit: | |
| 100 | 98 | return |
| 101 | 99 | } |
| 102 | 100 | } |
| 107 | 105 | case b.ops <- func(s *state) { |
| 108 | 106 | s.appendFuncs = nil |
| 109 | 107 | }: |
| 110 | case <-b.done: | |
| 108 | case <-b.quit: | |
| 111 | 109 | return |
| 112 | 110 | } |
| 113 | 111 | } |
| 139 | 137 | s.current = sum |
| 140 | 138 | s.blockStartTime = time.Now() |
| 141 | 139 | }: |
| 142 | case <-b.done: | |
| 140 | case <-b.quit: | |
| 143 | 141 | return |
| 144 | 142 | } |
| 145 | 143 | } |
| 154 | 152 | case b.ops <- func(s *state) { |
| 155 | 153 | s.refill = &refill{r, till} |
| 156 | 154 | }: |
| 157 | case <-b.done: | |
| 155 | case <-b.quit: | |
| 158 | 156 | return |
| 159 | 157 | } |
| 160 | 158 | } |
| 165 | 163 | case b.ops <- func(s *state) { result <- len(s.appendFuncs) }: |
| 166 | 164 | return <-result |
| 167 | 165 | case <-b.done: |
| 168 | return len(b.state.appendFuncs) | |
| 166 | return len(b.cacheState.appendFuncs) | |
| 169 | 167 | } |
| 170 | 168 | } |
| 171 | 169 | |
| 175 | 173 | case b.ops <- func(s *state) { result <- len(s.prependFuncs) }: |
| 176 | 174 | return <-result |
| 177 | 175 | case <-b.done: |
| 178 | return len(b.state.prependFuncs) | |
| 176 | return len(b.cacheState.prependFuncs) | |
| 179 | 177 | } |
| 180 | 178 | } |
| 181 | 179 | |
| 186 | 184 | case b.ops <- func(s *state) { result <- s.id }: |
| 187 | 185 | return <-result |
| 188 | 186 | case <-b.done: |
| 189 | return b.state.id | |
| 187 | return b.cacheState.id | |
| 188 | } | |
| 189 | } | |
| 190 | ||
| 191 | func (b *Bar) Current() int64 { | |
| 192 | result := make(chan int64, 1) | |
| 193 | select { | |
| 194 | case b.ops <- func(s *state) { result <- s.current }: | |
| 195 | return <-result | |
| 196 | case <-b.done: | |
| 197 | return b.cacheState.current | |
| 198 | } | |
| 199 | } | |
| 200 | ||
| 201 | func (b *Bar) Total() int64 { | |
| 202 | result := make(chan int64, 1) | |
| 203 | select { | |
| 204 | case b.ops <- func(s *state) { result <- s.total }: | |
| 205 | return <-result | |
| 206 | case <-b.done: | |
| 207 | return b.cacheState.total | |
| 190 | 208 | } |
| 191 | 209 | } |
| 192 | 210 | |
| 194 | 212 | // Can be used as condition in for loop |
| 195 | 213 | func (b *Bar) InProgress() bool { |
| 196 | 214 | select { |
| 197 | case <-b.completeReqCh: | |
| 215 | case <-b.quit: | |
| 198 | 216 | return false |
| 199 | 217 | default: |
| 200 | 218 | return true |
| 207 | 225 | // implicitly, upon p.Stop() call. |
| 208 | 226 | func (b *Bar) Complete() { |
| 209 | 227 | select { |
| 210 | case <-b.completeReqCh: | |
| 228 | case <-b.quit: | |
| 211 | 229 | default: |
| 212 | close(b.completeReqCh) | |
| 230 | close(b.quit) | |
| 213 | 231 | } |
| 214 | 232 | } |
| 215 | 233 | |
| 228 | 246 | func (b *Bar) server(s state, wg *sync.WaitGroup, cancel <-chan struct{}) { |
| 229 | 247 | |
| 230 | 248 | defer func() { |
| 231 | b.state = s | |
| 249 | b.cacheState = s | |
| 232 | 250 | close(b.done) |
| 233 | 251 | wg.Done() |
| 234 | 252 | }() |
| 237 | 255 | select { |
| 238 | 256 | case op := <-b.ops: |
| 239 | 257 | op(&s) |
| 240 | case <-b.completeReqCh: | |
| 258 | case <-b.quit: | |
| 241 | 259 | s.completed = true |
| 242 | 260 | return |
| 243 | 261 | case <-cancel: |
| 271 | 289 | }: |
| 272 | 290 | st = <-result |
| 273 | 291 | case <-b.done: |
| 274 | st = b.state | |
| 292 | st = b.cacheState | |
| 275 | 293 | } |
| 276 | 294 | buf := draw(&st, tw, prependWs, appendWs) |
| 277 | 295 | buf = append(buf, '\n') |
| 348 | 366 | barCount := utf8.RuneCount(barBlock) |
| 349 | 367 | totalCount := prependCount + barCount + appendCount |
| 350 | 368 | if totalCount > termWidth { |
| 351 | newWidth := termWidth - prependCount - appendCount | |
| 352 | barBlock = fillBar(s.total, s.current, newWidth, fmtBytes, s.refill) | |
| 369 | shrinkWidth := termWidth - prependCount - appendCount | |
| 370 | barBlock = fillBar(s.total, s.current, shrinkWidth, fmtBytes, s.refill) | |
| 353 | 371 | } |
| 354 | 372 | |
| 355 | 373 | return concatenateBlocks(buf, prependBlock, leftSpace, barBlock, rightSpace, appendBlock) |