Skip to content

Commit 39322b3

Browse files
Merge d1064a8 into ee33ebf
2 parents ee33ebf + d1064a8 commit 39322b3

33 files changed

+3722
-12462
lines changed
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { Firestore } from './database';
19+
import { DatabaseInfo } from '../../../src/core/database_info';
20+
import {
21+
FirestoreClient,
22+
PersistenceSettings
23+
} from '../../../src/core/firestore_client';
24+
import { Code, FirestoreError } from '../../../src/util/error';
25+
import {
26+
MemoryOfflineComponentProvider,
27+
OfflineComponentProvider,
28+
OnlineComponentProvider
29+
} from '../../../src/core/component_provider';
30+
import { DEFAULT_HOST, DEFAULT_SSL } from '../../../lite/src/api/components';
31+
import { LocalStore } from '../../../src/local/local_store';
32+
import { Deferred } from '../../../src/util/promise';
33+
34+
// The components module manages the lifetime of dependencies of the Firestore
35+
// client. Dependencies can be lazily constructed and only one exists per
36+
// Firestore instance.
37+
38+
// TODO: These should be promises too
39+
const offlineComponentProviders = new Map<
40+
Firestore,
41+
OfflineComponentProvider
42+
>();
43+
const onlineComponentProviders = new Map<Firestore, OnlineComponentProvider>();
44+
45+
/**
46+
* An instance map that ensures only one FirestoreClient exists per Firestore
47+
* instance.
48+
*/
49+
const firestoreClientInstances = new Map<Firestore, Promise<FirestoreClient>>();
50+
51+
/**
52+
* Returns the initialized and started FirestoreClient for the given Firestore
53+
* instance. If none exists, creates a new FirestoreClient with memory
54+
* persistence. Callers must invoke removeFirestoreClient() when the Firestore
55+
* instance is terminated.
56+
*/
57+
export function getFirestoreClient(
58+
firestore: Firestore
59+
): Promise<FirestoreClient> {
60+
if (firestore._terminated) {
61+
throw new FirestoreError(
62+
Code.FAILED_PRECONDITION,
63+
'The client has already been terminated.'
64+
);
65+
}
66+
if (!firestoreClientInstances.has(firestore)) {
67+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
68+
initializeFirestoreClient(firestore, {
69+
durable: false
70+
});
71+
}
72+
return firestoreClientInstances.get(firestore)!;
73+
}
74+
75+
async function getOfflineComponentProvider(
76+
firestore: Firestore
77+
): Promise<OfflineComponentProvider> {
78+
let offlineComponentProvider = offlineComponentProviders.get(firestore);
79+
if (!offlineComponentProvider) {
80+
offlineComponentProvider = new MemoryOfflineComponentProvider();
81+
offlineComponentProviders.set(firestore, offlineComponentProvider);
82+
const componentConfiguration = {
83+
asyncQueue: firestore._queue,
84+
databaseInfo: firestore._databaseId,
85+
clientId: null as any,
86+
credentials: null as any,
87+
initialUser: null as any,
88+
maxConcurrentLimboResolutions: null as any,
89+
persistenceSettings: null as any
90+
};
91+
await offlineComponentProvider.initialize(componentConfiguration as any);
92+
}
93+
return offlineComponentProvider;
94+
}
95+
96+
async function getOnlineComponentProvider(
97+
firestore: Firestore
98+
): Promise<OnlineComponentProvider> {
99+
let onlineComponentProvider = onlineComponentProviders.get(firestore);
100+
if (!onlineComponentProvider) {
101+
onlineComponentProvider = new OnlineComponentProvider();
102+
onlineComponentProviders.set(firestore, onlineComponentProvider);
103+
const componentConfiguration = {
104+
asyncQueue: firestore._queue,
105+
databaseInfo: firestore._databaseId,
106+
clientId: null as any,
107+
credentials: null as any,
108+
initialUser: null as any,
109+
maxConcurrentLimboResolutions: null as any,
110+
persistenceSettings: null as any
111+
};
112+
await onlineComponentProvider.initialize(
113+
await getOfflineComponentProvider(firestore),
114+
componentConfiguration as any
115+
);
116+
}
117+
return onlineComponentProvider;
118+
}
119+
120+
/**
121+
* Creates a new FirestoreClient for the given Firestore instance. Throws if the
122+
* instance exists.
123+
*
124+
* @param firestore The Firestore instance for which to create the
125+
* FirestoreClient.
126+
* @param componentProvider The component provider to use.
127+
* @param persistenceSettings Settings for the component provider.
128+
*/
129+
export function initializeFirestoreClient(
130+
firestore: Firestore,
131+
persistenceSettings: PersistenceSettings
132+
): Promise<void> {
133+
if (firestore._initialized) {
134+
throw new FirestoreError(
135+
Code.FAILED_PRECONDITION,
136+
'Firestore has already been started and persistence can no longer ' +
137+
'be enabled. You can only enable persistence before calling ' +
138+
'any other methods on a Firestore object.'
139+
);
140+
}
141+
const databaseInfo = firestore._getDatabaseInfo();
142+
const firestoreClient = new FirestoreClient(
143+
firestore._credentials,
144+
firestore._queue
145+
);
146+
const initializationDeferred = new Deferred<FirestoreClient>();
147+
firestoreClientInstances.set(firestore, initializationDeferred.promise);
148+
149+
Promise.all([
150+
getOfflineComponentProvider(firestore),
151+
getOnlineComponentProvider(firestore)
152+
]).then(([offlineComponentProvider, onlineComponentProvider]) => {
153+
firestoreClient
154+
.start(
155+
databaseInfo,
156+
offlineComponentProvider,
157+
onlineComponentProvider,
158+
persistenceSettings
159+
)
160+
.then(() => initializationDeferred.resolve(firestoreClient));
161+
});
162+
return initializationDeferred.promise.then(() => {});
163+
}
164+
165+
/**
166+
* Removes and terminates the FirestoreClient for the given instance if it has
167+
* been started.
168+
*/
169+
export async function removeFirestoreClient(
170+
firestore: Firestore
171+
): Promise<void> {
172+
const firestoreClient = await firestoreClientInstances.get(firestore);
173+
if (firestoreClient) {
174+
firestoreClientInstances.delete(firestore);
175+
return firestoreClient.terminate();
176+
}
177+
}
178+
179+
export async function setComponentProviders(
180+
firestore: Firestore,
181+
offlineComponentProvider: OfflineComponentProvider,
182+
onlineComponentProvider: OnlineComponentProvider
183+
): Promise<void> {
184+
const componentConfiguration = firestore._getConfiguration();
185+
await offlineComponentProvider.initialize(componentConfiguration);
186+
await onlineComponentProvider.initialize(
187+
offlineComponentProvider,
188+
componentConfiguration
189+
);
190+
offlineComponentProviders.set(firestore, offlineComponentProvider);
191+
onlineComponentProviders.set(firestore, onlineComponentProvider);
192+
}
193+
194+
export function getLocalStore(firestore: Firestore): Promise<LocalStore> {
195+
if (firestore._terminated) {
196+
throw new FirestoreError(
197+
Code.FAILED_PRECONDITION,
198+
'The client has already been terminated.'
199+
);
200+
}
201+
return getOfflineComponentProvider(firestore).then(
202+
provider => provider.localStore
203+
);
204+
}

0 commit comments

Comments
 (0)