Szinkronizáció javítása,
This commit is contained in:
@@ -13,6 +13,10 @@ class PhoneGpsConnection implements GnssConnection {
|
|||||||
final _positionController = StreamController<Position>.broadcast();
|
final _positionController = StreamController<Position>.broadcast();
|
||||||
StreamSubscription<Position>? _positionSub;
|
StreamSubscription<Position>? _positionSub;
|
||||||
|
|
||||||
|
int _retryCount = 0;
|
||||||
|
static const _maxRetries = 5;
|
||||||
|
Timer? _retryTimer;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Stream<String> get nmeaLines => const Stream.empty(); // Nincs NMEA
|
Stream<String> get nmeaLines => const Stream.empty(); // Nincs NMEA
|
||||||
|
|
||||||
@@ -42,20 +46,44 @@ class PhoneGpsConnection implements GnssConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_stateController.add(GnssConnectionState.connected);
|
_stateController.add(GnssConnectionState.connected);
|
||||||
|
_retryCount = 0;
|
||||||
|
await _startPositionStream();
|
||||||
|
}
|
||||||
|
|
||||||
// Belső GPS folyamatos olvasása
|
Future<void> _startPositionStream() async {
|
||||||
|
await _positionSub?.cancel();
|
||||||
_positionSub = Geolocator.getPositionStream(
|
_positionSub = Geolocator.getPositionStream(
|
||||||
locationSettings: const LocationSettings(
|
locationSettings: const LocationSettings(
|
||||||
accuracy: LocationAccuracy.high,
|
accuracy: LocationAccuracy.high,
|
||||||
distanceFilter: 0, // Folyamatos frissítés
|
distanceFilter: 0, // Folyamatos frissítés
|
||||||
),
|
),
|
||||||
).listen((Position pos) {
|
).listen(
|
||||||
_positionController.add(pos);
|
(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
|
@override
|
||||||
Future<void> disconnect() async {
|
Future<void> disconnect() async {
|
||||||
|
_retryTimer?.cancel();
|
||||||
await _positionSub?.cancel();
|
await _positionSub?.cancel();
|
||||||
_stateController.add(GnssConnectionState.disconnected);
|
_stateController.add(GnssConnectionState.disconnected);
|
||||||
}
|
}
|
||||||
@@ -67,6 +95,7 @@ class PhoneGpsConnection implements GnssConnection {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
_retryTimer?.cancel();
|
||||||
_positionSub?.cancel();
|
_positionSub?.cancel();
|
||||||
_positionController.close();
|
_positionController.close();
|
||||||
_stateController.close();
|
_stateController.close();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:get/get.dart';
|
|||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||||
import 'package:terepi_seged/services/app_database.dart';
|
import 'package:terepi_seged/services/app_database.dart';
|
||||||
|
import 'package:terepi_seged/services/app_logger.dart';
|
||||||
|
|
||||||
import 'stakeout_service.dart';
|
import 'stakeout_service.dart';
|
||||||
|
|
||||||
@@ -52,8 +53,23 @@ class StakeoutSyncService extends GetxService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> _pushThenPull() async {
|
Future<bool> _pushThenPull() async {
|
||||||
await _push();
|
try {
|
||||||
return _pull();
|
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 ─────────────────────────────────────────────────────────
|
// ── PUSH ─────────────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'dart:convert';
|
|||||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:supabase_flutter/supabase_flutter.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/contact_service.dart';
|
||||||
import 'package:terepi_seged/services/device_identity_service.dart';
|
import 'package:terepi_seged/services/device_identity_service.dart';
|
||||||
import 'package:terepi_seged/services/stakeout_sync_service.dart';
|
import 'package:terepi_seged/services/stakeout_sync_service.dart';
|
||||||
@@ -81,31 +82,35 @@ class TsSyncService extends GetxService {
|
|||||||
lastError.value = '';
|
lastError.value = '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
lastError.value = '';
|
||||||
// Eszköz-regiszter frissítése (last_seen_at).
|
// Eszköz-regiszter frissítése (last_seen_at).
|
||||||
if (Get.isRegistered<DeviceIdentityService>()) {
|
if (Get.isRegistered<DeviceIdentityService>()) {
|
||||||
await DeviceIdentityService.to.registerDevice();
|
await _isolate(
|
||||||
|
'eszköz regisztációja', DeviceIdentityService.to.registerDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _discoverMemberProjects();
|
await _isolate('tagság felderítése', _discoverMemberProjects);
|
||||||
await _push();
|
await _isolate('feltöltés', _push);
|
||||||
await _pull();
|
await _isolate('letöltés', _pull);
|
||||||
|
|
||||||
// Megosztott rétegek (5. lépés) — ha a service be van kötve.
|
// Megosztott rétegek (5. lépés) — ha a service be van kötve.
|
||||||
if (Get.isRegistered<LayerSyncService>()) {
|
if (Get.isRegistered<LayerSyncService>()) {
|
||||||
await LayerSyncService.to.pullAll();
|
await _isolate('rétegek', LayerSyncService.to.pullAll);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Get.isRegistered<StakeoutSyncService>()) {
|
if (Get.isRegistered<StakeoutSyncService>()) {
|
||||||
await StakeoutSyncService.to.sync();
|
await _isolate('kitűzés', StakeoutSyncService.to.sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Get.isRegistered<ContactService>()) {
|
if (Get.isRegistered<ContactService>()) {
|
||||||
await ContactService.to.flush();
|
await _isolate('kapcsolatok', () => ContactService.to.flush());
|
||||||
}
|
}
|
||||||
|
|
||||||
lastSyncedAt.value = DateTime.now();
|
lastSyncedAt.value = DateTime.now();
|
||||||
} catch (e) {
|
} catch (e, s) {
|
||||||
lastError.value = e.toString();
|
lastError.value = e.toString();
|
||||||
|
AppLogger.e('TsSyncService - SyncNow', lastError.value,
|
||||||
|
error: e, stack: s);
|
||||||
} finally {
|
} finally {
|
||||||
await refreshPendingCount();
|
await refreshPendingCount();
|
||||||
isSyncing.value = false;
|
isSyncing.value = false;
|
||||||
@@ -139,11 +144,11 @@ class TsSyncService extends GetxService {
|
|||||||
// ═════════════════════════════════════════════════════════════════
|
// ═════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
Future<void> _push() async {
|
Future<void> _push() async {
|
||||||
await _pushProjects();
|
await _isolate('projektek push', _pushProjects);
|
||||||
await _pushMeasuredPoints();
|
await _isolate('mérési pontok', _pushMeasuredPoints);
|
||||||
await pushTracks();
|
await _isolate('track-ek push', pushTracks);
|
||||||
await pushTrackPoints();
|
await _isolate('track-pontok push', pushTrackPoints);
|
||||||
await _pushNoteItems();
|
await _isolate('jegyzetek push', _pushNoteItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _pushProjects() async {
|
Future<void> _pushProjects() async {
|
||||||
@@ -287,7 +292,7 @@ class TsSyncService extends GetxService {
|
|||||||
// Minden szinkronizált (nem lokális) projekt.
|
// Minden szinkronizált (nem lokális) projekt.
|
||||||
final projects = await AppDatabase.instance.listProjects();
|
final projects = await AppDatabase.instance.listProjects();
|
||||||
for (final p in projects.where((p) => !p.isLocalOnly)) {
|
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;
|
if (localIso == null || localIso.isEmpty) return null;
|
||||||
return DateTime.parse(localIso).toUtc().toIso8601String();
|
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