This commit is contained in:
Yamozha
2021-04-02 02:24:13 +03:00
parent c23950b545
commit 7256d79e2c
31493 changed files with 3036630 additions and 0 deletions

141
node_modules/react-native/Libraries/Blob/Blob.js generated vendored Normal file
View File

@ -0,0 +1,141 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
import type {BlobData, BlobOptions} from './BlobTypes';
/**
* Opaque JS representation of some binary data in native.
*
* The API is modeled after the W3C Blob API, with one caveat
* regarding explicit deallocation. Refer to the `close()`
* method for further details.
*
* Example usage in a React component:
*
* class WebSocketImage extends React.Component {
* state = {blob: null};
* componentDidMount() {
* let ws = this.ws = new WebSocket(...);
* ws.binaryType = 'blob';
* ws.onmessage = (event) => {
* if (this.state.blob) {
* this.state.blob.close();
* }
* this.setState({blob: event.data});
* };
* }
* componentUnmount() {
* if (this.state.blob) {
* this.state.blob.close();
* }
* this.ws.close();
* }
* render() {
* if (!this.state.blob) {
* return <View />;
* }
* return <Image source={{uri: URL.createObjectURL(this.state.blob)}} />;
* }
* }
*
* Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob
*/
class Blob {
_data: ?BlobData;
/**
* Constructor for JS consumers.
* Currently we only support creating Blobs from other Blobs.
* Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob
*/
constructor(parts: Array<Blob | string> = [], options?: BlobOptions) {
const BlobManager = require('./BlobManager');
this.data = BlobManager.createFromParts(parts, options).data;
}
/*
* This method is used to create a new Blob object containing
* the data in the specified range of bytes of the source Blob.
* Reference: https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice
*/
set data(data: ?BlobData) {
this._data = data;
}
get data(): BlobData {
if (!this._data) {
throw new Error('Blob has been closed and is no longer available');
}
return this._data;
}
slice(start?: number, end?: number): Blob {
const BlobManager = require('./BlobManager');
let {offset, size} = this.data;
if (typeof start === 'number') {
if (start > size) {
start = size;
}
offset += start;
size -= start;
if (typeof end === 'number') {
if (end < 0) {
end = this.size + end;
}
size = end - start;
}
}
return BlobManager.createFromOptions({
blobId: this.data.blobId,
offset,
size,
});
}
/**
* This method is in the standard, but not actually implemented by
* any browsers at this point. It's important for how Blobs work in
* React Native, however, since we cannot de-allocate resources automatically,
* so consumers need to explicitly de-allocate them.
*
* Note that the semantics around Blobs created via `blob.slice()`
* and `new Blob([blob])` are different. `blob.slice()` creates a
* new *view* onto the same binary data, so calling `close()` on any
* of those views is enough to deallocate the data, whereas
* `new Blob([blob, ...])` actually copies the data in memory.
*/
close() {
const BlobManager = require('./BlobManager');
BlobManager.release(this.data.blobId);
this.data = null;
}
/**
* Size of the data contained in the Blob object, in bytes.
*/
get size(): number {
return this.data.size;
}
/*
* String indicating the MIME type of the data contained in the Blob.
* If the type is unknown, this string is empty.
*/
get type(): string {
return this.data.type || '';
}
}
module.exports = Blob;

182
node_modules/react-native/Libraries/Blob/BlobManager.js generated vendored Normal file
View File

@ -0,0 +1,182 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
'use strict';
const Blob = require('./Blob');
const BlobRegistry = require('./BlobRegistry');
import type {BlobData, BlobOptions, BlobCollector} from './BlobTypes';
import NativeBlobModule from './NativeBlobModule';
import invariant from 'invariant';
/*eslint-disable no-bitwise */
/*eslint-disable eqeqeq */
/**
* Based on the rfc4122-compliant solution posted at
* http://stackoverflow.com/questions/105034
*/
function uuidv4(): string {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
const r = (Math.random() * 16) | 0,
v = c == 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
// **Temporary workaround**
// TODO(#24654): Use turbomodules for the Blob module.
// Blob collector is a jsi::HostObject that is used by native to know
// when the a Blob instance is deallocated. This allows to free the
// underlying native resources. This is a hack to workaround the fact
// that the current bridge infra doesn't allow to track js objects
// deallocation. Ideally the whole Blob object should be a jsi::HostObject.
function createBlobCollector(blobId: string): BlobCollector | null {
if (global.__blobCollectorProvider == null) {
return null;
} else {
return global.__blobCollectorProvider(blobId);
}
}
/**
* Module to manage blobs. Wrapper around the native blob module.
*/
class BlobManager {
/**
* If the native blob module is available.
*/
static isAvailable: boolean = !!NativeBlobModule;
/**
* Create blob from existing array of blobs.
*/
static createFromParts(
parts: Array<Blob | string>,
options?: BlobOptions,
): Blob {
invariant(NativeBlobModule, 'NativeBlobModule is available.');
const blobId = uuidv4();
const items = parts.map(part => {
if (
part instanceof ArrayBuffer ||
(global.ArrayBufferView && part instanceof global.ArrayBufferView)
) {
throw new Error(
"Creating blobs from 'ArrayBuffer' and 'ArrayBufferView' are not supported",
);
}
if (part instanceof Blob) {
return {
data: part.data,
type: 'blob',
};
} else {
return {
data: String(part),
type: 'string',
};
}
});
const size = items.reduce((acc, curr) => {
if (curr.type === 'string') {
return acc + global.unescape(encodeURI(curr.data)).length;
} else {
return acc + curr.data.size;
}
}, 0);
NativeBlobModule.createFromParts(items, blobId);
return BlobManager.createFromOptions({
blobId,
offset: 0,
size,
type: options ? options.type : '',
lastModified: options ? options.lastModified : Date.now(),
});
}
/**
* Create blob instance from blob data from native.
* Used internally by modules like XHR, WebSocket, etc.
*/
static createFromOptions(options: BlobData): Blob {
BlobRegistry.register(options.blobId);
return Object.assign(Object.create(Blob.prototype), {
data:
// Reuse the collector instance when creating from an existing blob.
// This will make sure that the underlying resource is only deallocated
// when all blobs that refer to it are deallocated.
options.__collector == null
? {
...options,
__collector: createBlobCollector(options.blobId),
}
: options,
});
}
/**
* Deallocate resources for a blob.
*/
static release(blobId: string): void {
invariant(NativeBlobModule, 'NativeBlobModule is available.');
BlobRegistry.unregister(blobId);
if (BlobRegistry.has(blobId)) {
return;
}
NativeBlobModule.release(blobId);
}
/**
* Inject the blob content handler in the networking module to support blob
* requests and responses.
*/
static addNetworkingHandler(): void {
invariant(NativeBlobModule, 'NativeBlobModule is available.');
NativeBlobModule.addNetworkingHandler();
}
/**
* Indicate the websocket should return a blob for incoming binary
* messages.
*/
static addWebSocketHandler(socketId: number): void {
invariant(NativeBlobModule, 'NativeBlobModule is available.');
NativeBlobModule.addWebSocketHandler(socketId);
}
/**
* Indicate the websocket should no longer return a blob for incoming
* binary messages.
*/
static removeWebSocketHandler(socketId: number): void {
invariant(NativeBlobModule, 'NativeBlobModule is available.');
NativeBlobModule.removeWebSocketHandler(socketId);
}
/**
* Send a blob message to a websocket.
*/
static sendOverSocket(blob: Blob, socketId: number): void {
invariant(NativeBlobModule, 'NativeBlobModule is available.');
NativeBlobModule.sendOverSocket(blob.data, socketId);
}
}
module.exports = BlobManager;

View File

@ -0,0 +1,38 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
const registry: {[key: string]: number, ...} = {};
const register = (id: string) => {
if (registry[id]) {
registry[id]++;
} else {
registry[id] = 1;
}
};
const unregister = (id: string) => {
if (registry[id]) {
registry[id]--;
if (registry[id] <= 0) {
delete registry[id];
}
}
};
const has = (id: string): number | boolean => {
return registry[id] && registry[id] > 0;
};
module.exports = {
register,
unregister,
has,
};

30
node_modules/react-native/Libraries/Blob/BlobTypes.js generated vendored Normal file
View File

@ -0,0 +1,30 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
'use strict';
export opaque type BlobCollector = {...};
export type BlobData = {
blobId: string,
offset: number,
size: number,
name?: string,
type?: string,
lastModified?: number,
__collector?: ?BlobCollector,
...
};
export type BlobOptions = {
type: string,
lastModified: number,
...
};

56
node_modules/react-native/Libraries/Blob/File.js generated vendored Normal file
View File

@ -0,0 +1,56 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
const Blob = require('./Blob');
const invariant = require('invariant');
import type {BlobOptions} from './BlobTypes';
/**
* The File interface provides information about files.
*/
class File extends Blob {
/**
* Constructor for JS consumers.
*/
constructor(
parts: Array<Blob | string>,
name: string,
options?: BlobOptions,
) {
invariant(
parts != null && name != null,
'Failed to construct `File`: Must pass both `parts` and `name` arguments.',
);
super(parts, options);
this.data.name = name;
}
/**
* Name of the file.
*/
get name(): string {
invariant(this.data.name != null, 'Files must have a name set.');
return this.data.name;
}
/*
* Last modified time of the file.
*/
get lastModified(): number {
return this.data.lastModified || 0;
}
}
module.exports = File;

166
node_modules/react-native/Libraries/Blob/FileReader.js generated vendored Normal file
View File

@ -0,0 +1,166 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
const Blob = require('./Blob');
const EventTarget = require('event-target-shim');
import NativeFileReaderModule from './NativeFileReaderModule';
type ReadyState =
| 0 // EMPTY
| 1 // LOADING
| 2; // DONE
type ReaderResult = string | ArrayBuffer;
const READER_EVENTS = [
'abort',
'error',
'load',
'loadstart',
'loadend',
'progress',
];
const EMPTY = 0;
const LOADING = 1;
const DONE = 2;
class FileReader extends (EventTarget(...READER_EVENTS): any) {
static EMPTY: number = EMPTY;
static LOADING: number = LOADING;
static DONE: number = DONE;
EMPTY: number = EMPTY;
LOADING: number = LOADING;
DONE: number = DONE;
_readyState: ReadyState;
_error: ?Error;
_result: ?ReaderResult;
_aborted: boolean = false;
_subscriptions: Array<*> = [];
constructor() {
super();
this._reset();
}
_reset(): void {
this._readyState = EMPTY;
this._error = null;
this._result = null;
}
_clearSubscriptions(): void {
this._subscriptions.forEach(sub => sub.remove());
this._subscriptions = [];
}
_setReadyState(newState: ReadyState) {
this._readyState = newState;
this.dispatchEvent({type: 'readystatechange'});
if (newState === DONE) {
if (this._aborted) {
this.dispatchEvent({type: 'abort'});
} else if (this._error) {
this.dispatchEvent({type: 'error'});
} else {
this.dispatchEvent({type: 'load'});
}
this.dispatchEvent({type: 'loadend'});
}
}
readAsArrayBuffer() {
throw new Error('FileReader.readAsArrayBuffer is not implemented');
}
readAsDataURL(blob: ?Blob) {
this._aborted = false;
if (blob == null) {
throw new TypeError(
"Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'",
);
}
NativeFileReaderModule.readAsDataURL(blob.data).then(
(text: string) => {
if (this._aborted) {
return;
}
this._result = text;
this._setReadyState(DONE);
},
error => {
if (this._aborted) {
return;
}
this._error = error;
this._setReadyState(DONE);
},
);
}
readAsText(blob: ?Blob, encoding: string = 'UTF-8') {
this._aborted = false;
if (blob == null) {
throw new TypeError(
"Failed to execute 'readAsText' on 'FileReader': parameter 1 is not of type 'Blob'",
);
}
NativeFileReaderModule.readAsText(blob.data, encoding).then(
(text: string) => {
if (this._aborted) {
return;
}
this._result = text;
this._setReadyState(DONE);
},
error => {
if (this._aborted) {
return;
}
this._error = error;
this._setReadyState(DONE);
},
);
}
abort() {
this._aborted = true;
// only call onreadystatechange if there is something to abort, as per spec
if (this._readyState !== EMPTY && this._readyState !== DONE) {
this._reset();
this._setReadyState(DONE);
}
// Reset again after, in case modified in handler
this._reset();
}
get readyState(): ReadyState {
return this._readyState;
}
get error(): ?Error {
return this._error;
}
get result(): ?ReaderResult {
return this._result;
}
}
module.exports = FileReader;

View File

@ -0,0 +1,26 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
import type {TurboModule} from '../TurboModule/RCTExport';
import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+getConstants: () => {|BLOB_URI_SCHEME: ?string, BLOB_URI_HOST: ?string|};
+addNetworkingHandler: () => void;
+addWebSocketHandler: (id: number) => void;
+removeWebSocketHandler: (id: number) => void;
+sendOverSocket: (blob: Object, socketID: number) => void;
+createFromParts: (parts: Array<Object>, withId: string) => void;
+release: (blobId: string) => void;
}
export default (TurboModuleRegistry.get<Spec>('BlobModule'): ?Spec);

View File

@ -0,0 +1,23 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
import type {TurboModule} from '../TurboModule/RCTExport';
import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry';
export interface Spec extends TurboModule {
+readAsDataURL: (data: Object) => Promise<string>;
+readAsText: (data: Object, encoding: string) => Promise<string>;
}
export default (TurboModuleRegistry.getEnforcing<Spec>(
'FileReaderModule',
): Spec);

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <jsi/jsi.h>
using namespace facebook;
@class RCTBlobManager;
namespace facebook {
namespace react {
class JSI_EXPORT RCTBlobCollector : public jsi::HostObject {
public:
RCTBlobCollector(RCTBlobManager *blobManager, const std::string &blobId);
~RCTBlobCollector();
static void install(RCTBlobManager *blobManager);
private:
const std::string blobId_;
RCTBlobManager *blobManager_;
};
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTBlobCollector.h"
#import <React/RCTBridge+Private.h>
#import <React/RCTBlobManager.h>
namespace facebook {
namespace react {
RCTBlobCollector::RCTBlobCollector(RCTBlobManager *blobManager, const std::string &blobId)
: blobId_(blobId), blobManager_(blobManager) {}
RCTBlobCollector::~RCTBlobCollector() {
RCTBlobManager *blobManager = blobManager_;
NSString *blobId = [NSString stringWithUTF8String:blobId_.c_str()];
dispatch_async([blobManager_ methodQueue], ^{
[blobManager remove:blobId];
});
}
void RCTBlobCollector::install(RCTBlobManager *blobManager) {
__weak RCTCxxBridge *cxxBridge = (RCTCxxBridge *)blobManager.bridge;
[cxxBridge dispatchBlock:^{
if (!cxxBridge || cxxBridge.runtime == nullptr) {
return;
}
jsi::Runtime &runtime = *(jsi::Runtime *)cxxBridge.runtime;
runtime.global().setProperty(
runtime,
"__blobCollectorProvider",
jsi::Function::createFromHostFunction(
runtime,
jsi::PropNameID::forAscii(runtime, "__blobCollectorProvider"),
1,
[blobManager](jsi::Runtime& rt, const jsi::Value& thisVal, const jsi::Value* args, size_t count) {
auto blobId = args[0].asString(rt).utf8(rt);
auto blobCollector = std::make_shared<RCTBlobCollector>(blobManager, blobId);
return jsi::Object::createFromHostObject(rt, blobCollector);
}
)
);
} queue:RCTJSThread];
}
} // namespace react
} // namespace facebook

28
node_modules/react-native/Libraries/Blob/RCTBlobManager.h generated vendored Executable file
View File

@ -0,0 +1,28 @@
/*
* Copyright (c) Facebook, Inc. and its 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/RCTBridge.h>
#import <React/RCTBridgeModule.h>
#import <React/RCTURLRequestHandler.h>
@interface RCTBlobManager : NSObject <RCTBridgeModule, RCTURLRequestHandler>
- (NSString *)store:(NSData *)data;
- (void)store:(NSData *)data withId:(NSString *)blobId;
- (NSData *)resolve:(NSDictionary<NSString *, id> *)blob;
- (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger)size;
- (NSData *)resolveURL:(NSURL *)url;
- (void)remove:(NSString *)blobId;
- (void)createFromParts:(NSArray<NSDictionary<NSString *, id> *> *)parts withId:(NSString *)blobId;
@end

325
node_modules/react-native/Libraries/Blob/RCTBlobManager.mm generated vendored Executable file
View File

@ -0,0 +1,325 @@
/*
* Copyright (c) Facebook, Inc. and its 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/RCTBlobManager.h>
#import <mutex>
#import <FBReactNativeSpec/FBReactNativeSpec.h>
#import <React/RCTConvert.h>
#import <React/RCTNetworking.h>
#import <React/RCTUtils.h>
#import <React/RCTWebSocketModule.h>
#import "RCTBlobPlugins.h"
#import "RCTBlobCollector.h"
static NSString *const kBlobURIScheme = @"blob";
@interface RCTBlobManager () <RCTNetworkingRequestHandler, RCTNetworkingResponseHandler, RCTWebSocketContentHandler, NativeBlobModuleSpec>
@end
@implementation RCTBlobManager
{
// Blobs should be thread safe since they are used from the websocket and networking module,
// make sure to use proper locking when accessing this.
NSMutableDictionary<NSString *, NSData *> *_blobs;
std::mutex _blobsMutex;
NSOperationQueue *_queue;
}
RCT_EXPORT_MODULE(BlobModule)
@synthesize bridge = _bridge;
@synthesize methodQueue = _methodQueue;
@synthesize turboModuleLookupDelegate = _turboModuleLookupDelegate;
- (void)setBridge:(RCTBridge *)bridge
{
_bridge = bridge;
std::lock_guard<std::mutex> lock(_blobsMutex);
_blobs = [NSMutableDictionary new];
facebook::react::RCTBlobCollector::install(self);
}
+ (BOOL)requiresMainQueueSetup
{
return NO;
}
- (NSDictionary<NSString *, id> *)constantsToExport
{
return [self getConstants];
}
- (NSDictionary<NSString *, id> *)getConstants
{
return @{
@"BLOB_URI_SCHEME": kBlobURIScheme,
@"BLOB_URI_HOST": [NSNull null],
};
}
- (NSString *)store:(NSData *)data
{
NSString *blobId = [NSUUID UUID].UUIDString;
[self store:data withId:blobId];
return blobId;
}
- (void)store:(NSData *)data withId:(NSString *)blobId
{
std::lock_guard<std::mutex> lock(_blobsMutex);
_blobs[blobId] = data;
}
- (NSData *)resolve:(NSDictionary<NSString *, id> *)blob
{
NSString *blobId = [RCTConvert NSString:blob[@"blobId"]];
NSNumber *offset = [RCTConvert NSNumber:blob[@"offset"]];
NSNumber *size = [RCTConvert NSNumber:blob[@"size"]];
return [self resolve:blobId
offset:offset ? [offset integerValue] : 0
size:size ? [size integerValue] : -1];
}
- (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger)size
{
NSData *data;
{
std::lock_guard<std::mutex> lock(_blobsMutex);
data = _blobs[blobId];
}
if (!data) {
return nil;
}
if (offset != 0 || (size != -1 && size != data.length)) {
data = [data subdataWithRange:NSMakeRange(offset, size)];
}
return data;
}
- (NSData *)resolveURL:(NSURL *)url
{
NSURLComponents *components = [[NSURLComponents alloc] initWithURL:url resolvingAgainstBaseURL:NO];
NSString *blobId = components.path;
NSInteger offset = 0;
NSInteger size = -1;
if (components.queryItems) {
for (NSURLQueryItem *queryItem in components.queryItems) {
if ([queryItem.name isEqualToString:@"offset"]) {
offset = [queryItem.value integerValue];
}
if ([queryItem.name isEqualToString:@"size"]) {
size = [queryItem.value integerValue];
}
}
}
if (blobId) {
return [self resolve:blobId offset:offset size:size];
}
return nil;
}
- (void)remove:(NSString *)blobId
{
std::lock_guard<std::mutex> lock(_blobsMutex);
[_blobs removeObjectForKey:blobId];
}
RCT_EXPORT_METHOD(addNetworkingHandler)
{
RCTNetworking *const networking = _bridge ? _bridge.networking : [_turboModuleLookupDelegate moduleForName:"RCTNetworking"];
// TODO(T63516227): Why can methodQueue be nil here?
// We don't want to do anything when methodQueue is nil.
if (!networking.methodQueue) {
return;
}
dispatch_async(networking.methodQueue, ^{
[networking addRequestHandler:self];
[networking addResponseHandler:self];
});
}
RCT_EXPORT_METHOD(addWebSocketHandler:(double)socketID)
{
dispatch_async(_bridge.webSocketModule.methodQueue, ^{
[self->_bridge.webSocketModule setContentHandler:self forSocketID:[NSNumber numberWithDouble:socketID]];
});
}
RCT_EXPORT_METHOD(removeWebSocketHandler:(double)socketID)
{
dispatch_async(_bridge.webSocketModule.methodQueue, ^{
[self->_bridge.webSocketModule setContentHandler:nil forSocketID:[NSNumber numberWithDouble:socketID]];
});
}
// @lint-ignore FBOBJCUNTYPEDCOLLECTION1
RCT_EXPORT_METHOD(sendOverSocket:(NSDictionary *)blob socketID:(double)socketID)
{
dispatch_async(_bridge.webSocketModule.methodQueue, ^{
[self->_bridge.webSocketModule sendData:[self resolve:blob] forSocketID:[NSNumber numberWithDouble:socketID]];
});
}
RCT_EXPORT_METHOD(createFromParts:(NSArray<NSDictionary<NSString *, id> *> *)parts withId:(NSString *)blobId)
{
NSMutableData *data = [NSMutableData new];
for (NSDictionary<NSString *, id> *part in parts) {
NSString *type = [RCTConvert NSString:part[@"type"]];
if ([type isEqualToString:@"blob"]) {
NSData *partData = [self resolve:part[@"data"]];
[data appendData:partData];
} else if ([type isEqualToString:@"string"]) {
NSData *partData = [[RCTConvert NSString:part[@"data"]] dataUsingEncoding:NSUTF8StringEncoding];
[data appendData:partData];
} else {
[NSException raise:@"Invalid type for blob" format:@"%@ is invalid", type];
}
}
[self store:data withId:blobId];
}
RCT_EXPORT_METHOD(release:(NSString *)blobId)
{
[self remove:blobId];
}
#pragma mark - RCTURLRequestHandler methods
- (BOOL)canHandleRequest:(NSURLRequest *)request
{
return [request.URL.scheme caseInsensitiveCompare:kBlobURIScheme] == NSOrderedSame;
}
- (id)sendRequest:(NSURLRequest *)request withDelegate:(id<RCTURLRequestDelegate>)delegate
{
// Lazy setup
if (!_queue) {
_queue = [NSOperationQueue new];
_queue.maxConcurrentOperationCount = 2;
}
__weak __typeof(self) weakSelf = self;
__weak __block NSBlockOperation *weakOp;
__block NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
__typeof(self) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:request.URL
MIMEType:nil
expectedContentLength:-1
textEncodingName:nil];
[delegate URLRequest:weakOp didReceiveResponse:response];
NSData *data = [strongSelf resolveURL:response.URL];
NSError *error;
if (data) {
[delegate URLRequest:weakOp didReceiveData:data];
} else {
error = [[NSError alloc] initWithDomain:NSURLErrorDomain code:NSURLErrorBadURL userInfo:nil];
}
[delegate URLRequest:weakOp didCompleteWithError:error];
}];
weakOp = op;
[_queue addOperation:op];
return op;
}
- (void)cancelRequest:(NSOperation *)op
{
[op cancel];
}
#pragma mark - RCTNetworkingRequestHandler methods
// @lint-ignore FBOBJCUNTYPEDCOLLECTION1
- (BOOL)canHandleNetworkingRequest:(NSDictionary *)data
{
return data[@"blob"] != nil;
}
// @lint-ignore FBOBJCUNTYPEDCOLLECTION1
- (NSDictionary *)handleNetworkingRequest:(NSDictionary *)data
{
// @lint-ignore FBOBJCUNTYPEDCOLLECTION1
NSDictionary *blob = [RCTConvert NSDictionary:data[@"blob"]];
NSString *contentType = @"application/octet-stream";
NSString *blobType = [RCTConvert NSString:blob[@"type"]];
if (blobType != nil && blobType.length > 0) {
contentType = blob[@"type"];
}
return @{@"body": [self resolve:blob], @"contentType": contentType};
}
- (BOOL)canHandleNetworkingResponse:(NSString *)responseType
{
return [responseType isEqualToString:@"blob"];
}
- (id)handleNetworkingResponse:(NSURLResponse *)response data:(NSData *)data
{
// An empty body will have nil for data, in this case we need to return
// an empty blob as per the XMLHttpRequest spec.
data = data ?: [NSData new];
return @{
@"blobId": [self store:data],
@"offset": @0,
@"size": @(data.length),
@"name": RCTNullIfNil([response suggestedFilename]),
@"type": RCTNullIfNil([response MIMEType]),
};
}
#pragma mark - RCTWebSocketContentHandler methods
- (id)processWebsocketMessage:(id)message
forSocketID:(NSNumber *)socketID
withType:(NSString *__autoreleasing _Nonnull *)type
{
if (![message isKindOfClass:[NSData class]]) {
*type = @"text";
return message;
}
*type = @"blob";
return @{
@"blobId": [self store:message],
@"offset": @0,
@"size": @(((NSData *)message).length),
};
}
- (std::shared_ptr<facebook::react::TurboModule>)
getTurboModuleWithJsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
nativeInvoker:(std::shared_ptr<facebook::react::CallInvoker>)nativeInvoker
perfLogger:(id<RCTTurboModulePerformanceLogger>)perfLogger
{
return std::make_shared<facebook::react::NativeBlobModuleSpecJSI>(self, jsInvoker, nativeInvoker, perfLogger);
}
@end
Class RCTBlobManagerCls(void) {
return RCTBlobManager.class;
}

View File

@ -0,0 +1,41 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated by an internal plugin build system
*/
#ifdef RN_DISABLE_OSS_PLUGIN_HEADER
// FB Internal: FBRCTBlobPlugins.h is autogenerated by the build system.
#import <React/FBRCTBlobPlugins.h>
#else
// OSS-compatibility layer
#import <Foundation/Foundation.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wreturn-type-c-linkage"
#ifdef __cplusplus
extern "C" {
#endif
// RCTTurboModuleManagerDelegate should call this to resolve module classes.
Class RCTBlobClassProvider(const char *name);
// Lookup functions
Class RCTFileReaderModuleCls(void) __attribute__((used));
Class RCTBlobManagerCls(void) __attribute__((used));
#ifdef __cplusplus
}
#endif
#pragma GCC diagnostic pop
#endif // RN_DISABLE_OSS_PLUGIN_HEADER

View File

@ -0,0 +1,33 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated by an internal plugin build system
*/
#ifndef RN_DISABLE_OSS_PLUGIN_HEADER
// OSS-compatibility layer
#import "RCTBlobPlugins.h"
#import <string>
#import <unordered_map>
Class RCTBlobClassProvider(const char *name) {
static std::unordered_map<std::string, Class (*)(void)> sCoreModuleClassMap = {
{"FileReaderModule", RCTFileReaderModuleCls},
{"BlobModule", RCTBlobManagerCls},
};
auto p = sCoreModuleClassMap.find(name);
if (p != sCoreModuleClassMap.end()) {
auto classFunc = p->second;
return classFunc();
}
return nil;
}
#endif // RN_DISABLE_OSS_PLUGIN_HEADER

View File

@ -0,0 +1,12 @@
/*
* Copyright (c) Facebook, Inc. and its 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>
@interface RCTFileReaderModule : NSObject <RCTBridgeModule>
@end

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) Facebook, Inc. and its 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/RCTFileReaderModule.h>
#import <FBReactNativeSpec/FBReactNativeSpec.h>
#import <React/RCTBridge.h>
#import <React/RCTConvert.h>
#import <React/RCTBlobManager.h>
#import "RCTBlobPlugins.h"
@interface RCTFileReaderModule() <NativeFileReaderModuleSpec>
@end
@implementation RCTFileReaderModule
RCT_EXPORT_MODULE(FileReaderModule)
@synthesize bridge = _bridge;
RCT_EXPORT_METHOD(readAsText:(NSDictionary<NSString *, id> *)blob
encoding:(NSString *)encoding
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)
{
RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]];
NSData *data = [blobManager resolve:blob];
if (data == nil) {
reject(RCTErrorUnspecified,
[NSString stringWithFormat:@"Unable to resolve data for blob: %@", [RCTConvert NSString:blob[@"blobId"]]], nil);
} else {
NSStringEncoding stringEncoding;
if (encoding == nil) {
stringEncoding = NSUTF8StringEncoding;
} else {
stringEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef) encoding));
}
NSString *text = [[NSString alloc] initWithData:data encoding:stringEncoding];
resolve(text);
}
}
RCT_EXPORT_METHOD(readAsDataURL:(NSDictionary<NSString *, id> *)blob
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)
{
RCTBlobManager *blobManager = [[self bridge] moduleForClass:[RCTBlobManager class]];
NSData *data = [blobManager resolve:blob];
if (data == nil) {
reject(RCTErrorUnspecified,
[NSString stringWithFormat:@"Unable to resolve data for blob: %@", [RCTConvert NSString:blob[@"blobId"]]], nil);
} else {
NSString *type = [RCTConvert NSString:blob[@"type"]];
NSString *text = [NSString stringWithFormat:@"data:%@;base64,%@",
type != nil && [type length] > 0 ? type : @"application/octet-stream",
[data base64EncodedStringWithOptions:0]];
resolve(text);
}
}
- (std::shared_ptr<facebook::react::TurboModule>)
getTurboModuleWithJsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
nativeInvoker:(std::shared_ptr<facebook::react::CallInvoker>)nativeInvoker
perfLogger:(id<RCTTurboModulePerformanceLogger>)perfLogger
{
return std::make_shared<facebook::react::NativeFileReaderModuleSpecJSI>(self, jsInvoker, nativeInvoker, perfLogger);
}
@end
Class RCTFileReaderModuleCls(void)
{
return RCTFileReaderModule.class;
}

View File

@ -0,0 +1,49 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
require "json"
package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json")))
version = package['version']
source = { :git => 'https://github.com/facebook/react-native.git' }
if version == '1000.0.0'
# This is an unpublished version, use the latest commit hash of the react-native repo, which were presumably in.
source[:commit] = `git rev-parse HEAD`.strip
else
source[:tag] = "v#{version}"
end
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
folly_version = '2020.01.13.00'
Pod::Spec.new do |s|
s.name = "React-RCTBlob"
s.version = version
s.summary = "An API for displaying iOS action sheets and share sheets."
s.homepage = "https://reactnative.dev/"
s.license = package["license"]
s.author = "Facebook, Inc. and its affiliates"
s.platforms = { :ios => "10.0", :tvos => "10.0" }
s.compiler_flags = folly_compiler_flags + ' -Wno-nullability-completeness'
s.source = source
s.source_files = "*.{m,mm}"
s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs"
s.header_dir = "RCTBlob"
s.pod_target_xcconfig = {
"USE_HEADERMAP" => "YES",
"CLANG_CXX_LANGUAGE_STANDARD" => "c++14",
"HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/Folly\""
}
s.dependency "Folly", folly_version
s.dependency "FBReactNativeSpec", version
s.dependency "ReactCommon/turbomodule/core", version
s.dependency "React-jsi", version
s.dependency "React-Core/RCTBlobHeaders", version
s.dependency "React-Core/RCTWebSocket", version
s.dependency "React-RCTNetwork", version
s.dependency "React-jsi", version
end

222
node_modules/react-native/Libraries/Blob/URL.js generated vendored Normal file
View File

@ -0,0 +1,222 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
'use strict';
const Blob = require('./Blob');
import NativeBlobModule from './NativeBlobModule';
let BLOB_URL_PREFIX = null;
if (
NativeBlobModule &&
typeof NativeBlobModule.getConstants().BLOB_URI_SCHEME === 'string'
) {
const constants = NativeBlobModule.getConstants();
BLOB_URL_PREFIX = constants.BLOB_URI_SCHEME + ':';
if (typeof constants.BLOB_URI_HOST === 'string') {
BLOB_URL_PREFIX += `//${constants.BLOB_URI_HOST}/`;
}
}
/**
* To allow Blobs be accessed via `content://` URIs,
* you need to register `BlobProvider` as a ContentProvider in your app's `AndroidManifest.xml`:
*
* ```xml
* <manifest>
* <application>
* <provider
* android:name="com.facebook.react.modules.blob.BlobProvider"
* android:authorities="@string/blob_provider_authority"
* android:exported="false"
* />
* </application>
* </manifest>
* ```
* And then define the `blob_provider_authority` string in `res/values/strings.xml`.
* Use a dotted name that's entirely unique to your app:
*
* ```xml
* <resources>
* <string name="blob_provider_authority">your.app.package.blobs</string>
* </resources>
* ```
*/
// Small subset from whatwg-url: https://github.com/jsdom/whatwg-url/tree/master/lib
// The reference code bloat comes from Unicode issues with URLs, so those won't work here.
export class URLSearchParams {
_searchParams = [];
constructor(params: any) {
if (typeof params === 'object') {
Object.keys(params).forEach(key => this.append(key, params[key]));
}
}
append(key: string, value: string) {
this._searchParams.push([key, value]);
}
delete(name) {
throw new Error('not implemented');
}
get(name) {
throw new Error('not implemented');
}
getAll(name) {
throw new Error('not implemented');
}
has(name) {
throw new Error('not implemented');
}
set(name, value) {
throw new Error('not implemented');
}
sort() {
throw new Error('not implemented');
}
[Symbol.iterator]() {
return this._searchParams[Symbol.iterator]();
}
toString() {
if (this._searchParams.length === 0) {
return '';
}
const last = this._searchParams.length - 1;
return this._searchParams.reduce((acc, curr, index) => {
return acc + curr.join('=') + (index === last ? '' : '&');
}, '');
}
}
function validateBaseUrl(url: string) {
// from this MIT-licensed gist: https://gist.github.com/dperini/729294
return /^(?:(?:(?:https?|ftp):)?\/\/)(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,}))?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(
url,
);
}
export class URL {
_searchParamsInstance = null;
static createObjectURL(blob: Blob) {
if (BLOB_URL_PREFIX === null) {
throw new Error('Cannot create URL for blob!');
}
return `${BLOB_URL_PREFIX}${blob.data.blobId}?offset=${
blob.data.offset
}&size=${blob.size}`;
}
static revokeObjectURL(url: string) {
// Do nothing.
}
constructor(url: string, base: string) {
let baseUrl = null;
if (!base || validateBaseUrl(url)) {
this._url = url;
if (!this._url.endsWith('/')) {
this._url += '/';
}
} else {
if (typeof base === 'string') {
baseUrl = base;
if (!validateBaseUrl(baseUrl)) {
throw new TypeError(`Invalid base URL: ${baseUrl}`);
}
} else if (typeof base === 'object') {
baseUrl = base.toString();
}
if (baseUrl.endsWith('/')) {
baseUrl = baseUrl.slice(0, baseUrl.length - 1);
}
if (!url.startsWith('/')) {
url = `/${url}`;
}
if (baseUrl.endsWith(url)) {
url = '';
}
this._url = `${baseUrl}${url}`;
}
}
get hash() {
throw new Error('not implemented');
}
get host() {
throw new Error('not implemented');
}
get hostname() {
throw new Error('not implemented');
}
get href(): string {
return this.toString();
}
get origin() {
throw new Error('not implemented');
}
get password() {
throw new Error('not implemented');
}
get pathname() {
throw new Error('not implemented');
}
get port() {
throw new Error('not implemented');
}
get protocol() {
throw new Error('not implemented');
}
get search() {
throw new Error('not implemented');
}
get searchParams(): URLSearchParams {
if (this._searchParamsInstance == null) {
this._searchParamsInstance = new URLSearchParams();
}
return this._searchParamsInstance;
}
toJSON(): string {
return this.toString();
}
toString(): string {
if (this._searchParamsInstance === null) {
return this._url;
}
const separator = this._url.indexOf('?') > -1 ? '&' : '?';
return this._url + separator + this._searchParamsInstance.toString();
}
get username() {
throw new Error('not implemented');
}
}

View File

@ -0,0 +1,16 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
const BlobModule = {
createFromParts() {},
release() {},
};
module.exports = BlobModule;

View File

@ -0,0 +1,20 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict
* @format
*/
const FileReaderModule = {
async readAsText(): Promise<string> {
return '';
},
async readAsDataURL(): Promise<string> {
return 'data:text/plain;base64,NDI=';
},
};
module.exports = FileReaderModule;