chore: Update project version to 14 in project.pbxproj and Info.plist; enhance connection provider to throttle sync and login requests

This commit is contained in:
Janez T
2025-10-16 18:07:12 +02:00
parent 2a25574860
commit abca014720
3 changed files with 105 additions and 7 deletions

View File

@@ -489,7 +489,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 13; CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = JND55328G8; DEVELOPMENT_TEAM = JND55328G8;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
@@ -511,7 +511,7 @@
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 13; CURRENT_PROJECT_VERSION = 14;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.sar.meshcoreSarApp.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.sar.meshcoreSarApp.RunnerTests;
@@ -529,7 +529,7 @@
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 13; CURRENT_PROJECT_VERSION = 14;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.sar.meshcoreSarApp.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.sar.meshcoreSarApp.RunnerTests;
@@ -545,7 +545,7 @@
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 13; CURRENT_PROJECT_VERSION = 14;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.sar.meshcoreSarApp.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = com.meshcore.sar.meshcoreSarApp.RunnerTests;
@@ -676,7 +676,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 13; CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = JND55328G8; DEVELOPMENT_TEAM = JND55328G8;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
@@ -699,7 +699,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 13; CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_TEAM = JND55328G8; DEVELOPMENT_TEAM = JND55328G8;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;

View File

@@ -21,7 +21,7 @@
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>13</string> <string>14</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>UILaunchStoryboardName</key> <key>UILaunchStoryboardName</key>

View File

@@ -73,6 +73,23 @@ class ConnectionProvider with ChangeNotifier {
// Message sync state // Message sync state
bool _noMoreMessages = false; bool _noMoreMessages = false;
// Prevent overlapping/too-frequent sync requests
bool _isSyncingMessages = false;
DateTime? _lastSyncNextRequestedAt;
static const Duration _minSyncNextInterval = Duration(milliseconds: 150);
// Lightweight guards for other commands that can be double-tapped
bool _isLoginInProgress = false;
DateTime? _lastLoginRequestedAt;
static const Duration _minLoginInterval = Duration(seconds: 1);
bool _isStatusRequestInProgress = false;
DateTime? _lastStatusRequestedAt;
static const Duration _minStatusInterval = Duration(milliseconds: 200);
bool _isAdvertInProgress = false;
DateTime? _lastAdvertRequestedAt;
static const Duration _minAdvertInterval = Duration(milliseconds: 500);
// Helper instances // Helper instances
final RoomLoginManager _roomLoginManager = RoomLoginManager(); final RoomLoginManager _roomLoginManager = RoomLoginManager();
@@ -899,10 +916,24 @@ class ConnectionProvider with ChangeNotifier {
} }
try { try {
if (_isAdvertInProgress) return;
// Throttle rapid advert requests
final now = DateTime.now();
if (_lastAdvertRequestedAt != null) {
final elapsed = now.difference(_lastAdvertRequestedAt!);
if (elapsed < _minAdvertInterval) {
final wait = _minAdvertInterval - elapsed;
await Future.delayed(wait);
}
}
_isAdvertInProgress = true;
await _bleService.sendSelfAdvert(floodMode: floodMode); await _bleService.sendSelfAdvert(floodMode: floodMode);
_lastAdvertRequestedAt = DateTime.now();
} catch (e) { } catch (e) {
_error = 'Failed to send advertisement: $e'; _error = 'Failed to send advertisement: $e';
notifyListeners(); notifyListeners();
} finally {
_isAdvertInProgress = false;
} }
} }
@@ -1017,6 +1048,12 @@ class ConnectionProvider with ChangeNotifier {
/// Sync messages from device queue /// Sync messages from device queue
/// Call this repeatedly until no more messages are available /// Call this repeatedly until no more messages are available
Future<bool> syncNextMessage() async { Future<bool> syncNextMessage() async {
// Prevent re-entrancy and too-fast triggers
if (_isSyncingMessages) {
// Another sync (single or loop) is in progress
return false;
}
if (!_bleService.isConnected) { if (!_bleService.isConnected) {
_error = 'Not connected to device'; _error = 'Not connected to device';
notifyListeners(); notifyListeners();
@@ -1024,17 +1061,36 @@ class ConnectionProvider with ChangeNotifier {
} }
try { try {
// Enforce a small gap between consecutive requests
final now = DateTime.now();
if (_lastSyncNextRequestedAt != null) {
final elapsed = now.difference(_lastSyncNextRequestedAt!);
if (elapsed < _minSyncNextInterval) {
final remaining = _minSyncNextInterval - elapsed;
await Future.delayed(remaining);
}
}
_isSyncingMessages = true;
await _bleService.syncNextMessage(); await _bleService.syncNextMessage();
_lastSyncNextRequestedAt = DateTime.now();
return true; return true;
} catch (e) { } catch (e) {
_error = 'Failed to sync message: $e'; _error = 'Failed to sync message: $e';
notifyListeners(); notifyListeners();
return false; return false;
} finally {
_isSyncingMessages = false;
} }
} }
/// Sync all waiting messages from device /// Sync all waiting messages from device
Future<int> syncAllMessages() async { Future<int> syncAllMessages() async {
if (_isSyncingMessages) {
// Already syncing; avoid overlapping loops
return 0;
}
if (!_bleService.isConnected) { if (!_bleService.isConnected) {
_error = 'Not connected to device'; _error = 'Not connected to device';
notifyListeners(); notifyListeners();
@@ -1045,6 +1101,7 @@ class ConnectionProvider with ChangeNotifier {
_noMoreMessages = false; // Reset flag _noMoreMessages = false; // Reset flag
try { try {
_isSyncingMessages = true;
print('🔄 [Provider] Starting message sync loop...'); print('🔄 [Provider] Starting message sync loop...');
print(' Initial _noMoreMessages state: $_noMoreMessages'); print(' Initial _noMoreMessages state: $_noMoreMessages');
@@ -1065,7 +1122,18 @@ class ConnectionProvider with ChangeNotifier {
'📤 [Provider] Sync iteration ${i + 1}: Sending CMD_SYNC_NEXT_MESSAGE', '📤 [Provider] Sync iteration ${i + 1}: Sending CMD_SYNC_NEXT_MESSAGE',
); );
// Respect the minimum interval between requests
final now = DateTime.now();
if (_lastSyncNextRequestedAt != null) {
final elapsed = now.difference(_lastSyncNextRequestedAt!);
if (elapsed < _minSyncNextInterval) {
final remaining = _minSyncNextInterval - elapsed;
await Future.delayed(remaining);
}
}
await _bleService.syncNextMessage(); await _bleService.syncNextMessage();
_lastSyncNextRequestedAt = DateTime.now();
count++; count++;
// Small delay to allow response to be processed // Small delay to allow response to be processed
@@ -1089,6 +1157,8 @@ class ConnectionProvider with ChangeNotifier {
_error = 'Failed to sync messages: $e'; _error = 'Failed to sync messages: $e';
notifyListeners(); notifyListeners();
return count; return count;
} finally {
_isSyncingMessages = false;
} }
} }
@@ -1121,13 +1191,27 @@ class ConnectionProvider with ChangeNotifier {
} }
try { try {
if (_isLoginInProgress) return;
// Throttle rapid login attempts
final now = DateTime.now();
if (_lastLoginRequestedAt != null) {
final elapsed = now.difference(_lastLoginRequestedAt!);
if (elapsed < _minLoginInterval) {
final wait = _minLoginInterval - elapsed;
await Future.delayed(wait);
}
}
_isLoginInProgress = true;
await _bleService.loginToRoom( await _bleService.loginToRoom(
roomPublicKey: roomPublicKey, roomPublicKey: roomPublicKey,
password: password, password: password,
); );
_lastLoginRequestedAt = DateTime.now();
} catch (e) { } catch (e) {
_error = 'Failed to send login request: $e'; _error = 'Failed to send login request: $e';
notifyListeners(); notifyListeners();
} finally {
_isLoginInProgress = false;
} }
} }
@@ -1151,10 +1235,24 @@ class ConnectionProvider with ChangeNotifier {
} }
try { try {
if (_isStatusRequestInProgress) return;
// Throttle rapid status requests
final now = DateTime.now();
if (_lastStatusRequestedAt != null) {
final elapsed = now.difference(_lastStatusRequestedAt!);
if (elapsed < _minStatusInterval) {
final wait = _minStatusInterval - elapsed;
await Future.delayed(wait);
}
}
_isStatusRequestInProgress = true;
await _bleService.sendStatusRequest(contactPublicKey); await _bleService.sendStatusRequest(contactPublicKey);
_lastStatusRequestedAt = DateTime.now();
} catch (e) { } catch (e) {
_error = 'Failed to send status request: $e'; _error = 'Failed to send status request: $e';
notifyListeners(); notifyListeners();
} finally {
_isStatusRequestInProgress = false;
} }
} }