mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-11 16:30:28 +00:00
Summarize repo changes
This commit is contained in:
@@ -264,7 +264,6 @@ class ConnectionProvider with ChangeNotifier {
|
||||
|
||||
try {
|
||||
await _activeService.addOrUpdateContact(pendingOp.contact!);
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
|
||||
if (pendingOp.messageId != null) {
|
||||
_messageDeliveryTracker.trackPendingDirectMessage(
|
||||
@@ -1272,12 +1271,11 @@ class ConnectionProvider with ChangeNotifier {
|
||||
'⚠️ [ConnectionProvider] Rate limit hit: $pendingCount pending ACKs (max 7)',
|
||||
);
|
||||
debugPrint(
|
||||
'⚠️ Firmware only tracks 8 ACKs - waiting for delivery confirmations...',
|
||||
'⚠️ Firmware only tracks 8 ACKs - waiting for delivery confirmation...',
|
||||
);
|
||||
|
||||
// Wait briefly for some ACKs to arrive, then proceed anyway
|
||||
// (User action shouldn't be blocked forever)
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
// Wait for a slot to free up (delivery/timeout), max 500ms
|
||||
await _messageDeliveryTracker.waitForSlot();
|
||||
|
||||
if (_messageDeliveryTracker.shouldRateLimit) {
|
||||
debugPrint(
|
||||
@@ -1353,30 +1351,14 @@ class ConnectionProvider with ChangeNotifier {
|
||||
attempt: retryAttempt,
|
||||
);
|
||||
|
||||
if (messageId != null) {
|
||||
Future.delayed(const Duration(milliseconds: 350), () {
|
||||
if (_messageDeliveryTracker.hasAckForMessage(messageId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
debugPrint(
|
||||
'ℹ️ [ConnectionProvider] Missing RESP_CODE_SENT for $messageId; promoting to sent via fallback',
|
||||
);
|
||||
onMessageSent?.call(messageId, 0, 0);
|
||||
});
|
||||
}
|
||||
|
||||
// Clear pending operation after successful send (no error)
|
||||
// If ERR_CODE_NOT_FOUND occurs, the operation will be recovered automatically
|
||||
// Clear pending operation — any ERR_CODE_NOT_FOUND has already been
|
||||
// handled synchronously by onContactNotFound before sendTextMessage returns.
|
||||
if (effectiveContact != null) {
|
||||
final operationId = contactPublicKey
|
||||
.sublist(0, 6)
|
||||
.map((b) => b.toRadixString(16).padLeft(2, '0'))
|
||||
.join(':');
|
||||
// Use a small delay to allow error response to arrive before clearing
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
_pendingSendOperations.remove(operationId);
|
||||
});
|
||||
_pendingSendOperations.remove(operationId);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
/// Message delivery tracking helper
|
||||
@@ -30,6 +31,9 @@ class MessageDeliveryTracker {
|
||||
/// Map of ACK tag to timestamp for timeout cleanup
|
||||
final Map<int, DateTime> _ackTagTimestamps = {};
|
||||
|
||||
/// Completer signalled when a pending ACK slot is freed (delivery or removal).
|
||||
Completer<void>? _slotFreedCompleter;
|
||||
|
||||
/// Track a pending message ID before sending
|
||||
///
|
||||
/// This is called BEFORE sending the message. When RESP_CODE_SENT
|
||||
@@ -112,6 +116,7 @@ class MessageDeliveryTracker {
|
||||
_messageIdToAckTag.remove(messageId);
|
||||
}
|
||||
_ackTagTimestamps.remove(ackCode);
|
||||
_notifySlotFreed();
|
||||
}
|
||||
|
||||
/// Remove ACK tag mapping by message ID
|
||||
@@ -122,6 +127,7 @@ class MessageDeliveryTracker {
|
||||
if (ackTag != null) {
|
||||
_ackTagToMessageId.remove(ackTag);
|
||||
_ackTagTimestamps.remove(ackTag);
|
||||
_notifySlotFreed();
|
||||
}
|
||||
_pendingMessageIds.remove(messageId);
|
||||
final emptyKeys = <String>[];
|
||||
@@ -166,6 +172,7 @@ class MessageDeliveryTracker {
|
||||
_ackTagToMessageId.clear();
|
||||
_messageIdToAckTag.clear();
|
||||
_ackTagTimestamps.clear();
|
||||
_notifySlotFreed();
|
||||
}
|
||||
|
||||
/// Get count of pending ACK tags
|
||||
@@ -179,6 +186,27 @@ class MessageDeliveryTracker {
|
||||
/// Returns true if >= 7 pending ACKs (stay under firmware limit of 8)
|
||||
bool get shouldRateLimit => pendingCount >= 7;
|
||||
|
||||
/// Wait until a pending ACK slot is freed, or [timeout] elapses.
|
||||
///
|
||||
/// Returns immediately if not at the rate limit.
|
||||
Future<void> waitForSlot({
|
||||
Duration timeout = const Duration(milliseconds: 500),
|
||||
}) async {
|
||||
if (!shouldRateLimit) return;
|
||||
_slotFreedCompleter ??= Completer<void>();
|
||||
await _slotFreedCompleter!.future.timeout(
|
||||
timeout,
|
||||
onTimeout: () {},
|
||||
);
|
||||
}
|
||||
|
||||
void _notifySlotFreed() {
|
||||
if (_slotFreedCompleter != null && !_slotFreedCompleter!.isCompleted) {
|
||||
_slotFreedCompleter!.complete();
|
||||
}
|
||||
_slotFreedCompleter = null;
|
||||
}
|
||||
|
||||
/// Get oldest pending ACK timestamp (for debugging)
|
||||
DateTime? get oldestPendingTimestamp {
|
||||
if (_ackTagTimestamps.isEmpty) return null;
|
||||
|
||||
Reference in New Issue
Block a user