mirror of
https://github.com/dz0ny/meshcore-sar.git
synced 2026-08-11 16:30:28 +00:00
feat: Enhance message synchronization with response handling and improve logging in MessagesTab
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
{
|
{
|
||||||
"permissions": {
|
"permissions": {
|
||||||
"allow": [
|
"allow": [
|
||||||
"Bash(flutter analyze lib)"
|
"Bash(flutter analyze lib)",
|
||||||
|
"Read(//Users/dz0ny/meshcore-sar/MeshCore/**)",
|
||||||
|
"Bash(flutter analyze lib/providers/connection_provider.dart)",
|
||||||
|
"Bash(flutter analyze lib/providers/connection_provider.dart --fatal-infos)"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": []
|
"ask": []
|
||||||
|
|||||||
@@ -95,6 +95,9 @@ class ConnectionProvider with ChangeNotifier {
|
|||||||
DateTime? _lastSyncNextRequestedAt;
|
DateTime? _lastSyncNextRequestedAt;
|
||||||
static const Duration _minSyncNextInterval = Duration(milliseconds: 150);
|
static const Duration _minSyncNextInterval = Duration(milliseconds: 150);
|
||||||
|
|
||||||
|
// Completer to wait for response before sending next sync request
|
||||||
|
Completer<bool>? _syncResponseCompleter;
|
||||||
|
|
||||||
// Lightweight guards for other commands that can be double-tapped
|
// Lightweight guards for other commands that can be double-tapped
|
||||||
bool _isLoginInProgress = false;
|
bool _isLoginInProgress = false;
|
||||||
DateTime? _lastLoginRequestedAt;
|
DateTime? _lastLoginRequestedAt;
|
||||||
@@ -260,6 +263,11 @@ class ConnectionProvider with ChangeNotifier {
|
|||||||
// Parse SAR markers
|
// Parse SAR markers
|
||||||
final enhancedMessage = SarMessageParser.enhanceMessage(message);
|
final enhancedMessage = SarMessageParser.enhanceMessage(message);
|
||||||
onMessageReceived?.call(enhancedMessage);
|
onMessageReceived?.call(enhancedMessage);
|
||||||
|
|
||||||
|
// Complete sync response completer (message received = continue syncing)
|
||||||
|
if (_syncResponseCompleter != null && !_syncResponseCompleter!.isCompleted) {
|
||||||
|
_syncResponseCompleter!.complete(true);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_bleService.onTelemetryReceived = (publicKey, lppData) {
|
_bleService.onTelemetryReceived = (publicKey, lppData) {
|
||||||
@@ -284,6 +292,11 @@ class ConnectionProvider with ChangeNotifier {
|
|||||||
_bleService.onNoMoreMessages = () {
|
_bleService.onNoMoreMessages = () {
|
||||||
debugPrint('📥 [Provider] Received NoMoreMessages signal');
|
debugPrint('📥 [Provider] Received NoMoreMessages signal');
|
||||||
_noMoreMessages = true;
|
_noMoreMessages = true;
|
||||||
|
|
||||||
|
// Complete sync response completer (no more messages = stop syncing)
|
||||||
|
if (_syncResponseCompleter != null && !_syncResponseCompleter!.isCompleted) {
|
||||||
|
_syncResponseCompleter!.complete(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_bleService.onMessageWaiting = () {
|
_bleService.onMessageWaiting = () {
|
||||||
@@ -1273,6 +1286,9 @@ class ConnectionProvider with ChangeNotifier {
|
|||||||
'📤 [Provider] Sync iteration ${i + 1}: Sending CMD_SYNC_NEXT_MESSAGE',
|
'📤 [Provider] Sync iteration ${i + 1}: Sending CMD_SYNC_NEXT_MESSAGE',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Create new completer for this request
|
||||||
|
_syncResponseCompleter = Completer<bool>();
|
||||||
|
|
||||||
// Respect the minimum interval between requests
|
// Respect the minimum interval between requests
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
if (_lastSyncNextRequestedAt != null) {
|
if (_lastSyncNextRequestedAt != null) {
|
||||||
@@ -1287,10 +1303,22 @@ class ConnectionProvider with ChangeNotifier {
|
|||||||
_lastSyncNextRequestedAt = DateTime.now();
|
_lastSyncNextRequestedAt = DateTime.now();
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
// Small delay to allow response to be processed
|
// Wait for response (true = message received, false = no more messages)
|
||||||
await Future.delayed(const Duration(milliseconds: 150));
|
// Timeout after 2 seconds to prevent hanging
|
||||||
|
final hasMore = await _syncResponseCompleter!.future.timeout(
|
||||||
|
const Duration(seconds: 2),
|
||||||
|
onTimeout: () {
|
||||||
|
debugPrint('⚠️ [Provider] Sync timeout - no response after 2s');
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
debugPrint(' After iteration ${i + 1}: _noMoreMessages=$_noMoreMessages');
|
debugPrint(' After iteration ${i + 1}: hasMore=$hasMore, _noMoreMessages=$_noMoreMessages');
|
||||||
|
|
||||||
|
if (!hasMore) {
|
||||||
|
debugPrint(' ✅ No more messages available, stopping sync');
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_noMoreMessages && count >= 100) {
|
if (!_noMoreMessages && count >= 100) {
|
||||||
@@ -1310,6 +1338,7 @@ class ConnectionProvider with ChangeNotifier {
|
|||||||
return count;
|
return count;
|
||||||
} finally {
|
} finally {
|
||||||
_isSyncingMessages = false;
|
_isSyncingMessages = false;
|
||||||
|
_syncResponseCompleter = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,6 @@ class _MessagesTabState extends State<MessagesTab> {
|
|||||||
_focusNode.unfocus();
|
_focusNode.unfocus();
|
||||||
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ToastLogger.success(context, 'Message sent to public channel');
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
ToastLogger.error(context, 'Failed to send: $e');
|
ToastLogger.error(context, 'Failed to send: $e');
|
||||||
@@ -254,7 +253,9 @@ class _MessagesTabState extends State<MessagesTab> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
debugPrint('🔄 [MessagesTab] Manual refresh triggered - syncing messages');
|
debugPrint(
|
||||||
|
'🔄 [MessagesTab] Manual refresh triggered - syncing messages',
|
||||||
|
);
|
||||||
final messageCount = await connectionProvider.syncAllMessages();
|
final messageCount = await connectionProvider.syncAllMessages();
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
if (messageCount > 0) {
|
if (messageCount > 0) {
|
||||||
@@ -307,14 +308,18 @@ class _MessagesTabState extends State<MessagesTab> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.noMessagesYet,
|
AppLocalizations.of(
|
||||||
|
context,
|
||||||
|
)!.noMessagesYet,
|
||||||
style: Theme.of(
|
style: Theme.of(
|
||||||
context,
|
context,
|
||||||
).textTheme.titleLarge,
|
).textTheme.titleLarge,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
AppLocalizations.of(context)!.pullDownToSync,
|
AppLocalizations.of(
|
||||||
|
context,
|
||||||
|
)!.pullDownToSync,
|
||||||
style: Theme.of(
|
style: Theme.of(
|
||||||
context,
|
context,
|
||||||
).textTheme.bodyMedium,
|
).textTheme.bodyMedium,
|
||||||
@@ -971,7 +976,9 @@ class _MessageBubble extends StatelessWidget {
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.surfaceVariant.withValues(alpha: 0.5),
|
color: Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.surfaceVariant.withValues(alpha: 0.5),
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|||||||
Reference in New Issue
Block a user