watch method

Future<void> watch(
  1. String mountId, {
  2. Duration interval = const Duration(seconds: 15),
  3. Duration debounce = const Duration(milliseconds: 500),
  4. void log(
    1. String message
    )?,
  5. DriveProgress? onProgress,
  6. Future<void>? until,
})

Watches mountId and auto-syncs on local changes and on an interval poll. Runs until until completes; when omitted it runs until the returned future is never completed (the caller cancels via process signal). Directory mounts also react to filesystem events.

Implementation

Future<void> watch(
  String mountId, {
  Duration interval = const Duration(seconds: 15),
  Duration debounce = const Duration(milliseconds: 500),
  void Function(String message)? log,
  DriveProgress? onProgress,
  Future<void>? until,
}) async {
  final record = require(mountId);
  var running = false;
  Timer? debounceTimer;

  Future<void> trigger(String why) async {
    if (running) return;
    running = true;
    try {
      final o = await sync(mountId, onProgress: onProgress);
      if (o.isConflict) {
        log?.call('conflict ($why): ${o.conflict!.message}');
      } else if (o.direction != null) {
        log?.call(
          'synced ${o.direction!.wireValue} ($why): ${o.applied} change(s)',
        );
      }
    } on Object catch (e) {
      log?.call('sync failed ($why): $e');
    } finally {
      running = false;
    }
  }

  StreamSubscription<FileSystemEvent>? fsSub;
  if (!record.isGit && record.localPath != null) {
    fsSub = Directory(record.localPath!).watch(recursive: true).listen((_) {
      debounceTimer?.cancel();
      debounceTimer = Timer(debounce, () => trigger('fs'));
    });
  }
  final timer = Timer.periodic(interval, (_) => trigger('poll'));

  await trigger('initial');
  log?.call('watching ${record.id} (Ctrl-C to stop)');
  try {
    // Run until cancelled: either the caller-supplied [until] completes, or
    // (when none is given) the process is interrupted.
    await (until ?? Completer<void>().future);
  } finally {
    await fsSub?.cancel();
    timer.cancel();
    debounceTimer?.cancel();
  }
}