From f255bda51f6f66a79eeef7cae6a42a57b59900db Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Mon, 21 Nov 2016 07:02:58 -0800 Subject: [PATCH] Fix loop when websocket executor is used without packager present Reviewed By: mhorowitz Differential Revision: D4159911 fbshipit-source-id: db913704641daf055060f5fe4561479daf76cd5a --- Libraries/WebSocket/RCTWebSocketExecutor.h | 4 +- Libraries/WebSocket/RCTWebSocketExecutor.m | 46 ++++++++++++++-------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/Libraries/WebSocket/RCTWebSocketExecutor.h b/Libraries/WebSocket/RCTWebSocketExecutor.h index 9993cbc5a..4550a347b 100644 --- a/Libraries/WebSocket/RCTWebSocketExecutor.h +++ b/Libraries/WebSocket/RCTWebSocketExecutor.h @@ -9,10 +9,10 @@ #import "RCTDefines.h" -#if RCT_DEV // Debug executors are only supported in dev mode - #import "RCTJavaScriptExecutor.h" +#if RCT_DEV // Debug executors are only supported in dev mode + @interface RCTWebSocketExecutor : NSObject - (instancetype)initWithURL:(NSURL *)URL; diff --git a/Libraries/WebSocket/RCTWebSocketExecutor.m b/Libraries/WebSocket/RCTWebSocketExecutor.m index 930d2cd0e..a6fa20872 100644 --- a/Libraries/WebSocket/RCTWebSocketExecutor.m +++ b/Libraries/WebSocket/RCTWebSocketExecutor.m @@ -9,16 +9,17 @@ #import "RCTDefines.h" -#if RCT_DEV // Debug executors are only supported in dev mode - #import "RCTWebSocketExecutor.h" +#import "RCTAssert.h" #import "RCTBridge.h" #import "RCTConvert.h" #import "RCTLog.h" #import "RCTUtils.h" #import "RCTSRWebSocket.h" +#if RCT_DEV // Debug executors are only supported in dev mode + typedef void (^RCTWSMessageCallback)(NSError *error, NSDictionary *reply); @interface RCTWebSocketExecutor () @@ -33,6 +34,7 @@ typedef void (^RCTWSMessageCallback)(NSError *error, NSDictionary *_injectedObjects; NSURL *_url; + NSError *_setupError; } RCT_EXPORT_MODULE() @@ -81,10 +83,12 @@ RCT_EXPORT_MODULE() completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){}]; [dataTask resume]; if (![self connectToProxy]) { - RCTLogError(@"Connection to %@ timed out. Are you running node proxy? If " - "you are running on the device, check if you have the right IP " - "address in `RCTWebSocketExecutor.m`.", _url); [self invalidate]; + NSString *error = [NSString stringWithFormat:@"Connection to %@ timed out. Are you " + "running node proxy? If you are running on the device, check if " + "you have the right IP address in `RCTWebSocketExecutor.m`.", _url]; + _setupError = RCTErrorWithMessage(error); + RCTFatal(_setupError); return; } @@ -95,10 +99,13 @@ RCT_EXPORT_MODULE() retries--; } if (!runtimeIsReady) { - RCTLogError(@"Runtime is not ready for debugging.\n " - "- Make sure Packager server is running.\n" - "- Make sure the JavaScript Debugger is running and not paused on a breakpoint or exception and try reloading again."); [self invalidate]; + NSString *error = @"Runtime is not ready for debugging.\n " + "- Make sure Packager server is running.\n" + "- Make sure the JavaScript Debugger is running and not paused on a " + "breakpoint or exception and try reloading again."; + _setupError = RCTErrorWithMessage(error); + RCTFatal(_setupError); return; } } @@ -108,18 +115,21 @@ RCT_EXPORT_MODULE() _socketOpenSemaphore = dispatch_semaphore_create(0); [_socket open]; long connected = dispatch_semaphore_wait(_socketOpenSemaphore, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 10)); - return connected == 0; + return connected == 0 && _socket.readyState == RCTSR_OPEN; } - (BOOL)prepareJSRuntime { __block NSError *initError; dispatch_semaphore_t s = dispatch_semaphore_create(0); - [self sendMessage:@{@"method": @"prepareJSRuntime"} waitForReply:^(NSError *error, NSDictionary *reply) { + [self sendMessage:@{@"method": @"prepareJSRuntime"} onReply:^(NSError *error, NSDictionary *reply) { initError = error; dispatch_semaphore_signal(s); }]; long runtimeIsReady = dispatch_semaphore_wait(s, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC)); + if (initError) { + RCTLogInfo(@"Websocket runtime setup failed: %@", initError); + } return runtimeIsReady == 0 && initError == nil; } @@ -142,16 +152,18 @@ RCT_EXPORT_MODULE() - (void)webSocket:(RCTSRWebSocket *)webSocket didFailWithError:(NSError *)error { dispatch_semaphore_signal(_socketOpenSemaphore); - dispatch_async(dispatch_get_main_queue(), ^{ - // Give the setUp method an opportunity to report an error first - RCTLogError(@"WebSocket connection failed with error %@", error); - }); + RCTLogInfo(@"WebSocket connection failed with error %@", error); } -- (void)sendMessage:(NSDictionary *)message waitForReply:(RCTWSMessageCallback)callback +- (void)sendMessage:(NSDictionary *)message onReply:(RCTWSMessageCallback)callback { static NSUInteger lastID = 10000; + if (_setupError) { + callback(_setupError, nil); + return; + } + dispatch_async(_jsQueue, ^{ if (!self.valid) { NSError *error = [NSError errorWithDomain:@"WS" code:1 userInfo:@{ @@ -176,7 +188,7 @@ RCT_EXPORT_MODULE() @"url": RCTNullIfNil(URL.absoluteString), @"inject": _injectedObjects, }; - [self sendMessage:message waitForReply:^(NSError *error, NSDictionary *reply) { + [self sendMessage:message onReply:^(NSError *error, NSDictionary *reply) { onComplete(error); }]; } @@ -208,7 +220,7 @@ RCT_EXPORT_MODULE() @"method": method, @"arguments": arguments }; - [self sendMessage:message waitForReply:^(NSError *socketError, NSDictionary *reply) { + [self sendMessage:message onReply:^(NSError *socketError, NSDictionary *reply) { if (socketError) { onComplete(nil, socketError); return;