@@ -309,7 +309,12 @@ class StreamingSyncImplementation implements StreamingSync {
309
309
}
310
310
311
311
Future <void > _rustStreamingSyncIteration () async {
312
- await _ActiveRustStreamingIteration (this ).syncIteration ();
312
+ logger.info ('Starting Rust sync iteration' );
313
+ final response = await _ActiveRustStreamingIteration (this ).syncIteration ();
314
+ logger.info (
315
+ 'Ending Rust sync iteration. Immediate restart: ${response .immediateRestart }' );
316
+ // Note: With the current loop in streamingSync(), any return value that
317
+ // isn't an exception triggers an immediate restart.
313
318
}
314
319
315
320
Future <(List <BucketRequest >, Map <String , BucketDescription ?>)>
@@ -610,7 +615,7 @@ final class _ActiveRustStreamingIteration {
610
615
var _hadSyncLine = false ;
611
616
612
617
StreamSubscription <void >? _completedUploads;
613
- final Completer <void > _completedStream = Completer ();
618
+ final Completer <RustSyncIterationResult > _completedStream = Completer ();
614
619
615
620
_ActiveRustStreamingIteration (this .sync );
616
621
@@ -620,7 +625,7 @@ final class _ActiveRustStreamingIteration {
620
625
.toList ();
621
626
}
622
627
623
- Future <void > syncIteration () async {
628
+ Future <RustSyncIterationResult > syncIteration () async {
624
629
try {
625
630
await _control (
626
631
'start' ,
@@ -632,7 +637,7 @@ final class _ActiveRustStreamingIteration {
632
637
}),
633
638
);
634
639
assert (_completedStream.isCompleted, 'Should have started streaming' );
635
- await _completedStream.future;
640
+ return await _completedStream.future;
636
641
} finally {
637
642
_isActive = false ;
638
643
_completedUploads? .cancel ();
@@ -655,10 +660,12 @@ final class _ActiveRustStreamingIteration {
655
660
}).map (ReceivedLine .new );
656
661
}
657
662
658
- Future <void > _handleLines (EstablishSyncStream request) async {
663
+ Future <RustSyncIterationResult > _handleLines (
664
+ EstablishSyncStream request) async {
659
665
final events = addBroadcast (
660
666
_receiveLines (request.request), sync ._nonLineSyncEvents.stream);
661
667
668
+ var needsImmediateRestart = false ;
662
669
loop:
663
670
await for (final event in events) {
664
671
if (! _isActive || sync .aborted) {
@@ -674,7 +681,8 @@ final class _ActiveRustStreamingIteration {
674
681
await _control ('line_text' , line);
675
682
case UploadCompleted ():
676
683
await _control ('completed_upload' );
677
- case AbortCurrentIteration ():
684
+ case AbortCurrentIteration (: final hideDisconnectState):
685
+ needsImmediateRestart = hideDisconnectState;
678
686
break loop;
679
687
case TokenRefreshComplete ():
680
688
await _control ('refreshed_token' );
@@ -683,6 +691,8 @@ final class _ActiveRustStreamingIteration {
683
691
convert.json.encode (_encodeSubscriptions (currentSubscriptions)));
684
692
}
685
693
}
694
+
695
+ return (immediateRestart: needsImmediateRestart);
686
696
}
687
697
688
698
/// Triggers a local CRUD upload when the first sync line has been received.
@@ -736,10 +746,11 @@ final class _ActiveRustStreamingIteration {
736
746
sync .logger.warning ('Could not prefetch credentials' , e, s);
737
747
});
738
748
}
739
- case CloseSyncStream ():
749
+ case CloseSyncStream (: final hideDisconnect ):
740
750
if (! sync .aborted) {
741
751
_isActive = false ;
742
- sync ._nonLineSyncEvents.add (const AbortCurrentIteration ());
752
+ sync ._nonLineSyncEvents
753
+ .add (AbortCurrentIteration (hideDisconnectState: hideDisconnect));
743
754
}
744
755
case FlushFileSystem ():
745
756
await sync .adapter.flushFileSystem ();
@@ -751,6 +762,8 @@ final class _ActiveRustStreamingIteration {
751
762
}
752
763
}
753
764
765
+ typedef RustSyncIterationResult = ({bool immediateRestart});
766
+
754
767
sealed class SyncEvent {}
755
768
756
769
final class ReceivedLine implements SyncEvent {
@@ -768,7 +781,14 @@ final class TokenRefreshComplete implements SyncEvent {
768
781
}
769
782
770
783
final class AbortCurrentIteration implements SyncEvent {
771
- const AbortCurrentIteration ();
784
+ /// Whether we should immediately disconnect and hide the `disconnected`
785
+ /// state.
786
+ ///
787
+ /// This is used when we're changing subscription, to hide the brief downtime
788
+ /// we have while reconnecting.
789
+ final bool hideDisconnectState;
790
+
791
+ const AbortCurrentIteration ({this .hideDisconnectState = false });
772
792
}
773
793
774
794
final class HandleChangedSubscriptions implements SyncEvent {
0 commit comments