diff --git a/njs-progress/bar.go b/njs-progress/bar.go new file mode 100644 index 0000000..575249c --- /dev/null +++ b/njs-progress/bar.go @@ -0,0 +1,101 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package njs_progress + +import ( + "context" + + njs_semaphore "github.com/nabbar/golib/njs-semaphore" + "github.com/vbauerster/mpb/v5" +) + +type bar struct { + t int64 + b *mpb.Bar + s njs_semaphore.Sem +} + +type Bar interface { + Current() int64 + Completed() bool + + NewWorker() error + NewWorkerTry() bool + DeferWorker() + DeferMain(dropBar bool) + + WaitAll() error + Context() context.Context + Cancel() +} + +func newBar(b *mpb.Bar, s njs_semaphore.Sem) Bar { + return &bar{ + t: 0, + b: b, + s: s, + } +} + +func (b bar) Current() int64 { + return b.b.Current() +} + +func (b bar) Completed() bool { + return b.b.Completed() +} + +func (b *bar) NewWorker() error { + b.t++ + b.b.SetTotal(b.t, false) + return b.s.NewWorker() +} + +func (b *bar) NewWorkerTry() bool { + return b.s.NewWorkerTry() +} + +func (b *bar) DeferWorker() { + b.b.Increment() + b.s.DeferWorker() +} + +func (b *bar) DeferMain(dropBar bool) { + b.b.Abort(dropBar) + b.s.DeferMain() +} + +func (b *bar) WaitAll() error { + return b.s.WaitAll() +} + +func (b bar) Context() context.Context { + return b.s.Context() +} + +func (b bar) Cancel() { + b.s.Cancel() +} diff --git a/njs-progress/progress.go b/njs-progress/progress.go new file mode 100644 index 0000000..c1ec140 --- /dev/null +++ b/njs-progress/progress.go @@ -0,0 +1,113 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package njs_progress + +import ( + "context" + "time" + + "github.com/vbauerster/mpb/v5/decor" + + njs_semaphore "github.com/nabbar/golib/njs-semaphore" + + "github.com/vbauerster/mpb/v5" +) + +/* + https://github.com/vbauerster/mpb +*/ + +var ( + defaultStyle = "[=>-]<+" + defaultMessageDone = "done" +) + +func SetDefaultStyle(style string) { + defaultStyle = style +} + +func SetDefaultMessageDone(message string) { + defaultMessageDone = message +} + +type progressBar struct { + mpb *mpb.Progress + ctx context.Context + cnl context.CancelFunc + sTimeOut time.Duration + sMaxSimul int +} + +type ProgressBar interface { + SetSemaphoreOption(maxSimultaneous int, timeout time.Duration) + NewBar(parent context.Context, options ...mpb.BarOption) Bar +} + +func NewProgressBar(timeout time.Duration, deadline time.Time, parent context.Context, options ...mpb.ContainerOption) ProgressBar { + x, c := njs_semaphore.GetContext(timeout, deadline, parent) + + return &progressBar{ + mpb: mpb.New(options...), + ctx: x, + cnl: c, + sTimeOut: timeout, + sMaxSimul: njs_semaphore.GetMaxSimultaneous(), + } +} + +func (p *progressBar) SetSemaphoreOption(maxSimultaneous int, timeout time.Duration) { + p.sMaxSimul = maxSimultaneous + p.sTimeOut = timeout +} + +func (p progressBar) NewBar(parent context.Context, options ...mpb.BarOption) Bar { + if parent == nil { + parent = p.ctx + } + + return newBar( + p.mpb.AddBar(0, options...), + njs_semaphore.NewSemaphore(p.sMaxSimul, p.sTimeOut, njs_semaphore.GetEmptyTime(), parent), + ) +} + +func (p progressBar) NewBarSimple(name string) Bar { + return newBar( + p.mpb.AddBar(0, + mpb.BarStyle(defaultStyle), + mpb.PrependDecorators( + // display our name with one space on the right + decor.Name(name, decor.WC{W: len(name) + 1, C: decor.DidentRight}), + // replace ETA decorator with "done" message, OnComplete event + decor.OnComplete( + decor.AverageETA(decor.ET_STYLE_GO, decor.WC{W: 4}), defaultMessageDone, + ), + ), + mpb.AppendDecorators(decor.Percentage()), + ), + njs_semaphore.NewSemaphore(p.sMaxSimul, p.sTimeOut, njs_semaphore.GetEmptyTime(), p.ctx), + ) +} diff --git a/njs-semaphore/context.go b/njs-semaphore/context.go new file mode 100644 index 0000000..9640365 --- /dev/null +++ b/njs-semaphore/context.go @@ -0,0 +1,49 @@ +/* + * MIT License + * + * Copyright (c) 2020 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package njs_semaphore + +import ( + "context" + "time" +) + +func GetContext(timeout time.Duration, deadline time.Time, parent context.Context) (ctx context.Context, cancel context.CancelFunc) { + if parent == nil { + parent = context.Background() + } + + if timeout > 0 { + return context.WithTimeout(parent, timeout) + } else if deadline.Unix() > 0 { + return context.WithDeadline(parent, deadline) + } + + return context.WithCancel(parent) +} + +func GetEmptyTime() time.Time { + return time.Time{} +} diff --git a/njs-semaphore/semaphore.go b/njs-semaphore/semaphore.go index 3661fd2..a2441bb 100644 --- a/njs-semaphore/semaphore.go +++ b/njs-semaphore/semaphore.go @@ -60,22 +60,7 @@ func NewSemaphore(maxSimultaneous int, timeout time.Duration, deadline time.Time maxSimultaneous = GetMaxSimultaneous() } - var ( - c context.CancelFunc - x context.Context - ) - - if parent == nil { - parent = context.Background() - } - - if timeout > 0 { - x, c = context.WithTimeout(parent, timeout) - } else if deadline.Unix() > 0 { - x, c = context.WithDeadline(parent, deadline) - } else { - x, c = context.WithCancel(parent) - } + x, c := GetContext(timeout, deadline, parent) return &sem{ m: int64(maxSimultaneous),