mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Remove legacy InspectorPackagerConnection (#44746)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/44746 Cleanup after this experiment's removal in D57730921. Changelog: [Internal] Reviewed By: hoxyq Differential Revision: D58017460 fbshipit-source-id: f9328875d6ef9a76599ae560c58cef6caab87a57
This commit is contained in:
committed by
Facebook GitHub Bot
parent
ec1742a6bb
commit
c144382316
@@ -14,7 +14,6 @@
|
||||
|
||||
#import <React/RCTCxxInspectorPackagerConnection.h>
|
||||
#import <React/RCTDefines.h>
|
||||
#import <React/RCTInspectorPackagerConnection.h>
|
||||
|
||||
#import <CommonCrypto/CommonCrypto.h>
|
||||
#import <jsinspector-modern/InspectorFlags.h>
|
||||
@@ -181,12 +180,7 @@ static void sendEventToAllConnections(NSString *event)
|
||||
NSString *key = [inspectorURL absoluteString];
|
||||
id<RCTInspectorPackagerConnectionProtocol> connection = socketConnections[key];
|
||||
if (!connection || !connection.isConnected) {
|
||||
if (facebook::react::jsinspector_modern::InspectorFlags::getInstance().getFuseboxEnabled()) {
|
||||
connection = [[RCTCxxInspectorPackagerConnection alloc] initWithURL:inspectorURL];
|
||||
} else {
|
||||
// TODO(T190163403): Remove legacy RCTInspectorPackagerConnection
|
||||
connection = [[RCTInspectorPackagerConnection alloc] initWithURL:inspectorURL];
|
||||
}
|
||||
connection = [[RCTCxxInspectorPackagerConnection alloc] initWithURL:inspectorURL];
|
||||
|
||||
socketConnections[key] = connection;
|
||||
[connection connect];
|
||||
|
||||
@@ -1,325 +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/RCTInspectorPackagerConnection.h>
|
||||
|
||||
#if RCT_DEV || RCT_REMOTE_PROFILE
|
||||
|
||||
#import <React/RCTDefines.h>
|
||||
#import <React/RCTInspector.h>
|
||||
#import <React/RCTLog.h>
|
||||
#import <React/RCTUtils.h>
|
||||
#import <SocketRocket/SRWebSocket.h>
|
||||
|
||||
// This is a port of the Android impl, at
|
||||
// ReactAndroid/src/main/java/com/facebook/react/devsupport/InspectorPackagerConnection.java
|
||||
// please keep consistent :)
|
||||
|
||||
const int RECONNECT_DELAY_MS = 2000;
|
||||
|
||||
@interface RCTInspectorPackagerConnection () <SRWebSocketDelegate> {
|
||||
NSURL *_url;
|
||||
NSMutableDictionary<NSString *, RCTInspectorLocalConnection *> *_inspectorConnections;
|
||||
SRWebSocket *_webSocket;
|
||||
BOOL _closed;
|
||||
BOOL _suppressConnectionErrors;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface RCTInspectorRemoteConnection () {
|
||||
__weak RCTInspectorPackagerConnection *_owningPackagerConnection;
|
||||
NSString *_pageId;
|
||||
}
|
||||
- (instancetype)initWithPackagerConnection:(RCTInspectorPackagerConnection *)owningPackagerConnection
|
||||
pageId:(NSString *)pageId;
|
||||
@end
|
||||
|
||||
static NSDictionary<NSString *, id> *makePageIdPayload(NSString *pageId)
|
||||
{
|
||||
return @{@"pageId" : pageId};
|
||||
}
|
||||
|
||||
@implementation RCTInspectorPackagerConnection
|
||||
|
||||
RCT_NOT_IMPLEMENTED(-(instancetype)init)
|
||||
|
||||
- (instancetype)initWithURL:(NSURL *)url
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_url = url;
|
||||
_inspectorConnections = [NSMutableDictionary new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)handleProxyMessage:(NSDictionary<NSString *, id> *)message
|
||||
{
|
||||
NSString *event = message[@"event"];
|
||||
NSDictionary *payload = message[@"payload"];
|
||||
if ([@"getPages" isEqualToString:event]) {
|
||||
[self sendEvent:event payload:[self pages]];
|
||||
} else if ([@"wrappedEvent" isEqualToString:event]) {
|
||||
[self handleWrappedEvent:payload];
|
||||
} else if ([@"connect" isEqualToString:event]) {
|
||||
[self handleConnect:payload];
|
||||
} else if ([@"disconnect" isEqualToString:event]) {
|
||||
[self handleDisconnect:payload];
|
||||
} else {
|
||||
RCTLogError(@"Unknown event: %@", event);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sendEventToAllConnections:(NSString *)event
|
||||
{
|
||||
for (NSString *pageId in _inspectorConnections) {
|
||||
[_inspectorConnections[pageId] sendMessage:event];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)closeAllConnections
|
||||
{
|
||||
for (NSString *pageId in _inspectorConnections) {
|
||||
[[_inspectorConnections objectForKey:pageId] disconnect];
|
||||
}
|
||||
[_inspectorConnections removeAllObjects];
|
||||
}
|
||||
|
||||
- (void)handleConnect:(NSDictionary *)payload
|
||||
{
|
||||
NSString *pageId = payload[@"pageId"];
|
||||
RCTInspectorLocalConnection *existingConnection = _inspectorConnections[pageId];
|
||||
if (existingConnection) {
|
||||
[_inspectorConnections removeObjectForKey:pageId];
|
||||
[existingConnection disconnect];
|
||||
RCTLogWarn(@"Already connected: %@", pageId);
|
||||
return;
|
||||
}
|
||||
|
||||
RCTInspectorRemoteConnection *remoteConnection =
|
||||
[[RCTInspectorRemoteConnection alloc] initWithPackagerConnection:self pageId:pageId];
|
||||
|
||||
RCTInspectorLocalConnection *inspectorConnection = [RCTInspector connectPage:[pageId integerValue]
|
||||
forRemoteConnection:remoteConnection];
|
||||
_inspectorConnections[pageId] = inspectorConnection;
|
||||
}
|
||||
|
||||
- (void)handleDisconnect:(NSDictionary *)payload
|
||||
{
|
||||
NSString *pageId = payload[@"pageId"];
|
||||
RCTInspectorLocalConnection *inspectorConnection = _inspectorConnections[pageId];
|
||||
if (inspectorConnection) {
|
||||
[self removeConnectionForPage:pageId];
|
||||
[inspectorConnection disconnect];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeConnectionForPage:(NSString *)pageId
|
||||
{
|
||||
[_inspectorConnections removeObjectForKey:pageId];
|
||||
}
|
||||
|
||||
- (void)handleWrappedEvent:(NSDictionary *)payload
|
||||
{
|
||||
NSString *pageId = payload[@"pageId"];
|
||||
NSString *wrappedEvent = payload[@"wrappedEvent"];
|
||||
RCTInspectorLocalConnection *inspectorConnection = _inspectorConnections[pageId];
|
||||
if (!inspectorConnection) {
|
||||
RCTLogWarn(@"Not connected to page: %@ , failed trying to handle event: %@", pageId, wrappedEvent);
|
||||
return;
|
||||
}
|
||||
[inspectorConnection sendMessage:wrappedEvent];
|
||||
}
|
||||
|
||||
- (NSArray *)pages
|
||||
{
|
||||
NSArray<RCTInspectorPage *> *pages = [RCTInspector pages];
|
||||
NSMutableArray *array = [NSMutableArray arrayWithCapacity:pages.count];
|
||||
|
||||
for (RCTInspectorPage *page in pages) {
|
||||
NSDictionary *jsonPage = @{
|
||||
@"id" : [@(page.id) stringValue],
|
||||
@"title" : page.title,
|
||||
@"app" : [[NSBundle mainBundle] bundleIdentifier],
|
||||
@"vm" : page.vm,
|
||||
};
|
||||
[array addObject:jsonPage];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
- (void)sendWrappedEvent:(NSString *)pageId message:(NSString *)message
|
||||
{
|
||||
NSDictionary *payload = @{
|
||||
@"pageId" : pageId,
|
||||
@"wrappedEvent" : message,
|
||||
};
|
||||
[self sendEvent:@"wrappedEvent" payload:payload];
|
||||
}
|
||||
|
||||
- (void)sendEvent:(NSString *)name payload:(id)payload
|
||||
{
|
||||
NSDictionary *jsonMessage = @{
|
||||
@"event" : name,
|
||||
@"payload" : payload,
|
||||
};
|
||||
[self sendToPackager:jsonMessage];
|
||||
}
|
||||
|
||||
// analogous to InspectorPackagerConnection.Connection.onFailure(...)
|
||||
- (void)webSocket:(__unused SRWebSocket *)webSocket didFailWithError:(NSError *)error
|
||||
{
|
||||
if (_webSocket) {
|
||||
[self abort:@"Websocket exception" withCause:error];
|
||||
}
|
||||
if (!_closed && [error code] != ECONNREFUSED) {
|
||||
[self reconnect];
|
||||
}
|
||||
}
|
||||
|
||||
// analogous to InspectorPackagerConnection.Connection.onMessage(...)
|
||||
- (void)webSocket:(__unused SRWebSocket *)webSocket didReceiveMessageWithString:(nonnull NSString *)messageText
|
||||
{
|
||||
NSError *error = nil;
|
||||
id parsedJSON = RCTJSONParse(messageText, &error);
|
||||
if (error) {
|
||||
RCTLogWarn(@"Unrecognized inspector message, string was not valid JSON: %@", messageText);
|
||||
return;
|
||||
}
|
||||
|
||||
[self handleProxyMessage:parsedJSON];
|
||||
}
|
||||
|
||||
// analogous to InspectorPackagerConnection.Connection.onClosed(...)
|
||||
- (void)webSocket:(__unused SRWebSocket *)webSocket
|
||||
didCloseWithCode:(__unused NSInteger)code
|
||||
reason:(__unused NSString *)reason
|
||||
wasClean:(__unused BOOL)wasClean
|
||||
{
|
||||
_webSocket = nil;
|
||||
[self closeAllConnections];
|
||||
if (!_closed) {
|
||||
[self reconnect];
|
||||
}
|
||||
}
|
||||
|
||||
- (bool)isConnected
|
||||
{
|
||||
return _webSocket != nil;
|
||||
}
|
||||
|
||||
- (void)connect
|
||||
{
|
||||
if (_closed) {
|
||||
RCTLogError(@"Illegal state: Can't connect after having previously been closed.");
|
||||
return;
|
||||
}
|
||||
|
||||
// The corresponding android code has a lot of custom config options for
|
||||
// timeouts, but our previous class, RCTSRWebSocket didn't have the same
|
||||
// implemented options. Might be worth reinvestigating for SRWebSocket?
|
||||
_webSocket = [[SRWebSocket alloc] initWithURL:_url];
|
||||
_webSocket.delegate = self;
|
||||
[_webSocket open];
|
||||
}
|
||||
|
||||
- (void)reconnect
|
||||
{
|
||||
if (_closed) {
|
||||
RCTLogError(@"Illegal state: Can't reconnect after having previously been closed.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_suppressConnectionErrors) {
|
||||
RCTLogWarn(@"Couldn't connect to packager, will silently retry");
|
||||
_suppressConnectionErrors = true;
|
||||
}
|
||||
|
||||
__weak RCTInspectorPackagerConnection *weakSelf = self;
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, RECONNECT_DELAY_MS * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
|
||||
RCTInspectorPackagerConnection *strongSelf = weakSelf;
|
||||
if (strongSelf && !strongSelf->_closed) {
|
||||
[strongSelf connect];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)closeQuietly
|
||||
{
|
||||
_closed = true;
|
||||
[self disposeWebSocket];
|
||||
}
|
||||
|
||||
- (void)sendToPackager:(NSDictionary *)messageObject
|
||||
{
|
||||
__weak RCTInspectorPackagerConnection *weakSelf = self;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
RCTInspectorPackagerConnection *strongSelf = weakSelf;
|
||||
if (strongSelf && !strongSelf->_closed) {
|
||||
NSError *error;
|
||||
NSString *messageText = RCTJSONStringify(messageObject, &error);
|
||||
if (error) {
|
||||
RCTLogWarn(@"Couldn't send event to packager: %@", error);
|
||||
} else {
|
||||
[strongSelf->_webSocket sendString:messageText error:nil];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)abort:(NSString *)message withCause:(NSError *)cause
|
||||
{
|
||||
// Don't log ECONNREFUSED at all; it's expected in cases where the server isn't listening.
|
||||
if (![cause.domain isEqual:NSPOSIXErrorDomain] || cause.code != ECONNREFUSED) {
|
||||
RCTLogInfo(@"Error occurred, shutting down websocket connection: %@ %@", message, cause);
|
||||
}
|
||||
|
||||
[self closeAllConnections];
|
||||
[self disposeWebSocket];
|
||||
}
|
||||
|
||||
- (void)disposeWebSocket
|
||||
{
|
||||
if (_webSocket) {
|
||||
[_webSocket closeWithCode:1000 reason:@"End of session"];
|
||||
_webSocket.delegate = nil;
|
||||
_webSocket = nil;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTInspectorRemoteConnection
|
||||
|
||||
RCT_NOT_IMPLEMENTED(-(instancetype)init)
|
||||
|
||||
- (instancetype)initWithPackagerConnection:(RCTInspectorPackagerConnection *)owningPackagerConnection
|
||||
pageId:(NSString *)pageId
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_owningPackagerConnection = owningPackagerConnection;
|
||||
_pageId = pageId;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)onMessage:(NSString *)message
|
||||
{
|
||||
[_owningPackagerConnection sendWrappedEvent:_pageId message:message];
|
||||
}
|
||||
|
||||
- (void)onDisconnect
|
||||
{
|
||||
RCTInspectorPackagerConnection *owningPackagerConnectionStrong = _owningPackagerConnection;
|
||||
if (owningPackagerConnectionStrong) {
|
||||
[owningPackagerConnectionStrong removeConnectionForPage:_pageId];
|
||||
[owningPackagerConnectionStrong sendEvent:@"disconnect" payload:makePageIdPayload(_pageId)];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -2184,13 +2184,6 @@ public final class com/facebook/react/devsupport/InspectorFlags {
|
||||
public static final fun getFuseboxEnabled ()Z
|
||||
}
|
||||
|
||||
public class com/facebook/react/devsupport/InspectorPackagerConnection : com/facebook/react/devsupport/IInspectorPackagerConnection {
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;)V
|
||||
public fun closeQuietly ()V
|
||||
public fun connect ()V
|
||||
public fun sendEventToAllConnections (Ljava/lang/String;)V
|
||||
}
|
||||
|
||||
public class com/facebook/react/devsupport/JSCHeapCapture : com/facebook/fbreact/specs/NativeJSCHeapCaptureSpec {
|
||||
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;)V
|
||||
public fun captureComplete (Ljava/lang/String;Ljava/lang/String;)V
|
||||
|
||||
+2
-8
@@ -210,14 +210,8 @@ public class DevServerHelper {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
if (InspectorFlags.getFuseboxEnabled()) {
|
||||
mInspectorPackagerConnection =
|
||||
new CxxInspectorPackagerConnection(getInspectorDeviceUrl(), mPackageName);
|
||||
} else {
|
||||
// TODO(T190163403): Remove legacy InspectorPackagerConnection
|
||||
mInspectorPackagerConnection =
|
||||
new InspectorPackagerConnection(getInspectorDeviceUrl(), mPackageName);
|
||||
}
|
||||
mInspectorPackagerConnection =
|
||||
new CxxInspectorPackagerConnection(getInspectorDeviceUrl(), mPackageName);
|
||||
mInspectorPackagerConnection.connect();
|
||||
return null;
|
||||
}
|
||||
|
||||
-314
@@ -1,314 +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.
|
||||
*/
|
||||
|
||||
package com.facebook.react.devsupport;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.react.bridge.Inspector;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.WebSocket;
|
||||
import okhttp3.WebSocketListener;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class InspectorPackagerConnection implements IInspectorPackagerConnection {
|
||||
private static final String TAG = "InspectorPackagerConnection";
|
||||
|
||||
private final Connection mConnection;
|
||||
private final Map<String, Inspector.LocalConnection> mInspectorConnections;
|
||||
private final String mPackageName;
|
||||
|
||||
public InspectorPackagerConnection(String url, String packageName) {
|
||||
mConnection = new Connection(url);
|
||||
mInspectorConnections = new HashMap<>();
|
||||
mPackageName = packageName;
|
||||
}
|
||||
|
||||
public void connect() {
|
||||
mConnection.connect();
|
||||
}
|
||||
|
||||
public void closeQuietly() {
|
||||
mConnection.close();
|
||||
}
|
||||
|
||||
public void sendEventToAllConnections(String event) {
|
||||
for (Map.Entry<String, Inspector.LocalConnection> inspectorConnectionEntry :
|
||||
mInspectorConnections.entrySet()) {
|
||||
Inspector.LocalConnection inspectorConnection = inspectorConnectionEntry.getValue();
|
||||
inspectorConnection.sendMessage(event);
|
||||
}
|
||||
}
|
||||
|
||||
void handleProxyMessage(JSONObject message) throws JSONException, IOException {
|
||||
String event = message.getString("event");
|
||||
switch (event) {
|
||||
case "getPages":
|
||||
sendEvent("getPages", getPages());
|
||||
break;
|
||||
case "wrappedEvent":
|
||||
handleWrappedEvent(message.getJSONObject("payload"));
|
||||
break;
|
||||
case "connect":
|
||||
handleConnect(message.getJSONObject("payload"));
|
||||
break;
|
||||
case "disconnect":
|
||||
handleDisconnect(message.getJSONObject("payload"));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown event: " + event);
|
||||
}
|
||||
}
|
||||
|
||||
void closeAllConnections() {
|
||||
for (Map.Entry<String, Inspector.LocalConnection> entry : mInspectorConnections.entrySet()) {
|
||||
entry.getValue().disconnect();
|
||||
}
|
||||
mInspectorConnections.clear();
|
||||
}
|
||||
|
||||
private void handleConnect(JSONObject payload) throws JSONException {
|
||||
final String pageId = payload.getString("pageId");
|
||||
Inspector.LocalConnection inspectorConnection = mInspectorConnections.remove(pageId);
|
||||
if (inspectorConnection != null) {
|
||||
throw new IllegalStateException("Already connected: " + pageId);
|
||||
}
|
||||
|
||||
try {
|
||||
// TODO: Use strings for id's too
|
||||
inspectorConnection =
|
||||
Inspector.connect(
|
||||
Integer.parseInt(pageId),
|
||||
new Inspector.RemoteConnection() {
|
||||
@Override
|
||||
public void onMessage(String message) {
|
||||
try {
|
||||
sendWrappedEvent(pageId, message);
|
||||
} catch (JSONException e) {
|
||||
FLog.w(TAG, "Couldn't send event to packager", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnect() {
|
||||
try {
|
||||
mInspectorConnections.remove(pageId);
|
||||
sendEvent("disconnect", makePageIdPayload(pageId));
|
||||
} catch (JSONException e) {
|
||||
FLog.w(TAG, "Couldn't send event to packager", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
mInspectorConnections.put(pageId, inspectorConnection);
|
||||
} catch (Exception e) {
|
||||
FLog.w(TAG, "Failed to open page: " + pageId, e);
|
||||
sendEvent("disconnect", makePageIdPayload(pageId));
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDisconnect(JSONObject payload) throws JSONException {
|
||||
final String pageId = payload.getString("pageId");
|
||||
Inspector.LocalConnection inspectorConnection = mInspectorConnections.remove(pageId);
|
||||
if (inspectorConnection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
inspectorConnection.disconnect();
|
||||
}
|
||||
|
||||
private void handleWrappedEvent(JSONObject payload) throws JSONException {
|
||||
final String pageId = payload.getString("pageId");
|
||||
String wrappedEvent = payload.getString("wrappedEvent");
|
||||
Inspector.LocalConnection inspectorConnection = mInspectorConnections.get(pageId);
|
||||
if (inspectorConnection == null) {
|
||||
// This tends to happen during reloads, so don't panic.
|
||||
FLog.w(TAG, "PageID " + pageId + " is disconnected. Dropping event: " + wrappedEvent);
|
||||
return;
|
||||
}
|
||||
inspectorConnection.sendMessage(wrappedEvent);
|
||||
}
|
||||
|
||||
private JSONArray getPages() throws JSONException {
|
||||
List<Inspector.Page> pages = Inspector.getPages();
|
||||
JSONArray array = new JSONArray();
|
||||
for (Inspector.Page page : pages) {
|
||||
JSONObject jsonPage = new JSONObject();
|
||||
jsonPage.put("id", String.valueOf(page.getId()));
|
||||
jsonPage.put("title", page.getTitle());
|
||||
jsonPage.put("app", mPackageName);
|
||||
jsonPage.put("vm", page.getVM());
|
||||
array.put(jsonPage);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
private void sendWrappedEvent(String pageId, String message) throws JSONException {
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("pageId", pageId);
|
||||
payload.put("wrappedEvent", message);
|
||||
sendEvent("wrappedEvent", payload);
|
||||
}
|
||||
|
||||
private void sendEvent(String name, Object payload) throws JSONException {
|
||||
JSONObject jsonMessage = new JSONObject();
|
||||
jsonMessage.put("event", name);
|
||||
jsonMessage.put("payload", payload);
|
||||
mConnection.send(jsonMessage);
|
||||
}
|
||||
|
||||
private JSONObject makePageIdPayload(String pageId) throws JSONException {
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("pageId", pageId);
|
||||
return payload;
|
||||
}
|
||||
|
||||
private class Connection extends WebSocketListener {
|
||||
private static final int RECONNECT_DELAY_MS = 2000;
|
||||
|
||||
private final String mUrl;
|
||||
|
||||
private OkHttpClient mHttpClient;
|
||||
private @Nullable WebSocket mWebSocket;
|
||||
private final Handler mHandler;
|
||||
private boolean mClosed;
|
||||
private boolean mSuppressConnectionErrors;
|
||||
|
||||
public Connection(String url) {
|
||||
mUrl = url;
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(WebSocket webSocket, Response response) {
|
||||
mWebSocket = webSocket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
|
||||
if (mWebSocket != null) {
|
||||
abort("Websocket exception", t);
|
||||
}
|
||||
if (!mClosed) {
|
||||
reconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocket webSocket, String text) {
|
||||
try {
|
||||
handleProxyMessage(new JSONObject(text));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed(WebSocket webSocket, int code, String reason) {
|
||||
mWebSocket = null;
|
||||
closeAllConnections();
|
||||
if (!mClosed) {
|
||||
reconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public void connect() {
|
||||
if (mClosed) {
|
||||
throw new IllegalStateException("Can't connect closed client");
|
||||
}
|
||||
if (mHttpClient == null) {
|
||||
mHttpClient =
|
||||
new OkHttpClient.Builder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.writeTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(0, TimeUnit.MINUTES) // Disable timeouts for read
|
||||
.build();
|
||||
}
|
||||
|
||||
Request request = new Request.Builder().url(mUrl).build();
|
||||
mHttpClient.newWebSocket(request, this);
|
||||
}
|
||||
|
||||
private void reconnect() {
|
||||
if (mClosed) {
|
||||
throw new IllegalStateException("Can't reconnect closed client");
|
||||
}
|
||||
if (!mSuppressConnectionErrors) {
|
||||
FLog.w(TAG, "Couldn't connect to packager, will silently retry");
|
||||
mSuppressConnectionErrors = true;
|
||||
}
|
||||
mHandler.postDelayed(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// check that we haven't been closed in the meantime
|
||||
if (!mClosed) {
|
||||
connect();
|
||||
}
|
||||
}
|
||||
},
|
||||
RECONNECT_DELAY_MS);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
mClosed = true;
|
||||
if (mWebSocket != null) {
|
||||
try {
|
||||
mWebSocket.close(1000, "End of session");
|
||||
} catch (Exception e) {
|
||||
// swallow, no need to handle it here
|
||||
}
|
||||
mWebSocket = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void send(final JSONObject object) {
|
||||
new AsyncTask<WebSocket, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(WebSocket... sockets) {
|
||||
if (sockets == null || sockets.length == 0) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
sockets[0].send(object.toString());
|
||||
} catch (Exception e) {
|
||||
FLog.w(TAG, "Couldn't send event to packager", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}.execute(mWebSocket);
|
||||
}
|
||||
|
||||
private void abort(String message, Throwable cause) {
|
||||
FLog.e(TAG, "Error occurred, shutting down websocket connection: " + message, cause);
|
||||
closeAllConnections();
|
||||
closeWebSocketQuietly();
|
||||
}
|
||||
|
||||
private void closeWebSocketQuietly() {
|
||||
if (mWebSocket != null) {
|
||||
try {
|
||||
mWebSocket.close(1000, "End of session");
|
||||
} catch (Exception e) {
|
||||
// swallow, no need to handle it here
|
||||
}
|
||||
mWebSocket = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user