commit f3bfb03738e3f6e91260ee4ba6c98e8a63136b61 Author: nxshock Date: Wed Jun 30 18:35:00 2021 +0500 Initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f1c181e --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f9749a2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 nxshock + +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. diff --git a/progressmessage.go b/progressmessage.go new file mode 100644 index 0000000..ddb3e87 --- /dev/null +++ b/progressmessage.go @@ -0,0 +1,118 @@ +package progressmessage + +import ( + "fmt" + "io" + "os" + "sync" + "time" +) + +var ( + defaultWriter = os.Stderr + defaultUpdatePeriod = time.Second + defaultMessageDelimiter = "\r" +) + +type ProgressMessage struct { + // message format + format string + + // list of message params + params []interface{} + + // ticker for updating message + ticker *time.Ticker + + // chan for stopping updates + stopChan chan struct{} + + // previous message to prevent output of same message more than one time + prevMessage string + + writer io.Writer + isStarted bool + + // message update period + updatePeriod time.Duration + + mu sync.RWMutex +} + +func New(format string) *ProgressMessage { + pm := &ProgressMessage{ + format: format, + + stopChan: make(chan struct{}), + writer: defaultWriter, + updatePeriod: defaultUpdatePeriod} + + return pm +} + +func (pm *ProgressMessage) ChangeWriter(newWriter io.Writer) { + pm.mu.Lock() + defer pm.mu.Unlock() + + pm.writer = newWriter +} + +func (pm *ProgressMessage) ChangeFormat(newFormat string) { + pm.mu.Lock() + defer pm.mu.Unlock() + + pm.format = newFormat +} + +func (pm *ProgressMessage) Update(params ...interface{}) { + // TODO: use mutex? + + pm.params = params +} + +func (pm *ProgressMessage) ChangeUpdatePeriod(newUpdatePeriod time.Duration) { + pm.mu.Lock() + defer pm.mu.Unlock() + + if pm.isStarted { + defer func() { + pm.Stop() + pm.Start() + }() + } + + pm.updatePeriod = newUpdatePeriod +} + +func (pm *ProgressMessage) Start() { + pm.isStarted = true + + go func() { + pm.ticker = time.NewTicker(pm.updatePeriod) + + for { + select { + case <-pm.ticker.C: + if pm.params == nil { + continue + } + + m := fmt.Sprintf(pm.format, pm.params...) + if m == pm.prevMessage { + continue + } + pm.writer.Write([]byte(defaultMessageDelimiter + m)) + pm.prevMessage = m + case <-pm.stopChan: + pm.ticker.Stop() + break + } + } + }() +} + +func (pm *ProgressMessage) Stop() { + pm.stopChan <- struct{}{} + + pm.isStarted = false +}