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