Files
tia-love/internal/app/events.go
T

95 lines
2.3 KiB
Go

package app
import (
"context"
"strings"
"time"
tea "charm.land/bubbletea/v2"
"gitea.oxpoe.qzz.io/oxpoe/tia-love/internal/docker"
"gitea.oxpoe.qzz.io/oxpoe/tia-love/internal/i18n"
)
// eventMsg — satu event Docker dari stream (volume rendah; 1 event = 1 render).
type eventMsg struct {
id int64
ev docker.Event
}
type eventsClosedMsg struct{ id int64 }
type eventsRetryMsg struct{ id int64 }
type refreshTickMsg struct{ gen int64 }
const (
activityMax = 20
refreshDebounce = 500 * time.Millisecond
eventsRetryDelay = 5 * time.Second
)
// startEvents — (re)buka stream event daemon. Dipanggil dari New (init), `r`,
// dan retry otomatis saat koneksi putus.
func (m *Model) startEvents() tea.Cmd {
if m.eventsCancel != nil {
m.eventsCancel()
m.eventsCancel = nil
}
m.eventsCh = nil
if m.cl == nil {
return nil
}
m.eventsID++
ctx, cancel := context.WithCancel(context.Background())
m.eventsCancel = cancel
m.eventsCh = m.cl.StreamEvents(ctx)
return waitEvent(m.eventsID, m.eventsCh)
}
func waitEvent(id int64, ch <-chan docker.Event) tea.Cmd {
return func() tea.Msg {
ev, ok := <-ch
if !ok {
return eventsClosedMsg{id: id}
}
return eventMsg{id: id, ev: ev}
}
}
func refreshAfter(gen int64) tea.Cmd {
return tea.Tick(refreshDebounce, func(time.Time) tea.Msg { return refreshTickMsg{gen: gen} })
}
func eventsRetry(id int64) tea.Cmd {
return tea.Tick(eventsRetryDelay, func(time.Time) tea.Msg { return eventsRetryMsg{id: id} })
}
// evTypeKey — jenis event → kunci katalog bagian (untuk label terjemahan).
func evTypeKey(t string) string {
switch t {
case "image":
return "images"
case "volume":
return "volumes"
case "network":
return "networks"
default:
return "containers"
}
}
// activityLines — event terbaru di atas (untuk panel Aktivitas di beranda).
func (m Model) activityLines(w, h int) []string {
if len(m.activity) == 0 {
return []string{dim(i18n.T("activity.waiting"))}
}
out := make([]string, 0, h)
for i := len(m.activity) - 1; i >= 0 && len(out) < h; i-- {
ev := m.activity[i]
label := strings.ToLower(i18n.T("section." + evTypeKey(ev.Type)))
out = append(out, dim(ev.At.Format("15:04:05"))+" "+
dim("["+label+"]")+" "+
text("'"+truncate(ev.Actor, 20)+"'")+" "+
dim(truncate(ev.Action, 24)))
}
return out
}