mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-05-12 03:54:45 +00:00
e86b5a3a0c
## Summary Show 2-byte hash support indicator on map markers. Fixes #903. ## What changed ### Backend (`cmd/server/store.go`, `cmd/server/routes.go`) - **`EnrichNodeWithMultiByte()`** — new enrichment function that adds `multi_byte_status` (confirmed/suspected/unknown), `multi_byte_evidence` (advert/path), and `multi_byte_max_hash_size` fields to node API responses - **`GetMultiByteCapMap()`** — cached (15s TTL) map of pubkey → `MultiByteCapEntry`, reusing the existing `computeMultiByteCapability()` logic that combines advert-based and path-hop-based evidence - Wired into both `/api/nodes` (list) and `/api/nodes/{pubkey}` (detail) endpoints ### Frontend (`public/map.js`) - Added **"Multi-byte support"** checkbox in the map Display controls section - When toggled on, repeater markers change color: - 🟢 Green (`#27ae60`) — **confirmed** (advertised with hash_size ≥ 2) - 🟡 Yellow (`#f39c12`) — **suspected** (seen as hop in multi-byte path) - 🔴 Red (`#e74c3c`) — **unknown** (no multi-byte evidence) - Popup tooltip shows multi-byte status and evidence for repeaters - State persisted in localStorage (`meshcore-map-multibyte-overlay`) ## TDD - Red commit: `2f49cbc` — failing test for `EnrichNodeWithMultiByte` - Green commit: `4957782` — implementation + passing tests ## Performance - `GetMultiByteCapMap()` uses a 15s TTL cache (same pattern as `GetNodeHashSizeInfo`) - Enrichment is O(n) over nodes, no per-item API calls - Frontend color override is computed inline during existing marker render loop — no additional DOM rebuilds --------- Co-authored-by: you <you@example.com>
58 lines
1.7 KiB
Go
58 lines
1.7 KiB
Go
package main
|
|
|
|
import "testing"
|
|
|
|
func TestEnrichNodeWithMultiByte(t *testing.T) {
|
|
t.Run("nil entry leaves no fields", func(t *testing.T) {
|
|
node := map[string]interface{}{"public_key": "abc123"}
|
|
EnrichNodeWithMultiByte(node, nil)
|
|
if _, ok := node["multi_byte_status"]; ok {
|
|
t.Error("expected no multi_byte_status with nil entry")
|
|
}
|
|
})
|
|
|
|
t.Run("confirmed entry sets fields", func(t *testing.T) {
|
|
node := map[string]interface{}{"public_key": "abc123"}
|
|
entry := &MultiByteCapEntry{
|
|
Status: "confirmed",
|
|
Evidence: "advert",
|
|
MaxHashSize: 2,
|
|
}
|
|
EnrichNodeWithMultiByte(node, entry)
|
|
if node["multi_byte_status"] != "confirmed" {
|
|
t.Errorf("expected confirmed, got %v", node["multi_byte_status"])
|
|
}
|
|
if node["multi_byte_evidence"] != "advert" {
|
|
t.Errorf("expected advert, got %v", node["multi_byte_evidence"])
|
|
}
|
|
if node["multi_byte_max_hash_size"] != 2 {
|
|
t.Errorf("expected 2, got %v", node["multi_byte_max_hash_size"])
|
|
}
|
|
})
|
|
|
|
t.Run("suspected entry sets fields", func(t *testing.T) {
|
|
node := map[string]interface{}{"public_key": "abc123"}
|
|
entry := &MultiByteCapEntry{
|
|
Status: "suspected",
|
|
Evidence: "path",
|
|
MaxHashSize: 2,
|
|
}
|
|
EnrichNodeWithMultiByte(node, entry)
|
|
if node["multi_byte_status"] != "suspected" {
|
|
t.Errorf("expected suspected, got %v", node["multi_byte_status"])
|
|
}
|
|
})
|
|
|
|
t.Run("unknown entry sets status unknown", func(t *testing.T) {
|
|
node := map[string]interface{}{"public_key": "abc123"}
|
|
entry := &MultiByteCapEntry{
|
|
Status: "unknown",
|
|
MaxHashSize: 1,
|
|
}
|
|
EnrichNodeWithMultiByte(node, entry)
|
|
if node["multi_byte_status"] != "unknown" {
|
|
t.Errorf("expected unknown, got %v", node["multi_byte_status"])
|
|
}
|
|
})
|
|
}
|