yeet
This commit is contained in:
18
node_modules/react-native/React/DevSupport/RCTDevLoadingViewProtocol.h
generated
vendored
Normal file
18
node_modules/react-native/React/DevSupport/RCTDevLoadingViewProtocol.h
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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 <UIKit/UIKit.h>
|
||||
|
||||
@class RCTLoadingProgress;
|
||||
|
||||
@protocol RCTDevLoadingViewProtocol <NSObject>
|
||||
+ (void)setEnabled:(BOOL)enabled;
|
||||
- (void)showMessage:(NSString *)message color:(UIColor *)color backgroundColor:(UIColor *)backgroundColor;
|
||||
- (void)showWithURL:(NSURL *)URL;
|
||||
- (void)updateProgress:(RCTLoadingProgress *)progress;
|
||||
- (void)hide;
|
||||
@end
|
11
node_modules/react-native/React/DevSupport/RCTDevLoadingViewSetEnabled.h
generated
vendored
Normal file
11
node_modules/react-native/React/DevSupport/RCTDevLoadingViewSetEnabled.h
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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/RCTDefines.h>
|
||||
|
||||
RCT_EXTERN void RCTDevLoadingViewSetEnabled(BOOL enabled);
|
||||
RCT_EXTERN BOOL RCTDevLoadingViewGetEnabled(void);
|
24
node_modules/react-native/React/DevSupport/RCTDevLoadingViewSetEnabled.m
generated
vendored
Normal file
24
node_modules/react-native/React/DevSupport/RCTDevLoadingViewSetEnabled.m
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 "RCTDevLoadingViewSetEnabled.h"
|
||||
|
||||
#if RCT_DEV | RCT_ENABLE_LOADING_VIEW
|
||||
static BOOL isDevLoadingViewEnabled = YES;
|
||||
#else
|
||||
static BOOL isDevLoadingViewEnabled = NO;
|
||||
#endif
|
||||
|
||||
void RCTDevLoadingViewSetEnabled(BOOL enabled)
|
||||
{
|
||||
isDevLoadingViewEnabled = enabled;
|
||||
}
|
||||
|
||||
BOOL RCTDevLoadingViewGetEnabled()
|
||||
{
|
||||
return isDevLoadingViewEnabled;
|
||||
}
|
22
node_modules/react-native/React/DevSupport/RCTInspectorDevServerHelper.h
generated
vendored
Normal file
22
node_modules/react-native/React/DevSupport/RCTInspectorDevServerHelper.h
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <React/RCTDefines.h>
|
||||
#import <React/RCTInspectorPackagerConnection.h>
|
||||
|
||||
#if RCT_DEV
|
||||
|
||||
@interface RCTInspectorDevServerHelper : NSObject
|
||||
|
||||
+ (RCTInspectorPackagerConnection *)connectWithBundleURL:(NSURL *)bundleURL;
|
||||
+ (void)disableDebugger;
|
||||
@end
|
||||
|
||||
#endif
|
94
node_modules/react-native/React/DevSupport/RCTInspectorDevServerHelper.mm
generated
vendored
Normal file
94
node_modules/react-native/React/DevSupport/RCTInspectorDevServerHelper.mm
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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/RCTInspectorDevServerHelper.h>
|
||||
|
||||
#if RCT_DEV
|
||||
|
||||
#import <React/RCTLog.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import <React/RCTDefines.h>
|
||||
#import <React/RCTInspectorPackagerConnection.h>
|
||||
|
||||
static NSString *const kDebuggerMsgDisable = @"{ \"id\":1,\"method\":\"Debugger.disable\" }";
|
||||
|
||||
static NSString *getServerHost(NSURL *bundleURL, NSNumber *port)
|
||||
{
|
||||
NSString *host = [bundleURL host];
|
||||
if (!host) {
|
||||
host = @"localhost";
|
||||
}
|
||||
|
||||
// this is consistent with the Android implementation, where http:// is the
|
||||
// hardcoded implicit scheme for the debug server. Note, packagerURL
|
||||
// technically looks like it could handle schemes/protocols other than HTTP,
|
||||
// so rather than force HTTP, leave it be for now, in case someone is relying
|
||||
// on that ability when developing against iOS.
|
||||
return [NSString stringWithFormat:@"%@:%@", host, port];
|
||||
}
|
||||
|
||||
static NSURL *getInspectorDeviceUrl(NSURL *bundleURL)
|
||||
{
|
||||
NSNumber *inspectorProxyPort = @8081;
|
||||
NSString *inspectorProxyPortStr = [[[NSProcessInfo processInfo] environment] objectForKey:@"RCT_METRO_PORT"];
|
||||
if (inspectorProxyPortStr && [inspectorProxyPortStr length] > 0) {
|
||||
inspectorProxyPort = [NSNumber numberWithInt:[inspectorProxyPortStr intValue]];
|
||||
}
|
||||
NSString *escapedDeviceName = [[[UIDevice currentDevice] name]
|
||||
stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];
|
||||
NSString *escapedAppName = [[[NSBundle mainBundle] bundleIdentifier]
|
||||
stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLQueryAllowedCharacterSet];
|
||||
return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/inspector/device?name=%@&app=%@",
|
||||
getServerHost(bundleURL, inspectorProxyPort),
|
||||
escapedDeviceName,
|
||||
escapedAppName]];
|
||||
}
|
||||
|
||||
@implementation RCTInspectorDevServerHelper
|
||||
|
||||
RCT_NOT_IMPLEMENTED(-(instancetype)init)
|
||||
|
||||
static NSMutableDictionary<NSString *, RCTInspectorPackagerConnection *> *socketConnections = nil;
|
||||
|
||||
static void sendEventToAllConnections(NSString *event)
|
||||
{
|
||||
for (NSString *socketId in socketConnections) {
|
||||
[socketConnections[socketId] sendEventToAllConnections:event];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)disableDebugger
|
||||
{
|
||||
sendEventToAllConnections(kDebuggerMsgDisable);
|
||||
}
|
||||
|
||||
+ (RCTInspectorPackagerConnection *)connectWithBundleURL:(NSURL *)bundleURL
|
||||
{
|
||||
NSURL *inspectorURL = getInspectorDeviceUrl(bundleURL);
|
||||
|
||||
// Note, using a static dictionary isn't really the greatest design, but
|
||||
// the packager connection does the same thing, so it's at least consistent.
|
||||
// This is a static map that holds different inspector clients per the inspectorURL
|
||||
if (socketConnections == nil) {
|
||||
socketConnections = [NSMutableDictionary new];
|
||||
}
|
||||
|
||||
NSString *key = [inspectorURL absoluteString];
|
||||
RCTInspectorPackagerConnection *connection = socketConnections[key];
|
||||
if (!connection || !connection.isConnected) {
|
||||
connection = [[RCTInspectorPackagerConnection alloc] initWithURL:inspectorURL];
|
||||
socketConnections[key] = connection;
|
||||
[connection connect];
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
45
node_modules/react-native/React/DevSupport/RCTPackagerClient.h
generated
vendored
Normal file
45
node_modules/react-native/React/DevSupport/RCTPackagerClient.h
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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/RCTDefines.h>
|
||||
|
||||
#if RCT_DEV // Only supported in dev mode
|
||||
|
||||
@class RCTPackagerClientResponder;
|
||||
@class RCTReconnectingWebSocket;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const int RCT_PACKAGER_CLIENT_PROTOCOL_VERSION;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
@protocol RCTPackagerClientMethod <NSObject>
|
||||
|
||||
- (void)handleRequest:(NSDictionary<NSString *, id> *)params withResponder:(RCTPackagerClientResponder *)responder;
|
||||
- (void)handleNotification:(NSDictionary<NSString *, id> *)params;
|
||||
|
||||
@optional
|
||||
|
||||
/** By default object will receive its methods on the main queue, unless this method is overridden. */
|
||||
- (dispatch_queue_t)methodQueue;
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTPackagerClientResponder : NSObject
|
||||
|
||||
- (instancetype)initWithId:(id)msgId socket:(RCTReconnectingWebSocket *)socket;
|
||||
- (void)respondWithResult:(id)result;
|
||||
- (void)respondWithError:(id)error;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
65
node_modules/react-native/React/DevSupport/RCTPackagerClient.m
generated
vendored
Normal file
65
node_modules/react-native/React/DevSupport/RCTPackagerClient.m
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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/RCTPackagerClient.h>
|
||||
|
||||
#import <React/RCTLog.h>
|
||||
#import <React/RCTReconnectingWebSocket.h>
|
||||
#import <React/RCTUtils.h>
|
||||
|
||||
#if RCT_DEV // Only supported in dev mode
|
||||
|
||||
const int RCT_PACKAGER_CLIENT_PROTOCOL_VERSION = 2;
|
||||
|
||||
@implementation RCTPackagerClientResponder {
|
||||
id _msgId;
|
||||
__weak RCTReconnectingWebSocket *_socket;
|
||||
}
|
||||
|
||||
- (instancetype)initWithId:(id)msgId socket:(RCTReconnectingWebSocket *)socket
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_msgId = msgId;
|
||||
_socket = socket;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)respondWithResult:(id)result
|
||||
{
|
||||
NSDictionary<NSString *, id> *msg = @{
|
||||
@"version" : @(RCT_PACKAGER_CLIENT_PROTOCOL_VERSION),
|
||||
@"id" : _msgId,
|
||||
@"result" : result,
|
||||
};
|
||||
NSError *jsError = nil;
|
||||
NSString *message = RCTJSONStringify(msg, &jsError);
|
||||
if (jsError) {
|
||||
RCTLogError(@"%@ failed to stringify message with error %@", [self class], jsError);
|
||||
} else {
|
||||
[_socket send:message];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)respondWithError:(id)error
|
||||
{
|
||||
NSDictionary<NSString *, id> *msg = @{
|
||||
@"version" : @(RCT_PACKAGER_CLIENT_PROTOCOL_VERSION),
|
||||
@"id" : _msgId,
|
||||
@"error" : error,
|
||||
};
|
||||
NSError *jsError = nil;
|
||||
NSString *message = RCTJSONStringify(msg, &jsError);
|
||||
if (jsError) {
|
||||
RCTLogError(@"%@ failed to stringify message with error %@", [self class], jsError);
|
||||
} else {
|
||||
[_socket send:message];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
#endif
|
75
node_modules/react-native/React/DevSupport/RCTPackagerConnection.h
generated
vendored
Normal file
75
node_modules/react-native/React/DevSupport/RCTPackagerConnection.h
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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 <Foundation/Foundation.h>
|
||||
|
||||
#import <React/RCTDefines.h>
|
||||
|
||||
#if RCT_DEV
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol RCTPackagerClientMethod;
|
||||
@class RCTPackagerClientResponder;
|
||||
|
||||
typedef uint32_t RCTHandlerToken;
|
||||
typedef void (^RCTNotificationHandler)(NSDictionary<NSString *, id> *);
|
||||
typedef void (^RCTRequestHandler)(NSDictionary<NSString *, id> *, RCTPackagerClientResponder *);
|
||||
typedef void (^RCTConnectedHandler)(void);
|
||||
|
||||
/** Encapsulates singleton connection to React Native packager. */
|
||||
@interface RCTPackagerConnection : NSObject
|
||||
|
||||
+ (instancetype)sharedPackagerConnection;
|
||||
|
||||
/**
|
||||
* Registers a handler for a notification broadcast from the packager. An
|
||||
* example is "reload" - an instruction to reload from the packager.
|
||||
* If multiple notification handlers are registered for the same method, they
|
||||
* will all be invoked sequentially.
|
||||
*/
|
||||
- (RCTHandlerToken)addNotificationHandler:(RCTNotificationHandler)handler
|
||||
queue:(dispatch_queue_t)queue
|
||||
forMethod:(NSString *)method;
|
||||
|
||||
/**
|
||||
* Registers a handler for a request from the packager. An example is
|
||||
* pokeSamplingProfiler; it asks for profile data from the client.
|
||||
* Only one handler can be registered for a given method; calling this
|
||||
* displaces any previous request handler registered for that method.
|
||||
*/
|
||||
- (RCTHandlerToken)addRequestHandler:(RCTRequestHandler)handler
|
||||
queue:(dispatch_queue_t)queue
|
||||
forMethod:(NSString *)method;
|
||||
|
||||
/**
|
||||
* Registers a handler that runs at most once, when the connection to the
|
||||
* packager has been established. The handler will be dispatched immediately
|
||||
* if the connection is already established.
|
||||
*/
|
||||
- (RCTHandlerToken)addConnectedHandler:(RCTConnectedHandler)handler queue:(dispatch_queue_t)queue;
|
||||
|
||||
/** Removes a handler. Silently does nothing if the token is not valid. */
|
||||
- (void)removeHandler:(RCTHandlerToken)token;
|
||||
|
||||
/** Disconnects and removes all handlers. */
|
||||
- (void)stop;
|
||||
|
||||
/**
|
||||
* Historically no distinction was made between notification and request
|
||||
* handlers. If you use this method, it will be registered as *both* a
|
||||
* notification handler *and* a request handler. You should migrate to the
|
||||
* new block-based API instead.
|
||||
*/
|
||||
- (void)addHandler:(id<RCTPackagerClientMethod>)handler
|
||||
forMethod:(NSString *)method __deprecated_msg("Use addRequestHandler or addNotificationHandler instead");
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
300
node_modules/react-native/React/DevSupport/RCTPackagerConnection.mm
generated
vendored
Normal file
300
node_modules/react-native/React/DevSupport/RCTPackagerConnection.mm
generated
vendored
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* 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/RCTPackagerConnection.h>
|
||||
|
||||
#import <objc/runtime.h>
|
||||
#import <algorithm>
|
||||
#import <vector>
|
||||
|
||||
#import <React/RCTAssert.h>
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTBundleURLProvider.h>
|
||||
#import <React/RCTConvert.h>
|
||||
#import <React/RCTDefines.h>
|
||||
#import <React/RCTLog.h>
|
||||
#import <React/RCTPackagerClient.h>
|
||||
#import <React/RCTReconnectingWebSocket.h>
|
||||
#import <React/RCTUtils.h>
|
||||
|
||||
#if RCT_DEV
|
||||
|
||||
#import <React/RCTSRWebSocket.h>
|
||||
|
||||
@interface RCTPackagerConnection () <RCTReconnectingWebSocketDelegate>
|
||||
@end
|
||||
|
||||
template <typename Handler>
|
||||
struct Registration {
|
||||
NSString *method;
|
||||
Handler handler;
|
||||
dispatch_queue_t queue;
|
||||
uint32_t token;
|
||||
};
|
||||
|
||||
@implementation RCTPackagerConnection {
|
||||
std::mutex _mutex; // protects all ivars
|
||||
RCTReconnectingWebSocket *_socket;
|
||||
BOOL _socketConnected;
|
||||
NSString *_serverHostForSocket;
|
||||
id _bundleURLChangeObserver;
|
||||
uint32_t _nextToken;
|
||||
std::vector<Registration<RCTNotificationHandler>> _notificationRegistrations;
|
||||
std::vector<Registration<RCTRequestHandler>> _requestRegistrations;
|
||||
std::vector<Registration<RCTConnectedHandler>> _connectedRegistrations;
|
||||
}
|
||||
|
||||
+ (instancetype)sharedPackagerConnection
|
||||
{
|
||||
static RCTPackagerConnection *connection;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
connection = [RCTPackagerConnection new];
|
||||
});
|
||||
return connection;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_nextToken = 1; // Prevent randomly erasing a handler if you pass a bogus 0 token
|
||||
_serverHostForSocket = [[RCTBundleURLProvider sharedSettings] packagerServerHost];
|
||||
_socket = socketForLocation(_serverHostForSocket);
|
||||
_socket.delegate = self;
|
||||
[_socket start];
|
||||
|
||||
RCTPackagerConnection *const __weak weakSelf = self;
|
||||
_bundleURLChangeObserver =
|
||||
[[NSNotificationCenter defaultCenter] addObserverForName:RCTBundleURLProviderUpdatedNotification
|
||||
object:nil
|
||||
queue:[NSOperationQueue mainQueue]
|
||||
usingBlock:^(NSNotification *_Nonnull __unused note) {
|
||||
[weakSelf bundleURLSettingsChanged];
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
static RCTReconnectingWebSocket *socketForLocation(NSString *const serverHost)
|
||||
{
|
||||
NSURLComponents *const components = [NSURLComponents new];
|
||||
components.host = serverHost ?: @"localhost";
|
||||
components.scheme = @"http";
|
||||
components.port = @(kRCTBundleURLProviderDefaultPort);
|
||||
components.path = @"/message";
|
||||
components.queryItems = @[ [NSURLQueryItem queryItemWithName:@"role" value:@"ios"] ];
|
||||
static dispatch_queue_t queue;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
queue = dispatch_queue_create("com.facebook.RCTPackagerConnectionQueue", DISPATCH_QUEUE_SERIAL);
|
||||
});
|
||||
return [[RCTReconnectingWebSocket alloc] initWithURL:components.URL queue:queue];
|
||||
}
|
||||
|
||||
- (void)stop
|
||||
{
|
||||
std::lock_guard<std::mutex> l(_mutex);
|
||||
if (_socket == nil) {
|
||||
// Already stopped
|
||||
return;
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:_bundleURLChangeObserver];
|
||||
_bundleURLChangeObserver = nil;
|
||||
_socketConnected = NO;
|
||||
[_socket stop];
|
||||
_socket = nil;
|
||||
_notificationRegistrations.clear();
|
||||
_requestRegistrations.clear();
|
||||
}
|
||||
|
||||
- (void)bundleURLSettingsChanged
|
||||
{
|
||||
std::lock_guard<std::mutex> l(_mutex);
|
||||
if (_socket == nil) {
|
||||
return; // already stopped
|
||||
}
|
||||
|
||||
NSString *const serverHost = [[RCTBundleURLProvider sharedSettings] packagerServerHost];
|
||||
if ([serverHost isEqual:_serverHostForSocket]) {
|
||||
return; // unchanged
|
||||
}
|
||||
|
||||
_socket.delegate = nil;
|
||||
[_socket stop];
|
||||
_serverHostForSocket = serverHost;
|
||||
_socket = socketForLocation(serverHost);
|
||||
_socket.delegate = self;
|
||||
[_socket start];
|
||||
}
|
||||
|
||||
- (RCTHandlerToken)addNotificationHandler:(RCTNotificationHandler)handler
|
||||
queue:(dispatch_queue_t)queue
|
||||
forMethod:(NSString *)method
|
||||
{
|
||||
std::lock_guard<std::mutex> l(_mutex);
|
||||
const auto token = _nextToken++;
|
||||
_notificationRegistrations.push_back({method, handler, queue, token});
|
||||
return token;
|
||||
}
|
||||
|
||||
- (RCTHandlerToken)addRequestHandler:(RCTRequestHandler)handler
|
||||
queue:(dispatch_queue_t)queue
|
||||
forMethod:(NSString *)method
|
||||
{
|
||||
std::lock_guard<std::mutex> l(_mutex);
|
||||
const auto token = _nextToken++;
|
||||
_requestRegistrations.push_back({method, handler, queue, token});
|
||||
return token;
|
||||
}
|
||||
|
||||
- (RCTHandlerToken)addConnectedHandler:(RCTConnectedHandler)handler queue:(dispatch_queue_t)queue
|
||||
{
|
||||
std::lock_guard<std::mutex> l(_mutex);
|
||||
if (_socketConnected) {
|
||||
dispatch_async(queue, ^{
|
||||
handler();
|
||||
});
|
||||
return 0; // _nextToken starts at 1, so 0 is a no-op token
|
||||
} else {
|
||||
const auto token = _nextToken++;
|
||||
_connectedRegistrations.push_back({nil, handler, queue, token});
|
||||
return token;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeHandler:(RCTHandlerToken)token
|
||||
{
|
||||
std::lock_guard<std::mutex> l(_mutex);
|
||||
eraseRegistrationsWithToken(_notificationRegistrations, token);
|
||||
eraseRegistrationsWithToken(_requestRegistrations, token);
|
||||
eraseRegistrationsWithToken(_connectedRegistrations, token);
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
static void eraseRegistrationsWithToken(std::vector<Registration<Handler>> ®istrations, RCTHandlerToken token)
|
||||
{
|
||||
registrations.erase(
|
||||
std::remove_if(
|
||||
registrations.begin(), registrations.end(), [&token](const auto ®) { return reg.token == token; }),
|
||||
registrations.end());
|
||||
}
|
||||
|
||||
- (void)addHandler:(id<RCTPackagerClientMethod>)handler forMethod:(NSString *)method
|
||||
{
|
||||
dispatch_queue_t queue =
|
||||
[handler respondsToSelector:@selector(methodQueue)] ? [handler methodQueue] : dispatch_get_main_queue();
|
||||
|
||||
[self
|
||||
addNotificationHandler:^(NSDictionary<NSString *, id> *notification) {
|
||||
[handler handleNotification:notification];
|
||||
}
|
||||
queue:queue
|
||||
forMethod:method];
|
||||
[self
|
||||
addRequestHandler:^(NSDictionary<NSString *, id> *request, RCTPackagerClientResponder *responder) {
|
||||
[handler handleRequest:request withResponder:responder];
|
||||
}
|
||||
queue:queue
|
||||
forMethod:method];
|
||||
}
|
||||
|
||||
static BOOL isSupportedVersion(NSNumber *version)
|
||||
{
|
||||
NSArray<NSNumber *> *const kSupportedVersions = @[ @(RCT_PACKAGER_CLIENT_PROTOCOL_VERSION) ];
|
||||
return [kSupportedVersions containsObject:version];
|
||||
}
|
||||
|
||||
#pragma mark - RCTReconnectingWebSocketDelegate
|
||||
|
||||
- (void)reconnectingWebSocketDidOpen:(__unused RCTReconnectingWebSocket *)webSocket
|
||||
{
|
||||
std::vector<Registration<RCTConnectedHandler>> registrations;
|
||||
{
|
||||
std::lock_guard<std::mutex> l(_mutex);
|
||||
_socketConnected = YES;
|
||||
registrations = _connectedRegistrations;
|
||||
_connectedRegistrations.clear();
|
||||
}
|
||||
for (const auto ®istration : registrations) {
|
||||
// Beware: don't capture the reference to handler in a dispatched block!
|
||||
RCTConnectedHandler handler = registration.handler;
|
||||
dispatch_async(registration.queue, ^{
|
||||
handler();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reconnectingWebSocket:(RCTReconnectingWebSocket *)webSocket didReceiveMessage:(id)message
|
||||
{
|
||||
NSError *error = nil;
|
||||
NSDictionary<NSString *, id> *msg = RCTJSONParse(message, &error);
|
||||
|
||||
if (error) {
|
||||
RCTLogError(@"%@ failed to parse message with error %@\n<message>\n%@\n</message>", [self class], error, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isSupportedVersion(msg[@"version"])) {
|
||||
RCTLogError(@"%@ received message with not supported version %@", [self class], msg[@"version"]);
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *const method = msg[@"method"];
|
||||
NSDictionary<NSString *, id> *const params = msg[@"params"];
|
||||
id messageId = msg[@"id"];
|
||||
|
||||
if (messageId) { // Request
|
||||
const std::vector<Registration<RCTRequestHandler>> registrations(
|
||||
registrationsWithMethod(_mutex, _requestRegistrations, method));
|
||||
if (registrations.empty()) {
|
||||
RCTLogError(@"No handler found for packager method %@", msg[@"method"]);
|
||||
[[[RCTPackagerClientResponder alloc] initWithId:messageId socket:webSocket]
|
||||
respondWithError:[NSString stringWithFormat:@"No handler found for packager method %@", msg[@"method"]]];
|
||||
} else {
|
||||
// If there are multiple matching request registrations, only one can win;
|
||||
// otherwise the packager would get multiple responses. Choose the last one.
|
||||
RCTRequestHandler handler = registrations.back().handler;
|
||||
dispatch_async(registrations.back().queue, ^{
|
||||
handler(params, [[RCTPackagerClientResponder alloc] initWithId:messageId socket:webSocket]);
|
||||
});
|
||||
}
|
||||
} else { // Notification
|
||||
const std::vector<Registration<RCTNotificationHandler>> registrations(
|
||||
registrationsWithMethod(_mutex, _notificationRegistrations, method));
|
||||
for (const auto ®istration : registrations) {
|
||||
// Beware: don't capture the reference to handler in a dispatched block!
|
||||
RCTNotificationHandler handler = registration.handler;
|
||||
dispatch_async(registration.queue, ^{
|
||||
handler(params);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)reconnectingWebSocketDidClose:(__unused RCTReconnectingWebSocket *)webSocket
|
||||
{
|
||||
std::lock_guard<std::mutex> l(_mutex);
|
||||
_socketConnected = NO;
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
static std::vector<Registration<Handler>>
|
||||
registrationsWithMethod(std::mutex &mutex, const std::vector<Registration<Handler>> ®istrations, NSString *method)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(mutex); // Scope lock acquisition to prevent deadlock when calling out
|
||||
std::vector<Registration<Handler>> matches;
|
||||
for (const auto ® : registrations) {
|
||||
if ([reg.method isEqual:method]) {
|
||||
matches.push_back(reg);
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user