fix: observer locations case-insensitive match, regions from API not hardcoded

- Observer ID is uppercase, node pubkey is lowercase — added COLLATE NOCASE
- New /api/config/regions endpoint merges config regions + observed IATAs
- map.js and packets.js fetch regions from API instead of hardcoded maps
This commit is contained in:
you committed 2026-03-20 16:10:16 +00:00
1 parent 9bf78bd28d
commit f0db317051
4 files changed
+21 -7

No files matched your search

+2 -2
View File
@@ -81,8 +81,8 @@
<script src="vendor/qrcode.js"></script>
<script src="app.js?v=1773993532"></script>
<script src="home.js?v=1773977027"></script>
<script src="packets.js?v=1773999188"></script>
<script src="map.js?v=1774018568" onerror="console.error('Failed to load:', this.src)"></script>
<script src="packets.js?v=1774023016"></script>
<script src="map.js?v=1774023016" onerror="console.error('Failed to load:', this.src)"></script>
<script src="channels.js?v=1773977027" onerror="console.error('Failed to load:', this.src)"></script>
<script src="nodes.js?v=1773977027" onerror="console.error('Failed to load:', this.src)"></script>
<script src="traces.js?v=1773972187" onerror="console.error('Failed to load:', this.src)"></script>
+4 -1
View File
@@ -268,6 +268,9 @@
async function loadNodes() {
try {
// Load regions from config + observed IATAs
try { REGION_NAMES = await api('/config/regions', { ttl: 3600 }); } catch {}
const data = await api(`/nodes?limit=10000&lastHeard=${filters.lastHeard}`, { ttl: CLIENT_TTL.nodeList });
nodes = data.nodes || [];
@@ -308,7 +311,7 @@
}
}
const REGION_NAMES = { SJC: 'San Jose', SFO: 'San Francisco', OAK: 'Oakland', MTV: 'Mountain View', SCZ: 'Santa Cruz', MRY: 'Monterey', PAO: 'Palo Alto' };
let REGION_NAMES = {};
function buildJumpButtons() {
const el = document.getElementById('mcJumps');
+2 -3
View File
@@ -1090,11 +1090,10 @@
return '<div class="byop-row"><span class="byop-key">' + key + '</span><span class="byop-val">' + val + '</span></div>';
}
// Load regions from config
// Load regions from config API
(async () => {
try {
// We'll use a simple approach - hardcode from config
regionMap = {"SJC":"San Jose, US","SFO":"San Francisco, US","OAK":"Oakland, US","MRY":"Monterey, US","LAR":"Los Angeles, US"};
regionMap = await api('/config/regions', { ttl: 3600 });
} catch {}
})();
+13 -1
View File
@@ -188,6 +188,18 @@ app.get('/api/config/cache', (req, res) => {
res.json(config.cacheTTL || {});
});
app.get('/api/config/regions', (req, res) => {
// Merge config regions with any IATA codes seen from observers
const regions = { ...(config.regions || {}) };
try {
const rows = db.db.prepare("SELECT DISTINCT iata FROM observers WHERE iata IS NOT NULL").all();
for (const r of rows) {
if (r.iata && !regions[r.iata]) regions[r.iata] = r.iata; // fallback to code itself
}
} catch {}
res.json(regions);
});
app.get('/api/perf', (req, res) => {
const summary = {};
for (const [path, ep] of Object.entries(perfStats.endpoints)) {
@@ -1664,7 +1676,7 @@ app.get('/api/observers', (req, res) => {
const observers = db.getObservers();
const oneHourAgo = new Date(Date.now() - 3600000).toISOString();
// Join observer location from nodes table (observers are nodes — same pubkey)
const nodeLocStmt = db.db.prepare("SELECT lat, lon, role FROM nodes WHERE public_key = ?");
const nodeLocStmt = db.db.prepare("SELECT lat, lon, role FROM nodes WHERE public_key = ? COLLATE NOCASE");
const result = observers.map(o => {
const obsPackets = pktStore.byObserver.get(o.id) || [];
const lastHour = { count: obsPackets.filter(p => p.timestamp > oneHourAgo).length };