diff options
Diffstat (limited to 'Firestore/Source')
-rw-r--r-- | Firestore/Source/API/FIRFirestore+Internal.h | 7 | ||||
-rw-r--r-- | Firestore/Source/API/FIRFirestore.mm | 24 | ||||
-rw-r--r-- | Firestore/Source/Auth/FSTCredentialsProvider.h | 88 | ||||
-rw-r--r-- | Firestore/Source/Auth/FSTCredentialsProvider.mm | 157 | ||||
-rw-r--r-- | Firestore/Source/Auth/FSTEmptyCredentialsProvider.h | 28 | ||||
-rw-r--r-- | Firestore/Source/Auth/FSTEmptyCredentialsProvider.mm | 53 | ||||
-rw-r--r-- | Firestore/Source/Core/FSTFirestoreClient.h | 5 | ||||
-rw-r--r-- | Firestore/Source/Core/FSTFirestoreClient.mm | 59 | ||||
-rw-r--r-- | Firestore/Source/Remote/FSTDatastore.h | 9 | ||||
-rw-r--r-- | Firestore/Source/Remote/FSTDatastore.mm | 51 | ||||
-rw-r--r-- | Firestore/Source/Remote/FSTStream.h | 18 | ||||
-rw-r--r-- | Firestore/Source/Remote/FSTStream.mm | 30 |
12 files changed, 117 insertions, 412 deletions
diff --git a/Firestore/Source/API/FIRFirestore+Internal.h b/Firestore/Source/API/FIRFirestore+Internal.h index 7bc419a..a52533d 100644 --- a/Firestore/Source/API/FIRFirestore+Internal.h +++ b/Firestore/Source/API/FIRFirestore+Internal.h @@ -16,6 +16,9 @@ #import "FIRFirestore.h" +#include <memory> + +#include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "absl/strings/string_view.h" @@ -24,7 +27,6 @@ NS_ASSUME_NONNULL_BEGIN @class FSTDispatchQueue; @class FSTFirestoreClient; @class FSTUserDataConverter; -@protocol FSTCredentialsProvider; @interface FIRFirestore (/* Init */) @@ -35,7 +37,8 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithProjectID:(const absl::string_view)projectID database:(const absl::string_view)database persistenceKey:(NSString *)persistenceKey - credentialsProvider:(id<FSTCredentialsProvider>)credentialsProvider + credentialsProvider:(std::unique_ptr<firebase::firestore::auth::CredentialsProvider>) + credentialsProvider workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue firebaseApp:(FIRApp *)app; diff --git a/Firestore/Source/API/FIRFirestore.mm b/Firestore/Source/API/FIRFirestore.mm index ce8f8ab..eff0605 100644 --- a/Firestore/Source/API/FIRFirestore.mm +++ b/Firestore/Source/API/FIRFirestore.mm @@ -16,6 +16,10 @@ #import "FIRFirestore.h" +#include <memory> +#include <utility> + +#import <FirebaseCore/FIRApp.h> #import <FirebaseCore/FIRAppInternal.h> #import <FirebaseCore/FIRLogger.h> #import <FirebaseCore/FIROptions.h> @@ -28,7 +32,6 @@ #import "Firestore/Source/API/FIRWriteBatch+Internal.h" #import "Firestore/Source/API/FSTUserDataConverter.h" -#import "Firestore/Source/Auth/FSTCredentialsProvider.h" #import "Firestore/Source/Core/FSTFirestoreClient.h" #import "Firestore/Source/Model/FSTDocumentKey.h" #import "Firestore/Source/Model/FSTPath.h" @@ -37,11 +40,16 @@ #import "Firestore/Source/Util/FSTLogger.h" #import "Firestore/Source/Util/FSTUsageValidation.h" +#include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" +#include "Firestore/core/src/firebase/firestore/auth/firebase_credentials_provider_apple.h" #include "Firestore/core/src/firebase/firestore/core/database_info.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" +#include "absl/memory/memory.h" namespace util = firebase::firestore::util; +using firebase::firestore::auth::CredentialsProvider; +using firebase::firestore::auth::FirebaseCredentialsProvider; using firebase::firestore::core::DatabaseInfo; using firebase::firestore::model::DatabaseId; @@ -52,10 +60,10 @@ extern "C" NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain"; @interface FIRFirestore () { /** The actual owned DatabaseId instance is allocated in FIRFirestore. */ DatabaseId _databaseID; + std::unique_ptr<CredentialsProvider> _credentialsProvider; } @property(nonatomic, strong) NSString *persistenceKey; -@property(nonatomic, strong) id<FSTCredentialsProvider> credentialsProvider; @property(nonatomic, strong) FSTDispatchQueue *workerDispatchQueue; // Note that `client` is updated after initialization, but marking this readwrite would generate an @@ -152,15 +160,15 @@ extern "C" NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain"; FSTDispatchQueue *workerDispatchQueue = [FSTDispatchQueue queueWith:dispatch_queue_create("com.google.firebase.firestore", DISPATCH_QUEUE_SERIAL)]; - id<FSTCredentialsProvider> credentialsProvider; - credentialsProvider = [[FSTFirebaseCredentialsProvider alloc] initWithApp:app]; + std::unique_ptr<CredentialsProvider> credentials_provider = + absl::make_unique<FirebaseCredentialsProvider>(app); NSString *persistenceKey = app.name; firestore = [[FIRFirestore alloc] initWithProjectID:util::MakeStringView(projectID) database:util::MakeStringView(database) persistenceKey:persistenceKey - credentialsProvider:credentialsProvider + credentialsProvider:std::move(credentials_provider) workerDispatchQueue:workerDispatchQueue firebaseApp:app]; instances[key] = firestore; @@ -173,7 +181,7 @@ extern "C" NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain"; - (instancetype)initWithProjectID:(const absl::string_view)projectID database:(const absl::string_view)database persistenceKey:(NSString *)persistenceKey - credentialsProvider:(id<FSTCredentialsProvider>)credentialsProvider + credentialsProvider:(std::unique_ptr<CredentialsProvider>)credentialsProvider workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue firebaseApp:(FIRApp *)app { if (self = [super init]) { @@ -190,7 +198,7 @@ extern "C" NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain"; _dataConverter = [[FSTUserDataConverter alloc] initWithDatabaseID:&_databaseID preConverter:block]; _persistenceKey = persistenceKey; - _credentialsProvider = credentialsProvider; + _credentialsProvider = std::move(credentialsProvider); _workerDispatchQueue = workerDispatchQueue; _app = app; _settings = [[FIRFirestoreSettings alloc] init]; @@ -241,7 +249,7 @@ extern "C" NSString *const FIRFirestoreErrorDomain = @"FIRFirestoreErrorDomain"; _client = [FSTFirestoreClient clientWithDatabaseInfo:database_info usePersistence:_settings.persistenceEnabled - credentialsProvider:_credentialsProvider + credentialsProvider:_credentialsProvider.get() userDispatchQueue:userDispatchQueue workerDispatchQueue:_workerDispatchQueue]; } diff --git a/Firestore/Source/Auth/FSTCredentialsProvider.h b/Firestore/Source/Auth/FSTCredentialsProvider.h deleted file mode 100644 index d2f04e0..0000000 --- a/Firestore/Source/Auth/FSTCredentialsProvider.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2017 Google - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import <Foundation/Foundation.h> - -#include "Firestore/core/src/firebase/firestore/auth/token.h" -#include "Firestore/core/src/firebase/firestore/auth/user.h" - -NS_ASSUME_NONNULL_BEGIN - -@class FIRApp; -@class FSTDispatchQueue; - -#pragma mark - Typedefs - -/** - * `FSTVoidTokenErrorBlock` is a block that gets a token or an error. - * - * @param token An auth token, either valid or invalid when error occurred. - * @param error The error if one occurred, or else `nil`. - */ -typedef void (^FSTVoidGetTokenResultBlock)(firebase::firestore::auth::Token token, - NSError *_Nullable error); - -/** Listener block notified with a User. */ -typedef void (^FSTVoidUserBlock)(firebase::firestore::auth::User user); - -#pragma mark - FSTCredentialsProvider - -/** Provides methods for getting the uid and token for the current user and listen for changes. */ -@protocol FSTCredentialsProvider <NSObject> - -/** Requests token for the current user, optionally forcing a refreshed token to be fetched. */ -- (void)getTokenForcingRefresh:(BOOL)forceRefresh completion:(FSTVoidGetTokenResultBlock)completion; - -/** - * A listener to be notified of user changes (sign-in / sign-out). It is immediately called once - * with the initial user. - * - * Note that this block will be called back on an arbitrary thread that is not the normal Firestore - * worker thread. - */ -@property(nonatomic, copy, nullable, readwrite) FSTVoidUserBlock userChangeListener; - -@end - -#pragma mark - FSTFirebaseCredentialsProvider - -/** - * `FSTFirebaseCredentialsProvider` uses Firebase Auth via `FIRApp` to get an auth token. - * - * NOTE: To simplify the implementation, it requires that you set `userChangeListener` with a - * non-`nil` value no more than once and don't call `getTokenForcingRefresh:` after setting - * it to `nil`. - * - * This class must be implemented in a thread-safe manner since it is accessed from the thread - * backing our internal worker queue and the callbacks from FIRAuth will be executed on an - * arbitrary different thread. - */ -@interface FSTFirebaseCredentialsProvider : NSObject <FSTCredentialsProvider> - -/** - * Initializes a new FSTFirebaseCredentialsProvider. - * - * @param app The Firebase app from which to get credentials. - * - * @return A new instance of FSTFirebaseCredentialsProvider. - */ -- (instancetype)initWithApp:(FIRApp *)app NS_DESIGNATED_INITIALIZER; - -- (id)init NS_UNAVAILABLE; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Auth/FSTCredentialsProvider.mm b/Firestore/Source/Auth/FSTCredentialsProvider.mm deleted file mode 100644 index e0dc8aa..0000000 --- a/Firestore/Source/Auth/FSTCredentialsProvider.mm +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2017 Google - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import "Firestore/Source/Auth/FSTCredentialsProvider.h" - -#import <FirebaseCore/FIRApp.h> -#import <FirebaseCore/FIRAppInternal.h> -#import <GRPCClient/GRPCCall.h> - -#import "FIRFirestoreErrors.h" -#import "Firestore/Source/Util/FSTAssert.h" -#import "Firestore/Source/Util/FSTClasses.h" -#import "Firestore/Source/Util/FSTDispatchQueue.h" - -#include "Firestore/core/src/firebase/firestore/auth/token.h" -#include "Firestore/core/src/firebase/firestore/auth/user.h" -#include "Firestore/core/src/firebase/firestore/util/string_apple.h" - -namespace util = firebase::firestore::util; -using firebase::firestore::auth::Token; -using firebase::firestore::auth::User; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - FSTFirebaseCredentialsProvider -@interface FSTFirebaseCredentialsProvider () { - /** The current user as reported to us via our AuthStateDidChangeListener. */ - User _currentUser; -} - -@property(nonatomic, strong, readonly) FIRApp *app; - -/** Handle used to stop receiving auth changes once userChangeListener is removed. */ -@property(nonatomic, strong, nullable, readwrite) id<NSObject> authListenerHandle; - -/** - * Counter used to detect if the user changed while a -getTokenForcingRefresh: request was - * outstanding. - */ -@property(nonatomic, assign, readwrite) int userCounter; - -@end - -@implementation FSTFirebaseCredentialsProvider { - FSTVoidUserBlock _userChangeListener; -} - -- (instancetype)initWithApp:(FIRApp *)app { - self = [super init]; - if (self) { - _app = app; - _currentUser = User::FromUid([self.app getUID]); - _userCounter = 0; - - // Register for user changes so that we can internally track the current user. - FSTWeakify(self); - _authListenerHandle = [[NSNotificationCenter defaultCenter] - addObserverForName:FIRAuthStateDidChangeInternalNotification - object:nil - queue:nil - usingBlock:^(NSNotification *notification) { - FSTStrongify(self); - if (self) { - @synchronized(self) { - NSDictionary *userInfo = notification.userInfo; - - // ensure we're only notifiying for the current app. - FIRApp *notifiedApp = - userInfo[FIRAuthStateDidChangeInternalNotificationAppKey]; - if (![self.app isEqual:notifiedApp]) { - return; - } - - NSString *uid = userInfo[FIRAuthStateDidChangeInternalNotificationUIDKey]; - User newUser = User::FromUid(uid); - if (newUser != self->_currentUser) { - self->_currentUser = newUser; - self.userCounter++; - FSTVoidUserBlock listenerBlock = self.userChangeListener; - if (listenerBlock) { - listenerBlock(self->_currentUser); - } - } - } - } - }]; - } - return self; -} - -- (void)getTokenForcingRefresh:(BOOL)forceRefresh - completion:(FSTVoidGetTokenResultBlock)completion { - FSTAssert(self.authListenerHandle, @"getToken cannot be called after listener removed."); - - // Take note of the current value of the userCounter so that this method can fail (with a - // FIRFirestoreErrorCodeAborted error) if there is a user change while the request is outstanding. - int initialUserCounter = self.userCounter; - - void (^getTokenCallback)(NSString *, NSError *) = - ^(NSString *_Nullable token, NSError *_Nullable error) { - @synchronized(self) { - if (initialUserCounter != self.userCounter) { - // Cancel the request since the user changed while the request was outstanding so the - // response is likely for a previous user (which user, we can't be sure). - NSDictionary *errorInfo = @{@"details" : @"getToken aborted due to user change."}; - NSError *cancelError = [NSError errorWithDomain:FIRFirestoreErrorDomain - code:FIRFirestoreErrorCodeAborted - userInfo:errorInfo]; - completion(Token::Invalid(), cancelError); - } else { - completion(Token(util::MakeStringView(token), self->_currentUser), error); - } - }; - }; - - [self.app getTokenForcingRefresh:forceRefresh withCallback:getTokenCallback]; -} - -- (void)setUserChangeListener:(nullable FSTVoidUserBlock)block { - @synchronized(self) { - if (block) { - FSTAssert(!_userChangeListener, @"UserChangeListener set twice!"); - - // Fire initial event. - block(_currentUser); - } else { - FSTAssert(self.authListenerHandle, @"UserChangeListener removed twice!"); - FSTAssert(_userChangeListener, @"UserChangeListener removed without being set!"); - [[NSNotificationCenter defaultCenter] removeObserver:self.authListenerHandle]; - self.authListenerHandle = nil; - } - _userChangeListener = block; - } -} - -- (nullable FSTVoidUserBlock)userChangeListener { - @synchronized(self) { - return _userChangeListener; - } -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Auth/FSTEmptyCredentialsProvider.h b/Firestore/Source/Auth/FSTEmptyCredentialsProvider.h deleted file mode 100644 index f805363..0000000 --- a/Firestore/Source/Auth/FSTEmptyCredentialsProvider.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2017 Google - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import <Foundation/Foundation.h> - -#import "Firestore/Source/Auth/FSTCredentialsProvider.h" - -NS_ASSUME_NONNULL_BEGIN - -/** `FSTEmptyCredentialsProvider` always yields an empty token. */ -@interface FSTEmptyCredentialsProvider : NSObject <FSTCredentialsProvider> - -@end - -NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Auth/FSTEmptyCredentialsProvider.mm b/Firestore/Source/Auth/FSTEmptyCredentialsProvider.mm deleted file mode 100644 index 77c08d1..0000000 --- a/Firestore/Source/Auth/FSTEmptyCredentialsProvider.mm +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2017 Google - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#import "Firestore/Source/Auth/FSTEmptyCredentialsProvider.h" - -#import "Firestore/Source/Util/FSTAssert.h" -#import "Firestore/Source/Util/FSTDispatchQueue.h" - -#include "Firestore/core/src/firebase/firestore/auth/token.h" -#include "Firestore/core/src/firebase/firestore/auth/user.h" - -using firebase::firestore::auth::Token; -using firebase::firestore::auth::User; - -NS_ASSUME_NONNULL_BEGIN - -@implementation FSTEmptyCredentialsProvider - -- (void)getTokenForcingRefresh:(BOOL)forceRefresh - completion:(FSTVoidGetTokenResultBlock)completion { - // Invalid token will force the GRPC fallback to use default settings. - completion(Token::Invalid(), nil); -} - -- (void)setUserChangeListener:(nullable FSTVoidUserBlock)block { - // Since the user never changes, we just need to fire the initial event and don't need to hang - // onto the block. - if (block) { - block(User::Unauthenticated()); - } -} - -- (nullable FSTVoidUserBlock)userChangeListener { - // TODO(mikelehen): Implementation omitted for convenience since it's not actually required. - FSTFail(@"Not implemented."); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/Firestore/Source/Core/FSTFirestoreClient.h b/Firestore/Source/Core/FSTFirestoreClient.h index 56101ab..6da5ed3 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.h +++ b/Firestore/Source/Core/FSTFirestoreClient.h @@ -20,6 +20,7 @@ #import "Firestore/Source/Core/FSTViewSnapshot.h" #import "Firestore/Source/Remote/FSTRemoteStore.h" +#include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" #include "Firestore/core/src/firebase/firestore/core/database_info.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" @@ -30,7 +31,6 @@ @class FSTQuery; @class FSTQueryListener; @class FSTTransaction; -@protocol FSTCredentialsProvider; NS_ASSUME_NONNULL_BEGIN @@ -48,7 +48,8 @@ NS_ASSUME_NONNULL_BEGIN */ + (instancetype)clientWithDatabaseInfo:(const firebase::firestore::core::DatabaseInfo &)databaseInfo usePersistence:(BOOL)usePersistence - credentialsProvider:(id<FSTCredentialsProvider>)credentialsProvider + credentialsProvider:(firebase::firestore::auth::CredentialsProvider *) + credentialsProvider // no passing ownership userDispatchQueue:(FSTDispatchQueue *)userDispatchQueue workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue; diff --git a/Firestore/Source/Core/FSTFirestoreClient.mm b/Firestore/Source/Core/FSTFirestoreClient.mm index c60bb7c..fb86e0b 100644 --- a/Firestore/Source/Core/FSTFirestoreClient.mm +++ b/Firestore/Source/Core/FSTFirestoreClient.mm @@ -16,7 +16,8 @@ #import "Firestore/Source/Core/FSTFirestoreClient.h" -#import "Firestore/Source/Auth/FSTCredentialsProvider.h" +#import <future> + #import "Firestore/Source/Core/FSTEventManager.h" #import "Firestore/Source/Core/FSTSyncEngine.h" #import "Firestore/Source/Core/FSTTransaction.h" @@ -34,11 +35,13 @@ #import "Firestore/Source/Util/FSTDispatchQueue.h" #import "Firestore/Source/Util/FSTLogger.h" +#include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" #include "Firestore/core/src/firebase/firestore/core/database_info.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; +using firebase::firestore::auth::CredentialsProvider; using firebase::firestore::auth::User; using firebase::firestore::core::DatabaseInfo; using firebase::firestore::model::DatabaseId; @@ -51,7 +54,8 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithDatabaseInfo:(const DatabaseInfo &)databaseInfo usePersistence:(BOOL)usePersistence - credentialsProvider:(id<FSTCredentialsProvider>)credentialsProvider + credentialsProvider: + (CredentialsProvider *)credentialsProvider // no passing ownership userDispatchQueue:(FSTDispatchQueue *)userDispatchQueue workerDispatchQueue:(FSTDispatchQueue *)queue NS_DESIGNATED_INITIALIZER; @@ -70,7 +74,8 @@ NS_ASSUME_NONNULL_BEGIN */ @property(nonatomic, strong, readonly) FSTDispatchQueue *workerDispatchQueue; -@property(nonatomic, strong, readonly) id<FSTCredentialsProvider> credentialsProvider; +// Does not own the CredentialsProvider instance. +@property(nonatomic, assign, readonly) CredentialsProvider *credentialsProvider; @end @@ -78,7 +83,8 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)clientWithDatabaseInfo:(const DatabaseInfo &)databaseInfo usePersistence:(BOOL)usePersistence - credentialsProvider:(id<FSTCredentialsProvider>)credentialsProvider + credentialsProvider: + (CredentialsProvider *)credentialsProvider // no passing ownership userDispatchQueue:(FSTDispatchQueue *)userDispatchQueue workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue { return [[FSTFirestoreClient alloc] initWithDatabaseInfo:databaseInfo @@ -90,7 +96,8 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithDatabaseInfo:(const DatabaseInfo &)databaseInfo usePersistence:(BOOL)usePersistence - credentialsProvider:(id<FSTCredentialsProvider>)credentialsProvider + credentialsProvider: + (CredentialsProvider *)credentialsProvider // no passing ownership userDispatchQueue:(FSTDispatchQueue *)userDispatchQueue workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue { if (self = [super init]) { @@ -99,32 +106,32 @@ NS_ASSUME_NONNULL_BEGIN _userDispatchQueue = userDispatchQueue; _workerDispatchQueue = workerDispatchQueue; - dispatch_semaphore_t initialUserAvailable = dispatch_semaphore_create(0); - __block bool initialized = false; - __block User initialUser; - FSTWeakify(self); - _credentialsProvider.userChangeListener = ^(User user) { - FSTStrongify(self); - if (self) { - if (!initialized) { - initialUser = user; - initialized = true; - dispatch_semaphore_signal(initialUserAvailable); - } else { - [workerDispatchQueue dispatchAsync:^{ - [self userDidChange:user]; - }]; - } + auto userPromise = std::make_shared<std::promise<User>>(); + + __weak typeof(self) weakSelf = self; + auto userChangeListener = [initialized = false, userPromise, weakSelf, + workerDispatchQueue](User user) mutable { + typeof(self) strongSelf = weakSelf; + if (!strongSelf) return; + + if (!initialized) { + initialized = true; + userPromise->set_value(user); + } else { + [workerDispatchQueue dispatchAsync:^{ + [strongSelf userDidChange:user]; + }]; } }; + _credentialsProvider->SetUserChangeListener(userChangeListener); + // Defer initialization until we get the current user from the userChangeListener. This is // guaranteed to be synchronously dispatched onto our worker queue, so we will be initialized // before any subsequently queued work runs. [_workerDispatchQueue dispatchAsync:^{ - dispatch_semaphore_wait(initialUserAvailable, DISPATCH_TIME_FOREVER); - - [self initializeWithUser:initialUser usePersistence:usePersistence]; + User user = userPromise->get_future().get(); + [self initializeWithUser:user usePersistence:usePersistence]; }]; } return self; @@ -172,7 +179,7 @@ NS_ASSUME_NONNULL_BEGIN FSTDatastore *datastore = [FSTDatastore datastoreWithDatabase:self.databaseInfo workerDispatchQueue:self.workerDispatchQueue - credentials:self.credentialsProvider]; + credentials:_credentialsProvider]; _remoteStore = [FSTRemoteStore remoteStoreWithLocalStore:_localStore datastore:datastore]; @@ -229,7 +236,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)shutdownWithCompletion:(nullable FSTVoidErrorBlock)completion { [self.workerDispatchQueue dispatchAsync:^{ - self.credentialsProvider.userChangeListener = nil; + self->_credentialsProvider->SetUserChangeListener(nullptr); [self.remoteStore shutdown]; [self.localStore shutdown]; diff --git a/Firestore/Source/Remote/FSTDatastore.h b/Firestore/Source/Remote/FSTDatastore.h index 481b6e8..7b8274c 100644 --- a/Firestore/Source/Remote/FSTDatastore.h +++ b/Firestore/Source/Remote/FSTDatastore.h @@ -18,6 +18,7 @@ #import "Firestore/Source/Core/FSTTypes.h" +#include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" #include "Firestore/core/src/firebase/firestore/core/database_info.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "absl/strings/string_view.h" @@ -35,8 +36,6 @@ @class GRPCCall; @class GRXWriter; -@protocol FSTCredentialsProvider; - NS_ASSUME_NONNULL_BEGIN /** @@ -56,13 +55,15 @@ NS_ASSUME_NONNULL_BEGIN /** Creates a new Datastore instance with the given database info. */ + (instancetype)datastoreWithDatabase:(const firebase::firestore::core::DatabaseInfo *)databaseInfo workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue - credentials:(id<FSTCredentialsProvider>)credentials; + credentials:(firebase::firestore::auth::CredentialsProvider *) + credentials; // no passing ownership - (instancetype)init __attribute__((unavailable("Use a static constructor method."))); - (instancetype)initWithDatabaseInfo:(const firebase::firestore::core::DatabaseInfo *)databaseInfo workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue - credentials:(id<FSTCredentialsProvider>)credentials + credentials:(firebase::firestore::auth::CredentialsProvider *) + credentials // no passing ownership NS_DESIGNATED_INITIALIZER; /** diff --git a/Firestore/Source/Remote/FSTDatastore.mm b/Firestore/Source/Remote/FSTDatastore.mm index a6029ee..cb4516e 100644 --- a/Firestore/Source/Remote/FSTDatastore.mm +++ b/Firestore/Source/Remote/FSTDatastore.mm @@ -22,7 +22,6 @@ #import "FIRFirestoreErrors.h" #import "Firestore/Source/API/FIRFirestore+Internal.h" #import "Firestore/Source/API/FIRFirestoreVersion.h" -#import "Firestore/Source/Auth/FSTCredentialsProvider.h" #import "Firestore/Source/Local/FSTLocalStore.h" #import "Firestore/Source/Model/FSTDocument.h" #import "Firestore/Source/Model/FSTDocumentKey.h" @@ -35,12 +34,15 @@ #import "Firestore/Protos/objc/google/firestore/v1beta1/Firestore.pbrpc.h" +#include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" #include "Firestore/core/src/firebase/firestore/auth/token.h" #include "Firestore/core/src/firebase/firestore/core/database_info.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" +#include "Firestore/core/src/firebase/firestore/util/error_apple.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; +using firebase::firestore::auth::CredentialsProvider; using firebase::firestore::auth::Token; using firebase::firestore::core::DatabaseInfo; using firebase::firestore::model::DatabaseId; @@ -70,8 +72,11 @@ typedef GRPCProtoCall * (^RPCFactory)(void); @property(nonatomic, strong, readonly) FSTDispatchQueue *workerDispatchQueue; -/** An object for getting an auth token before each request. */ -@property(nonatomic, strong, readonly) id<FSTCredentialsProvider> credentials; +/** + * An object for getting an auth token before each request. Does not own the CredentialsProvider + * instance. + */ +@property(nonatomic, assign, readonly) CredentialsProvider *credentials; @property(nonatomic, strong, readonly) FSTSerializerBeta *serializer; @@ -81,7 +86,7 @@ typedef GRPCProtoCall * (^RPCFactory)(void); + (instancetype)datastoreWithDatabase:(const DatabaseInfo *)databaseInfo workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue - credentials:(id<FSTCredentialsProvider>)credentials { + credentials:(CredentialsProvider *)credentials { return [[FSTDatastore alloc] initWithDatabaseInfo:databaseInfo workerDispatchQueue:workerDispatchQueue credentials:credentials]; @@ -89,7 +94,7 @@ typedef GRPCProtoCall * (^RPCFactory)(void); - (instancetype)initWithDatabaseInfo:(const DatabaseInfo *)databaseInfo workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue - credentials:(id<FSTCredentialsProvider>)credentials { + credentials:(CredentialsProvider *)credentials { if (self = [super init]) { _databaseInfo = databaseInfo; NSString *host = util::WrapNSStringNoCopy(databaseInfo->host()); @@ -301,24 +306,24 @@ typedef GRPCProtoCall * (^RPCFactory)(void); errorHandler:(FSTVoidErrorBlock)errorHandler { // TODO(mikelehen): We should force a refresh if the previous RPC failed due to an expired token, // but I'm not sure how to detect that right now. http://b/32762461 - [self.credentials - getTokenForcingRefresh:NO - completion:^(Token result, NSError *_Nullable error) { - error = [FSTDatastore firestoreErrorForError:error]; - [self.workerDispatchQueue dispatchAsyncAllowingSameQueue:^{ - if (error) { - errorHandler(error); - } else { - GRPCProtoCall *rpc = rpcFactory(); - [FSTDatastore - prepareHeadersForRPC:rpc - databaseID:&self.databaseInfo->database_id() - token:(result.is_valid() ? result.token() - : absl::string_view())]; - [rpc start]; - } - }]; - }]; + _credentials->GetToken( + /*force_refresh=*/false, + [self, rpcFactory, errorHandler](Token result, const int64_t error_code, + const absl::string_view error_msg) { + NSError *error = util::WrapNSError(error_code, error_msg); + [self.workerDispatchQueue dispatchAsyncAllowingSameQueue:^{ + if (error) { + errorHandler(error); + } else { + GRPCProtoCall *rpc = rpcFactory(); + [FSTDatastore + prepareHeadersForRPC:rpc + databaseID:&self.databaseInfo->database_id() + token:(result.is_valid() ? result.token() : absl::string_view())]; + [rpc start]; + } + }]; + }); } - (FSTWatchStream *)createWatchStream { diff --git a/Firestore/Source/Remote/FSTStream.h b/Firestore/Source/Remote/FSTStream.h index 297d016..e48f1da 100644 --- a/Firestore/Source/Remote/FSTStream.h +++ b/Firestore/Source/Remote/FSTStream.h @@ -19,6 +19,7 @@ #import "Firestore/Source/Core/FSTTypes.h" #import "Firestore/Source/Util/FSTDispatchQueue.h" +#include "Firestore/core/src/firebase/firestore/auth/credentials_provider.h" #include "Firestore/core/src/firebase/firestore/core/database_info.h" @class FSTDocumentKey; @@ -34,7 +35,6 @@ @class GRPCCall; @class GRXWriter; -@protocol FSTCredentialsProvider; @protocol FSTWatchStreamDelegate; @protocol FSTWriteStreamDelegate; @@ -47,7 +47,7 @@ NS_ASSUME_NONNULL_BEGIN * * - Restarting a stream is allowed (after failure) * - Exponential backoff on failure (independent of the underlying channel) - * - Authentication via FSTCredentialsProvider + * - Authentication via CredentialsProvider * - Dispatching all callbacks into the shared worker queue * * Subclasses of FSTStream implement serialization of models to and from bytes (via protocol @@ -94,7 +94,7 @@ NS_ASSUME_NONNULL_BEGIN workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue connectionTimerID:(FSTTimerID)connectionTimerID idleTimerID:(FSTTimerID)idleTimerID - credentials:(id<FSTCredentialsProvider>)credentials + credentials:(firebase::firestore::auth::CredentialsProvider *)credentials // no passing ownership responseMessageClass:(Class)responseMessageClass NS_DESIGNATED_INITIALIZER; - (instancetype)init NS_UNAVAILABLE; @@ -208,14 +208,16 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithDatabase:(const firebase::firestore::core::DatabaseInfo *)database workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue - credentials:(id<FSTCredentialsProvider>)credentials + credentials:(firebase::firestore::auth::CredentialsProvider *) + credentials // no passsing ownership serializer:(FSTSerializerBeta *)serializer NS_DESIGNATED_INITIALIZER; - (instancetype)initWithDatabase:(const firebase::firestore::core::DatabaseInfo *)database workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue connectionTimerID:(FSTTimerID)connectionTimerID idleTimerID:(FSTTimerID)idleTimerID - credentials:(id<FSTCredentialsProvider>)credentials + credentials:(firebase::firestore::auth::CredentialsProvider *) + credentials // no passing ownership responseMessageClass:(Class)responseMessageClass NS_UNAVAILABLE; - (instancetype)init NS_UNAVAILABLE; @@ -284,14 +286,16 @@ NS_ASSUME_NONNULL_BEGIN */ - (instancetype)initWithDatabase:(const firebase::firestore::core::DatabaseInfo *)database workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue - credentials:(id<FSTCredentialsProvider>)credentials + credentials:(firebase::firestore::auth::CredentialsProvider *) + credentials // no passing ownership serializer:(FSTSerializerBeta *)serializer; - (instancetype)initWithDatabase:(const firebase::firestore::core::DatabaseInfo *)database workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue connectionTimerID:(FSTTimerID)connectionTimerID idleTimerID:(FSTTimerID)idleTimerID - credentials:(id<FSTCredentialsProvider>)credentials + credentials:(firebase::firestore::auth::CredentialsProvider *) + credentials // no passing ownership responseMessageClass:(Class)responseMessageClass NS_UNAVAILABLE; - (instancetype)init NS_UNAVAILABLE; diff --git a/Firestore/Source/Remote/FSTStream.mm b/Firestore/Source/Remote/FSTStream.mm index a9aa245..6bec3ad 100644 --- a/Firestore/Source/Remote/FSTStream.mm +++ b/Firestore/Source/Remote/FSTStream.mm @@ -21,7 +21,6 @@ #import "FIRFirestoreErrors.h" #import "Firestore/Source/API/FIRFirestore+Internal.h" -#import "Firestore/Source/Auth/FSTCredentialsProvider.h" #import "Firestore/Source/Local/FSTQueryData.h" #import "Firestore/Source/Model/FSTMutation.h" #import "Firestore/Source/Remote/FSTBufferedWriter.h" @@ -38,9 +37,11 @@ #include "Firestore/core/src/firebase/firestore/auth/token.h" #include "Firestore/core/src/firebase/firestore/core/database_info.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" +#include "Firestore/core/src/firebase/firestore/util/error_apple.h" #include "Firestore/core/src/firebase/firestore/util/string_apple.h" namespace util = firebase::firestore::util; +using firebase::firestore::auth::CredentialsProvider; using firebase::firestore::auth::Token; using firebase::firestore::core::DatabaseInfo; using firebase::firestore::model::DatabaseId; @@ -103,12 +104,12 @@ typedef NS_ENUM(NSInteger, FSTStreamState) { */ - (instancetype)initWithDatabase:(const DatabaseInfo *)database workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue - credentials:(id<FSTCredentialsProvider>)credentials + credentials:(CredentialsProvider *)credentials serializer:(FSTSerializerBeta *)serializer NS_DESIGNATED_INITIALIZER; - (instancetype)initWithDatabase:(const DatabaseInfo *)database workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue - credentials:(id<FSTCredentialsProvider>)credentials + credentials:(CredentialsProvider *)credentials responseMessageClass:(Class)responseMessageClass NS_UNAVAILABLE; @end @@ -126,7 +127,7 @@ typedef NS_ENUM(NSInteger, FSTStreamState) { // Does not own this DatabaseInfo. @property(nonatomic, assign, readonly) const DatabaseInfo *databaseInfo; @property(nonatomic, strong, readonly) FSTDispatchQueue *workerDispatchQueue; -@property(nonatomic, strong, readonly) id<FSTCredentialsProvider> credentials; +@property(nonatomic, assign, readonly) CredentialsProvider *credentials; @property(nonatomic, unsafe_unretained, readonly) Class responseMessageClass; @property(nonatomic, strong, readonly) FSTExponentialBackoff *backoff; @@ -213,7 +214,7 @@ static const NSTimeInterval kIdleTimeout = 60.0; workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue connectionTimerID:(FSTTimerID)connectionTimerID idleTimerID:(FSTTimerID)idleTimerID - credentials:(id<FSTCredentialsProvider>)credentials + credentials:(CredentialsProvider *)credentials responseMessageClass:(Class)responseMessageClass { if (self = [super init]) { _databaseInfo = database; @@ -263,13 +264,14 @@ static const NSTimeInterval kIdleTimeout = 60.0; FSTAssert(_delegate == nil, @"Delegate must be nil"); _delegate = delegate; - [self.credentials getTokenForcingRefresh:NO - completion:^(Token result, NSError *_Nullable error) { - error = [FSTDatastore firestoreErrorForError:error]; - [self.workerDispatchQueue dispatchAsyncAllowingSameQueue:^{ - [self resumeStartWithToken:result error:error]; - }]; - }]; + _credentials->GetToken( + /*force_refresh=*/false, + [self](Token result, const int64_t error_code, const absl::string_view error_msg) { + NSError *error = util::WrapNSError(error_code, error_msg); + [self.workerDispatchQueue dispatchAsyncAllowingSameQueue:^{ + [self resumeStartWithToken:result error:error]; + }]; + }); } /** Add an access token to our RPC, after obtaining one from the credentials provider. */ @@ -614,7 +616,7 @@ static const NSTimeInterval kIdleTimeout = 60.0; - (instancetype)initWithDatabase:(const DatabaseInfo *)database workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue - credentials:(id<FSTCredentialsProvider>)credentials + credentials:(CredentialsProvider *)credentials serializer:(FSTSerializerBeta *)serializer { self = [super initWithDatabase:database workerDispatchQueue:workerDispatchQueue @@ -699,7 +701,7 @@ static const NSTimeInterval kIdleTimeout = 60.0; - (instancetype)initWithDatabase:(const DatabaseInfo *)database workerDispatchQueue:(FSTDispatchQueue *)workerDispatchQueue - credentials:(id<FSTCredentialsProvider>)credentials + credentials:(CredentialsProvider *)credentials serializer:(FSTSerializerBeta *)serializer { self = [super initWithDatabase:database workerDispatchQueue:workerDispatchQueue |