Files
learngo/30-concurrency/xxx-concurrent-downloader/fetch/ui.go
2019-04-27 20:18:24 +03:00

97 lines
2.0 KiB
Go

package fetch
import (
"fmt"
"time"
"github.com/inancgumus/screen"
)
const refreshPeriod = time.Second / 10
// uiProgress is the default UI for the downloader
type uiProgress struct {
urls []string
transfers map[string]Progress
}
// UI listens for the progress updates from the updates chan
// and it refreshes the ui
func UI(updates <-chan Progress) {
ui := &uiProgress{transfers: make(map[string]Progress)}
// NOTE: we didn't use time.After here directly
// because doing so can create a lot of Timer chans unnecessarily
// instead we're just waiting on the same timer value
tick := time.After(refreshPeriod)
for {
select {
case p, ok := <-updates:
// if no more updates close the ui
if !ok {
ui.shutdown()
return
}
ui.update(p)
case <-tick:
// `case <-tick:` allows updating the ui independently
// from the progress update signals. or the ui would hang
// the updaters (transfers).
ui.refresh()
tick = time.After(refreshPeriod)
}
}
}
// shutdown refreshes the ui for the last time and closes it
func (ui *uiProgress) shutdown() {
ui.refresh()
if debug {
fmt.Printf("[ UI ] DONE\n")
}
}
// update updates the progress data from the received message
func (ui *uiProgress) update(p Progress) {
if _, ok := ui.transfers[p.URL]; !ok {
ui.urls = append(ui.urls, p.URL)
}
// update the latest progress for the url
ui.transfers[p.URL] = p
}
// refresh refreshes the UI with the latest progress
func (ui *uiProgress) refresh() {
if !debug {
screen.Clear()
screen.MoveTopLeft()
}
var total, downloaded int
for _, u := range ui.urls {
p := ui.transfers[u]
msg := "Downloading"
if p.Done && p.Error == nil {
msg = "👍 Completed"
}
if p.Error != nil {
msg = fmt.Sprintf("❌ %s", p.Error)
}
fmt.Println(p.URL)
fmt.Printf("\t%d/%d\n", p.Downloaded, p.Total)
fmt.Printf("\t%s\n", msg)
total += p.Total
downloaded += p.Downloaded
}
fmt.Printf("\n%s %d/%d\n", "TOTAL DOWNLOADED BYTES:", downloaded, total)
}