Skip to content

Commit 8d275ad

Browse files
reilemtido64
authored andcommitted
fix: iOS clean migration from RNCAsyncStorage_V1 to RTCAsyncStorage_V1 (#64)
1 parent 85f289c commit 8d275ad

File tree

1 file changed

+101
-7
lines changed

1 file changed

+101
-7
lines changed

ios/RNCAsyncStorage.m

+101-7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#import <React/RCTUtils.h>
1818

1919
static NSString *const RCTStorageDirectory = @"RCTAsyncLocalStorage_V1";
20+
static NSString *const RCTOldStorageDirectory = @"RNCAsyncLocalStorage_V1";
2021
static NSString *const RCTManifestFileName = @"manifest.json";
2122
static const NSUInteger RCTInlineValueThreshold = 1024;
2223

@@ -78,27 +79,38 @@ static void RCTAppendError(NSDictionary *error, NSMutableArray<NSDictionary *> *
7879
return nil;
7980
}
8081

82+
static NSString *RCTCreateStorageDirectoryPath(NSString *storageDir) {
83+
NSString *storageDirectoryPath;
84+
#if TARGET_OS_TV
85+
storageDirectoryPath = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
86+
#else
87+
storageDirectoryPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
88+
#endif
89+
storageDirectoryPath = [storageDirectoryPath stringByAppendingPathComponent:storageDir];
90+
return storageDirectoryPath;
91+
}
92+
8193
static NSString *RCTGetStorageDirectory()
8294
{
8395
static NSString *storageDirectory = nil;
8496
static dispatch_once_t onceToken;
8597
dispatch_once(&onceToken, ^{
86-
#if TARGET_OS_TV
87-
storageDirectory = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
88-
#else
89-
storageDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
90-
#endif
91-
storageDirectory = [storageDirectory stringByAppendingPathComponent:RCTStorageDirectory];
98+
storageDirectory = RCTCreateStorageDirectoryPath(RCTStorageDirectory);
9299
});
93100
return storageDirectory;
94101
}
95102

103+
static NSString *RCTCreateManifestFilePath(NSString *storageDirectory)
104+
{
105+
return [RCTCreateStorageDirectoryPath(storageDirectory) stringByAppendingPathComponent:RCTManifestFileName];
106+
}
107+
96108
static NSString *RCTGetManifestFilePath()
97109
{
98110
static NSString *manifestFilePath = nil;
99111
static dispatch_once_t onceToken;
100112
dispatch_once(&onceToken, ^{
101-
manifestFilePath = [RCTGetStorageDirectory() stringByAppendingPathComponent:RCTManifestFileName];
113+
manifestFilePath = RCTCreateManifestFilePath(RCTStorageDirectory);
102114
});
103115
return manifestFilePath;
104116
}
@@ -168,6 +180,74 @@ static dispatch_queue_t RCTGetMethodQueue()
168180
return error ? RCTMakeError(@"Failed to delete storage directory.", error, nil) : nil;
169181
}
170182

183+
static NSDate *RCTManifestModificationDate(NSString *manifestFilePath)
184+
{
185+
NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:manifestFilePath error:nil];
186+
return [attributes fileModificationDate];
187+
}
188+
189+
/**
190+
* Creates an NSException used during Storage Directory Migration.
191+
*/
192+
static void RCTStorageDirectoryMigrationLogError(NSString *reason, NSError *error)
193+
{
194+
RCTLogWarn(@"%@: %@", reason, error ? error.description : @"");
195+
}
196+
197+
static void RCTStorageDirectoryCleanupOld()
198+
{
199+
NSError *error;
200+
if (![[NSFileManager defaultManager] removeItemAtPath:RCTCreateStorageDirectoryPath(RCTOldStorageDirectory) error:&error]) {
201+
RCTStorageDirectoryMigrationLogError(@"Failed to remove old storage directory during migration", error);
202+
}
203+
}
204+
205+
static void RCTStorageDirectoryMigrate()
206+
{
207+
NSError *error;
208+
// Migrate data by copying old storage directory to new storage directory location
209+
if (![[NSFileManager defaultManager] copyItemAtPath:RCTCreateStorageDirectoryPath(RCTOldStorageDirectory) toPath:RCTGetStorageDirectory() error:&error]) {
210+
RCTStorageDirectoryMigrationLogError(@"Failed to copy old storage directory to new storage directory location during migration", error);
211+
} else {
212+
// If copying succeeds, remove old storage directory
213+
RCTStorageDirectoryCleanupOld();
214+
}
215+
}
216+
217+
/**
218+
* This check is added to make sure that anyone coming from pre-1.2.2 does not lose cached data.
219+
* Data is migrated from the "RNCAsyncLocalStorage_V1" directory to the "RCTAsyncLocalStorage_V1" directory.
220+
*/
221+
static void RCTStorageDirectoryMigrationCheck()
222+
{
223+
static dispatch_once_t onceToken;
224+
dispatch_once(&onceToken, ^{
225+
NSError *error;
226+
BOOL isDir;
227+
// If the old directory exists, it means we may need to migrate old data to the new directory
228+
if ([[NSFileManager defaultManager] fileExistsAtPath:RCTCreateStorageDirectoryPath(RCTOldStorageDirectory) isDirectory:&isDir] && isDir) {
229+
// Check if the new storage directory location already exists
230+
if ([[NSFileManager defaultManager] fileExistsAtPath:RCTGetStorageDirectory()]) {
231+
// If new storage location exists, check if the new storage has been modified sooner
232+
if ([RCTManifestModificationDate(RCTGetManifestFilePath()) compare:RCTManifestModificationDate(RCTCreateManifestFilePath(RCTOldStorageDirectory))] == 1) {
233+
// If new location has been modified more recently, simply clean out old data
234+
RCTStorageDirectoryCleanupOld();
235+
} else {
236+
// If old location has been modified more recently, remove new storage and migrate
237+
if (![[NSFileManager defaultManager] removeItemAtPath:RCTGetStorageDirectory() error:&error]) {
238+
RCTStorageDirectoryMigrationLogError(@"Failed to remove new storage directory during migration", error);
239+
} else {
240+
RCTStorageDirectoryMigrate();
241+
}
242+
}
243+
} else {
244+
// If new storage location doesn't exist, migrate data
245+
RCTStorageDirectoryMigrate();
246+
}
247+
}
248+
});
249+
}
250+
171251
#pragma mark - RNCAsyncStorage
172252

173253
@implementation RNCAsyncStorage
@@ -179,6 +259,20 @@ @implementation RNCAsyncStorage
179259
NSMutableDictionary<NSString *, NSString *> *_manifest;
180260
}
181261

262+
+ (BOOL)requiresMainQueueSetup
263+
{
264+
return NO;
265+
}
266+
267+
- (instancetype)init
268+
{
269+
if (!(self = [super init])) {
270+
return nil;
271+
}
272+
RCTStorageDirectoryMigrationCheck();
273+
return self;
274+
}
275+
182276
RCT_EXPORT_MODULE()
183277

184278
- (dispatch_queue_t)methodQueue

0 commit comments

Comments
 (0)