Add Starlink status lines for the physical gateway pane (closes #3)
check / check (push) Failing after 1s

When the non-VPN physical gateway is a Starlink dish, two lines are shown
under that pane: state, uptime, obstruction and alert count; then pop-ping
latency and drop rate with downlink/uplink throughput. They turn red when
the dish is not connected or an alert is active.

Detection is a TCP connect to the dish's fixed endpoint 192.168.100.1:9200,
bound to the physical interface the same way the latency probes bind. Until
a dish answers nothing is drawn and no status is fetched, so an absent dish
adds no noise. Status comes from the dish's local get_status gRPC call.

Detection and the fetch sit behind a small Client interface; the loop and
the pure Render function are tested with a fake, no dish and no network.

Model: opus-4-8
This commit is contained in:
2026-09-21 22:51:45 +00:00
parent 486a47397c
commit e3ef4f2f48
15 changed files with 1535 additions and 0 deletions
+45
View File
@@ -1,7 +1,52 @@
package monitor
import (
"context"
"git.eeqj.de/sneak/rtnetmon/internal/starlink"
)
// Test-only accessors exposing unexported state for white-box assertions.
// SetStarlinkClient injects a Starlink client for iface, bypassing the real
// gRPC dialer so the loop can be driven with a fake.
func (m *Monitor) SetStarlinkClient(iface string, c starlink.Client) {
for _, st := range m.interfaces {
if st.Name == iface {
m.slPane = st
m.slState = &starlinkState{}
m.slClient = c
return
}
}
}
// StarlinkEnabled reports whether a Starlink client is configured.
func (m *Monitor) StarlinkEnabled() bool { return m.slClient != nil }
// StarlinkPaneName returns the name of the pane the Starlink lines attach
// to, or "" if none.
func (m *Monitor) StarlinkPaneName() string {
if m.slPane == nil {
return ""
}
return m.slPane.Name
}
// StarlinkProbeStep runs one detection step.
func (m *Monitor) StarlinkProbeStep(ctx context.Context) { m.starlinkProbe(ctx) }
// StarlinkRefreshStep runs one status-refresh step.
func (m *Monitor) StarlinkRefreshStep(ctx context.Context) { m.starlinkRefresh(ctx) }
// StarlinkSnapshot returns the current Starlink display state: detected,
// have-status, and the latest status.
func (m *Monitor) StarlinkSnapshot() (bool, bool, starlink.Status) {
return m.slState.snapshot()
}
// ReachabilityHosts returns the configured reachability hosts.
func (m *Monitor) ReachabilityHosts() []string { return m.reachabilityHosts }