105 lines
2.2 KiB
Go
105 lines
2.2 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
)
|
|
|
|
// modelConfig is the static configuration the dashboard needs beyond the
|
|
// scanner.
|
|
type modelConfig struct {
|
|
Interval time.Duration
|
|
Title string
|
|
BaseURL string
|
|
}
|
|
|
|
// tickMsg drives the clock and the scan countdown.
|
|
type tickMsg time.Time
|
|
|
|
// snapshotMsg carries a finished scan back into the model.
|
|
type snapshotMsg snapshot
|
|
|
|
type model struct {
|
|
sc *scanner
|
|
cfg modelConfig
|
|
snap snapshot
|
|
// scanErr is kept separately so a failed refresh does not erase the last
|
|
// successful data from the display.
|
|
scanErr error
|
|
|
|
scanning bool
|
|
nextScanAt time.Time
|
|
|
|
width, height int
|
|
ready bool
|
|
}
|
|
|
|
func newModel(sc *scanner, cfg modelConfig) model {
|
|
return model{sc: sc, cfg: cfg, nextScanAt: time.Now()}
|
|
}
|
|
|
|
func (m model) Init() tea.Cmd {
|
|
return tea.Batch(tickClock(), m.scanCmd())
|
|
}
|
|
|
|
func tickClock() tea.Cmd {
|
|
return tea.Tick(time.Second, func(t time.Time) tea.Msg { return tickMsg(t) })
|
|
}
|
|
|
|
func (m *model) scanCmd() tea.Cmd {
|
|
sc := m.sc
|
|
return func() tea.Msg { return snapshotMsg(sc.Scan(context.Background(), time.Now())) }
|
|
}
|
|
|
|
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|
switch msg := msg.(type) {
|
|
case tea.WindowSizeMsg:
|
|
m.width, m.height, m.ready = msg.Width, msg.Height, true
|
|
return m, nil
|
|
|
|
case tea.KeyMsg:
|
|
switch msg.String() {
|
|
case "q", "esc", "ctrl+c":
|
|
return m, tea.Quit
|
|
case "r":
|
|
if !m.scanning {
|
|
m.scanning = true
|
|
return m, m.scanCmd()
|
|
}
|
|
return m, nil
|
|
}
|
|
return m, nil
|
|
|
|
case tickMsg:
|
|
now := time.Time(msg)
|
|
cmd := tickClock()
|
|
if !m.scanning && !now.Before(m.nextScanAt) {
|
|
m.scanning = true
|
|
return m, tea.Batch(cmd, m.scanCmd())
|
|
}
|
|
return m, cmd
|
|
|
|
case snapshotMsg:
|
|
snap := snapshot(msg)
|
|
if snap.Err != nil {
|
|
m.scanErr = snap.Err
|
|
} else {
|
|
m.snap = snap
|
|
m.scanErr = nil
|
|
}
|
|
m.scanning = false
|
|
m.nextScanAt = time.Now().Add(m.cfg.Interval)
|
|
return m, nil
|
|
}
|
|
return m, nil
|
|
}
|
|
|
|
func (m model) View() string {
|
|
return renderSnapshot(m.snap, snapshotOptions{
|
|
Width: m.width, Height: m.height, Title: m.cfg.Title, BaseURL: m.cfg.BaseURL,
|
|
Scanning: m.scanning, NextScanAt: m.nextScanAt, Now: time.Now(), ScanError: m.scanErr,
|
|
})
|
|
}
|