github.com/henvic/wedeploycli@v1.7.6-0.20200319005353-3630f582f284/waitlivemsg/waitlivemsg.go (about) 1 package waitlivemsg 2 3 import ( 4 "fmt" 5 "sync" 6 "time" 7 8 "bytes" 9 10 "github.com/henvic/uilive" 11 ) 12 13 var spinners = []string{ 14 "⠋", 15 "⠙", 16 "⠹", 17 "⠸", 18 "⠼", 19 "⠴", 20 "⠦", 21 "⠧", 22 "⠇", 23 "⠏", 24 } 25 26 // Message to print 27 type Message struct { 28 text string 29 counter int 30 mutex sync.RWMutex 31 } 32 33 // NewMessage creates a Message with a given text 34 func NewMessage(text string) *Message { 35 var m = Message{} 36 m.PlayText(text) 37 return &m 38 } 39 40 // EmptyLine creates a Message with an empty line 41 // it has the side-effect of using no symbols as prefixes 42 func EmptyLine() *Message { 43 return NewMessage("") 44 } 45 46 // PlayText as a live message 47 func (m *Message) PlayText(text string) { 48 m.mutex.Lock() 49 m.text = text 50 if m.counter == -1 { 51 m.counter = 0 52 } 53 m.mutex.Unlock() 54 } 55 56 // StopText of the live messages 57 func (m *Message) StopText(text string) { 58 m.mutex.Lock() 59 m.text = text 60 m.counter = -1 61 m.mutex.Unlock() 62 } 63 64 // GetText of the message 65 func (m *Message) GetText() string { 66 m.mutex.RLock() 67 var text = m.text 68 m.mutex.RUnlock() 69 return text 70 } 71 72 func (m *Message) getSymbol() string { 73 m.mutex.RLock() 74 var c = m.counter 75 m.mutex.RUnlock() 76 77 if c == -1 || m.text == "" { 78 return "" 79 } 80 81 var symbol = spinners[c] 82 m.mutex.Lock() 83 m.counter = (c + 1) % len(spinners) 84 m.mutex.Unlock() 85 86 return symbol 87 } 88 89 func (m *Message) getText() string { 90 m.mutex.RLock() 91 defer m.mutex.RUnlock() 92 return m.text 93 } 94 95 // End of live message 96 func (m *Message) End() { 97 m.mutex.Lock() 98 m.counter = -1 99 m.mutex.Unlock() 100 } 101 102 // WaitLiveMsg is used for "waiting" live message 103 type WaitLiveMsg struct { 104 msgs []*Message 105 stream *uilive.Writer 106 msgsMutex sync.RWMutex 107 start time.Time 108 tickerd chan bool 109 tickerdMutex sync.RWMutex 110 waitEnd sync.WaitGroup 111 } 112 113 // New creates a WaitLiveMsg 114 func New(ws *uilive.Writer) *WaitLiveMsg { 115 if ws == nil { 116 ws = uilive.New() 117 } 118 119 return &WaitLiveMsg{ 120 stream: ws, 121 } 122 } 123 124 // AddMessage to display 125 func (w *WaitLiveMsg) AddMessage(msg *Message) { 126 w.msgsMutex.Lock() 127 w.msgs = append(w.msgs, msg) 128 w.msgsMutex.Unlock() 129 } 130 131 // SetMessage to display 132 func (w *WaitLiveMsg) SetMessage(msg *Message) { 133 w.msgsMutex.Lock() 134 w.msgs = []*Message{msg} 135 w.msgsMutex.Unlock() 136 } 137 138 // SetMessages to display 139 func (w *WaitLiveMsg) SetMessages(msgs []*Message) { 140 w.msgsMutex.Lock() 141 w.msgs = msgs 142 w.msgsMutex.Unlock() 143 } 144 145 // GetMessages displayed 146 func (w *WaitLiveMsg) GetMessages() []*Message { 147 w.msgsMutex.RLock() 148 defer w.msgsMutex.RUnlock() 149 return w.msgs 150 } 151 152 // RemoveMessage from the messages slice 153 func (w *WaitLiveMsg) RemoveMessage(msg *Message) { 154 w.msgsMutex.Lock() 155 var newSlice = []*Message{} 156 for _, m := range w.msgs { 157 if m != msg { 158 newSlice = append(newSlice, m) 159 } 160 } 161 w.msgs = newSlice 162 w.msgsMutex.Unlock() 163 } 164 165 // ResetMessages to display 166 func (w *WaitLiveMsg) ResetMessages() { 167 w.msgsMutex.Lock() 168 w.msgs = []*Message{} 169 w.msgsMutex.Unlock() 170 } 171 172 // SetStream to output to 173 func (w *WaitLiveMsg) SetStream(ws *uilive.Writer) { 174 w.msgsMutex.Lock() 175 w.stream = ws 176 w.msgsMutex.Unlock() 177 } 178 179 // Wait starts the waiting message 180 func (w *WaitLiveMsg) Wait() { 181 w.waitEnd.Add(1) 182 w.tickerdMutex.Lock() 183 w.tickerd = make(chan bool, 1) 184 w.start = time.Now() 185 w.tickerdMutex.Unlock() 186 187 w.waitLoop() 188 189 w.print() 190 w.waitEnd.Done() 191 } 192 193 func (w *WaitLiveMsg) waitLoop() { 194 var ticker = time.NewTicker(60 * time.Millisecond) 195 for { 196 w.tickerdMutex.RLock() 197 select { 198 case <-ticker.C: 199 w.print() 200 case <-w.tickerd: 201 ticker.Stop() 202 ticker = nil 203 return 204 } 205 w.tickerdMutex.RUnlock() 206 } 207 } 208 209 // Stop the waiting message 210 func (w *WaitLiveMsg) Stop() { 211 w.msgsMutex.RLock() 212 for _, m := range w.msgs { 213 m.mutex.RLock() 214 c := m.counter 215 m.mutex.RUnlock() 216 if c != -1 { 217 m.End() 218 } 219 } 220 w.msgsMutex.RUnlock() 221 w.tickerdMutex.Lock() 222 223 if w.tickerd != nil { 224 w.tickerd <- true 225 } 226 227 w.tickerdMutex.Unlock() 228 w.waitEnd.Wait() 229 } 230 231 // ResetDuration to restart counter 232 func (w *WaitLiveMsg) ResetDuration() { 233 w.tickerdMutex.RLock() 234 w.start = time.Now() 235 w.tickerdMutex.RUnlock() 236 } 237 238 // Duration in seconds 239 func (w *WaitLiveMsg) Duration() time.Duration { 240 w.tickerdMutex.RLock() 241 var duration = time.Since(w.start) 242 w.tickerdMutex.RUnlock() 243 return duration 244 } 245 246 func (w *WaitLiveMsg) print() { 247 var buf = bytes.Buffer{} 248 249 w.msgsMutex.RLock() 250 var msgs = w.msgs 251 w.msgsMutex.RUnlock() 252 253 for _, m := range msgs { 254 var txt = m.getText() 255 256 if len(txt) == 0 { 257 continue 258 } 259 260 var s = m.getSymbol() 261 262 if len(s) != 0 { 263 buf.WriteString(s) 264 buf.WriteString(" ") 265 } 266 267 buf.WriteString(txt) 268 buf.WriteString("\n") 269 } 270 271 w.pb(buf) 272 } 273 274 func (w *WaitLiveMsg) pb(buf bytes.Buffer) { 275 w.msgsMutex.Lock() 276 defer w.msgsMutex.Unlock() 277 _, _ = fmt.Fprintf(w.stream, "%v", buf.String()) 278 _ = w.stream.Flush() 279 }