fix: require exact telemetry bundle CSV schema during restore

This commit is contained in:
bponders12-cell 2026-09-01 21:20:38 -04:00
parent b0e53591b5
commit 9074234fd3
1 changed files with 16 additions and 25 deletions

View File

@ -62,11 +62,7 @@ class CloudRestoreService {
} }
final metadataResult = await _metadata.reconcileMetadata(); final metadataResult = await _metadata.reconcileMetadata();
final snapshot = await _firestore final snapshot = await _firestore.collection('users').doc(user.uid).collection('rides').get();
.collection('users')
.doc(user.uid)
.collection('rides')
.get();
var telemetryRestored = 0; var telemetryRestored = 0;
var telemetrySkipped = 0; var telemetrySkipped = 0;
@ -80,37 +76,26 @@ class CloudRestoreService {
continue; continue;
} }
final localRide = await (_db.select(_db.rides) final localRide = await (_db.select(_db.rides)..where((ride) => ride.cloudRideId.equals(cloudRideId))).getSingleOrNull();
..where((ride) => ride.cloudRideId.equals(cloudRideId)))
.getSingleOrNull();
if (localRide == null) { if (localRide == null) {
telemetryFailed++; telemetryFailed++;
continue; continue;
} }
final telemetryCount = await (_db.select(_db.telemetrySamples) final telemetryCount = await (_db.select(_db.telemetrySamples)..where((sample) => sample.rideId.equals(localRide.id))).get().then((rows) => rows.length);
..where((sample) => sample.rideId.equals(localRide.id)))
.get()
.then((rows) => rows.length);
if (telemetryCount > 0) { if (telemetryCount > 0) {
telemetrySkipped++; telemetrySkipped++;
continue; continue;
} }
final result = await _r2DownloadService.downloadTelemetryBundle( final result = await _r2DownloadService.downloadTelemetryBundle(idToken: idToken, cloudRideId: cloudRideId);
idToken: idToken,
cloudRideId: cloudRideId,
);
if (!result.success || result.zipBytes == null) { if (!result.success || result.zipBytes == null) {
telemetryFailed++; telemetryFailed++;
continue; continue;
} }
try { try {
final restoredCount = await _restoreTelemetryCsv( final restoredCount = await _restoreTelemetryCsv(localRide.id, result.zipBytes!);
localRide.id,
result.zipBytes!,
);
if (restoredCount > 0) { if (restoredCount > 0) {
telemetryRestored++; telemetryRestored++;
} else { } else {
@ -138,8 +123,7 @@ class CloudRestoreService {
final lines = const LineSplitter().convert(csv); final lines = const LineSplitter().convert(csv);
if (lines.length < 2) return 0; if (lines.length < 2) return 0;
final header = lines.first.split(','); const expected = <String>[
final expected = <String>[
'timestamp', 'timestamp',
'latitude', 'latitude',
'longitude', 'longitude',
@ -155,8 +139,8 @@ class CloudRestoreService {
'longitudinalG', 'longitudinalG',
'lateralG', 'lateralG',
]; ];
if (header.length != expected.length || !List<String>.generate(header.length, (i) => header[i]) final header = lines.first.split(',');
.every((value) => expected.contains(value))) { if (header.length != expected.length || !_sameStringList(header, expected)) {
throw const FormatException('Unsupported telemetry.csv schema.'); throw const FormatException('Unsupported telemetry.csv schema.');
} }
@ -189,7 +173,6 @@ class CloudRestoreService {
} }
if (companions.isEmpty) return 0; if (companions.isEmpty) return 0;
await _db.transaction(() async { await _db.transaction(() async {
for (final companion in companions) { for (final companion in companions) {
await _db.into(_db.telemetrySamples).insert(companion); await _db.into(_db.telemetrySamples).insert(companion);
@ -206,5 +189,13 @@ class CloudRestoreService {
return drift.Value(parsed); return drift.Value(parsed);
} }
bool _sameStringList(List<String> actual, List<String> expected) {
if (actual.length != expected.length) return false;
for (var i = 0; i < expected.length; i++) {
if (actual[i] != expected[i]) return false;
}
return true;
}
bool _isValidCloudRideId(String id) => RegExp(r'^ride_[A-Za-z0-9_-]+$').hasMatch(id); bool _isValidCloudRideId(String id) => RegExp(r'^ride_[A-Za-z0-9_-]+$').hasMatch(id);
} }