onSnapshotStateChange method

  1. @override
void Function()? onSnapshotStateChange(
  1. String snapshotId,
  2. void callback(
    1. SessionSnapshot snapshot
    ), {
  3. Map<String, dynamic>? context,
})

Watches a snapshot for state changes via polling and invokes callback with the reconstructed snapshot whenever it changes.

The Dart Firestore client has no real-time listener, so this re-reads the snapshot on the configured snapshotWatchPollInterval, de-duplicating by serialized content so only real changes fire the callback. Transient read failures (network / permission) are swallowed; the next poll retries.

Returns an unsubscribe function that stops polling.

Implementation

@override
void Function()? onSnapshotStateChange(
  String snapshotId,
  void Function(SessionSnapshot snapshot) callback, {
  Map<String, dynamic>? context,
}) {
  var closed = false;
  var isReading = false;
  String? lastSerialized;

  Future<void> poll() async {
    if (closed || isReading) return;
    isReading = true;
    try {
      final snapshot = await getSnapshot(
        snapshotId: snapshotId,
        context: context,
      );
      if (closed || snapshot == null) return;
      final serialized = jsonEncode(snapshot.toJson());
      if (serialized == lastSerialized) return;
      lastSerialized = serialized;
      callback(snapshot);
    } catch (err) {
      // Swallow errors so a transient read failure doesn't crash the poller.
      // The next tick retries.
      _logger.warning(
        'FirestoreSessionStore.onSnapshotStateChange failed to load '
        'snapshot $snapshotId',
        err,
      );
    } finally {
      isReading = false;
    }
  }

  final timer = Timer.periodic(
    _snapshotWatchPollInterval,
    (_) => unawaited(poll()),
  );
  // Surface the current state immediately (if the snapshot already exists).
  unawaited(poll());

  return () {
    closed = true;
    timer.cancel();
  };
}