mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-12 00:40:28 +00:00
feat: Add location-based DM retries
This commit is contained in:
@@ -1761,6 +1761,7 @@ class AppProvider with ChangeNotifier {
|
||||
return _prepareDirectMessageSend(
|
||||
messageId: messageId,
|
||||
contact: contact,
|
||||
retryAttempt: retryAttempt,
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1830,23 +1831,47 @@ class AppProvider with ChangeNotifier {
|
||||
Future<Contact> _prepareDirectMessageSend({
|
||||
required String messageId,
|
||||
required Contact contact,
|
||||
required int retryAttempt,
|
||||
}) async {
|
||||
final latestContact =
|
||||
contactsProvider.findContactByKey(contact.publicKey) ?? contact;
|
||||
var session = _directMessageRouteSessions[messageId];
|
||||
if (session == null) {
|
||||
final selection = await _pathHistoryService.getSelectionForContact(
|
||||
latestContact,
|
||||
autoRouteRotationEnabled: _autoRouteRotationEnabled,
|
||||
);
|
||||
final selection = latestContact.routeHasPath && latestContact.routeHopCount > 0
|
||||
? PathSelection(
|
||||
mode: PathSelectionMode.directCurrent,
|
||||
pathBytes: Uint8List.fromList(latestContact.routePathBytes),
|
||||
hopCount: latestContact.routeHopCount,
|
||||
hashSize: latestContact.routeHashSize,
|
||||
)
|
||||
: await _pathHistoryService.getSelectionForContact(
|
||||
latestContact,
|
||||
autoRouteRotationEnabled: _autoRouteRotationEnabled,
|
||||
);
|
||||
session = _DirectMessageRouteSession(
|
||||
currentSelection: selection,
|
||||
originalRoute: ContactRouteCodec.fromContact(latestContact),
|
||||
routerFallbackAttempted: false,
|
||||
);
|
||||
_directMessageRouteSessions[messageId] = session;
|
||||
}
|
||||
|
||||
if (!session.routerFallbackAttempted) {
|
||||
final currentSignature =
|
||||
latestContact.routeHasPath && latestContact.routeHopCount > 0
|
||||
? latestContact.routePathBytes
|
||||
.map((byte) => byte.toRadixString(16).padLeft(2, '0'))
|
||||
.join()
|
||||
: null;
|
||||
final selection = await _resolveDirectMessageSelectionForRetry(
|
||||
latestContact,
|
||||
retryAttempt: retryAttempt,
|
||||
currentSignature: currentSignature,
|
||||
fallbackSelection: session.currentSelection,
|
||||
);
|
||||
session = session.copyWith(currentSelection: selection);
|
||||
}
|
||||
_directMessageRouteSessions[messageId] = session;
|
||||
|
||||
await _applyPathSelection(
|
||||
latestContact,
|
||||
session.currentSelection,
|
||||
@@ -1857,6 +1882,43 @@ class AppProvider with ChangeNotifier {
|
||||
latestContact;
|
||||
}
|
||||
|
||||
Future<PathSelection> _resolveDirectMessageSelectionForRetry(
|
||||
Contact contact, {
|
||||
required int retryAttempt,
|
||||
required String? currentSignature,
|
||||
required PathSelection fallbackSelection,
|
||||
}) async {
|
||||
if (contact.routeHasPath && contact.routeHopCount > 0 && retryAttempt <= 1) {
|
||||
return PathSelection(
|
||||
mode: PathSelectionMode.directCurrent,
|
||||
pathBytes: Uint8List.fromList(contact.routePathBytes),
|
||||
hopCount: contact.routeHopCount,
|
||||
hashSize: contact.routeHashSize,
|
||||
);
|
||||
}
|
||||
|
||||
if (retryAttempt == 2) {
|
||||
return PathSelection.flood();
|
||||
}
|
||||
|
||||
if (retryAttempt >= 3) {
|
||||
final historicalSelection = await _pathHistoryService
|
||||
.getLastSuccessfulDirectSelection(
|
||||
contact,
|
||||
excludeSignature: currentSignature,
|
||||
senderLatitude: locationTrackingService.currentPosition?.latitude,
|
||||
senderLongitude: locationTrackingService.currentPosition?.longitude,
|
||||
recipientLatitude: contact.displayLocation?.latitude,
|
||||
recipientLongitude: contact.displayLocation?.longitude,
|
||||
);
|
||||
if (historicalSelection != null) {
|
||||
return historicalSelection;
|
||||
}
|
||||
}
|
||||
|
||||
return fallbackSelection;
|
||||
}
|
||||
|
||||
Future<void> _applyPathSelection(
|
||||
Contact contact,
|
||||
PathSelection selection, {
|
||||
@@ -2031,6 +2093,10 @@ class AppProvider with ChangeNotifier {
|
||||
session.currentSelection,
|
||||
success: true,
|
||||
roundTripTimeMs: roundTripTimeMs,
|
||||
senderLatitude: locationTrackingService.currentPosition?.latitude,
|
||||
senderLongitude: locationTrackingService.currentPosition?.longitude,
|
||||
recipientLatitude: contact.displayLocation?.latitude,
|
||||
recipientLongitude: contact.displayLocation?.longitude,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ class MessageRetryManager {
|
||||
final Map<String, int> _pathFailureStreaks = {};
|
||||
|
||||
/// Max retry attempts when the contact has a known path.
|
||||
/// Official MeshCore app uses 5 (with auto-retry) or 3 (without).
|
||||
static const int maxRetryAttemptsWithPath = 5;
|
||||
/// Sequence: 2 direct attempts, flood, then last successful route.
|
||||
static const int maxRetryAttemptsWithPath = 3;
|
||||
|
||||
/// No retries for flood-only contacts (no known path).
|
||||
/// Value 0 means: don't retry at all, go straight to fallback/fail.
|
||||
|
||||
@@ -2354,17 +2354,6 @@ class MessagesProvider with ChangeNotifier {
|
||||
return;
|
||||
}
|
||||
|
||||
// On the last attempt, reset the path to force flood mode
|
||||
// (matches official MeshCore app behaviour)
|
||||
if (_retryManager.isLastAttempt(currentMessage, contact)) {
|
||||
debugPrint(
|
||||
'🔄 [MessagesProvider] Last attempt — resetting path to flood for $messageId',
|
||||
);
|
||||
if (resetPathBeforeLastRetryCallback != null) {
|
||||
await resetPathBeforeLastRetryCallback!(contact);
|
||||
}
|
||||
}
|
||||
|
||||
if (sendMessageCallback != null) {
|
||||
final queued = await sendMessageCallback!(
|
||||
contactPublicKey: contact.publicKey,
|
||||
|
||||
Reference in New Issue
Block a user