5849898283
Unit tests functional and coverage back to 100% Add more routes to dictionary, add more credentials, add default port 5554, rename cameradar logs ENV variable, improve unit test readability, remove tmp file
123 lines
2.4 KiB
Go
123 lines
2.4 KiB
Go
package wow
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/gernest/wow/spin"
|
|
"golang.org/x/crypto/ssh/terminal"
|
|
)
|
|
|
|
const erase = "\033[2K\r"
|
|
|
|
// Wow writes beautiful spinners on the terminal.
|
|
type Wow struct {
|
|
txt string
|
|
s spin.Spinner
|
|
out io.Writer
|
|
running bool
|
|
done func()
|
|
mu sync.RWMutex
|
|
IsTerminal bool
|
|
}
|
|
|
|
// New creates a new wow instance ready to start spinning.
|
|
func New(o io.Writer, s spin.Spinner, text string, options ...func(*Wow)) *Wow {
|
|
isTerminal := terminal.IsTerminal(int(os.Stdout.Fd()))
|
|
|
|
wow := Wow{out: o, s: s, txt: text, IsTerminal: isTerminal}
|
|
|
|
for _, option := range options {
|
|
option(&wow)
|
|
}
|
|
|
|
return &wow
|
|
}
|
|
|
|
// Start starts the spinner. The frames are written based on the spinner
|
|
// interval.
|
|
func (w *Wow) Start() {
|
|
if !w.running {
|
|
ctx, done := context.WithCancel(context.Background())
|
|
t := time.NewTicker(time.Duration(w.s.Interval) * time.Millisecond)
|
|
w.done = done
|
|
w.running = true
|
|
go func() {
|
|
at := 0
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
t.Stop()
|
|
break
|
|
case <-t.C:
|
|
txt := erase + w.s.Frames[at%len(w.s.Frames)] + w.txt
|
|
if w.IsTerminal {
|
|
fmt.Fprint(w.out, txt)
|
|
}
|
|
at++
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
}
|
|
|
|
// Stop stops the spinner
|
|
func (w *Wow) Stop() {
|
|
if w.done != nil {
|
|
w.done()
|
|
}
|
|
w.running = false
|
|
}
|
|
|
|
// Spinner sets s to the current spinner
|
|
func (w *Wow) Spinner(s spin.Spinner) *Wow {
|
|
w.Stop()
|
|
w.s = s
|
|
w.Start()
|
|
return w
|
|
}
|
|
|
|
// Text adds text to the current spinner
|
|
func (w *Wow) Text(txt string) *Wow {
|
|
w.mu.Lock()
|
|
w.txt = txt
|
|
w.mu.Unlock()
|
|
return w
|
|
}
|
|
|
|
// Persist writes the last character of the currect spinner frames together with
|
|
// the text on stdout.
|
|
//
|
|
// A new line is added at the end to ensure the text stay that way.
|
|
func (w *Wow) Persist() {
|
|
w.Stop()
|
|
at := len(w.s.Frames) - 1
|
|
txt := erase + w.s.Frames[at] + w.txt + "\n"
|
|
if w.IsTerminal {
|
|
fmt.Fprint(w.out, txt)
|
|
}
|
|
}
|
|
|
|
// PersistWith writes the last frame of s together with text with a new line
|
|
// added to make it stick.
|
|
func (w *Wow) PersistWith(s spin.Spinner, text string) {
|
|
w.Stop()
|
|
var a string
|
|
if len(s.Frames) > 0 {
|
|
a = s.Frames[len(s.Frames)-1]
|
|
}
|
|
txt := erase + a + text + "\n"
|
|
if w.IsTerminal {
|
|
fmt.Fprint(w.out, txt)
|
|
}
|
|
}
|
|
|
|
// ForceOutput forces all output even if not not outputting directly to a terminal
|
|
func ForceOutput(w *Wow) {
|
|
w.IsTerminal = true
|
|
}
|