Szinkronizáció javítása,
This commit is contained in:
@@ -13,6 +13,10 @@ class PhoneGpsConnection implements GnssConnection {
|
||||
final _positionController = StreamController<Position>.broadcast();
|
||||
StreamSubscription<Position>? _positionSub;
|
||||
|
||||
int _retryCount = 0;
|
||||
static const _maxRetries = 5;
|
||||
Timer? _retryTimer;
|
||||
|
||||
@override
|
||||
Stream<String> get nmeaLines => const Stream.empty(); // Nincs NMEA
|
||||
|
||||
@@ -42,20 +46,44 @@ class PhoneGpsConnection implements GnssConnection {
|
||||
}
|
||||
|
||||
_stateController.add(GnssConnectionState.connected);
|
||||
_retryCount = 0;
|
||||
await _startPositionStream();
|
||||
}
|
||||
|
||||
// Belső GPS folyamatos olvasása
|
||||
Future<void> _startPositionStream() async {
|
||||
await _positionSub?.cancel();
|
||||
_positionSub = Geolocator.getPositionStream(
|
||||
locationSettings: const LocationSettings(
|
||||
accuracy: LocationAccuracy.high,
|
||||
distanceFilter: 0, // Folyamatos frissítés
|
||||
),
|
||||
).listen((Position pos) {
|
||||
_positionController.add(pos);
|
||||
});
|
||||
).listen(
|
||||
(Position pos) {
|
||||
_retryCount = 0;
|
||||
_positionController.add(pos);
|
||||
},
|
||||
onError: _handleStreamError,
|
||||
onDone: () =>
|
||||
_handleStreamError(Exception('A GPS-stream váratlanul lezárult.')),
|
||||
);
|
||||
}
|
||||
|
||||
/// A Geolocator stream NEM öngyógyuló — lásd a PhoneGpsSource-nál már
|
||||
/// javított, ugyanilyen hibát. Ez a kapcsolat idáig SEMMILYEN hiba
|
||||
/// esetén nem próbálkozott újra, csendben, véglegesen elhallgatott.
|
||||
void _handleStreamError(Object e) {
|
||||
_retryCount++;
|
||||
if (_retryCount > _maxRetries) {
|
||||
_stateController.add(GnssConnectionState.error);
|
||||
return;
|
||||
}
|
||||
_retryTimer?.cancel();
|
||||
_retryTimer = Timer(const Duration(seconds: 1), _startPositionStream);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> disconnect() async {
|
||||
_retryTimer?.cancel();
|
||||
await _positionSub?.cancel();
|
||||
_stateController.add(GnssConnectionState.disconnected);
|
||||
}
|
||||
@@ -67,6 +95,7 @@ class PhoneGpsConnection implements GnssConnection {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_retryTimer?.cancel();
|
||||
_positionSub?.cancel();
|
||||
_positionController.close();
|
||||
_stateController.close();
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:get/get.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'package:terepi_seged/services/app_database.dart';
|
||||
import 'package:terepi_seged/services/app_logger.dart';
|
||||
|
||||
import 'stakeout_service.dart';
|
||||
|
||||
@@ -52,8 +53,23 @@ class StakeoutSyncService extends GetxService {
|
||||
}
|
||||
|
||||
Future<bool> _pushThenPull() async {
|
||||
await _push();
|
||||
return _pull();
|
||||
try {
|
||||
await _push().timeout(const Duration(seconds: 25));
|
||||
} catch (e, s) {
|
||||
lastError.value = 'kitűzés push: $e';
|
||||
AppLogger.e('StackeoutSyncService - _pushThenPull', lastError.value,
|
||||
error: e, stack: s);
|
||||
}
|
||||
try {
|
||||
return _pull().timeout(const Duration(seconds: 25));
|
||||
} catch (e, s) {
|
||||
lastError.value = lastError.value.isEmpty
|
||||
? 'kitűzés pull: $e'
|
||||
: '${lastError.value} · kitűzés pull: $e';
|
||||
AppLogger.e('StackeoutSyncService - _pushThenPull', lastError.value,
|
||||
error: e, stack: s);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ── PUSH ─────────────────────────────────────────────────────────
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'dart:convert';
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
import 'package:terepi_seged/services/app_logger.dart';
|
||||
import 'package:terepi_seged/services/contact_service.dart';
|
||||
import 'package:terepi_seged/services/device_identity_service.dart';
|
||||
import 'package:terepi_seged/services/stakeout_sync_service.dart';
|
||||
@@ -81,31 +82,35 @@ class TsSyncService extends GetxService {
|
||||
lastError.value = '';
|
||||
|
||||
try {
|
||||
lastError.value = '';
|
||||
// Eszköz-regiszter frissítése (last_seen_at).
|
||||
if (Get.isRegistered<DeviceIdentityService>()) {
|
||||
await DeviceIdentityService.to.registerDevice();
|
||||
await _isolate(
|
||||
'eszköz regisztációja', DeviceIdentityService.to.registerDevice);
|
||||
}
|
||||
|
||||
await _discoverMemberProjects();
|
||||
await _push();
|
||||
await _pull();
|
||||
await _isolate('tagság felderítése', _discoverMemberProjects);
|
||||
await _isolate('feltöltés', _push);
|
||||
await _isolate('letöltés', _pull);
|
||||
|
||||
// Megosztott rétegek (5. lépés) — ha a service be van kötve.
|
||||
if (Get.isRegistered<LayerSyncService>()) {
|
||||
await LayerSyncService.to.pullAll();
|
||||
await _isolate('rétegek', LayerSyncService.to.pullAll);
|
||||
}
|
||||
|
||||
if (Get.isRegistered<StakeoutSyncService>()) {
|
||||
await StakeoutSyncService.to.sync();
|
||||
await _isolate('kitűzés', StakeoutSyncService.to.sync);
|
||||
}
|
||||
|
||||
if (Get.isRegistered<ContactService>()) {
|
||||
await ContactService.to.flush();
|
||||
await _isolate('kapcsolatok', () => ContactService.to.flush());
|
||||
}
|
||||
|
||||
lastSyncedAt.value = DateTime.now();
|
||||
} catch (e) {
|
||||
} catch (e, s) {
|
||||
lastError.value = e.toString();
|
||||
AppLogger.e('TsSyncService - SyncNow', lastError.value,
|
||||
error: e, stack: s);
|
||||
} finally {
|
||||
await refreshPendingCount();
|
||||
isSyncing.value = false;
|
||||
@@ -139,11 +144,11 @@ class TsSyncService extends GetxService {
|
||||
// ═════════════════════════════════════════════════════════════════
|
||||
|
||||
Future<void> _push() async {
|
||||
await _pushProjects();
|
||||
await _pushMeasuredPoints();
|
||||
await pushTracks();
|
||||
await pushTrackPoints();
|
||||
await _pushNoteItems();
|
||||
await _isolate('projektek push', _pushProjects);
|
||||
await _isolate('mérési pontok', _pushMeasuredPoints);
|
||||
await _isolate('track-ek push', pushTracks);
|
||||
await _isolate('track-pontok push', pushTrackPoints);
|
||||
await _isolate('jegyzetek push', _pushNoteItems);
|
||||
}
|
||||
|
||||
Future<void> _pushProjects() async {
|
||||
@@ -287,7 +292,7 @@ class TsSyncService extends GetxService {
|
||||
// Minden szinkronizált (nem lokális) projekt.
|
||||
final projects = await AppDatabase.instance.listProjects();
|
||||
for (final p in projects.where((p) => !p.isLocalOnly)) {
|
||||
await _pullProject(p.id!, p.uuid);
|
||||
await _isolate('letöltés (${p.name})', () => _pullProject(p.id!, p.uuid));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,4 +451,20 @@ class TsSyncService extends GetxService {
|
||||
if (localIso == null || localIso.isEmpty) return null;
|
||||
return DateTime.parse(localIso).toUtc().toIso8601String();
|
||||
}
|
||||
|
||||
/// Egy lépés elszigetelt futtatása: hiba vagy időtúllépés esetén NEM
|
||||
/// dobja tovább — csak feljegyzi és a szinkron a KÖVETKEZŐ lépéssel
|
||||
/// folytatódik. Enélkül egyetlen hibás sor (típushiba, FK-ütközés stb.)
|
||||
/// vagy egy beragadt hálózati hívás CSENDBEN leállítaná az összes
|
||||
/// további lépést, minden ciklusban, örökre.
|
||||
Future<void> _isolate(String label, Future<void> Function() fn,
|
||||
{Duration timeout = const Duration(seconds: 25)}) async {
|
||||
try {
|
||||
await fn().timeout(timeout);
|
||||
} catch (e) {
|
||||
lastError.value = lastError.value.isEmpty
|
||||
? '$label: $e'
|
||||
: '${lastError.value} · $label: $e';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user