aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firebase/Database/Api/FIRDatabase.m
diff options
context:
space:
mode:
Diffstat (limited to 'Firebase/Database/Api/FIRDatabase.m')
-rw-r--r--Firebase/Database/Api/FIRDatabase.m95
1 files changed, 68 insertions, 27 deletions
diff --git a/Firebase/Database/Api/FIRDatabase.m b/Firebase/Database/Api/FIRDatabase.m
index 2dd77f6..4a8f5b8 100644
--- a/Firebase/Database/Api/FIRDatabase.m
+++ b/Firebase/Database/Api/FIRDatabase.m
@@ -36,6 +36,9 @@
@implementation FIRDatabase
+/** A NSMutableDictionary of FirebaseApp name and FRepoInfo to FirebaseDatabase instance. */
+typedef NSMutableDictionary<NSString *, NSMutableDictionary<FRepoInfo *, FIRDatabase *> *> FIRDatabaseDictionary;
+
// The STR and STR_EXPAND macro allow a numeric version passed to he compiler driver
// with a -D to be treated as a string instead of an invalid floating point value.
#define STR(x) STR_EXPAND(x)
@@ -51,13 +54,15 @@ static const char *FIREBASE_SEMVER = (const char *)STR(FIRDatabase_VERSION);
NSString *appName = note.userInfo[kFIRAppNameKey];
if (appName == nil) { return; }
- NSMutableDictionary *instances = [self instances];
+ FIRDatabaseDictionary* instances = [self instances];
@synchronized (instances) {
- FIRDatabase *deletedApp = instances[appName];
- if (deletedApp) {
+ NSMutableDictionary<FRepoInfo *, FIRDatabase *> *databaseInstances = instances[appName];
+ if (databaseInstances) {
// Clean up the deleted instance in an effort to remove any resources still in use.
// Note: Any leftover instances of this exact database will be invalid.
- [FRepoManager disposeRepos:deletedApp.config];
+ for (FIRDatabase * database in [databaseInstances allValues]) {
+ [FRepoManager disposeRepos:database.config];
+ }
[instances removeObjectForKey:appName];
}
}
@@ -65,16 +70,18 @@ static const char *FIREBASE_SEMVER = (const char *)STR(FIRDatabase_VERSION);
}
/**
- * A static NSMutableDictionary of FirebaseApp names to FirebaseDatabase instance. To ensure thread-
- * safety, it should only be accessed in databaseForApp, which is synchronized.
+ * A static NSMutableDictionary of FirebaseApp name and FRepoInfo to
+ * FirebaseDatabase instance. To ensure thread-safety, it should only be
+ * accessed in databaseForApp:URL:, which is synchronized.
*
* TODO: This serves a duplicate purpose as RepoManager. We should clean up.
- * TODO: We should maybe be conscious of leaks and make this a weak map or similar
- * but we have a lot of work to do to allow FirebaseDatabase/Repo etc. to be GC'd.
+ * TODO: We should maybe be conscious of leaks and make this a weak map or
+ * similar but we have a lot of work to do to allow FirebaseDatabase/Repo etc.
+ * to be GC'd.
*/
-+ (NSMutableDictionary *)instances {
++ (FIRDatabaseDictionary *)instances {
static dispatch_once_t pred = 0;
- static NSMutableDictionary *instances;
+ static FIRDatabaseDictionary *instances;
dispatch_once(&pred, ^{
instances = [NSMutableDictionary dictionary];
});
@@ -92,27 +99,59 @@ static const char *FIREBASE_SEMVER = (const char *)STR(FIRDatabase_VERSION);
return [FIRDatabase databaseForApp:app];
}
++ (FIRDatabase *)databaseWithURL:(NSString *)url {
+ FIRApp *app = [FIRApp defaultApp];
+ if (app == nil) {
+ [NSException raise:@"FIRAppNotConfigured"
+ format:@"Failed to get default Firebase Database instance. "
+ @"Must call `[FIRApp configure]` (`FirebaseApp.configure()` in Swift) "
+ @"before using Firebase Database."];
+ }
+ return [FIRDatabase databaseForApp:app URL:url];
+}
+
+ (FIRDatabase *)databaseForApp:(FIRApp *)app {
if (app == nil) {
[NSException raise:@"InvalidFIRApp" format:@"nil FIRApp instance passed to databaseForApp."];
}
- NSMutableDictionary *instances = [self instances];
- @synchronized (instances) {
- FIRDatabase *database = instances[app.name];
- if (!database) {
- NSString *databaseUrl = app.options.databaseURL;
- if (databaseUrl == nil) {
- [NSException raise:@"MissingDatabaseURL" format:@"Failed to get FIRDatabase instance: FIRApp object has no "
- "databaseURL in its FirebaseOptions object."];
- }
- FParsedUrl *parsedUrl = [FUtilities parseUrl:databaseUrl];
- if (![parsedUrl.path isEmpty]) {
- [NSException raise:@"InvalidDatabaseURL" format:@"Configured Database URL '%@' is invalid. It should "
- "point to the root of a Firebase Database but it includes a path: %@",
- databaseUrl, [parsedUrl.path toString]];
- }
+ return [FIRDatabase databaseForApp:app URL:app.options.databaseURL];
+}
++ (FIRDatabase *)databaseForApp:(FIRApp *)app URL:(NSString *)url {
+ if (app == nil) {
+ [NSException raise:@"InvalidFIRApp"
+ format:@"nil FIRApp instance passed to databaseForApp."];
+ }
+
+ if (url == nil) {
+ [NSException raise:@"MissingDatabaseURL"
+ format:@"Failed to get FirebaseDatabase instance: "
+ "Specify DatabaseURL within FIRApp or from your databaseForApp:URL: call."];
+ }
+
+ NSURL *databaseUrl = [NSURL URLWithString:url];
+
+ if (databaseUrl == nil) {
+ [NSException raise:@"InvalidDatabaseURL" format:@"The Database URL '%@' cannot be parsed. "
+ "Specify a valid DatabaseURL within FIRApp or from your databaseForApp:URL: call.", databaseUrl];
+ } else if (![databaseUrl.path isEqualToString:@""] && ![databaseUrl.path isEqualToString:@"/"]) {
+ [NSException raise:@"InvalidDatabaseURL" format:@"Configured Database URL '%@' is invalid. It should point "
+ "to the root of a Firebase Database but it includes a path: %@",databaseUrl, databaseUrl.path];
+ }
+
+ FIRDatabaseDictionary *instances = [self instances];
+ @synchronized (instances) {
+ NSMutableDictionary<FRepoInfo *, FIRDatabase *> *urlInstanceMap =
+ instances[app.name];
+ if (!urlInstanceMap) {
+ urlInstanceMap = [NSMutableDictionary dictionary];
+ instances[app.name] = urlInstanceMap;
+ }
+
+ FParsedUrl *parsedUrl = [FUtilities parseUrl:databaseUrl.absoluteString];
+ FIRDatabase *database = urlInstanceMap[parsedUrl.repoInfo];
+ if (!database) {
id<FAuthTokenProvider> authTokenProvider = [FAuthTokenProvider authTokenProviderForApp:app];
// If this is the default app, don't set the session persistence key so that we use our
@@ -125,8 +164,10 @@ static const char *FIREBASE_SEMVER = (const char *)STR(FIRDatabase_VERSION);
FIRDatabaseConfig *config = [[FIRDatabaseConfig alloc] initWithSessionIdentifier:sessionIdentifier
authTokenProvider:authTokenProvider];
- database = [[FIRDatabase alloc] initWithApp:app repoInfo:parsedUrl.repoInfo config:config];
- instances[app.name] = database;
+ database = [[FIRDatabase alloc] initWithApp:app
+ repoInfo:parsedUrl.repoInfo
+ config:config];
+ urlInstanceMap[parsedUrl.repoInfo] = database;
}
return database;