Skip to content

Commit c2d808c

Browse files
Next round
1 parent 761d0d3 commit c2d808c

File tree

3 files changed

+126
-122
lines changed

3 files changed

+126
-122
lines changed

packages/firestore/src/core/component_provider.ts

Lines changed: 78 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,19 @@ import {
4444
MemoryReferenceDelegate
4545
} from '../local/memory_persistence';
4646

47-
export interface Components {
47+
/**
48+
* Initializes and wires up all core components for Firestore. Implementations
49+
* override `initialize()` to provide all components.
50+
*/
51+
export interface ComponentProvider {
4852
persistence: Persistence;
4953
sharedClientState: SharedClientState;
5054
localStore: LocalStore;
5155
syncEngine: SyncEngine;
5256
gcScheduler: GarbageCollectionScheduler | null;
5357
remoteStore: RemoteStore;
5458
eventManager: EventManager;
55-
}
5659

57-
/**
58-
* Initializes and wires up all core components for Firestore.
59-
*/
60-
export interface ComponentProvider {
6160
initialize(
6261
asyncQueue: AsyncQueue,
6362
databaseInfo: DatabaseInfo,
@@ -67,7 +66,7 @@ export interface ComponentProvider {
6766
initialUser: User,
6867
maxConcurrentLimboResolutions: number,
6968
persistenceSettings: PersistenceSettings
70-
): Promise<Components>;
69+
): Promise<void>;
7170

7271
clearPersistence(databaseId: DatabaseInfo): Promise<void>;
7372
}
@@ -76,6 +75,14 @@ export interface ComponentProvider {
7675
* Provides all components needed for Firestore with IndexedDB persistence.
7776
*/
7877
export class IndexedDbComponentProvider implements ComponentProvider {
78+
persistence!: IndexedDbPersistence;
79+
sharedClientState!: SharedClientState;
80+
localStore!: LocalStore;
81+
syncEngine!: SyncEngine;
82+
gcScheduler!: GarbageCollectionScheduler | null;
83+
remoteStore!: RemoteStore;
84+
eventManager!: EventManager;
85+
7986
async initialize(
8087
asyncQueue: AsyncQueue,
8188
databaseInfo: DatabaseInfo,
@@ -85,13 +92,12 @@ export class IndexedDbComponentProvider implements ComponentProvider {
8592
initialUser: User,
8693
maxConcurrentLimboResolutions: number,
8794
persistenceSettings: PersistenceSettings
88-
): Promise<Components> {
95+
): Promise<void> {
8996
assert(
9097
persistenceSettings.durable,
9198
'IndexedDbComponentProvider can only provide durable persistence'
9299
);
93-
94-
const components: Partial<Components> = {};
100+
assert(!this.sharedClientState, 'initialize() already called');
95101

96102
const persistenceKey = IndexedDbPersistence.buildStoragePrefix(
97103
databaseInfo
@@ -105,7 +111,7 @@ export class IndexedDbComponentProvider implements ComponentProvider {
105111
);
106112
}
107113

108-
components.sharedClientState = persistenceSettings.synchronizeTabs
114+
this.sharedClientState = persistenceSettings.synchronizeTabs
109115
? new WebStorageSharedClientState(
110116
asyncQueue,
111117
platform,
@@ -114,73 +120,69 @@ export class IndexedDbComponentProvider implements ComponentProvider {
114120
initialUser
115121
)
116122
: new MemorySharedClientState();
117-
components.sharedClientState.onlineStateHandler = onlineState =>
118-
components.syncEngine!.applyOnlineStateChange(
123+
this.sharedClientState.onlineStateHandler = onlineState =>
124+
this.syncEngine!.applyOnlineStateChange(
119125
onlineState,
120126
OnlineStateSource.SharedClientState
121127
);
122128

123-
components.persistence = await IndexedDbPersistence.createIndexedDbPersistence(
124-
{
125-
allowTabSynchronization: persistenceSettings.synchronizeTabs,
126-
persistenceKey,
127-
clientId,
128-
platform,
129-
queue: asyncQueue,
130-
serializer,
131-
lruParams: LruParams.withCacheSize(persistenceSettings.cacheSizeBytes),
132-
sequenceNumberSyncer: components.sharedClientState
133-
}
134-
);
129+
this.persistence = await IndexedDbPersistence.createIndexedDbPersistence({
130+
allowTabSynchronization: persistenceSettings.synchronizeTabs,
131+
persistenceKey,
132+
clientId,
133+
platform,
134+
queue: asyncQueue,
135+
serializer,
136+
lruParams: LruParams.withCacheSize(persistenceSettings.cacheSizeBytes),
137+
sequenceNumberSyncer: this.sharedClientState
138+
});
135139

136-
const garbageCollector = (components.persistence as IndexedDbPersistence)
137-
.referenceDelegate.garbageCollector;
140+
const garbageCollector = this.persistence.referenceDelegate
141+
.garbageCollector;
138142

139-
components.gcScheduler = new LruScheduler(garbageCollector, asyncQueue);
140-
components.localStore = new LocalStore(
141-
components.persistence,
143+
this.gcScheduler = new LruScheduler(garbageCollector, asyncQueue);
144+
this.localStore = new LocalStore(
145+
this.persistence,
142146
new IndexFreeQueryEngine(),
143147
initialUser
144148
);
145-
components.remoteStore = new RemoteStore(
146-
components.localStore,
149+
this.remoteStore = new RemoteStore(
150+
this.localStore,
147151
datastore,
148152
asyncQueue,
149153
onlineState =>
150-
components.syncEngine!.applyOnlineStateChange(
154+
this.syncEngine!.applyOnlineStateChange(
151155
onlineState,
152156
OnlineStateSource.RemoteStore
153157
),
154158
platform.newConnectivityMonitor()
155159
);
156-
components.syncEngine = new SyncEngine(
157-
components.localStore,
158-
components.remoteStore,
159-
components.sharedClientState,
160+
this.syncEngine = new SyncEngine(
161+
this.localStore,
162+
this.remoteStore,
163+
this.sharedClientState,
160164
initialUser,
161165
maxConcurrentLimboResolutions
162166
);
163-
components.eventManager = new EventManager(components.syncEngine);
167+
this.eventManager = new EventManager(this.syncEngine);
164168

165-
components.remoteStore.syncEngine = components.syncEngine;
166-
components.sharedClientState.syncEngine = components.syncEngine;
169+
this.remoteStore.syncEngine = this.syncEngine;
170+
this.sharedClientState.syncEngine = this.syncEngine;
167171

168-
await components.sharedClientState.start();
169-
await components.remoteStore.start();
170-
await components.localStore.start();
172+
await this.sharedClientState.start();
173+
await this.remoteStore.start();
174+
await this.localStore.start();
171175

172176
// NOTE: This will immediately call the listener, so we make sure to
173177
// set it after localStore / remoteStore are started.
174-
await components.persistence.setPrimaryStateListener(async isPrimary => {
175-
await components.syncEngine!.applyPrimaryState(isPrimary);
176-
if (isPrimary && !components.gcScheduler!.started) {
177-
components.gcScheduler!.start(components.localStore!);
178+
await this.persistence.setPrimaryStateListener(async isPrimary => {
179+
await this.syncEngine.applyPrimaryState(isPrimary);
180+
if (isPrimary && !this.gcScheduler!.started) {
181+
this.gcScheduler!.start(this.localStore);
178182
} else if (!isPrimary) {
179-
components.gcScheduler!.stop();
183+
this.gcScheduler!.stop();
180184
}
181185
});
182-
183-
return components as Components;
184186
}
185187

186188
clearPersistence(databaseInfo: DatabaseInfo): Promise<void> {
@@ -200,6 +202,14 @@ const MEMORY_ONLY_PERSISTENCE_ERROR_MESSAGE =
200202
* Provides all components needed for Firestore with in-memory persistence.
201203
*/
202204
export class MemoryComponentProvider implements ComponentProvider {
205+
persistence!: Persistence;
206+
sharedClientState!: SharedClientState;
207+
localStore!: LocalStore;
208+
syncEngine!: SyncEngine;
209+
gcScheduler!: GarbageCollectionScheduler | null;
210+
remoteStore!: RemoteStore;
211+
eventManager!: EventManager;
212+
203213
constructor(
204214
readonly referenceDelegateFactory: (
205215
p: MemoryPersistence
@@ -215,54 +225,50 @@ export class MemoryComponentProvider implements ComponentProvider {
215225
initialUser: User,
216226
maxConcurrentLimboResolutions: number,
217227
persistenceSettings: PersistenceSettings
218-
): Promise<Components> {
228+
): Promise<void> {
219229
if (persistenceSettings.durable) {
220230
throw new FirestoreError(
221231
Code.FAILED_PRECONDITION,
222232
MEMORY_ONLY_PERSISTENCE_ERROR_MESSAGE
223233
);
224234
}
225235

226-
const components: Partial<Components> = {};
227-
228-
components.persistence = new MemoryPersistence(
236+
this.persistence = new MemoryPersistence(
229237
clientId,
230238
this.referenceDelegateFactory
231239
);
232-
components.gcScheduler = null;
233-
components.sharedClientState = new MemorySharedClientState();
234-
components.localStore = new LocalStore(
235-
components.persistence,
240+
this.gcScheduler = null;
241+
this.sharedClientState = new MemorySharedClientState();
242+
this.localStore = new LocalStore(
243+
this.persistence,
236244
new IndexFreeQueryEngine(),
237245
initialUser
238246
);
239-
components.remoteStore = new RemoteStore(
240-
components.localStore,
247+
this.remoteStore = new RemoteStore(
248+
this.localStore,
241249
datastore,
242250
asyncQueue,
243251
onlineState =>
244-
components.syncEngine!.applyOnlineStateChange(
252+
this.syncEngine!.applyOnlineStateChange(
245253
onlineState,
246254
OnlineStateSource.RemoteStore
247255
),
248256
platform.newConnectivityMonitor()
249257
);
250-
components.syncEngine = new SyncEngine(
251-
components.localStore,
252-
components.remoteStore,
253-
components.sharedClientState,
258+
this.syncEngine = new SyncEngine(
259+
this.localStore,
260+
this.remoteStore,
261+
this.sharedClientState,
254262
initialUser,
255263
maxConcurrentLimboResolutions
256264
);
257-
components.eventManager = new EventManager(components.syncEngine);
258-
259-
components.remoteStore.syncEngine = components.syncEngine;
265+
this.eventManager = new EventManager(this.syncEngine);
260266

261-
await components.remoteStore.start();
262-
await components.remoteStore.applyPrimaryState(true);
263-
await components.syncEngine.applyPrimaryState(true);
267+
this.remoteStore.syncEngine = this.syncEngine;
264268

265-
return components as Components;
269+
await this.remoteStore.start();
270+
await this.remoteStore.applyPrimaryState(true);
271+
await this.syncEngine.applyPrimaryState(true);
266272
}
267273

268274
clearPersistence(): never {

packages/firestore/src/core/firestore_client.ts

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -171,28 +171,12 @@ export class FirestoreClient {
171171

172172
logDebug(LOG_TAG, 'Initializing. user=', user.uid);
173173

174-
this.platform
175-
.loadConnection(this.databaseInfo)
176-
.then(async connection => {
177-
const serializer = this.platform.newSerializer(
178-
this.databaseInfo.databaseId
179-
);
180-
const datastore = new Datastore(
181-
this.asyncQueue,
182-
connection,
183-
this.credentials,
184-
serializer
185-
);
186-
187-
await this.initializeComponents(
188-
datastore,
189-
componentProvider,
190-
persistenceSettings,
191-
user,
192-
persistenceResult
193-
);
194-
})
195-
.then(initializationDone.resolve, initializationDone.reject);
174+
return this.initializeComponents(
175+
componentProvider,
176+
persistenceSettings,
177+
user,
178+
persistenceResult
179+
).then(initializationDone.resolve, initializationDone.reject);
196180
} else {
197181
this.asyncQueue.enqueueAndForget(() => {
198182
return this.handleCredentialChange(user);
@@ -227,7 +211,6 @@ export class FirestoreClient {
227211
* platform can't possibly support our implementation then this method rejects
228212
* the persistenceResult and falls back on memory-only persistence.
229213
*
230-
* @param datastore The Datastore component.
231214
* @param componentProvider The provider that provides all core componennts
232215
* for IndexedDB or memory-backed persistence
233216
* @param persistenceSettings Settings object to configure offline persistence
@@ -241,14 +224,28 @@ export class FirestoreClient {
241224
* succeeded.
242225
*/
243226
private async initializeComponents(
244-
datastore: Datastore,
245227
componentProvider: ComponentProvider,
246228
persistenceSettings: PersistenceSettings,
247229
user: User,
248230
persistenceResult: Deferred<void>
249231
): Promise<void> {
250232
try {
251-
const components = await componentProvider.initialize(
233+
// TODO(mrschmidt): Ideally, ComponentProvider would also initialize
234+
// Datastore (without duplicating the initializing logic once per
235+
// provider).
236+
237+
const connection = await this.platform.loadConnection(this.databaseInfo);
238+
const serializer = this.platform.newSerializer(
239+
this.databaseInfo.databaseId
240+
);
241+
const datastore = new Datastore(
242+
this.asyncQueue,
243+
connection,
244+
this.credentials,
245+
serializer
246+
);
247+
248+
await componentProvider.initialize(
252249
this.asyncQueue,
253250
this.databaseInfo,
254251
this.platform,
@@ -259,13 +256,13 @@ export class FirestoreClient {
259256
persistenceSettings
260257
);
261258

262-
this.persistence = components.persistence;
263-
this.sharedClientState = components.sharedClientState;
264-
this.localStore = components.localStore;
265-
this.remoteStore = components.remoteStore;
266-
this.syncEngine = components.syncEngine;
267-
this.gcScheduler = components.gcScheduler;
268-
this.eventMgr = components.eventManager;
259+
this.persistence = componentProvider.persistence;
260+
this.sharedClientState = componentProvider.sharedClientState;
261+
this.localStore = componentProvider.localStore;
262+
this.remoteStore = componentProvider.remoteStore;
263+
this.syncEngine = componentProvider.syncEngine;
264+
this.gcScheduler = componentProvider.gcScheduler;
265+
this.eventMgr = componentProvider.eventManager;
269266

270267
// When a user calls clearPersistence() in one client, all other clients
271268
// need to be terminated to allow the delete to succeed.
@@ -289,7 +286,6 @@ export class FirestoreClient {
289286
error
290287
);
291288
return this.initializeComponents(
292-
datastore,
293289
new MemoryComponentProvider(),
294290
{ durable: false },
295291
user,

0 commit comments

Comments
 (0)