mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-11-12 13:18:03 +00:00
The RF endpoint now applies the current blacklist and hidden-name policy to both exposed node metadata and deviations, including after cache warm-up. Unhiding a node restores its data without waiting for cache expiry. Fixes #2268. The shared RF snapshot and peer calculation remain unchanged; filtering copies only the response data. This adds a linear node pass and bounded deviation copies, with no additional database calls or cache invalidation. The feature remains opt-in. Validation: RED reproduces both response leaks. The full server and standalone frontend suites pass, as do focused race tests and the RF browser suite. Regressions cover warm/cold caches, policy updates, unhide, visible controls and default-off behavior. Common ingestor validation is covered by the separate #2272 test-stability change.
70 lines
2.0 KiB
Go
70 lines
2.0 KiB
Go
package main
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// handleRfParams — GET /api/rf-params (issue #1268).
|
|
//
|
|
// Returns the radio settings the MeshCore map holds for the visible nodes this
|
|
// instance knows, limited to adverts within maxAgeDays and not dated in the
|
|
// future (rfAdvertFresh), plus the named presets and when the map was last
|
|
// fetched. Served straight from the atomic snapshot; never waits on the
|
|
// upstream fetch.
|
|
func (s *Server) handleRfParams(w http.ResponseWriter, r *http.Request) {
|
|
resp := RfParamsResponse{Presets: []RfPreset{}, Nodes: map[string]RfParams{}, Deviations: map[string]RfDeviation{}}
|
|
if s.rfParams == nil {
|
|
writeJSON(w, resp)
|
|
return
|
|
}
|
|
resp.Enabled = true
|
|
snap := s.rfParams.load()
|
|
if snap == nil {
|
|
w.Header().Set("Cache-Control", "public, max-age=30")
|
|
writeJSON(w, resp)
|
|
return
|
|
}
|
|
fetched := snap.FetchedAt
|
|
resp.FetchedAt = &fetched
|
|
resp.Source = snap.Source
|
|
if snap.Presets != nil {
|
|
resp.Presets = snap.Presets
|
|
}
|
|
now := time.Now().UTC()
|
|
maxAge := s.rfParams.cfg.maxAge()
|
|
nodes, _ := s.store.getCachedNodesAndPM()
|
|
for _, n := range nodes {
|
|
pk := strings.ToLower(n.PublicKey)
|
|
p, ok := snap.Nodes[pk]
|
|
if !ok {
|
|
continue
|
|
}
|
|
if at, err := time.Parse(time.RFC3339, p.LastAdvert); err != nil || !rfAdvertFresh(at, now, maxAge) {
|
|
continue
|
|
}
|
|
resp.Nodes[pk] = p
|
|
}
|
|
deviations := s.rfParams.deviations.get(snap, time.Now(), func() map[string]RfDeviation {
|
|
return computeRfDeviations(resp.Nodes, nodes, s.rfParams.cfg.compareRadiusKm(), rfMinPeers)
|
|
})
|
|
// Keep the shared computation independent of visibility. Filter only the
|
|
// response maps so hiding or unhiding a node takes effect even on a cache hit.
|
|
for _, n := range nodes {
|
|
pk := strings.ToLower(n.PublicKey)
|
|
if _, fresh := resp.Nodes[pk]; !fresh {
|
|
continue
|
|
}
|
|
if s.cfg.IsBlacklisted(pk) || s.cfg.IsNameHidden(n.Name) {
|
|
delete(resp.Nodes, pk)
|
|
continue
|
|
}
|
|
if d, ok := deviations[pk]; ok {
|
|
resp.Deviations[pk] = d
|
|
}
|
|
}
|
|
w.Header().Set("Cache-Control", "public, max-age=300")
|
|
writeJSON(w, resp)
|
|
}
|