1717#import < React/RCTUtils.h>
1818
1919static NSString *const RCTStorageDirectory = @" RCTAsyncLocalStorage_V1" ;
20+ static NSString *const RCTOldStorageDirectory = @" RNCAsyncLocalStorage_V1" ;
2021static NSString *const RCTManifestFileName = @" manifest.json" ;
2122static 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+
8193static 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+
96108static 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+
182276RCT_EXPORT_MODULE ()
183277
184278- (dispatch_queue_t )methodQueue
0 commit comments