mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-04-27 04:25:12 +00:00
Geographic prefix collision disambiguation on live page
When a 1-byte hop prefix matches multiple nodes, pick the one geographically closest to the center of other known hops in the path — same logic as /api/resolve-hops but client-side. Previously just took the first match, which could be a node in Chicago matching a local Bay Area hop prefix.
This commit is contained in:
+32
-6
@@ -948,17 +948,23 @@
|
||||
|
||||
function resolveHopPositions(hops, payload) {
|
||||
const known = Object.values(nodeData);
|
||||
|
||||
// First pass: find all candidates per hop
|
||||
const raw = hops.map(hop => {
|
||||
let found = null;
|
||||
for (const n of known) {
|
||||
if (n.public_key.toLowerCase().startsWith(hop.toLowerCase())) { found = n; break; }
|
||||
}
|
||||
if (found && !(found.lat === 0 && found.lon === 0)) {
|
||||
return { key: found.public_key, pos: [found.lat, found.lon], name: found.name || hop, known: true };
|
||||
const hopLower = hop.toLowerCase();
|
||||
const candidates = known.filter(n =>
|
||||
n.public_key.toLowerCase().startsWith(hopLower) &&
|
||||
n.lat != null && n.lon != null && !(n.lat === 0 && n.lon === 0)
|
||||
);
|
||||
if (candidates.length === 1) {
|
||||
return { key: candidates[0].public_key, pos: [candidates[0].lat, candidates[0].lon], name: candidates[0].name || hop, known: true };
|
||||
} else if (candidates.length > 1) {
|
||||
return { key: 'ambig-' + hop, pos: null, name: hop, known: false, candidates };
|
||||
}
|
||||
return { key: 'hop-' + hop, pos: null, name: hop, known: false };
|
||||
});
|
||||
|
||||
// Add sender position if available
|
||||
if (payload.pubKey && payload.lat != null && !(payload.lat === 0 && payload.lon === 0)) {
|
||||
const existing = raw.find(p => p.key === payload.pubKey);
|
||||
if (!existing) {
|
||||
@@ -966,6 +972,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass: disambiguate by geographic proximity to known hops
|
||||
const knownPositions = raw.filter(h => h.known && h.pos).map(h => h.pos);
|
||||
if (knownPositions.length > 0) {
|
||||
const centerLat = knownPositions.reduce((s, p) => s + p[0], 0) / knownPositions.length;
|
||||
const centerLon = knownPositions.reduce((s, p) => s + p[1], 0) / knownPositions.length;
|
||||
const dist = (lat, lon) => Math.sqrt((lat - centerLat) ** 2 + (lon - centerLon) ** 2);
|
||||
|
||||
for (const hop of raw) {
|
||||
if (hop.candidates) {
|
||||
hop.candidates.sort((a, b) => dist(a.lat, a.lon) - dist(b.lat, b.lon));
|
||||
const best = hop.candidates[0];
|
||||
hop.key = best.public_key;
|
||||
hop.pos = [best.lat, best.lon];
|
||||
hop.name = best.name || best.public_key.slice(0, 8);
|
||||
hop.known = true;
|
||||
delete hop.candidates;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!showGhostHops) return raw.filter(h => h.known);
|
||||
|
||||
const knownPositions = raw.filter(h => h.known);
|
||||
|
||||
Reference in New Issue
Block a user