Zone-based firewall page, per-sensor temperatures, 15 minute default
The firewall page now manages zones (assign each LAN or tunnel, add and remove zones) and rules with zone, address and port on both sides plus the protocol. router.firewall.zones declares zones without members and rules take sourcePorts. The temperature chart draws every thermal zone and hwmon sensor; the overview defaults to 15 minutes, 1h stays an option. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AeFqV9dZrK6nipHkPfyM4F
This commit is contained in:
@@ -120,14 +120,18 @@ type seriesSpec struct {
|
||||
Scale float64 // e.g. 8 for bytes/s -> bit/s
|
||||
}
|
||||
|
||||
func (a *app) chart(title, unit string, tier int, now time.Time, specs []seriesSpec) Chart {
|
||||
func (a *app) chart(title, unit string, rg timeRange, now time.Time, specs []seriesSpec) Chart {
|
||||
c := Chart{Title: title, Unit: unit}
|
||||
var start time.Time
|
||||
var step time.Duration
|
||||
cols := make([][]float64, len(specs))
|
||||
ymax := 0.0
|
||||
for i, sp := range specs {
|
||||
st, stp, vals := a.metrics.store.Read(sp.Name, tier, now)
|
||||
st, stp, vals := a.metrics.store.Read(sp.Name, rg.Tier, now)
|
||||
if keep := rg.slots(); keep < len(vals) {
|
||||
st = st.Add(stp * time.Duration(len(vals)-keep))
|
||||
vals = vals[len(vals)-keep:]
|
||||
}
|
||||
start, step = st, stp
|
||||
cols[i] = downsample(vals, chartCols, sp.Scale)
|
||||
for _, v := range cols[i] {
|
||||
@@ -137,7 +141,7 @@ func (a *app) chart(title, unit string, tier int, now time.Time, specs []seriesS
|
||||
}
|
||||
}
|
||||
n := chartCols
|
||||
span := step * time.Duration(tiers[tier].Slots)
|
||||
span := step * time.Duration(rg.slots())
|
||||
colDur := span / time.Duration(n)
|
||||
if unit == "%" {
|
||||
ymax = math.Max(ymax, 1)
|
||||
@@ -148,7 +152,7 @@ func (a *app) chart(title, unit string, tier int, now time.Time, specs []seriesS
|
||||
ymax = niceCeil(ymax)
|
||||
c.Empty = true
|
||||
for i, sp := range specs {
|
||||
line := ChartLine{Label: sp.Label, Class: fmt.Sprintf("s%d", i), Now: "–"}
|
||||
line := ChartLine{Label: sp.Label, Class: fmt.Sprintf("s%d", i%10), Now: "–"}
|
||||
var path strings.Builder
|
||||
pen := false
|
||||
for j, v := range cols[i] {
|
||||
@@ -316,18 +320,18 @@ type dashboard struct {
|
||||
}
|
||||
|
||||
func (a *app) dashboardData(rangeName string) dashboard {
|
||||
tier, rangeName := rangeTier(rangeName)
|
||||
rg := findRange(rangeName)
|
||||
now := time.Now()
|
||||
s, _ := loadSettings(a.sys.settingsPath())
|
||||
f := s.form()
|
||||
d := dashboard{Range: rangeName, Interval: 5, Snap: a.metrics.Snapshot(), Prefs: a.sys.loadPrefs()}
|
||||
d := dashboard{Range: rg.Name, Interval: 5, Snap: a.metrics.Snapshot(), Prefs: a.sys.loadPrefs()}
|
||||
// Newest first, the last few.
|
||||
ev := d.Snap.Uplink.Events
|
||||
d.Events = make([]Event, 0, 10)
|
||||
for i := len(ev) - 1; i >= 0 && len(d.Events) < 10; i-- {
|
||||
d.Events = append(d.Events, ev[i])
|
||||
}
|
||||
if tier > 0 {
|
||||
if rg.Tier > 0 {
|
||||
d.Interval = 60
|
||||
}
|
||||
for _, r := range ranges {
|
||||
@@ -336,7 +340,7 @@ func (a *app) dashboardData(rangeName string) dashboard {
|
||||
d.Leases = readLeases(a.metrics.leasesPath, f.LANs, now)
|
||||
|
||||
traffic := func(title, dev string) Chart {
|
||||
return a.chart(title, "bit/s", tier, now, []seriesSpec{
|
||||
return a.chart(title, "bit/s", rg, now, []seriesSpec{
|
||||
{"if:" + dev + ":rx", "down", 8},
|
||||
{"if:" + dev + ":tx", "up", 8},
|
||||
})
|
||||
@@ -359,12 +363,16 @@ func (a *app) dashboardData(rangeName string) dashboard {
|
||||
loss = append(loss, seriesSpec{"ping:" + t + ":loss", t, 1})
|
||||
}
|
||||
if len(rtt) > 0 {
|
||||
d.Charts = append(d.Charts, a.chart("Latency", "ms", tier, now, rtt), a.chart("Packet loss", "%", tier, now, loss))
|
||||
d.Charts = append(d.Charts, a.chart("Latency", "ms", rg, now, rtt), a.chart("Packet loss", "%", rg, now, loss))
|
||||
}
|
||||
d.Charts = append(d.Charts,
|
||||
a.chart("CPU and memory", "%", tier, now, []seriesSpec{{"sys:cpu", "CPU", 1}, {"sys:mem", "memory", 1}}))
|
||||
if temp := a.chart("Temperature", "°C", tier, now, []seriesSpec{{"sys:temp", "hottest sensor", 1}}); !temp.Empty || !math.IsNaN(d.Snap.System.Temperature) {
|
||||
d.Charts = append(d.Charts, temp)
|
||||
a.chart("CPU and memory", "%", rg, now, []seriesSpec{{"sys:cpu", "CPU", 1}, {"sys:mem", "memory", 1}}))
|
||||
var temps []seriesSpec
|
||||
for _, t := range d.Snap.System.Sensors {
|
||||
temps = append(temps, seriesSpec{"temp:" + t.Key, t.Label, 1})
|
||||
}
|
||||
if len(temps) > 0 {
|
||||
d.Charts = append(d.Charts, a.chart("Temperature", "°C", rg, now, temps))
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user