From 49e6d6d0b70d4a8667437906dcf5d42bf41d6cd7 Mon Sep 17 00:00:00 2001 From: you Date: Mon, 23 Mar 2026 19:20:13 +0000 Subject: [PATCH] fix: advert flags are a 4-bit enum type, not individual bit flags ADV_TYPE_ROOM=3 (0b0011) was misread as chat+repeater because decoder treated lower nibble as individual bits. Now correctly: type & 0x0F as enum (0=none, 1=chat, 2=repeater, 3=room, 4=sensor). Includes startup backfill: scans all adverts and fixes any node roles in the DB that were incorrectly set to 'repeater' when they should be 'room'. Logs count of fixed nodes on startup. --- decoder.js | 10 ++++++---- server.js | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/decoder.js b/decoder.js index e2ed9f4b..57f8f377 100644 --- a/decoder.js +++ b/decoder.js @@ -109,12 +109,14 @@ function decodeAdvert(buf) { if (appdata.length > 0) { const flags = appdata[0]; + const advType = flags & 0x0F; // lower nibble is enum type, not individual bits result.flags = { raw: flags, - chat: !!(flags & 0x01), - repeater: !!(flags & 0x02), - room: !!(flags & 0x04), - sensor: !!(flags & 0x08), + type: advType, + chat: advType === 1, + repeater: advType === 2, + room: advType === 3, + sensor: advType === 4, hasLocation: !!(flags & 0x10), hasName: !!(flags & 0x80), }; diff --git a/server.js b/server.js index bbbfb126..10fe2c04 100644 --- a/server.js +++ b/server.js @@ -171,6 +171,32 @@ const db = require('./db'); const pktStore = new PacketStore(db, config.packetStore || {}).load(); _rebuildHashSizeMap(); +// Backfill: fix roles for nodes whose adverts were decoded with old bitfield flags +// ADV_TYPE is a 4-bit enum (0=none, 1=chat, 2=repeater, 3=room, 4=sensor), not individual bits +(function _backfillRoles() { + const ADV_ROLES = { 1: 'companion', 2: 'repeater', 3: 'room', 4: 'sensor' }; + let fixed = 0; + for (const p of pktStore.packets) { + if (p.payload_type !== 4 || !p.raw_hex) continue; + try { + const d = JSON.parse(p.decoded_json || '{}'); + const pk = d.pubKey || d.public_key; + if (!pk) continue; + const appStart = p.raw_hex.length - (d.flags?.raw != null ? 2 : 0); // flags byte position varies + const flagsByte = d.flags?.raw; + if (flagsByte == null) continue; + const advType = flagsByte & 0x0F; + const correctRole = ADV_ROLES[advType] || 'companion'; + const node = db.db.prepare('SELECT role FROM nodes WHERE public_key = ?').get(pk); + if (node && node.role !== correctRole) { + db.db.prepare('UPDATE nodes SET role = ? WHERE public_key = ?').run(correctRole, pk); + fixed++; + } + } catch {} + } + if (fixed > 0) console.log(`[backfill] Fixed ${fixed} node roles (advert type enum vs bitfield)`); +})(); + // --- Shared cached node list (refreshed every 30s, avoids repeated SQLite queries) --- let _cachedAllNodes = null; let _cachedAllNodesWithRole = null;