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.
This commit is contained in:
you committed 2026-03-23 19:20:13 +00:00
1 parent c524efc74d
commit 49e6d6d0b7
2 files changed
+32 -4

No files matched your search

+6 -4
View File
@@ -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),
};
+26
View File
@@ -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;