Files
felhom.eu/hub/internal/web/pbsdr_box.go
T

115 lines
3.5 KiB
Go

package web
// PBS DR datastore fill surfaces (v0.65.0, R-5): the Offsite "PBS DR" tab panel + the Dashboard PBS
// gauge. The web layer reads only the checker's cached snapshot (s.pbsdrBox) — it never polls ep0. The
// snapshot carries its own state (ok / unavailable / degraded) so the UI renders each honestly.
import (
"fmt"
"time"
"gitea.dooplex.hu/admin/felhom-hub/internal/monitor"
)
// pbsdrBoxView is the PBS-DR panel model.
type pbsdrBoxView struct {
Configured bool // s.pbsdrBox wired (tenantsync client present)
Pending bool // configured but the first poll hasn't landed yet
State string // ok | unavailable | degraded
Unavailable bool // endpoint script predates the usage op (≤ v1.1.0) — expected pre-update
Degraded bool // last poll failed — values shown stale
HasFill bool // numbers available (ok or degraded-with-last-known)
CapacityStr string
UsedStr string
UsedExact string // R-92: exact bytes ("8 590 000 000 bytes") — UsedStr is 0.1 GB-granular
FillPercent float64
FillBand string
FetchedAt time.Time
}
// fmtBytesExact renders the exact byte count grouped by spaces ("8 590 000 000 bytes"), so a
// 50 MB delta on the PBS DR datastore is visible next to the 0.1 GB-granular UsedStr (R-92).
func fmtBytesExact(b int64) string {
neg := b < 0
if neg {
b = -b
}
digits := fmt.Sprintf("%d", b)
var out []byte
for i := range digits {
if i > 0 && (len(digits)-i)%3 == 0 {
out = append(out, ' ')
}
out = append(out, digits[i])
}
if neg {
return "-" + string(out) + " bytes"
}
return string(out) + " bytes"
}
// pbsdrTile is the compact Dashboard PBS gauge: fill %, band-colored; "n/a" when unavailable.
type pbsdrTile struct {
Unavailable bool
FillPercent float64
Band string
Degraded bool
}
// pbsdrBoxData builds the PBS-DR panel view. Nil provider → Configured:false ("not configured"). Never polls.
func (s *Server) pbsdrBoxData() pbsdrBoxView {
if s.pbsdrBox == nil {
return pbsdrBoxView{Configured: false}
}
view := pbsdrBoxView{Configured: true}
snap, ok := s.pbsdrBox()
if !ok {
view.Pending = true // configured, first poll pending
return view
}
view.State = snap.State
view.FetchedAt = snap.FetchedAt
switch snap.State {
case monitor.PBSStateUnavailable:
view.Unavailable = true
case monitor.PBSStateDegraded:
view.Degraded = true
if snap.CapacityBytes > 0 { // last-known values persist across a degraded poll
view.HasFill = true
view.CapacityStr = fmtBytesGB(snap.CapacityBytes)
view.UsedStr = fmtBytesGB(snap.UsedBytes)
view.UsedExact = fmtBytesExact(snap.UsedBytes)
view.FillPercent = snap.FillPercent
view.FillBand = snap.FillBand
}
default: // ok
view.HasFill = true
view.CapacityStr = fmtBytesGB(snap.CapacityBytes)
view.UsedStr = fmtBytesGB(snap.UsedBytes)
view.UsedExact = fmtBytesExact(snap.UsedBytes)
view.FillPercent = snap.FillPercent
view.FillBand = snap.FillBand
}
return view
}
// pbsdrBoxTile builds the Dashboard PBS gauge, or nil when there is nothing to show (no provider, or the
// first poll hasn't landed). Unavailable → a neutral "n/a" gauge (never a fake 0%).
func (s *Server) pbsdrBoxTile() *pbsdrTile {
if s.pbsdrBox == nil {
return nil
}
snap, ok := s.pbsdrBox()
if !ok {
return nil
}
if snap.State == monitor.PBSStateUnavailable {
return &pbsdrTile{Unavailable: true}
}
return &pbsdrTile{
FillPercent: snap.FillPercent,
Band: snap.FillBand,
Degraded: snap.State == monitor.PBSStateDegraded,
}
}