refactor(AsyncStorage): move iOS files from react-native-github

Summary:
## Changelog:
[iOS][Removed] - Removed AsyncStorage module

Reviewed By: lunaleaps

Differential Revision: D40283712

fbshipit-source-id: 5e74c71915c2fbba4363e3fc917555039069038e
This commit is contained in:
Ruslan Lesiutin 2022-10-31 14:39:19 -07:00 коммит произвёл Facebook GitHub Bot
Родитель 5738fe6426
Коммит 4de2aaba50
6 изменённых файлов: 7 добавлений и 523 удалений

Просмотреть файл

@ -78,9 +78,6 @@ rn_apple_library(
) + react_module_plugin_providers(
name = "AlertManager",
native_class_func = "RCTAlertManagerCls",
) + react_module_plugin_providers(
name = "AsyncLocalStorage",
native_class_func = "RCTAsyncLocalStorageCls",
) + react_module_plugin_providers(
name = "Timing",
native_class_func = "RCTTimingCls",

Просмотреть файл

@ -39,7 +39,6 @@ Class RCTI18nManagerCls(void) __attribute__((used));
Class RCTSourceCodeCls(void) __attribute__((used));
Class RCTActionSheetManagerCls(void) __attribute__((used));
Class RCTAlertManagerCls(void) __attribute__((used));
Class RCTAsyncLocalStorageCls(void) __attribute__((used));
Class RCTTimingCls(void) __attribute__((used));
Class RCTStatusBarManagerCls(void) __attribute__((used));
Class RCTKeyboardObserverCls(void) __attribute__((used));

Просмотреть файл

@ -29,7 +29,6 @@ Class RCTCoreModulesClassProvider(const char *name) {
{"SourceCode", RCTSourceCodeCls},
{"ActionSheetManager", RCTActionSheetManagerCls},
{"AlertManager", RCTAlertManagerCls},
{"AsyncLocalStorage", RCTAsyncLocalStorageCls},
{"Timing", RCTTimingCls},
{"StatusBarManager", RCTStatusBarManagerCls},
{"KeyboardObserver", RCTKeyboardObserverCls},

Просмотреть файл

@ -1,41 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <React/RCTBridgeModule.h>
#import <React/RCTInvalidating.h>
/**
* A simple, asynchronous, persistent, key-value storage system designed as a
* backend to the AsyncStorage JS module, which is modeled after LocalStorage.
*
* Current implementation stores small values in serialized dictionary and
* larger values in separate files. Since we use a serial file queue
* `RKFileQueue`, reading/writing from multiple threads should be perceived as
* being atomic, unless someone bypasses the `RCTAsyncLocalStorage` API.
*
* Keys and values must always be strings or an error is returned.
*/
@interface RCTAsyncLocalStorage : NSObject <RCTBridgeModule, RCTInvalidating>
@property (nonatomic, assign) BOOL clearOnInvalidate;
@property (nonatomic, readonly, getter=isValid) BOOL valid;
// Clear the RCTAsyncLocalStorage data from native code
- (void)clearAllData;
// For clearing data when the bridge may not exist, e.g. when logging out.
+ (void)clearAllData;
// Grab data from the cache. ResponseBlock result array will have an error at position 0, and an array of arrays at
// position 1.
- (void)multiGet:(NSArray<NSString *> *)keys callback:(RCTResponseSenderBlock)callback;
// Add multiple key value pairs to the cache.
- (void)multiSet:(NSArray<NSArray<NSString *> *> *)kvPairs callback:(RCTResponseSenderBlock)callback;
@end

Просмотреть файл

@ -1,470 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTAsyncLocalStorage.h"
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCryptor.h>
#import <CommonCrypto/CommonDigest.h>
#import <FBReactNativeSpec/FBReactNativeSpec.h>
#import <React/RCTConvert.h>
#import <React/RCTLog.h>
#import <React/RCTUtils.h>
#import "CoreModulesPlugins.h"
static NSString *const RCTStorageDirectory = @"RCTAsyncLocalStorage_V1";
static NSString *const RCTManifestFileName = @"manifest.json";
static const NSUInteger RCTInlineValueThreshold = 1024;
#pragma mark - Static helper functions
static NSDictionary *RCTErrorForKey(NSString *key)
{
if (![key isKindOfClass:[NSString class]]) {
return RCTMakeAndLogError(@"Invalid key - must be a string. Key: ", key, @{@"key" : key});
} else if (key.length < 1) {
return RCTMakeAndLogError(@"Invalid key - must be at least one character. Key: ", key, @{@"key" : key});
} else {
return nil;
}
}
static void RCTAppendError(NSDictionary *error, NSMutableArray<NSDictionary *> **errors)
{
if (error && errors) {
if (!*errors) {
*errors = [NSMutableArray new];
}
[*errors addObject:error];
}
}
static NSString *RCTReadFile(NSString *filePath, NSString *key, NSDictionary **errorOut)
{
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
NSError *error;
NSStringEncoding encoding;
NSString *entryString = [NSString stringWithContentsOfFile:filePath usedEncoding:&encoding error:&error];
NSDictionary *extraData = @{@"key" : RCTNullIfNil(key)};
if (error) {
if (errorOut)
*errorOut = RCTMakeError(@"Failed to read storage file.", error, extraData);
return nil;
}
if (encoding != NSUTF8StringEncoding) {
if (errorOut)
*errorOut = RCTMakeError(@"Incorrect encoding of storage file: ", @(encoding), extraData);
return nil;
}
return entryString;
}
return nil;
}
static NSString *RCTGetStorageDirectory()
{
static NSString *storageDirectory = nil;
static dispatch_once_t onceToken;
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)
static BOOL RCTMergeRecursive(NSMutableDictionary *destination, NSDictionary *source)
{
BOOL modified = NO;
for (NSString *key in source) {
id sourceValue = source[key];
id destinationValue = destination[key];
if ([sourceValue isKindOfClass:[NSDictionary class]]) {
if ([destinationValue isKindOfClass:[NSDictionary class]]) {
if ([destinationValue classForCoder] != [NSMutableDictionary class]) {
destinationValue = [destinationValue mutableCopy];
}
if (RCTMergeRecursive(destinationValue, sourceValue)) {
destination[key] = destinationValue;
modified = YES;
}
} else {
destination[key] = [sourceValue copy];
modified = YES;
}
} else if (![source isEqual:destinationValue]) {
destination[key] = [sourceValue copy];
modified = YES;
}
}
return modified;
}
static dispatch_queue_t RCTGetMethodQueue()
{
// We want all instances to share the same queue since they will be reading/writing the same files.
static dispatch_queue_t queue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
queue = dispatch_queue_create("com.facebook.react.AsyncLocalStorageQueue", DISPATCH_QUEUE_SERIAL);
});
return queue;
}
static NSCache *RCTGetCache()
{
// We want all instances to share the same cache since they will be reading/writing the same files.
static NSCache *cache;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
cache = [NSCache new];
cache.totalCostLimit = 2 * 1024 * 1024; // 2MB
// Clear cache in the event of a memory warning
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidReceiveMemoryWarningNotification
object:nil
queue:nil
usingBlock:^(__unused NSNotification *note) {
[cache removeAllObjects];
}];
});
return cache;
}
static BOOL RCTHasCreatedStorageDirectory = NO;
static NSDictionary *RCTDeleteStorageDirectory()
{
NSError *error;
[[NSFileManager defaultManager] removeItemAtPath:RCTGetStorageDirectory() error:&error];
RCTHasCreatedStorageDirectory = NO;
return error ? RCTMakeError(@"Failed to delete storage directory.", error, nil) : nil;
}
#pragma mark - RCTAsyncLocalStorage
@interface RCTAsyncLocalStorage () <NativeAsyncLocalStorageSpec>
@end
@implementation RCTAsyncLocalStorage {
BOOL _haveSetup;
// The manifest is a dictionary of all keys with small values inlined. Null values indicate values that are stored
// 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.
NSMutableDictionary<NSString *, NSString *> *_manifest;
}
RCT_EXPORT_MODULE()
- (dispatch_queue_t)methodQueue
{
return RCTGetMethodQueue();
}
- (void)clearAllData
{
dispatch_async(RCTGetMethodQueue(), ^{
[self->_manifest removeAllObjects];
[RCTGetCache() removeAllObjects];
RCTDeleteStorageDirectory();
});
}
+ (void)clearAllData
{
dispatch_async(RCTGetMethodQueue(), ^{
[RCTGetCache() removeAllObjects];
RCTDeleteStorageDirectory();
});
}
- (void)invalidate
{
if (_clearOnInvalidate) {
[RCTGetCache() removeAllObjects];
RCTDeleteStorageDirectory();
}
_clearOnInvalidate = NO;
[_manifest removeAllObjects];
_haveSetup = NO;
}
- (BOOL)isValid
{
return _haveSetup;
}
- (void)dealloc
{
[self invalidate];
}
- (NSString *)_filePathForKey:(NSString *)key
{
NSString *safeFileName = RCTMD5Hash(key);
return [RCTGetStorageDirectory() stringByAppendingPathComponent:safeFileName];
}
- (NSDictionary *)_ensureSetup
{
RCTAssertThread(RCTGetMethodQueue(), @"Must be executed on storage thread");
NSError *error = nil;
if (!RCTHasCreatedStorageDirectory) {
[[NSFileManager defaultManager] createDirectoryAtPath:RCTGetStorageDirectory()
withIntermediateDirectories:YES
attributes:nil
error:&error];
if (error) {
return RCTMakeError(@"Failed to create storage directory.", error, nil);
}
RCTHasCreatedStorageDirectory = YES;
}
if (!_haveSetup) {
NSDictionary *errorOut;
NSString *serialized = RCTReadFile(RCTGetManifestFilePath(), RCTManifestFileName, &errorOut);
_manifest = serialized ? RCTJSONParseMutable(serialized, &error) : [NSMutableDictionary new];
if (error) {
RCTLogWarn(@"Failed to parse manifest - creating new one.\n\n%@", error);
_manifest = [NSMutableDictionary new];
}
_haveSetup = YES;
}
return nil;
}
- (NSDictionary *)_writeManifest:(NSMutableArray<NSDictionary *> **)errors
{
NSError *error;
NSString *serialized = RCTJSONStringify(_manifest, &error);
[serialized writeToFile:RCTGetManifestFilePath() atomically:YES encoding:NSUTF8StringEncoding error:&error];
NSDictionary *errorOut;
if (error) {
errorOut = RCTMakeError(@"Failed to write manifest file.", error, nil);
RCTAppendError(errorOut, errors);
}
return errorOut;
}
- (NSDictionary *)_appendItemForKey:(NSString *)key toArray:(NSMutableArray<NSArray<NSString *> *> *)result
{
NSDictionary *errorOut = RCTErrorForKey(key);
if (errorOut) {
return errorOut;
}
NSString *value = [self _getValueForKey:key errorOut:&errorOut];
[result addObject:@[ key, RCTNullIfNil(value) ]]; // Insert null if missing or failure.
return errorOut;
}
- (NSString *)_getValueForKey:(NSString *)key errorOut:(NSDictionary **)errorOut
{
NSString *value = _manifest[key]; // nil means missing, null means there may be a data file, else: NSString
if (value == (id)kCFNull) {
value = [RCTGetCache() objectForKey:key];
if (!value) {
NSString *filePath = [self _filePathForKey:key];
value = RCTReadFile(filePath, key, errorOut);
if (value) {
[RCTGetCache() setObject:value forKey:key cost:value.length];
} else {
// file does not exist after all, so remove from manifest (no need to save
// manifest immediately though, as cost of checking again next time is negligible)
[_manifest removeObjectForKey:key];
}
}
}
return value;
}
- (NSDictionary *)_writeEntry:(NSArray<NSString *> *)entry changedManifest:(BOOL *)changedManifest
{
if (entry.count != 2) {
return RCTMakeAndLogError(@"Entries must be arrays of the form [key: string, value: string], got: ", entry, nil);
}
NSString *key = entry[0];
NSDictionary *errorOut = RCTErrorForKey(key);
if (errorOut) {
return errorOut;
}
if (![entry[1] isKindOfClass:[NSString class]]) {
return RCTMakeAndLogError(@"Invalid value for entry - must be a string. Got entry: ", entry, nil);
}
NSString *value = entry[1];
NSString *filePath = [self _filePathForKey:key];
NSError *error;
if (value.length <= RCTInlineValueThreshold) {
if (_manifest[key] == (id)kCFNull) {
// If the value already existed but wasn't inlined, remove the old file.
[[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
[RCTGetCache() removeObjectForKey:key];
}
*changedManifest = YES;
_manifest[key] = value;
return nil;
}
[value writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:&error];
[RCTGetCache() setObject:value forKey:key cost:value.length];
if (error) {
errorOut = RCTMakeError(@"Failed to write value.", error, @{@"key" : key});
} else if (_manifest[key] != (id)kCFNull) {
*changedManifest = YES;
_manifest[key] = (id)kCFNull;
}
return errorOut;
}
#pragma mark - Exported JS Functions
RCT_EXPORT_METHOD(multiGet : (NSArray<NSString *> *)keys callback : (RCTResponseSenderBlock)callback)
{
NSDictionary *errorOut = [self _ensureSetup];
if (errorOut) {
callback(@[ @[ errorOut ], (id)kCFNull ]);
return;
}
NSMutableArray<NSDictionary *> *errors;
NSMutableArray<NSArray<NSString *> *> *result = [[NSMutableArray alloc] initWithCapacity:keys.count];
for (NSString *key in keys) {
id keyError;
id value = [self _getValueForKey:key errorOut:&keyError];
[result addObject:@[ key, RCTNullIfNil(value) ]];
RCTAppendError(keyError, &errors);
}
callback(@[ RCTNullIfNil(errors), result ]);
}
RCT_EXPORT_METHOD(multiSet : (NSArray<NSArray<NSString *> *> *)kvPairs callback : (RCTResponseSenderBlock)callback)
{
NSDictionary *errorOut = [self _ensureSetup];
if (errorOut) {
callback(@[ @[ errorOut ] ]);
return;
}
BOOL changedManifest = NO;
NSMutableArray<NSDictionary *> *errors;
for (NSArray<NSString *> *entry in kvPairs) {
NSDictionary *keyError = [self _writeEntry:entry changedManifest:&changedManifest];
RCTAppendError(keyError, &errors);
}
if (changedManifest) {
[self _writeManifest:&errors];
}
callback(@[ RCTNullIfNil(errors) ]);
}
RCT_EXPORT_METHOD(multiMerge : (NSArray<NSArray<NSString *> *> *)kvPairs callback : (RCTResponseSenderBlock)callback)
{
NSDictionary *errorOut = [self _ensureSetup];
if (errorOut) {
callback(@[ @[ errorOut ] ]);
return;
}
BOOL changedManifest = NO;
NSMutableArray<NSDictionary *> *errors;
for (__strong NSArray<NSString *> *entry in kvPairs) {
NSDictionary *keyError;
NSString *value = [self _getValueForKey:entry[0] errorOut:&keyError];
if (!keyError) {
if (value) {
NSError *jsonError;
NSMutableDictionary *mergedVal = RCTJSONParseMutable(value, &jsonError);
if (RCTMergeRecursive(mergedVal, RCTJSONParse(entry[1], &jsonError))) {
entry = @[ entry[0], RCTNullIfNil(RCTJSONStringify(mergedVal, NULL)) ];
}
if (jsonError) {
keyError = RCTJSErrorFromNSError(jsonError);
}
}
if (!keyError) {
keyError = [self _writeEntry:entry changedManifest:&changedManifest];
}
}
RCTAppendError(keyError, &errors);
}
if (changedManifest) {
[self _writeManifest:&errors];
}
callback(@[ RCTNullIfNil(errors) ]);
}
RCT_EXPORT_METHOD(multiRemove : (NSArray<NSString *> *)keys callback : (RCTResponseSenderBlock)callback)
{
NSDictionary *errorOut = [self _ensureSetup];
if (errorOut) {
callback(@[ @[ errorOut ] ]);
return;
}
NSMutableArray<NSDictionary *> *errors;
BOOL changedManifest = NO;
for (NSString *key in keys) {
NSDictionary *keyError = RCTErrorForKey(key);
if (!keyError) {
if (_manifest[key] == (id)kCFNull) {
NSString *filePath = [self _filePathForKey:key];
[[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
[RCTGetCache() removeObjectForKey:key];
}
if (_manifest[key]) {
changedManifest = YES;
[_manifest removeObjectForKey:key];
}
}
RCTAppendError(keyError, &errors);
}
if (changedManifest) {
[self _writeManifest:&errors];
}
callback(@[ RCTNullIfNil(errors) ]);
}
RCT_EXPORT_METHOD(clear : (RCTResponseSenderBlock)callback)
{
[_manifest removeAllObjects];
[RCTGetCache() removeAllObjects];
NSDictionary *error = RCTDeleteStorageDirectory();
callback(@[ RCTNullIfNil(error) ]);
}
RCT_EXPORT_METHOD(getAllKeys : (RCTResponseSenderBlock)callback)
{
NSDictionary *errorOut = [self _ensureSetup];
if (errorOut) {
callback(@[ errorOut, (id)kCFNull ]);
} else {
callback(@[ (id)kCFNull, _manifest.allKeys ]);
}
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return std::make_shared<facebook::react::NativeAsyncLocalStorageSpecJSI>(params);
}
@end
Class RCTAsyncLocalStorageCls(void)
{
return RCTAsyncLocalStorage.class;
}

Просмотреть файл

@ -929,7 +929,7 @@ EXTERNAL SOURCES:
:path: "../../ReactCommon/yoga"
SPEC CHECKSUMS:
boost: a7c83b31436843459a1961bfd74b96033dc77234
boost: 57d2868c099736d80fcd648bf211b4431e51a558
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
FBLazyVector: 19e408e76fa9258dd32191a50d60c41444f52d29
@ -948,7 +948,7 @@ SPEC CHECKSUMS:
hermes-engine: cd15ebd246edff3a995ec666e898dd1cbdcaa10d
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
RCTRequired: 1c8808cf84569265784a6c33984bbb506ada8c6e
RCTTypeSafety: b6dcb5036a808864ee8cad66ca15f263c24661cc
React: 8d809d414723bb5763093ddec7658066a21ccabc
@ -957,15 +957,15 @@ SPEC CHECKSUMS:
React-Codegen: d2434d5e4d238bceef25f40c4f58b199eb981ad0
React-Core: 3965263aa4b4e1ebf7b4fdb50d2f49ce7bf28f63
React-CoreModules: 675170bccf156da3a3348e04e2036ce401b2010d
React-cxxreact: 7276467c246302fedf598cc40d7003896ddb20ba
React-cxxreact: ebed982230716c3515ab2f435cb13aec8a56af02
React-Fabric: 141459e61c825acf02d26ece099acbd9cbd87b99
React-graphics: 5ccc9cc0d91794fd42bc1c693e9aea207554bbef
React-graphics: 2dda97baebb0082bb85499c862c3f269a194f416
React-hermes: 0a5145bae4207edf0def8e28fbcb6a8fd6e806c2
React-jsi: c24dbcfdf7ea075138b73372387c7f17c0db56ef
React-jsidynamic: 2b14ac1b6d3a1b7daa1e5a424b98de87da981698
React-jsiexecutor: 14e899380e3fe9ca74c4e19727540a03e7574721
React-jsinspector: 7733dd522d044aef87caa39f3eda77593358a7eb
React-logger: c7960346b021767ed90971aff592a44e3d69f8bb
React-logger: a2b4f0f204e45e25f493ca4ce245a336217c923e
React-perflogger: c4fdd48988c2d3047186fc1bc1772d634cfca2ea
React-RCTActionSheet: 166fd1df85ac10219466b45d12a5884d3eaceac1
React-RCTAnimation: d6127046c6bb44bd3e67b7503c4ad7f91131b58e
@ -977,13 +977,13 @@ SPEC CHECKSUMS:
React-RCTNetwork: a865deadacbf6b3d863f0496e7d2c2e81c269317
React-RCTPushNotification: 7f678a88147254ede5d21a1e1e71e8a964dd0051
React-RCTSettings: 23ce1aa52ddf5db44c973bb5cc93713e871e09b6
React-RCTTest: 06c388632dc7b30df17af01c8f9e89e641b4d31c
React-RCTTest: be92171ef0a1818f96324eac3be0356f4fa08844
React-RCTText: a861fbf2835299d3cc4189697cddd8bd8602afb9
React-RCTVibration: 0386f50996a153b3f39cecbe7d139763ac9a9fdf
React-rncore: 665c70690f404bbfa3948148de72689672a906d2
React-runtimeexecutor: 97dca9247f4d3cfe0733384b189c6930fbd402b7
ReactCommon: b1f213aa09e3dfd0a89389b5023fdb1cd6528e96
ScreenshotManager: 3fc534a218e7b8dde632158411d0f15b0ca8893c
ScreenshotManager: 06cb3d1794c8082d92b3e91813d1678d0977a4fb
SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
Yoga: 1b1a12ff3d86a10565ea7cbe057d42f5e5fb2a07
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a