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 _batch = []; Timer? _flushTimer; StreamSubscription? _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 start(Stream 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 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 _flush() async { if (_batch.isEmpty || _sessionId == null) return; final toWrite = List.from(_batch); _batch.clear(); await _db.insertFrames(_sessionId!, toWrite); } void dispose() { _flushTimer?.cancel(); _frameSub?.cancel(); } }