@@ -55,12 +55,29 @@ import {
55
55
} from './watch_change' ;
56
56
import { ByteString } from '../util/byte_string' ;
57
57
import { isIndexedDbTransactionError } from '../local/simple_db' ;
58
+ import { User } from '../auth/user' ;
58
59
59
60
const LOG_TAG = 'RemoteStore' ;
60
61
61
62
// TODO(b/35853402): Negotiate this with the stream.
62
63
const MAX_PENDING_WRITES = 10 ;
63
64
65
+ /** Reasons for why the RemoteStore may be offline. */
66
+ const enum OfflineCause {
67
+ /** The user has explicitly disabled the network (via `disableNetwork()`). */
68
+ UserDisabled ,
69
+ /** An IndexedDb failure occurred while persisting a stream update. */
70
+ IndexedDbFailed ,
71
+ /** The tab is not the primary tab (only relevant with multi-tab). */
72
+ IsSecondary ,
73
+ /** We are restarting the streams due to an Auth credential change. */
74
+ CredentialChange ,
75
+ /** The connectivity state of the environment has changed. */
76
+ ConnectivityChange ,
77
+ /** The RemoteStore has been shut down. */
78
+ Shutdown
79
+ }
80
+
64
81
/**
65
82
* RemoteStore - An interface to remotely stored data, basically providing a
66
83
* wrapper around the Datastore that is more reliable for the rest of the
@@ -117,19 +134,10 @@ export class RemoteStore implements TargetMetadataProvider {
117
134
private watchChangeAggregator : WatchChangeAggregator | null = null ;
118
135
119
136
/**
120
- * Set to true by enableNetwork() and false by disableNetwork() and indicates
121
- * the user-preferred network state .
137
+ * A set of reasons for why the RemoteStore may be offline. If empty, the
138
+ * RemoteStore may start its network connections .
122
139
*/
123
- private networkEnabled = false ;
124
-
125
- private isPrimary = false ;
126
-
127
- /**
128
- * When set to `true`, the network was taken offline due to an IndexedDB
129
- * failure. The state is flipped to `false` when access becomes available
130
- * again.
131
- */
132
- private indexedDbFailed = false ;
140
+ private offlineCauses = new Set < OfflineCause > ( ) ;
133
141
134
142
private onlineStateTracker : OnlineStateTracker ;
135
143
@@ -193,7 +201,7 @@ export class RemoteStore implements TargetMetadataProvider {
193
201
194
202
/** Re-enables the network. Idempotent. */
195
203
enableNetwork ( ) : Promise < void > {
196
- this . networkEnabled = true ;
204
+ this . offlineCauses . delete ( OfflineCause . UserDisabled ) ;
197
205
return this . enableNetworkInternal ( ) ;
198
206
}
199
207
@@ -215,7 +223,7 @@ export class RemoteStore implements TargetMetadataProvider {
215
223
* enableNetwork().
216
224
*/
217
225
async disableNetwork ( ) : Promise < void > {
218
- this . networkEnabled = false ;
226
+ this . offlineCauses . add ( OfflineCause . UserDisabled ) ;
219
227
await this . disableNetworkInternal ( ) ;
220
228
221
229
// Set the OnlineState to Offline so get()s return from cache, etc.
@@ -239,7 +247,7 @@ export class RemoteStore implements TargetMetadataProvider {
239
247
240
248
async shutdown ( ) : Promise < void > {
241
249
logDebug ( LOG_TAG , 'RemoteStore shutting down.' ) ;
242
- this . networkEnabled = false ;
250
+ this . offlineCauses . add ( OfflineCause . Shutdown ) ;
243
251
await this . disableNetworkInternal ( ) ;
244
252
this . connectivityMonitor . shutdown ( ) ;
245
253
@@ -348,7 +356,7 @@ export class RemoteStore implements TargetMetadataProvider {
348
356
}
349
357
350
358
canUseNetwork ( ) : boolean {
351
- return ! this . indexedDbFailed && this . isPrimary && this . networkEnabled ;
359
+ return this . offlineCauses . size === 0 ;
352
360
}
353
361
354
362
private cleanUpWatchStreamState ( ) : void {
@@ -456,10 +464,10 @@ export class RemoteStore implements TargetMetadataProvider {
456
464
) : Promise < void > {
457
465
if ( isIndexedDbTransactionError ( e ) ) {
458
466
debugAssert (
459
- ! this . indexedDbFailed ,
467
+ ! this . offlineCauses . has ( OfflineCause . IndexedDbFailed ) ,
460
468
'Unexpected network event when IndexedDB was marked failed.'
461
469
) ;
462
- this . indexedDbFailed = true ;
470
+ this . offlineCauses . add ( OfflineCause . IndexedDbFailed ) ;
463
471
464
472
// Disable network and raise offline snapshots
465
473
await this . disableNetworkInternal ( ) ;
@@ -476,7 +484,7 @@ export class RemoteStore implements TargetMetadataProvider {
476
484
this . asyncQueue . enqueueRetryable ( async ( ) => {
477
485
logDebug ( LOG_TAG , 'Retrying IndexedDB access' ) ;
478
486
await op ! ( ) ;
479
- this . indexedDbFailed = false ;
487
+ this . offlineCauses . delete ( OfflineCause . IndexedDbFailed ) ;
480
488
await this . enableNetworkInternal ( ) ;
481
489
} ) ;
482
490
} else {
@@ -750,31 +758,39 @@ export class RemoteStore implements TargetMetadataProvider {
750
758
}
751
759
752
760
private async restartNetwork ( ) : Promise < void > {
753
- this . networkEnabled = false ;
761
+ this . offlineCauses . add ( OfflineCause . ConnectivityChange ) ;
754
762
await this . disableNetworkInternal ( ) ;
755
763
this . onlineStateTracker . set ( OnlineState . Unknown ) ;
756
- await this . enableNetwork ( ) ;
764
+ this . offlineCauses . delete ( OfflineCause . ConnectivityChange ) ;
765
+ await this . enableNetworkInternal ( ) ;
757
766
}
758
767
759
- async handleCredentialChange ( ) : Promise < void > {
760
- if ( this . canUseNetwork ( ) ) {
761
- // Tear down and re-create our network streams. This will ensure we get a fresh auth token
762
- // for the new user and re-fill the write pipeline with new mutations from the LocalStore
763
- // (since mutations are per-user).
764
- logDebug ( LOG_TAG , 'RemoteStore restarting streams for new credential' ) ;
765
- await this . restartNetwork ( ) ;
766
- }
768
+ async handleCredentialChange ( user : User ) : Promise < void > {
769
+ this . asyncQueue . verifyOperationInProgress ( ) ;
770
+
771
+ // Tear down and re-create our network streams. This will ensure we get a
772
+ // fresh auth token for the new user and re-fill the write pipeline with
773
+ // new mutations from the LocalStore (since mutations are per-user).
774
+ logDebug ( LOG_TAG , 'RemoteStore received new credentials' ) ;
775
+ this . offlineCauses . add ( OfflineCause . CredentialChange ) ;
776
+
777
+ await this . disableNetworkInternal ( ) ;
778
+ this . onlineStateTracker . set ( OnlineState . Unknown ) ;
779
+ await this . syncEngine . handleCredentialChange ( user ) ;
780
+
781
+ this . offlineCauses . delete ( OfflineCause . CredentialChange ) ;
782
+ await this . enableNetworkInternal ( ) ;
767
783
}
768
784
769
785
/**
770
786
* Toggles the network state when the client gains or loses its primary lease.
771
787
*/
772
788
async applyPrimaryState ( isPrimary : boolean ) : Promise < void > {
773
- this . isPrimary = isPrimary ;
774
-
775
- if ( isPrimary && this . networkEnabled ) {
776
- await this . enableNetwork ( ) ;
789
+ if ( isPrimary ) {
790
+ this . offlineCauses . delete ( OfflineCause . IsSecondary ) ;
791
+ await this . enableNetworkInternal ( ) ;
777
792
} else if ( ! isPrimary ) {
793
+ this . offlineCauses . add ( OfflineCause . IsSecondary ) ;
778
794
await this . disableNetworkInternal ( ) ;
779
795
this . onlineStateTracker . set ( OnlineState . Unknown ) ;
780
796
}
0 commit comments