17
17
#import < React/RCTUtils.h>
18
18
19
19
static NSString *const RCTStorageDirectory = @" RCTAsyncLocalStorage_V1" ;
20
+ static NSString *const RCTOldStorageDirectory = @" RNCAsyncLocalStorage_V1" ;
20
21
static NSString *const RCTManifestFileName = @" manifest.json" ;
21
22
static const NSUInteger RCTInlineValueThreshold = 1024 ;
22
23
@@ -78,27 +79,38 @@ static void RCTAppendError(NSDictionary *error, NSMutableArray<NSDictionary *> *
78
79
return nil ;
79
80
}
80
81
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
+
81
93
static NSString *RCTGetStorageDirectory ()
82
94
{
83
95
static NSString *storageDirectory = nil ;
84
96
static dispatch_once_t onceToken;
85
97
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);
92
99
});
93
100
return storageDirectory;
94
101
}
95
102
103
+ static NSString *RCTCreateManifestFilePath (NSString *storageDirectory)
104
+ {
105
+ return [RCTCreateStorageDirectoryPath (storageDirectory) stringByAppendingPathComponent: RCTManifestFileName];
106
+ }
107
+
96
108
static NSString *RCTGetManifestFilePath ()
97
109
{
98
110
static NSString *manifestFilePath = nil ;
99
111
static dispatch_once_t onceToken;
100
112
dispatch_once (&onceToken, ^{
101
- manifestFilePath = [ RCTGetStorageDirectory () stringByAppendingPathComponent: RCTManifestFileName] ;
113
+ manifestFilePath = RCTCreateManifestFilePath (RCTStorageDirectory) ;
102
114
});
103
115
return manifestFilePath;
104
116
}
@@ -168,6 +180,74 @@ static dispatch_queue_t RCTGetMethodQueue()
168
180
return error ? RCTMakeError (@" Failed to delete storage directory." , error, nil ) : nil ;
169
181
}
170
182
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
+
171
251
#pragma mark - RNCAsyncStorage
172
252
173
253
@implementation RNCAsyncStorage
@@ -179,6 +259,20 @@ @implementation RNCAsyncStorage
179
259
NSMutableDictionary <NSString *, NSString *> *_manifest;
180
260
}
181
261
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
+
182
276
RCT_EXPORT_MODULE ()
183
277
184
278
- (dispatch_queue_t )methodQueue
0 commit comments