Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/react-native/Libraries/Blob/RCTBlobCollector.mm
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
{
RCTBlobManager *blobManager = blobManager_;
NSString *blobId = [NSString stringWithUTF8String:blobId_.c_str()];
dispatch_async([blobManager_ methodQueue], ^{
dispatch_async([blobManager_ executionQueue], ^{
[blobManager remove:blobId];
});
}
Expand Down
4 changes: 4 additions & 0 deletions packages/react-native/Libraries/Blob/RCTBlobManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#import <React/RCTInitializing.h>
#import <React/RCTURLRequestHandler.h>

RCT_EXTERN void RCTEnableBlobManagerProcessingQueue(BOOL enabled);

@interface RCTBlobManager : NSObject <RCTBridgeModule, RCTURLRequestHandler, RCTInitializing>

- (NSString *)store:(NSData *)data;
Expand All @@ -26,4 +28,6 @@

- (void)createFromParts:(NSArray<NSDictionary<NSString *, id> *> *)parts withId:(NSString *)blobId;

- (dispatch_queue_t)executionQueue;

@end
30 changes: 28 additions & 2 deletions packages/react-native/Libraries/Blob/RCTBlobManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,24 @@

#import <FBReactNativeSpec/FBReactNativeSpec.h>
#import <React/RCTConvert.h>
#import <React/RCTMockDef.h>
#import <React/RCTNetworking.h>
#import <React/RCTUtils.h>
#import <React/RCTWebSocketModule.h>

#import "RCTBlobCollector.h"
#import "RCTBlobPlugins.h"

RCT_MOCK_DEF(RCTBlobManager, dispatch_async);
#define dispatch_async RCT_MOCK_USE(RCTBlobManager, dispatch_async)

static BOOL gBlobManagerProcessingQueueEnabled = NO;

RCT_EXTERN void RCTEnableBlobManagerProcessingQueue(BOOL enabled)
{
gBlobManagerProcessingQueueEnabled = enabled;
}

static NSString *const kBlobURIScheme = @"blob";

@interface RCTBlobManager () <
Expand All @@ -35,6 +46,7 @@ @implementation RCTBlobManager {
std::mutex _blobsMutex;

NSOperationQueue *_queue;
dispatch_queue_t _processingQueue;
}

RCT_EXPORT_MODULE(BlobModule)
Expand All @@ -48,6 +60,10 @@ - (void)initialize
std::lock_guard<std::mutex> lock(_blobsMutex);
_blobs = [NSMutableDictionary new];

if (gBlobManagerProcessingQueueEnabled) {
_processingQueue = dispatch_queue_create("com.facebook.react.blobmanager.processing", DISPATCH_QUEUE_SERIAL);
}

facebook::react::RCTBlobCollector::install(self);
}

Expand Down Expand Up @@ -194,12 +210,22 @@ - (void)remove:(NSString *)blobId
[NSException raise:@"Invalid type for blob" format:@"%@ is invalid", type];
}
}
[self store:data withId:blobId];

dispatch_async([self executionQueue], ^{
[self store:data withId:blobId];
});
}

RCT_EXPORT_METHOD(release : (NSString *)blobId)
{
[self remove:blobId];
dispatch_async([self executionQueue], ^{
[self remove:blobId];
});
}

- (dispatch_queue_t)executionQueue
{
return gBlobManagerProcessingQueueEnabled ? _processingQueue : _methodQueue;
}

#pragma mark - RCTURLRequestHandler methods
Expand Down
4 changes: 2 additions & 2 deletions packages/react-native/Libraries/Blob/RCTFileReaderModule.mm
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ @implementation RCTFileReaderModule
: (RCTPromiseRejectBlock)reject)
{
RCTBlobManager *blobManager = [_moduleRegistry moduleForName:"BlobModule"];
dispatch_async(blobManager.methodQueue, ^{
dispatch_async([blobManager executionQueue], ^{
NSData *data = [blobManager resolve:blob];

if (data == nil) {
Expand Down Expand Up @@ -62,7 +62,7 @@ @implementation RCTFileReaderModule
: (RCTPromiseRejectBlock)reject)
{
RCTBlobManager *blobManager = [_moduleRegistry moduleForName:"BlobModule"];
dispatch_async(blobManager.methodQueue, ^{
dispatch_async([blobManager executionQueue], ^{
NSData *data = [blobManager resolve:blob];

if (data == nil) {
Expand Down
53 changes: 53 additions & 0 deletions packages/rn-tester/RNTesterUnitTests/RCTBlobManagerTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@
#import <XCTest/XCTest.h>

#import <React/RCTBlobManager.h>
#import <React/RCTMockDef.h>

RCT_MOCK_REF(RCTBlobManager, dispatch_async);

static void _mock_dispatch_async(dispatch_queue_t queue, dispatch_block_t block)
{
XCTAssertNotNil(queue);
block();
}

@interface RCTBlobManagerTests : XCTestCase

Expand All @@ -23,8 +32,12 @@ - (void)setUp
{
[super setUp];

RCT_MOCK_SET(RCTBlobManager, dispatch_async, _mock_dispatch_async);

_module = [RCTBlobManager new];
dispatch_queue_t methodQueue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
[_module setValue:nil forKey:@"bridge"];
[_module setValue:methodQueue forKey:@"methodQueue"];
[_module initialize];
NSInteger size = 120;
_data = [NSMutableData dataWithCapacity:size];
Expand All @@ -36,6 +49,13 @@ - (void)setUp
[_module store:_data withId:_blobId];
}

- (void)tearDown
{
[super tearDown];

RCT_MOCK_RESET(RCTBlobManager, dispatch_async);
}

- (void)testResolve
{
XCTAssertTrue([_data isEqualToData:[_module resolve:_blobId offset:0 size:_data.length]]);
Expand Down Expand Up @@ -98,4 +118,37 @@ - (void)testCreateFromParts
XCTAssertTrue([expectedData isEqualToData:result]);
}

- (void)testCreateFromPartsProcessingQueue
{
RCTEnableBlobManagerProcessingQueue(YES);
[self setUp];

NSDictionary<NSString *, id> *blobData = @{
@"blobId" : _blobId,
@"offset" : @0,
@"size" : @(_data.length),
};
NSDictionary<NSString *, id> *blob = @{
@"data" : blobData,
@"type" : @"blob",
};
NSString *stringData = @"i \u2665 dogs";
NSDictionary<NSString *, id> *string = @{
@"data" : stringData,
@"type" : @"string",
};
NSString *resultId = [NSUUID UUID].UUIDString;
NSArray<id> *parts = @[ blob, string ];

[_module createFromParts:parts withId:resultId];

NSMutableData *expectedData = [NSMutableData new];
[expectedData appendData:_data];
[expectedData appendData:[stringData dataUsingEncoding:NSUTF8StringEncoding]];

NSData *result = [_module resolve:resultId offset:0 size:expectedData.length];

XCTAssertTrue([expectedData isEqualToData:result]);
}

@end