hondavert-dev/lib/core/datalog/datalog_recorder.dart
2026-10-13 00:34:11 +00:00

95 lines
2.3 KiB
Dart

import 'dart:async';
import 'dart:typed_data';
import 'datalog_db.dart';
import '../models/datalog_session.dart';
/// Listens to a raw frame stream and batches writes to SQLite every 500ms.
class DatalogRecorder {
final DatalogDb _db;
int? _sessionId;
String? _ecuType;
DateTime? _startTime;
int _frameCount = 0;
final List<PendingFrame> _batch = [];
Timer? _flushTimer;
StreamSubscription<Uint8List>? _frameSub;
bool get isRecording => _sessionId != null;
int get frameCount => _frameCount;
int? get sessionId => _sessionId;
DatalogRecorder(this._db);
/// Start a new recording session, listening to [frameStream].
Future<void> start(Stream<Uint8List> frameStream, String ecuType) async {
if (isRecording) await stop();
_ecuType = ecuType;
_startTime = DateTime.now();
_frameCount = 0;
_batch.clear();
final session = DatalogSession(
ecuType: ecuType,
startTime: _startTime!,
);
_sessionId = await _db.insertSession(session);
// Collect frames into batch buffer
_frameSub = frameStream.listen((Uint8List frame) {
_batch.add(PendingFrame(DateTime.now(), frame));
_frameCount++;
});
// Flush to DB every 500ms
_flushTimer = Timer.periodic(const Duration(milliseconds: 500), (_) {
_flush();
});
}
/// Stop recording and finalise the session row.
Future<DatalogSession?> stop() async {
if (!isRecording) return null;
_flushTimer?.cancel();
_flushTimer = null;
await _frameSub?.cancel();
_frameSub = null;
await _flush(); // write any remaining buffered frames
final endTime = DateTime.now();
await _db.closeSession(_sessionId!, endTime, _frameCount);
final finished = DatalogSession(
id: _sessionId,
ecuType: _ecuType!,
startTime: _startTime!,
endTime: endTime,
frameCount: _frameCount,
);
_sessionId = null;
_ecuType = null;
_startTime = null;
_frameCount = 0;
return finished;
}
Future<void> _flush() async {
if (_batch.isEmpty || _sessionId == null) return;
final toWrite = List<PendingFrame>.from(_batch);
_batch.clear();
await _db.insertFrames(_sessionId!, toWrite);
}
void dispose() {
_flushTimer?.cancel();
_frameSub?.cancel();
}
}