From 15eaafe7f07394bb73bb04cdf46dd73d9dcfeb57 Mon Sep 17 00:00:00 2001 From: Reinert Date: Mon, 8 Apr 2019 23:06:10 +0200 Subject: [PATCH 01/12] Add init & extract storage directory path creation --- ios/RNCAsyncStorage.m | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/ios/RNCAsyncStorage.m b/ios/RNCAsyncStorage.m index d258f554..a2785d04 100644 --- a/ios/RNCAsyncStorage.m +++ b/ios/RNCAsyncStorage.m @@ -78,17 +78,23 @@ static void RCTAppendError(NSDictionary *error, NSMutableArray * return nil; } +static NSString *RCTCreateStorageDirectoryPath(NSString *storageDir) { + NSString *storageDirectoryPath; +#if TARGET_OS_TV + storageDirectoryPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject; +#else + storageDirectoryPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject; +#endif + storageDirectoryPath = [storageDirectoryPath stringByAppendingPathComponent:RCTStorageDirectory]; + return storageDirectoryPath; +} + static NSString *RCTGetStorageDirectory() { static NSString *storageDirectory = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ -#if TARGET_OS_TV - storageDirectory = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject; -#else - storageDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject; -#endif - storageDirectory = [storageDirectory stringByAppendingPathComponent:RCTStorageDirectory]; + storageDirectory = RCTCreateStorageDirectoryPath(RCTStorageDirectory); }); return storageDirectory; } @@ -168,6 +174,12 @@ static dispatch_queue_t RCTGetMethodQueue() return error ? RCTMakeError(@"Failed to delete storage directory.", error, nil) : nil; } +static void RCTPerformDirectoryMigrationCheck() { +// NSString *oldRCTStorageDirectory = @"RNCAsyncLocalStorage_V1"; +// NSString *storageDir = RCTCreateStorageDirectoryPath(oldRCTStorageDirectory); +// printf("%s%s\n", "TESTING: ", [storageDir UTF8String]); +} + #pragma mark - RNCAsyncStorage @implementation RNCAsyncStorage @@ -179,6 +191,19 @@ @implementation RNCAsyncStorage NSMutableDictionary *_manifest; } ++ (BOOL)requiresMainQueueSetup { + return YES; +} + +- (instancetype)init +{ + if (!(self = [super init])) { + return nil; + } + RCTPerformDirectoryMigrationCheck(); + return self; +} + RCT_EXPORT_MODULE() - (dispatch_queue_t)methodQueue @@ -441,7 +466,7 @@ - (BOOL)_passthroughDelegate } RCT_EXPORT_METHOD(multiMerge:(NSArray *> *)kvPairs - callback:(RCTResponseSenderBlock)callback) + callback:(RCTResponseSenderBlock)callback) { if (self.delegate != nil) { NSMutableArray *keys = [NSMutableArray arrayWithCapacity:kvPairs.count]; @@ -575,3 +600,4 @@ - (BOOL)_passthroughDelegate } @end + From b165aa3320fca57b4d313f01469d71a52f438158 Mon Sep 17 00:00:00 2001 From: Reinert L Date: Tue, 9 Apr 2019 00:02:05 +0200 Subject: [PATCH 02/12] Implement RCTStorageDirectoryMigrationCheck --- ios/RNCAsyncStorage.m | 62 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/ios/RNCAsyncStorage.m b/ios/RNCAsyncStorage.m index a2785d04..5c4f2764 100644 --- a/ios/RNCAsyncStorage.m +++ b/ios/RNCAsyncStorage.m @@ -85,7 +85,7 @@ static void RCTAppendError(NSDictionary *error, NSMutableArray * #else storageDirectoryPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject; #endif - storageDirectoryPath = [storageDirectoryPath stringByAppendingPathComponent:RCTStorageDirectory]; + storageDirectoryPath = [storageDirectoryPath stringByAppendingPathComponent:storageDir]; return storageDirectoryPath; } @@ -174,10 +174,60 @@ static dispatch_queue_t RCTGetMethodQueue() return error ? RCTMakeError(@"Failed to delete storage directory.", error, nil) : nil; } -static void RCTPerformDirectoryMigrationCheck() { -// NSString *oldRCTStorageDirectory = @"RNCAsyncLocalStorage_V1"; -// NSString *storageDir = RCTCreateStorageDirectoryPath(oldRCTStorageDirectory); -// printf("%s%s\n", "TESTING: ", [storageDir UTF8String]); +/** + * This check is added to make sure that anyone coming from pre-1.2.2 does not lose cached data. + * Data is migrated from the "RNCAsyncLocalStorage_V1" directory to the "RCTAsyncLocalStorage_V1" directory. + */ +static void RCTStorageDirectoryMigrationCheck() { + NSString *oldStorageDir = RCTCreateStorageDirectoryPath(@"RNCAsyncLocalStorage_V1"); + + BOOL isDir; + BOOL oldExists = [[NSFileManager defaultManager] fileExistsAtPath:oldStorageDir isDirectory:&isDir]; + + // If the old directory exists, it means we need to migrate data to the new directory + if (oldExists && isDir) { + NSError *error; + BOOL migrationSuccess; + // If the new storage directory already exists, then this may be caused by ever older data being left behind from previous versions. + // This old data will need to be overwritten. + NSString *newStorageDir = RCTGetStorageDirectory(); + BOOL newExists = [[NSFileManager defaultManager] fileExistsAtPath:newStorageDir isDirectory:&isDir]; + if (newExists && isDir) { + NSString *backupStorageDir = RCTCreateStorageDirectoryPath(@"RCTBackupAsyncLocalStorage_V1"); + // Replace any possible existing data in the new storage with old storage directory + migrationSuccess = [[NSFileManager defaultManager] replaceItemAtURL:[[NSURL alloc] initWithString:newStorageDir] + withItemAtURL:[[NSURL alloc] initWithString:oldStorageDir] + backupItemName:backupStorageDir + options:NSFileManagerItemReplacementUsingNewMetadataOnly + resultingItemURL:nil + error:&error]; + if (error || !success) { + // Attempt to recover from failed overwriting + [[NSFileManager defaultManager] removeItemAtPath:newStorageDir error:nil]; + [[NSFileManager defaultManager] copyItemAtPath:backupStorageDir toPath:newStorageDir error:nil]; + [[NSFileManager defaultManager] removeItemAtPath:backupStorageDir error:nil]; + if (error) { + RCTMakeError(@"Failed to overwrite old storage directory to new storage directory location during migration", error, nil); + return; + } + } + } else { + // Copy over the old storage directory to new storage directory path + migrationSuccess = [[NSFileManager defaultManager] copyItemAtPath:oldStorageDir toPath:newStorageDir error:&error]; + if (error) { + RCTMakeError(@"Failed to copy old storage directory to new storage directory location during migration", error, nil); + return; + } + } + + // If the migration was a success, remove old storage directory + if (migrationSuccess) { + [[NSFileManager defaultManager] removeItemAtPath:oldStorageDir error:error]; + if (error) { + RCTMakeError(@"Failed to remove old storage directory after migration", error, nil); + } + } + } } #pragma mark - RNCAsyncStorage @@ -200,7 +250,7 @@ - (instancetype)init if (!(self = [super init])) { return nil; } - RCTPerformDirectoryMigrationCheck(); + RCTStorageDirectoryMigrationCheck(); return self; } From 9a54cdd58010d5d67b07969acb0d498f28180a9a Mon Sep 17 00:00:00 2001 From: Reinert L Date: Tue, 9 Apr 2019 09:49:09 +0200 Subject: [PATCH 03/12] Fix RCTStorageDirectoryMigrationCheck build errors & styling --- ios/RNCAsyncStorage.m | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ios/RNCAsyncStorage.m b/ios/RNCAsyncStorage.m index 5c4f2764..dbb94854 100644 --- a/ios/RNCAsyncStorage.m +++ b/ios/RNCAsyncStorage.m @@ -181,12 +181,13 @@ static dispatch_queue_t RCTGetMethodQueue() static void RCTStorageDirectoryMigrationCheck() { NSString *oldStorageDir = RCTCreateStorageDirectoryPath(@"RNCAsyncLocalStorage_V1"); + NSError *error; BOOL isDir; BOOL oldExists = [[NSFileManager defaultManager] fileExistsAtPath:oldStorageDir isDirectory:&isDir]; // If the old directory exists, it means we need to migrate data to the new directory if (oldExists && isDir) { - NSError *error; + BOOL migrationSuccess; // If the new storage directory already exists, then this may be caused by ever older data being left behind from previous versions. // This old data will need to be overwritten. @@ -196,12 +197,12 @@ static void RCTStorageDirectoryMigrationCheck() { NSString *backupStorageDir = RCTCreateStorageDirectoryPath(@"RCTBackupAsyncLocalStorage_V1"); // Replace any possible existing data in the new storage with old storage directory migrationSuccess = [[NSFileManager defaultManager] replaceItemAtURL:[[NSURL alloc] initWithString:newStorageDir] - withItemAtURL:[[NSURL alloc] initWithString:oldStorageDir] - backupItemName:backupStorageDir - options:NSFileManagerItemReplacementUsingNewMetadataOnly - resultingItemURL:nil - error:&error]; - if (error || !success) { + withItemAtURL:[[NSURL alloc] initWithString:oldStorageDir] + backupItemName:backupStorageDir + options:NSFileManagerItemReplacementUsingNewMetadataOnly + resultingItemURL:nil + error:&error]; + if (error || !migrationSuccess) { // Attempt to recover from failed overwriting [[NSFileManager defaultManager] removeItemAtPath:newStorageDir error:nil]; [[NSFileManager defaultManager] copyItemAtPath:backupStorageDir toPath:newStorageDir error:nil]; @@ -222,7 +223,7 @@ static void RCTStorageDirectoryMigrationCheck() { // If the migration was a success, remove old storage directory if (migrationSuccess) { - [[NSFileManager defaultManager] removeItemAtPath:oldStorageDir error:error]; + [[NSFileManager defaultManager] removeItemAtPath:oldStorageDir error:&error]; if (error) { RCTMakeError(@"Failed to remove old storage directory after migration", error, nil); } From 3f7fc19a36e1ff9086b4982914781886332c8089 Mon Sep 17 00:00:00 2001 From: Reinert L Date: Tue, 9 Apr 2019 12:52:19 +0200 Subject: [PATCH 04/12] Use explicit item deletion instead of replaceItem & added NSExceptions --- ios/RNCAsyncStorage.m | 81 +++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 46 deletions(-) diff --git a/ios/RNCAsyncStorage.m b/ios/RNCAsyncStorage.m index dbb94854..f6f257b3 100644 --- a/ios/RNCAsyncStorage.m +++ b/ios/RNCAsyncStorage.m @@ -174,61 +174,50 @@ static dispatch_queue_t RCTGetMethodQueue() return error ? RCTMakeError(@"Failed to delete storage directory.", error, nil) : nil; } + +NSString *OldStorageDirectory = @"RNCAsyncLocalStorage_V1"; +/** + * Creates an NSException used during Storage Directory Migration. + */ +static NSException *RCTStorageDirectionMigrationException(NSString *reason, NSError *error) { + NSMutableString *reasonString = [[NSMutableString alloc] initWithString:reason]; + [reasonString appendString:@" - "]; + [reasonString appendString:[error description]]; + return [[NSException alloc] initWithName:@"RCTStorageDirectoryMigrationFailure" reason:reasonString userInfo:nil]; +} + /** * This check is added to make sure that anyone coming from pre-1.2.2 does not lose cached data. * Data is migrated from the "RNCAsyncLocalStorage_V1" directory to the "RCTAsyncLocalStorage_V1" directory. */ static void RCTStorageDirectoryMigrationCheck() { - NSString *oldStorageDir = RCTCreateStorageDirectoryPath(@"RNCAsyncLocalStorage_V1"); - - NSError *error; - BOOL isDir; - BOOL oldExists = [[NSFileManager defaultManager] fileExistsAtPath:oldStorageDir isDirectory:&isDir]; - - // If the old directory exists, it means we need to migrate data to the new directory - if (oldExists && isDir) { - - BOOL migrationSuccess; - // If the new storage directory already exists, then this may be caused by ever older data being left behind from previous versions. - // This old data will need to be overwritten. - NSString *newStorageDir = RCTGetStorageDirectory(); - BOOL newExists = [[NSFileManager defaultManager] fileExistsAtPath:newStorageDir isDirectory:&isDir]; - if (newExists && isDir) { - NSString *backupStorageDir = RCTCreateStorageDirectoryPath(@"RCTBackupAsyncLocalStorage_V1"); - // Replace any possible existing data in the new storage with old storage directory - migrationSuccess = [[NSFileManager defaultManager] replaceItemAtURL:[[NSURL alloc] initWithString:newStorageDir] - withItemAtURL:[[NSURL alloc] initWithString:oldStorageDir] - backupItemName:backupStorageDir - options:NSFileManagerItemReplacementUsingNewMetadataOnly - resultingItemURL:nil - error:&error]; - if (error || !migrationSuccess) { - // Attempt to recover from failed overwriting - [[NSFileManager defaultManager] removeItemAtPath:newStorageDir error:nil]; - [[NSFileManager defaultManager] copyItemAtPath:backupStorageDir toPath:newStorageDir error:nil]; - [[NSFileManager defaultManager] removeItemAtPath:backupStorageDir error:nil]; - if (error) { - RCTMakeError(@"Failed to overwrite old storage directory to new storage directory location during migration", error, nil); - return; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSError *error; + BOOL isDir; + // If the old directory exists, it means we need to migrate data to the new directory + if ([[NSFileManager defaultManager] fileExistsAtPath:RCTCreateStorageDirectoryPath(OldStorageDirectory) isDirectory:&isDir] && isDir) { + // Check if the new storage directory location already exists + BOOL newStorageDirectoryExists = [[NSFileManager defaultManager] fileExistsAtPath:RCTGetStorageDirectory() isDirectory:&isDir]; + if (newStorageDirectoryExists) { + // If the new storage directory location already exists, remove existing directory + newStorageDirectoryExists = !([[NSFileManager defaultManager] removeItemAtPath:RCTGetStorageDirectory() error:&error]); + if (newStorageDirectoryExists) { + @throw RCTStorageDirectionMigrationException(@"Failed to clear pre-existing storage directory", error); } } - } else { - // Copy over the old storage directory to new storage directory path - migrationSuccess = [[NSFileManager defaultManager] copyItemAtPath:oldStorageDir toPath:newStorageDir error:&error]; - if (error) { - RCTMakeError(@"Failed to copy old storage directory to new storage directory location during migration", error, nil); - return; - } - } - - // If the migration was a success, remove old storage directory - if (migrationSuccess) { - [[NSFileManager defaultManager] removeItemAtPath:oldStorageDir error:&error]; - if (error) { - RCTMakeError(@"Failed to remove old storage directory after migration", error, nil); + if (!newStorageDirectoryExists) { + // If new storage direction doesn't exist, copy old storage directory to new location + if (![[NSFileManager defaultManager] copyItemAtPath:RCTCreateStorageDirectoryPath(OldStorageDirectory) toPath:RCTGetStorageDirectory() error:&error]) { + @throw RCTStorageDirectionMigrationException(@"Failed to copy old storage directory to new storage directory", error); + } else { + // If copying succeeds, remove old storage directory + [[NSFileManager defaultManager] removeItemAtPath:RCTCreateStorageDirectoryPath(OldStorageDirectory) error:&error]; + if (error) @throw RCTStorageDirectionMigrationException(@"Failed to remove old storage directory after migration", error); + } } } - } + }); } #pragma mark - RNCAsyncStorage From 0601d5cf904348a5c4e2cf210ca0b477901eb5da Mon Sep 17 00:00:00 2001 From: Reinert L Date: Tue, 9 Apr 2019 13:11:59 +0200 Subject: [PATCH 05/12] Revert styling changes --- ios/RNCAsyncStorage.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ios/RNCAsyncStorage.m b/ios/RNCAsyncStorage.m index f6f257b3..a2242baf 100644 --- a/ios/RNCAsyncStorage.m +++ b/ios/RNCAsyncStorage.m @@ -506,7 +506,7 @@ - (BOOL)_passthroughDelegate } RCT_EXPORT_METHOD(multiMerge:(NSArray *> *)kvPairs - callback:(RCTResponseSenderBlock)callback) + callback:(RCTResponseSenderBlock)callback) { if (self.delegate != nil) { NSMutableArray *keys = [NSMutableArray arrayWithCapacity:kvPairs.count]; @@ -640,4 +640,3 @@ - (BOOL)_passthroughDelegate } @end - From 2aa0c17cca4249b28f1b3902db6093329316f03f Mon Sep 17 00:00:00 2001 From: Reinert L Date: Tue, 9 Apr 2019 22:25:40 +0200 Subject: [PATCH 06/12] Minor requested changes * Use const and RCT prefix for RCTOldStorageDirectory * Log errors instead of throwing exceptions * Disable main queue setup --- ios/RNCAsyncStorage.m | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/ios/RNCAsyncStorage.m b/ios/RNCAsyncStorage.m index a2242baf..bcef9a92 100644 --- a/ios/RNCAsyncStorage.m +++ b/ios/RNCAsyncStorage.m @@ -175,15 +175,12 @@ static dispatch_queue_t RCTGetMethodQueue() } -NSString *OldStorageDirectory = @"RNCAsyncLocalStorage_V1"; +NSString *const RCTOldStorageDirectory = @"RNCAsyncLocalStorage_V1"; /** * Creates an NSException used during Storage Directory Migration. */ -static NSException *RCTStorageDirectionMigrationException(NSString *reason, NSError *error) { - NSMutableString *reasonString = [[NSMutableString alloc] initWithString:reason]; - [reasonString appendString:@" - "]; - [reasonString appendString:[error description]]; - return [[NSException alloc] initWithName:@"RCTStorageDirectoryMigrationFailure" reason:reasonString userInfo:nil]; +static void RCTStorageDirectoryMigrationLogError(NSString *reason, NSError *error) { + NSLog(@"%@: %@", reason, error ? error.description : @""); } /** @@ -196,24 +193,24 @@ static void RCTStorageDirectoryMigrationCheck() { NSError *error; BOOL isDir; // If the old directory exists, it means we need to migrate data to the new directory - if ([[NSFileManager defaultManager] fileExistsAtPath:RCTCreateStorageDirectoryPath(OldStorageDirectory) isDirectory:&isDir] && isDir) { + if ([[NSFileManager defaultManager] fileExistsAtPath:RCTCreateStorageDirectoryPath(RCTOldStorageDirectory) isDirectory:&isDir] && isDir) { // Check if the new storage directory location already exists BOOL newStorageDirectoryExists = [[NSFileManager defaultManager] fileExistsAtPath:RCTGetStorageDirectory() isDirectory:&isDir]; if (newStorageDirectoryExists) { // If the new storage directory location already exists, remove existing directory newStorageDirectoryExists = !([[NSFileManager defaultManager] removeItemAtPath:RCTGetStorageDirectory() error:&error]); if (newStorageDirectoryExists) { - @throw RCTStorageDirectionMigrationException(@"Failed to clear pre-existing storage directory", error); + RCTStorageDirectoryMigrationLogError(@"Failed to clear pre-existing storage directory", error); } } if (!newStorageDirectoryExists) { // If new storage direction doesn't exist, copy old storage directory to new location - if (![[NSFileManager defaultManager] copyItemAtPath:RCTCreateStorageDirectoryPath(OldStorageDirectory) toPath:RCTGetStorageDirectory() error:&error]) { - @throw RCTStorageDirectionMigrationException(@"Failed to copy old storage directory to new storage directory", error); + if (![[NSFileManager defaultManager] copyItemAtPath:RCTCreateStorageDirectoryPath(RCTOldStorageDirectory) toPath:RCTGetStorageDirectory() error:&error]) { + RCTStorageDirectoryMigrationLogError(@"Failed to copy old storage directory to new storage directory", error); } else { // If copying succeeds, remove old storage directory - [[NSFileManager defaultManager] removeItemAtPath:RCTCreateStorageDirectoryPath(OldStorageDirectory) error:&error]; - if (error) @throw RCTStorageDirectionMigrationException(@"Failed to remove old storage directory after migration", error); + [[NSFileManager defaultManager] removeItemAtPath:RCTCreateStorageDirectoryPath(RCTOldStorageDirectory) error:&error]; + if (error) RCTStorageDirectoryMigrationLogError(@"Failed to remove old storage directory after migration", error); } } } @@ -232,7 +229,7 @@ @implementation RNCAsyncStorage } + (BOOL)requiresMainQueueSetup { - return YES; + return NO; } - (instancetype)init @@ -506,7 +503,7 @@ - (BOOL)_passthroughDelegate } RCT_EXPORT_METHOD(multiMerge:(NSArray *> *)kvPairs - callback:(RCTResponseSenderBlock)callback) + callback:(RCTResponseSenderBlock)callback) { if (self.delegate != nil) { NSMutableArray *keys = [NSMutableArray arrayWithCapacity:kvPairs.count]; @@ -640,3 +637,4 @@ - (BOOL)_passthroughDelegate } @end + From 964b16a841e4d6bcc7a081d04b53fecec10b4fee Mon Sep 17 00:00:00 2001 From: Reinert L Date: Tue, 9 Apr 2019 22:56:35 +0200 Subject: [PATCH 07/12] Check manifest's last modified date during migration --- ios/RNCAsyncStorage.m | 72 +++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/ios/RNCAsyncStorage.m b/ios/RNCAsyncStorage.m index bcef9a92..275f128b 100644 --- a/ios/RNCAsyncStorage.m +++ b/ios/RNCAsyncStorage.m @@ -99,12 +99,17 @@ static void RCTAppendError(NSDictionary *error, NSMutableArray * return storageDirectory; } +static NSString *RCTCreateManifestFilePath(NSString *storageDirectory) +{ + return [RCTCreateStorageDirectoryPath(storageDirectory) stringByAppendingString:RCTManifestFileName]; +} + static NSString *RCTGetManifestFilePath() { static NSString *manifestFilePath = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - manifestFilePath = [RCTGetStorageDirectory() stringByAppendingPathComponent:RCTManifestFileName]; + manifestFilePath = RCTCreateManifestFilePath(RCTStorageDirectory); }); return manifestFilePath; } @@ -174,44 +179,70 @@ static dispatch_queue_t RCTGetMethodQueue() return error ? RCTMakeError(@"Failed to delete storage directory.", error, nil) : nil; } +static NSDate *RCTManifestModificationDate(NSString *manifestFilePath) +{ + NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:manifestFilePath error:nil]; + return [attributes fileModificationDate]; +} NSString *const RCTOldStorageDirectory = @"RNCAsyncLocalStorage_V1"; /** * Creates an NSException used during Storage Directory Migration. */ -static void RCTStorageDirectoryMigrationLogError(NSString *reason, NSError *error) { +static void RCTStorageDirectoryMigrationLogError(NSString *reason, NSError *error) +{ NSLog(@"%@: %@", reason, error ? error.description : @""); } +static void RCTStorageDirectoryCleanupOld() +{ + NSError *error; + if (![[NSFileManager defaultManager] removeItemAtPath:RCTCreateStorageDirectoryPath(RCTOldStorageDirectory) error:&error]) { + RCTStorageDirectoryMigrationLogError(@"Failed to remove old storage directory during migration", error); + } +} + +static void RCTStorageDirectoryMigrate() +{ + NSError *error; + // Migrate data by copying old storage directory to new storage directory location + if (![[NSFileManager defaultManager] copyItemAtPath:RCTCreateStorageDirectoryPath(RCTOldStorageDirectory) toPath:RCTGetStorageDirectory() error:&error]) { + RCTStorageDirectoryMigrationLogError(@"Failed to copy old storage directory to new storage directory location during migration", error); + } else { + // If copying succeeds, remove old storage directory + RCTStorageDirectoryCleanupOld(); + } +} + /** * This check is added to make sure that anyone coming from pre-1.2.2 does not lose cached data. * Data is migrated from the "RNCAsyncLocalStorage_V1" directory to the "RCTAsyncLocalStorage_V1" directory. */ -static void RCTStorageDirectoryMigrationCheck() { +static void RCTStorageDirectoryMigrationCheck() +{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSError *error; BOOL isDir; - // If the old directory exists, it means we need to migrate data to the new directory + // If the old directory exists, it means we may need to migrate old data to the new directory if ([[NSFileManager defaultManager] fileExistsAtPath:RCTCreateStorageDirectoryPath(RCTOldStorageDirectory) isDirectory:&isDir] && isDir) { // Check if the new storage directory location already exists - BOOL newStorageDirectoryExists = [[NSFileManager defaultManager] fileExistsAtPath:RCTGetStorageDirectory() isDirectory:&isDir]; - if (newStorageDirectoryExists) { - // If the new storage directory location already exists, remove existing directory - newStorageDirectoryExists = !([[NSFileManager defaultManager] removeItemAtPath:RCTGetStorageDirectory() error:&error]); - if (newStorageDirectoryExists) { - RCTStorageDirectoryMigrationLogError(@"Failed to clear pre-existing storage directory", error); - } - } - if (!newStorageDirectoryExists) { - // If new storage direction doesn't exist, copy old storage directory to new location - if (![[NSFileManager defaultManager] copyItemAtPath:RCTCreateStorageDirectoryPath(RCTOldStorageDirectory) toPath:RCTGetStorageDirectory() error:&error]) { - RCTStorageDirectoryMigrationLogError(@"Failed to copy old storage directory to new storage directory", error); + if ([[NSFileManager defaultManager] fileExistsAtPath:RCTGetStorageDirectory()]) { + // If new storage location exists, check if the new storage has been modified sooner + if ([RCTManifestModificationDate(RCTGetManifestFilePath()) compare:RCTManifestModificationDate(RCTCreateManifestFilePath(RCTOldStorageDirectory))] == 1) { + // If new location has been modified more recently, simply clean out old data + RCTStorageDirectoryCleanupOld(); } else { - // If copying succeeds, remove old storage directory - [[NSFileManager defaultManager] removeItemAtPath:RCTCreateStorageDirectoryPath(RCTOldStorageDirectory) error:&error]; - if (error) RCTStorageDirectoryMigrationLogError(@"Failed to remove old storage directory after migration", error); + // If old location has been modified more recently, remove new storage and migrate + if (![[NSFileManager defaultManager] removeItemAtPath:RCTGetStorageDirectory() error:&error]) { + RCTStorageDirectoryMigrationLogError(@"Failed to remove new storage directory during migration", error); + } else { + RCTStorageDirectoryMigrate(); + } } + } else { + // If new storage location doesn't exist, migrate data + RCTStorageDirectoryMigrate(); } } }); @@ -228,7 +259,8 @@ @implementation RNCAsyncStorage NSMutableDictionary *_manifest; } -+ (BOOL)requiresMainQueueSetup { ++ (BOOL)requiresMainQueueSetup +{ return NO; } From e55fd44ca8a465701380a60eb8767c3000203af0 Mon Sep 17 00:00:00 2001 From: Reinert L Date: Tue, 9 Apr 2019 23:23:55 +0200 Subject: [PATCH 08/12] Make RCTOldStorageDirectory static --- ios/RNCAsyncStorage.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/RNCAsyncStorage.m b/ios/RNCAsyncStorage.m index 275f128b..844ccff8 100644 --- a/ios/RNCAsyncStorage.m +++ b/ios/RNCAsyncStorage.m @@ -185,7 +185,7 @@ static dispatch_queue_t RCTGetMethodQueue() return [attributes fileModificationDate]; } -NSString *const RCTOldStorageDirectory = @"RNCAsyncLocalStorage_V1"; +static NSString *const RCTOldStorageDirectory = @"RNCAsyncLocalStorage_V1"; /** * Creates an NSException used during Storage Directory Migration. */ From 3a26f423616adcc7550561b1587b55f0a10f2f3b Mon Sep 17 00:00:00 2001 From: Reinert L Date: Wed, 10 Apr 2019 12:31:08 +0200 Subject: [PATCH 09/12] Fix manifest path --- ios/RNCAsyncStorage.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/RNCAsyncStorage.m b/ios/RNCAsyncStorage.m index 844ccff8..7f81590f 100644 --- a/ios/RNCAsyncStorage.m +++ b/ios/RNCAsyncStorage.m @@ -101,7 +101,7 @@ static void RCTAppendError(NSDictionary *error, NSMutableArray * static NSString *RCTCreateManifestFilePath(NSString *storageDirectory) { - return [RCTCreateStorageDirectoryPath(storageDirectory) stringByAppendingString:RCTManifestFileName]; + return [RCTCreateStorageDirectoryPath(storageDirectory) stringByAppendingPathComponent:RCTManifestFileName]; } static NSString *RCTGetManifestFilePath() From bcce5927744d628b086e177372f9df29932b8df2 Mon Sep 17 00:00:00 2001 From: Reinert L Date: Wed, 10 Apr 2019 12:40:05 +0200 Subject: [PATCH 10/12] Use RCTLogWarn instead of NSLog to log errors --- ios/RNCAsyncStorage.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/RNCAsyncStorage.m b/ios/RNCAsyncStorage.m index 7f81590f..0e765d57 100644 --- a/ios/RNCAsyncStorage.m +++ b/ios/RNCAsyncStorage.m @@ -191,7 +191,7 @@ static dispatch_queue_t RCTGetMethodQueue() */ static void RCTStorageDirectoryMigrationLogError(NSString *reason, NSError *error) { - NSLog(@"%@: %@", reason, error ? error.description : @""); + RCTLogWarn(@"%@: %@", reason, error ? error.description : @""); } static void RCTStorageDirectoryCleanupOld() From c28e978d7f72f1ea45f259381de494fd070b76f5 Mon Sep 17 00:00:00 2001 From: Reinert L Date: Wed, 10 Apr 2019 12:41:56 +0200 Subject: [PATCH 11/12] Revert style changes --- ios/RNCAsyncStorage.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ios/RNCAsyncStorage.m b/ios/RNCAsyncStorage.m index 0e765d57..8dba2d5c 100644 --- a/ios/RNCAsyncStorage.m +++ b/ios/RNCAsyncStorage.m @@ -535,7 +535,7 @@ - (BOOL)_passthroughDelegate } RCT_EXPORT_METHOD(multiMerge:(NSArray *> *)kvPairs - callback:(RCTResponseSenderBlock)callback) + callback:(RCTResponseSenderBlock)callback) { if (self.delegate != nil) { NSMutableArray *keys = [NSMutableArray arrayWithCapacity:kvPairs.count]; @@ -669,4 +669,3 @@ - (BOOL)_passthroughDelegate } @end - From 0b5034d008e87b328b8dc3ce2dd56bb2bffef4a6 Mon Sep 17 00:00:00 2001 From: Reinert L Date: Thu, 11 Apr 2019 09:34:57 +0200 Subject: [PATCH 12/12] Move OldStorageDirectory const to top --- ios/RNCAsyncStorage.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/RNCAsyncStorage.m b/ios/RNCAsyncStorage.m index 8dba2d5c..18556296 100644 --- a/ios/RNCAsyncStorage.m +++ b/ios/RNCAsyncStorage.m @@ -17,6 +17,7 @@ #import static NSString *const RCTStorageDirectory = @"RCTAsyncLocalStorage_V1"; +static NSString *const RCTOldStorageDirectory = @"RNCAsyncLocalStorage_V1"; static NSString *const RCTManifestFileName = @"manifest.json"; static const NSUInteger RCTInlineValueThreshold = 1024; @@ -185,7 +186,6 @@ static dispatch_queue_t RCTGetMethodQueue() return [attributes fileModificationDate]; } -static NSString *const RCTOldStorageDirectory = @"RNCAsyncLocalStorage_V1"; /** * Creates an NSException used during Storage Directory Migration. */