Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support restart of FirestoreClient #8430

Merged
merged 13 commits into from
Sep 20, 2024
5 changes: 5 additions & 0 deletions .changeset/small-geckos-mix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@firebase/firestore': patch
---

Refactor Firestore client instantiation. This prepares for future features that require client to restart.
83 changes: 45 additions & 38 deletions packages/firestore/src/api/cache_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import {
LruGcMemoryOfflineComponentProvider,
MemoryOfflineComponentProvider,
MultiTabOfflineComponentProvider,
OfflineComponentProvider,
OfflineComponentProviderFactory,
OnlineComponentProviderFactory,
OnlineComponentProvider
} from '../core/component_provider';

Expand All @@ -38,31 +39,31 @@ export type MemoryLocalCache = {
/**
* @internal
*/
_onlineComponentProvider: OnlineComponentProvider;
_onlineComponentProvider: OnlineComponentProviderFactory;
/**
* @internal
*/
_offlineComponentProvider: MemoryOfflineComponentProvider;
_offlineComponentProvider: OfflineComponentProviderFactory;
};

class MemoryLocalCacheImpl implements MemoryLocalCache {
kind: 'memory' = 'memory';
/**
* @internal
*/
_onlineComponentProvider: OnlineComponentProvider;
_onlineComponentProvider: OnlineComponentProviderFactory;
/**
* @internal
*/
_offlineComponentProvider: MemoryOfflineComponentProvider;
_offlineComponentProvider: OfflineComponentProviderFactory;

constructor(settings?: MemoryCacheSettings) {
this._onlineComponentProvider = new OnlineComponentProvider();
this._onlineComponentProvider = OnlineComponentProvider.provider;
if (settings?.garbageCollector) {
this._offlineComponentProvider =
settings.garbageCollector._offlineComponentProvider;
} else {
this._offlineComponentProvider = new MemoryOfflineComponentProvider();
this._offlineComponentProvider = MemoryOfflineComponentProvider.provider;
}
}

Expand All @@ -83,23 +84,23 @@ export type PersistentLocalCache = {
/**
* @internal
*/
_onlineComponentProvider: OnlineComponentProvider;
_onlineComponentProvider: OnlineComponentProviderFactory;
/**
* @internal
*/
_offlineComponentProvider: OfflineComponentProvider;
_offlineComponentProvider: OfflineComponentProviderFactory;
};

class PersistentLocalCacheImpl implements PersistentLocalCache {
kind: 'persistent' = 'persistent';
/**
* @internal
*/
_onlineComponentProvider: OnlineComponentProvider;
_onlineComponentProvider: OnlineComponentProviderFactory;
/**
* @internal
*/
_offlineComponentProvider: OfflineComponentProvider;
_offlineComponentProvider: OfflineComponentProviderFactory;

constructor(settings: PersistentCacheSettings | undefined) {
let tabManager: PersistentTabManager;
Expand Down Expand Up @@ -147,7 +148,7 @@ export type MemoryEagerGarbageCollector = {
/**
* @internal
*/
_offlineComponentProvider: MemoryOfflineComponentProvider;
_offlineComponentProvider: OfflineComponentProviderFactory;
};

/**
Expand All @@ -167,18 +168,18 @@ export type MemoryLruGarbageCollector = {
/**
* @internal
*/
_offlineComponentProvider: MemoryOfflineComponentProvider;
_offlineComponentProvider: OfflineComponentProviderFactory;
};

class MemoryEagerGarbageCollectorImpl implements MemoryEagerGarbageCollector {
kind: 'memoryEager' = 'memoryEager';
/**
* @internal
*/
_offlineComponentProvider: MemoryOfflineComponentProvider;
_offlineComponentProvider: OfflineComponentProviderFactory;

constructor() {
this._offlineComponentProvider = new MemoryOfflineComponentProvider();
this._offlineComponentProvider = MemoryOfflineComponentProvider.provider;
}

toJSON(): {} {
Expand All @@ -191,12 +192,12 @@ class MemoryLruGarbageCollectorImpl implements MemoryLruGarbageCollector {
/**
* @internal
*/
_offlineComponentProvider: MemoryOfflineComponentProvider;
_offlineComponentProvider: OfflineComponentProviderFactory;

constructor(cacheSize?: number) {
this._offlineComponentProvider = new LruGcMemoryOfflineComponentProvider(
cacheSize
);
this._offlineComponentProvider = {
build: () => new LruGcMemoryOfflineComponentProvider(cacheSize)
};
}

toJSON(): {} {
Expand Down Expand Up @@ -297,11 +298,11 @@ export type PersistentSingleTabManager = {
/**
* @internal
*/
_onlineComponentProvider?: OnlineComponentProvider;
_onlineComponentProvider?: OnlineComponentProviderFactory;
/**
* @internal
*/
_offlineComponentProvider?: OfflineComponentProvider;
_offlineComponentProvider?: OfflineComponentProviderFactory;
};

class SingleTabManagerImpl implements PersistentSingleTabManager {
Expand All @@ -310,11 +311,11 @@ class SingleTabManagerImpl implements PersistentSingleTabManager {
/**
* @internal
*/
_onlineComponentProvider?: OnlineComponentProvider;
_onlineComponentProvider?: OnlineComponentProviderFactory;
/**
* @internal
*/
_offlineComponentProvider?: OfflineComponentProvider;
_offlineComponentProvider?: OfflineComponentProviderFactory;

constructor(private forceOwnership?: boolean) {}

Expand All @@ -328,12 +329,15 @@ class SingleTabManagerImpl implements PersistentSingleTabManager {
_initialize(
settings: Omit<PersistentCacheSettings, 'tabManager'> | undefined
): void {
this._onlineComponentProvider = new OnlineComponentProvider();
this._offlineComponentProvider = new IndexedDbOfflineComponentProvider(
this._onlineComponentProvider,
settings?.cacheSizeBytes,
this.forceOwnership
);
this._onlineComponentProvider = OnlineComponentProvider.provider;
this._offlineComponentProvider = {
build: (onlineComponents: OnlineComponentProvider) =>
new IndexedDbOfflineComponentProvider(
onlineComponents,
settings?.cacheSizeBytes,
this.forceOwnership
)
};
}
}

Expand All @@ -350,12 +354,12 @@ export type PersistentMultipleTabManager = {
/**
* @internal
*/
_onlineComponentProvider?: OnlineComponentProvider;
_onlineComponentProvider?: OnlineComponentProviderFactory;
/**
* @internal
*/

_offlineComponentProvider?: OfflineComponentProvider;
_offlineComponentProvider?: OfflineComponentProviderFactory;
};

class MultiTabManagerImpl implements PersistentMultipleTabManager {
Expand All @@ -364,11 +368,11 @@ class MultiTabManagerImpl implements PersistentMultipleTabManager {
/**
* @internal
*/
_onlineComponentProvider?: OnlineComponentProvider;
_onlineComponentProvider?: OnlineComponentProviderFactory;
/**
* @internal
*/
_offlineComponentProvider?: OfflineComponentProvider;
_offlineComponentProvider?: OfflineComponentProviderFactory;

toJSON(): {} {
return { kind: this.kind };
Expand All @@ -380,11 +384,14 @@ class MultiTabManagerImpl implements PersistentMultipleTabManager {
_initialize(
settings: Omit<PersistentCacheSettings, 'tabManager'> | undefined
): void {
this._onlineComponentProvider = new OnlineComponentProvider();
this._offlineComponentProvider = new MultiTabOfflineComponentProvider(
this._onlineComponentProvider,
settings?.cacheSizeBytes
);
this._onlineComponentProvider = OnlineComponentProvider.provider;
this._offlineComponentProvider = {
build: (onlineComponents: OnlineComponentProvider) =>
new MultiTabOfflineComponentProvider(
onlineComponents,
settings?.cacheSizeBytes
)
};
}
}

Expand Down
33 changes: 24 additions & 9 deletions packages/firestore/src/api/credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ export class FirebaseAuthCredentialsProvider
* The auth token listener registered with FirebaseApp, retained here so we
* can unregister it.
*/
private tokenListener!: () => void;
private tokenListener: (() => void) | undefined;

/** Tracks the current User. */
private currentUser: User = User.UNAUTHENTICATED;
Expand All @@ -256,6 +256,10 @@ export class FirebaseAuthCredentialsProvider
asyncQueue: AsyncQueue,
changeListener: CredentialChangeListener<User>
): void {
hardAssert(
this.tokenListener === undefined,
'Token listener already added'
);
let lastTokenId = this.tokenCounter;

// A change listener that prevents double-firing for the same token change.
Expand Down Expand Up @@ -293,8 +297,10 @@ export class FirebaseAuthCredentialsProvider
const registerAuth = (auth: FirebaseAuthInternal): void => {
logDebug('FirebaseAuthCredentialsProvider', 'Auth detected');
this.auth = auth;
this.auth.addAuthTokenListener(this.tokenListener);
awaitNextToken();
if (this.tokenListener) {
this.auth.addAuthTokenListener(this.tokenListener);
awaitNextToken();
}
};

this.authProvider.onInit(auth => registerAuth(auth));
Expand Down Expand Up @@ -365,9 +371,10 @@ export class FirebaseAuthCredentialsProvider
}

shutdown(): void {
if (this.auth) {
this.auth.removeAuthTokenListener(this.tokenListener!);
if (this.auth && this.tokenListener) {
this.auth.removeAuthTokenListener(this.tokenListener);
}
this.tokenListener = undefined;
}

// Auth.getUid() can return null even with a user logged in. It is because
Expand Down Expand Up @@ -484,7 +491,7 @@ export class FirebaseAppCheckTokenProvider
* The AppCheck token listener registered with FirebaseApp, retained here so
* we can unregister it.
*/
private tokenListener!: AppCheckTokenListener;
private tokenListener: AppCheckTokenListener | undefined;
private forceRefresh = false;
private appCheck: FirebaseAppCheckInternal | null = null;
private latestAppCheckToken: string | null = null;
Expand All @@ -497,6 +504,11 @@ export class FirebaseAppCheckTokenProvider
asyncQueue: AsyncQueue,
changeListener: CredentialChangeListener<string>
): void {
hardAssert(
this.tokenListener === undefined,
'Token listener already added'
);

const onTokenChanged: (
tokenResult: AppCheckTokenResult
) => Promise<void> = tokenResult => {
Expand Down Expand Up @@ -524,7 +536,9 @@ export class FirebaseAppCheckTokenProvider
const registerAppCheck = (appCheck: FirebaseAppCheckInternal): void => {
logDebug('FirebaseAppCheckTokenProvider', 'AppCheck detected');
this.appCheck = appCheck;
this.appCheck.addTokenListener(this.tokenListener);
if (this.tokenListener) {
this.appCheck.addTokenListener(this.tokenListener);
}
};

this.appCheckProvider.onInit(appCheck => registerAppCheck(appCheck));
Expand Down Expand Up @@ -579,9 +593,10 @@ export class FirebaseAppCheckTokenProvider
}

shutdown(): void {
if (this.appCheck) {
this.appCheck.removeTokenListener(this.tokenListener!);
if (this.appCheck && this.tokenListener) {
this.appCheck.removeTokenListener(this.tokenListener);
}
this.tokenListener = undefined;
}
}

Expand Down
Loading
Loading