Refactor userConf to pConf
Vladimir Bauer
9 years ago
| 19 | 19 | result []chan int |
| 20 | 20 | } |
| 21 | 21 | |
| 22 | // config changeable by user | |
| 23 | userConf struct { | |
| 22 | // progress config, all fieals are adjustable by user | |
| 23 | pConf struct { | |
| 24 | 24 | bars []*Bar |
| 25 | 25 | |
| 26 | 26 | width int |
| 52 | 52 | wg *sync.WaitGroup |
| 53 | 53 | |
| 54 | 54 | done chan struct{} |
| 55 | ops chan func(*userConf) | |
| 55 | ops chan func(*pConf) | |
| 56 | 56 | stopReqCh chan struct{} |
| 57 | 57 | |
| 58 | 58 | // following is used after (*Progress.done) is closed |
| 59 | conf userConf | |
| 59 | conf pConf | |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | 62 | // New creates new Progress instance, which will orchestrate bars rendering |
| 66 | 66 | p := &Progress{ |
| 67 | 67 | wg: new(sync.WaitGroup), |
| 68 | 68 | done: make(chan struct{}), |
| 69 | ops: make(chan func(*userConf)), | |
| 69 | ops: make(chan func(*pConf)), | |
| 70 | 70 | stopReqCh: make(chan struct{}), |
| 71 | 71 | } |
| 72 | go p.server(userConf{ | |
| 72 | go p.server(pConf{ | |
| 73 | 73 | bars: make([]*Bar, 0, 3), |
| 74 | 74 | width: pwidth, |
| 75 | 75 | format: pformat, |
| 86 | 86 | if ch == nil { |
| 87 | 87 | panic("nil cancel channel") |
| 88 | 88 | } |
| 89 | return updateConf(p, func(c *userConf) { | |
| 89 | return updateConf(p, func(c *pConf) { | |
| 90 | 90 | c.cancel = ch |
| 91 | 91 | }) |
| 92 | 92 | } |
| 96 | 96 | if width < 2 { |
| 97 | 97 | return p |
| 98 | 98 | } |
| 99 | return updateConf(p, func(c *userConf) { | |
| 99 | return updateConf(p, func(c *pConf) { | |
| 100 | 100 | c.width = width |
| 101 | 101 | }) |
| 102 | 102 | } |
| 106 | 106 | if w == nil { |
| 107 | 107 | return p |
| 108 | 108 | } |
| 109 | return updateConf(p, func(c *userConf) { | |
| 109 | return updateConf(p, func(c *pConf) { | |
| 110 | 110 | c.cw.Flush() |
| 111 | 111 | c.cw = cwriter.New(w) |
| 112 | 112 | }) |
| 114 | 114 | |
| 115 | 115 | // RefreshRate overrides default (100ms) refresh rate value |
| 116 | 116 | func (p *Progress) RefreshRate(d time.Duration) *Progress { |
| 117 | return updateConf(p, func(c *userConf) { | |
| 117 | return updateConf(p, func(c *pConf) { | |
| 118 | 118 | c.ticker.Stop() |
| 119 | 119 | c.ticker = time.NewTicker(d) |
| 120 | 120 | c.rr = d |
| 123 | 123 | |
| 124 | 124 | // BeforeRenderFunc accepts a func, which gets called before render process. |
| 125 | 125 | func (p *Progress) BeforeRenderFunc(f BeforeRender) *Progress { |
| 126 | return updateConf(p, func(c *userConf) { | |
| 126 | return updateConf(p, func(c *pConf) { | |
| 127 | 127 | c.beforeRender = f |
| 128 | 128 | }) |
| 129 | 129 | } |
| 136 | 136 | // AddBarWithID creates a new progress bar and adds to the container. |
| 137 | 137 | func (p *Progress) AddBarWithID(id int, total int64) *Bar { |
| 138 | 138 | result := make(chan *Bar, 1) |
| 139 | op := func(c *userConf) { | |
| 139 | op := func(c *pConf) { | |
| 140 | 140 | bar := newBar(id, total, c.width, c.format, p.wg, c.cancel) |
| 141 | 141 | c.bars = append(c.bars, bar) |
| 142 | 142 | p.wg.Add(1) |
| 153 | 153 | // RemoveBar removes bar at any time. |
| 154 | 154 | func (p *Progress) RemoveBar(b *Bar) bool { |
| 155 | 155 | result := make(chan bool, 1) |
| 156 | op := func(c *userConf) { | |
| 156 | op := func(c *pConf) { | |
| 157 | 157 | var ok bool |
| 158 | 158 | for i, bar := range c.bars { |
| 159 | 159 | if bar == b { |
| 173 | 173 | } |
| 174 | 174 | } |
| 175 | 175 | |
| 176 | // BarCount returns bars count in the container. | |
| 176 | // BarCount returns bars count | |
| 177 | 177 | func (p *Progress) BarCount() int { |
| 178 | 178 | result := make(chan int, 1) |
| 179 | op := func(c *userConf) { | |
| 179 | op := func(c *pConf) { | |
| 180 | 180 | result <- len(c.bars) |
| 181 | 181 | } |
| 182 | 182 | select { |
| 189 | 189 | |
| 190 | 190 | // ShutdownNotify means to be notified when main rendering goroutine quits, usualy after p.Stop() call. |
| 191 | 191 | func (p *Progress) ShutdownNotify(ch chan struct{}) *Progress { |
| 192 | return updateConf(p, func(c *userConf) { | |
| 192 | return updateConf(p, func(c *pConf) { | |
| 193 | 193 | c.shutdownNotifier = ch |
| 194 | 194 | }) |
| 195 | 195 | } |
| 199 | 199 | if utf8.RuneCountInString(format) != numFmtRunes { |
| 200 | 200 | return p |
| 201 | 201 | } |
| 202 | return updateConf(p, func(c *userConf) { | |
| 202 | return updateConf(p, func(c *pConf) { | |
| 203 | 203 | c.format = format |
| 204 | 204 | }) |
| 205 | 205 | } |
| 214 | 214 | return |
| 215 | 215 | default: |
| 216 | 216 | // complete Total unknown bars |
| 217 | p.ops <- func(c *userConf) { | |
| 217 | p.ops <- func(c *pConf) { | |
| 218 | 218 | for _, b := range c.bars { |
| 219 | 219 | s := b.getState() |
| 220 | 220 | if !s.completed && !s.aborted { |
| 231 | 231 | } |
| 232 | 232 | } |
| 233 | 233 | |
| 234 | // func (p *Progress) getConf() userConf { | |
| 235 | // select { | |
| 236 | // case conf := <-p.userConfCh: | |
| 237 | // return conf | |
| 238 | // case <-p.done: | |
| 239 | // return p.conf | |
| 240 | // } | |
| 241 | // } | |
| 242 | ||
| 243 | // func (p *Progress) updateConf(op func(*userConf)) { | |
| 244 | // // c := p.getConf() | |
| 245 | // // cb(&c) | |
| 246 | // select { | |
| 247 | // case p.ops <- op: | |
| 248 | // case <-p.done: | |
| 249 | // return | |
| 250 | // } | |
| 251 | // } | |
| 252 | ||
| 253 | func updateConf(p *Progress, op func(*userConf)) *Progress { | |
| 254 | select { | |
| 255 | case p.ops <- op: | |
| 256 | return p | |
| 257 | case <-p.done: | |
| 258 | return nil | |
| 259 | } | |
| 260 | } | |
| 261 | ||
| 262 | 234 | // server monitors underlying channels and renders any progress bars |
| 263 | func (p *Progress) server(conf userConf) { | |
| 235 | func (p *Progress) server(conf pConf) { | |
| 264 | 236 | |
| 265 | 237 | defer func() { |
| 266 | 238 | conf.ticker.Stop() |
| 385 | 357 | return ch |
| 386 | 358 | } |
| 387 | 359 | |
| 360 | func updateConf(p *Progress, op func(*pConf)) *Progress { | |
| 361 | select { | |
| 362 | case p.ops <- op: | |
| 363 | return p | |
| 364 | case <-p.done: | |
| 365 | return nil | |
| 366 | } | |
| 367 | } | |
| 368 | ||
| 388 | 369 | func max(slice []int) int { |
| 389 | 370 | max := slice[0] |
| 390 | 371 | |