Fixed async local storage

This commit is contained in:
Nick Lockwood 2015-06-23 14:17:31 -07:00
parent 47508566a0
commit 0624a0fe52
2 changed files with 30 additions and 17 deletions

View File

@ -54,6 +54,9 @@ function expectEqual(lhs, rhs, testname) {
} }
function expectAsyncNoError(place, err) { function expectAsyncNoError(place, err) {
if (err instanceof Error) {
err = err.message;
}
expectTrue(err === null, 'Unexpected error in ' + place + ': ' + JSON.stringify(err)); expectTrue(err === null, 'Unexpected error in ' + place + ': ' + JSON.stringify(err));
} }

View File

@ -17,9 +17,9 @@
#import "RCTLog.h" #import "RCTLog.h"
#import "RCTUtils.h" #import "RCTUtils.h"
static NSString *const kStorageDir = @"RCTAsyncLocalStorage_V1"; static NSString *const RCTStorageDirectory = @"RCTAsyncLocalStorage_V1";
static NSString *const kManifestFilename = @"manifest.json"; static NSString *const RCTManifestFileName = @"manifest.json";
static const NSUInteger kInlineValueThreshold = 100; static const NSUInteger RCTInlineValueThreshold = 100;
#pragma mark - Static helper functions #pragma mark - Static helper functions
@ -61,11 +61,25 @@ static id RCTReadFile(NSString *filePath, NSString *key, NSDictionary **errorOut
return nil; return nil;
} }
static NSString *RCTGetStorageDir() static NSString *RCTGetStorageDirectory()
{ {
NSString *documentDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; static NSString *storageDirectory = nil;
NSURL *homeURL = [NSURL fileURLWithPath:documentDirectory isDirectory:YES]; static dispatch_once_t onceToken;
return [[homeURL URLByAppendingPathComponent:kStorageDir isDirectory:YES] path]; dispatch_once(&onceToken, ^{
storageDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
storageDirectory = [storageDirectory stringByAppendingPathComponent:RCTStorageDirectory];
});
return storageDirectory;
}
static NSString *RCTGetManifestFilePath()
{
static NSString *manifestFilePath = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manifestFilePath = [RCTGetStorageDirectory() stringByAppendingPathComponent:RCTManifestFileName];
});
return manifestFilePath;
} }
// Only merges objects - all other types are just clobbered (including arrays) // Only merges objects - all other types are just clobbered (including arrays)
@ -111,7 +125,7 @@ static BOOL RCTHasCreatedStorageDirectory = NO;
static NSError *RCTDeleteStorageDirectory() static NSError *RCTDeleteStorageDirectory()
{ {
NSError *error; NSError *error;
[[NSFileManager defaultManager] removeItemAtPath:RCTGetStorageDir() error:&error]; [[NSFileManager defaultManager] removeItemAtPath:RCTGetStorageDirectory() error:&error];
RCTHasCreatedStorageDirectory = NO; RCTHasCreatedStorageDirectory = NO;
return error; return error;
} }
@ -125,8 +139,6 @@ static NSError *RCTDeleteStorageDirectory()
// in separate files (as opposed to nil values which don't exist). The manifest is read off disk at startup, and // in separate files (as opposed to nil values which don't exist). The manifest is read off disk at startup, and
// written to disk after all mutations. // written to disk after all mutations.
NSMutableDictionary *_manifest; NSMutableDictionary *_manifest;
NSString *_manifestPath;
NSString *_storageDirectory;
} }
RCT_EXPORT_MODULE() RCT_EXPORT_MODULE()
@ -165,7 +177,7 @@ RCT_EXPORT_MODULE()
- (NSString *)_filePathForKey:(NSString *)key - (NSString *)_filePathForKey:(NSString *)key
{ {
NSString *safeFileName = RCTMD5Hash(key); NSString *safeFileName = RCTMD5Hash(key);
return [_storageDirectory stringByAppendingPathComponent:safeFileName]; return [RCTGetStorageDirectory() stringByAppendingPathComponent:safeFileName];
} }
- (id)_ensureSetup - (id)_ensureSetup
@ -174,8 +186,7 @@ RCT_EXPORT_MODULE()
NSError *error = nil; NSError *error = nil;
if (!RCTHasCreatedStorageDirectory) { if (!RCTHasCreatedStorageDirectory) {
_storageDirectory = RCTGetStorageDir(); [[NSFileManager defaultManager] createDirectoryAtPath:RCTGetStorageDirectory()
[[NSFileManager defaultManager] createDirectoryAtPath:_storageDirectory
withIntermediateDirectories:YES withIntermediateDirectories:YES
attributes:nil attributes:nil
error:&error]; error:&error];
@ -185,9 +196,8 @@ RCT_EXPORT_MODULE()
RCTHasCreatedStorageDirectory = YES; RCTHasCreatedStorageDirectory = YES;
} }
if (!_haveSetup) { if (!_haveSetup) {
_manifestPath = [_storageDirectory stringByAppendingPathComponent:kManifestFilename];
NSDictionary *errorOut; NSDictionary *errorOut;
NSString *serialized = RCTReadFile(_manifestPath, nil, &errorOut); NSString *serialized = RCTReadFile(RCTGetManifestFilePath(), nil, &errorOut);
_manifest = serialized ? [RCTJSONParse(serialized, &error) mutableCopy] : [[NSMutableDictionary alloc] init]; _manifest = serialized ? [RCTJSONParse(serialized, &error) mutableCopy] : [[NSMutableDictionary alloc] init];
if (error) { if (error) {
RCTLogWarn(@"Failed to parse manifest - creating new one.\n\n%@", error); RCTLogWarn(@"Failed to parse manifest - creating new one.\n\n%@", error);
@ -202,7 +212,7 @@ RCT_EXPORT_MODULE()
{ {
NSError *error; NSError *error;
NSString *serialized = RCTJSONStringify(_manifest, &error); NSString *serialized = RCTJSONStringify(_manifest, &error);
[serialized writeToFile:_manifestPath atomically:YES encoding:NSUTF8StringEncoding error:&error]; [serialized writeToFile:RCTGetManifestFilePath() atomically:YES encoding:NSUTF8StringEncoding error:&error];
id errorOut; id errorOut;
if (error) { if (error) {
errorOut = RCTMakeError(@"Failed to write manifest file.", error, nil); errorOut = RCTMakeError(@"Failed to write manifest file.", error, nil);
@ -248,7 +258,7 @@ RCT_EXPORT_MODULE()
NSString *value = entry[1]; NSString *value = entry[1];
NSString *filePath = [self _filePathForKey:key]; NSString *filePath = [self _filePathForKey:key];
NSError *error; NSError *error;
if (value.length <= kInlineValueThreshold) { if (value.length <= RCTInlineValueThreshold) {
if (_manifest[key] && _manifest[key] != (id)kCFNull) { if (_manifest[key] && _manifest[key] != (id)kCFNull) {
// If the value already existed but wasn't inlined, remove the old file. // If the value already existed but wasn't inlined, remove the old file.
[[NSFileManager defaultManager] removeItemAtPath:filePath error:nil]; [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];