a6bb9a7aff
Remove store.Get()/SetGlobal()/Current. Store is now passed explicitly to all consumers via constructor parameters and function arguments. - TUI Model holds store field, set via InitialModel(isAdmin, store) - monitor.StartEngine(s) and InitHistoryFromStore(s) accept store - server.Start(cfg, s) closes over store in HTTP handlers - main.go threads store to SSH server, TUI, monitor, server - isKeyAllowed receives store as parameter No more hidden dependency on package-level mutable state in store pkg. Monitor package still uses package-level state (LiveState, etc.) — will be encapsulated into Engine struct in Phase 7.
101 lines
2.0 KiB
Go
101 lines
2.0 KiB
Go
package monitor
|
|
|
|
import (
|
|
"go-upkeep/internal/store"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
const maxHistoryLen = 30
|
|
|
|
type SiteHistory struct {
|
|
Latencies []time.Duration
|
|
Statuses []bool
|
|
TotalChecks int
|
|
UpChecks int
|
|
}
|
|
|
|
var (
|
|
histories = make(map[int]*SiteHistory)
|
|
historyMu sync.RWMutex
|
|
)
|
|
|
|
func InitHistoryFromStore(s store.Store) {
|
|
all, err := s.LoadAllHistory(maxHistoryLen)
|
|
if err != nil {
|
|
AddLog("Failed to load check history: " + err.Error())
|
|
return
|
|
}
|
|
historyMu.Lock()
|
|
defer historyMu.Unlock()
|
|
for siteID, records := range all {
|
|
h := &SiteHistory{}
|
|
for _, r := range records {
|
|
h.TotalChecks++
|
|
if r.IsUp {
|
|
h.UpChecks++
|
|
}
|
|
h.Latencies = append(h.Latencies, time.Duration(r.LatencyNs))
|
|
h.Statuses = append(h.Statuses, r.IsUp)
|
|
}
|
|
histories[siteID] = h
|
|
}
|
|
if len(all) > 0 {
|
|
AddLog("Loaded check history from database")
|
|
}
|
|
}
|
|
|
|
func RecordCheck(siteID int, latency time.Duration, isUp bool) {
|
|
historyMu.Lock()
|
|
defer historyMu.Unlock()
|
|
|
|
h, ok := histories[siteID]
|
|
if !ok {
|
|
h = &SiteHistory{}
|
|
histories[siteID] = h
|
|
}
|
|
|
|
h.TotalChecks++
|
|
if isUp {
|
|
h.UpChecks++
|
|
}
|
|
|
|
h.Latencies = append(h.Latencies, latency)
|
|
if len(h.Latencies) > maxHistoryLen {
|
|
h.Latencies = h.Latencies[len(h.Latencies)-maxHistoryLen:]
|
|
}
|
|
|
|
h.Statuses = append(h.Statuses, isUp)
|
|
if len(h.Statuses) > maxHistoryLen {
|
|
h.Statuses = h.Statuses[len(h.Statuses)-maxHistoryLen:]
|
|
}
|
|
|
|
if db != nil {
|
|
go func() { _ = db.SaveCheck(siteID, latency.Nanoseconds(), isUp) }()
|
|
}
|
|
}
|
|
|
|
func GetHistory(siteID int) (SiteHistory, bool) {
|
|
historyMu.RLock()
|
|
defer historyMu.RUnlock()
|
|
h, ok := histories[siteID]
|
|
if !ok {
|
|
return SiteHistory{}, false
|
|
}
|
|
cp := SiteHistory{
|
|
TotalChecks: h.TotalChecks,
|
|
UpChecks: h.UpChecks,
|
|
Latencies: make([]time.Duration, len(h.Latencies)),
|
|
Statuses: make([]bool, len(h.Statuses)),
|
|
}
|
|
copy(cp.Latencies, h.Latencies)
|
|
copy(cp.Statuses, h.Statuses)
|
|
return cp, true
|
|
}
|
|
|
|
func RemoveHistory(siteID int) {
|
|
historyMu.Lock()
|
|
defer historyMu.Unlock()
|
|
delete(histories, siteID)
|
|
}
|