fix double entry due to mixed 1byte and 2byte paths

This commit is contained in:
ericz
2026-05-18 21:30:37 +02:00
parent 87708e2684
commit 91759f531a
2 changed files with 116 additions and 7 deletions
+106 -7
View File
@@ -49,14 +49,16 @@ import 'meshcore_protocol.dart';
class DirectRepeater { class DirectRepeater {
static const int maxAgeMinutes = 30; // Max age for direct repeater info static const int maxAgeMinutes = 30; // Max age for direct repeater info
final List<int> pubkeyPrefix; List<int> pubkeyPrefix;
final int pathHashWidth; int pathHashWidth;
String? contactKeyHex;
double snr; double snr;
DateTime lastUpdated; DateTime lastUpdated;
DirectRepeater({ DirectRepeater({
required List<int> pubkeyPrefix, required List<int> pubkeyPrefix,
required this.pathHashWidth, required this.pathHashWidth,
this.contactKeyHex,
required this.snr, required this.snr,
DateTime? lastUpdated, DateTime? lastUpdated,
}) : pubkeyPrefix = List.unmodifiable(pubkeyPrefix), }) : pubkeyPrefix = List.unmodifiable(pubkeyPrefix),
@@ -79,8 +81,21 @@ class DirectRepeater {
return listEquals(pubkeyPrefix, pathBytes.sublist(0, width)); return listEquals(pubkeyPrefix, pathBytes.sublist(0, width));
} }
void update(double newSNR) { void update(
double newSNR, {
List<int>? pubkeyPrefix,
int? pathHashWidth,
String? contactKeyHex,
}) {
snr = newSNR; snr = newSNR;
if (pubkeyPrefix != null &&
pubkeyPrefix.length >= this.pubkeyPrefix.length) {
this.pubkeyPrefix = List.unmodifiable(pubkeyPrefix);
}
if (pathHashWidth != null && pathHashWidth >= this.pathHashWidth) {
this.pathHashWidth = pathHashWidth;
}
this.contactKeyHex ??= contactKeyHex;
lastUpdated = DateTime.now(); lastUpdated = DateTime.now();
} }
@@ -6239,6 +6254,25 @@ class MeshCoreConnector extends ChangeNotifier {
0, 0,
math.min(hashWidth, contact.publicKey.length), math.min(hashWidth, contact.publicKey.length),
); );
final contactKeyHex = _resolveDirectRepeaterContactKeyHex(
contact,
pubkeyPrefix,
path.isEmpty,
);
final knownRepeaters = contactKeyHex == null
? _directRepeaters
.where(
(r) =>
r.contactKeyHex != null &&
_contactKeyMatchesPrefix(r.contactKeyHex!, pubkeyPrefix),
)
.toList()
: const <DirectRepeater>[];
final knownRepeater = knownRepeaters.length == 1
? knownRepeaters.first
: null;
final effectiveContactKeyHex =
contactKeyHex ?? knownRepeater?.contactKeyHex;
_directRepeaters.removeWhere((r) => r.isStale()); _directRepeaters.removeWhere((r) => r.isStale());
@@ -6249,9 +6283,25 @@ class MeshCoreConnector extends ChangeNotifier {
return; return;
} }
final isTracked = _directRepeaters.where( final isTracked = _directRepeaters.where((r) {
(r) => r.pathHashWidth == hashWidth && r.matchesPrefix(pubkeyPrefix), if (knownRepeater != null) {
); return identical(r, knownRepeater);
}
if (effectiveContactKeyHex != null) {
return r.contactKeyHex == effectiveContactKeyHex ||
(r.contactKeyHex == null &&
_contactKeyMatchesPrefix(
effectiveContactKeyHex,
r.pubkeyPrefix,
));
}
if (r.contactKeyHex == null &&
r.pathHashWidth == hashWidth &&
r.matchesPrefix(pubkeyPrefix)) {
return true;
}
return false;
}).toList();
final sortedRepeaters = List<DirectRepeater>.from(_directRepeaters) final sortedRepeaters = List<DirectRepeater>.from(_directRepeaters)
..sort((a, b) => b.snr.compareTo(a.snr)); ..sort((a, b) => b.snr.compareTo(a.snr));
@@ -6267,12 +6317,30 @@ class MeshCoreConnector extends ChangeNotifier {
if (isTracked.isNotEmpty) { if (isTracked.isNotEmpty) {
final repeater = isTracked.first; final repeater = isTracked.first;
repeater.update(snr); repeater.update(
snr,
pubkeyPrefix: pubkeyPrefix,
pathHashWidth: hashWidth,
contactKeyHex: effectiveContactKeyHex,
);
if (effectiveContactKeyHex != null) {
_directRepeaters.removeWhere(
(r) =>
!identical(r, repeater) &&
(r.contactKeyHex == effectiveContactKeyHex ||
(r.contactKeyHex == null &&
_contactKeyMatchesPrefix(
effectiveContactKeyHex,
r.pubkeyPrefix,
))),
);
}
} else if (_directRepeaters.length < 5) { } else if (_directRepeaters.length < 5) {
_directRepeaters.add( _directRepeaters.add(
DirectRepeater( DirectRepeater(
pubkeyPrefix: pubkeyPrefix, pubkeyPrefix: pubkeyPrefix,
pathHashWidth: hashWidth, pathHashWidth: hashWidth,
contactKeyHex: effectiveContactKeyHex,
snr: snr, snr: snr,
), ),
); );
@@ -6280,6 +6348,37 @@ class MeshCoreConnector extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
String? _resolveDirectRepeaterContactKeyHex(
Contact contact,
List<int> pubkeyPrefix,
bool pathIsEmpty,
) {
if (pathIsEmpty &&
(contact.type == advTypeRepeater || contact.type == advTypeRoom)) {
return contact.publicKeyHex;
}
final prefixMatches = allContacts
.where(
(c) =>
(c.type == advTypeRepeater || c.type == advTypeRoom) &&
_contactKeyMatchesPrefix(c.publicKeyHex, pubkeyPrefix),
)
.toList();
if (prefixMatches.length == 1) {
return prefixMatches.first.publicKeyHex;
}
return null;
}
bool _contactKeyMatchesPrefix(String contactKeyHex, List<int> pubkeyPrefix) {
final prefixHex = pubkeyPrefix
.map((b) => b.toRadixString(16).padLeft(2, '0'))
.join();
return contactKeyHex.startsWith(prefixHex);
}
void _handleAutoAddConfig(Uint8List frame) { void _handleAutoAddConfig(Uint8List frame) {
final reader = BufferReader(frame); final reader = BufferReader(frame);
try { try {
+10
View File
@@ -12,9 +12,18 @@ import 'signal_ui.dart';
Contact? _getRepeaterPrefixMatchNearLocation( Contact? _getRepeaterPrefixMatchNearLocation(
List<Contact> contacts, List<Contact> contacts,
List<int> pubkeyPrefix, { List<int> pubkeyPrefix, {
String? contactKeyHex,
LatLng? searchPoint, LatLng? searchPoint,
bool preferFavorites = false, bool preferFavorites = false,
}) { }) {
if (contactKeyHex != null) {
for (final c in contacts) {
if (c.publicKeyHex == contactKeyHex) {
return c;
}
}
}
final candidates = contacts final candidates = contacts
.where( .where(
(c) => (c) =>
@@ -242,6 +251,7 @@ class _SNRIndicatorState extends State<SNRIndicator> {
final contact = _getRepeaterPrefixMatchNearLocation( final contact = _getRepeaterPrefixMatchNearLocation(
allContacts, allContacts,
repeater.pubkeyPrefix, repeater.pubkeyPrefix,
contactKeyHex: repeater.contactKeyHex,
searchPoint: selfPoint, searchPoint: selfPoint,
preferFavorites: true, preferFavorites: true,
); );