mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Split JSPackagerWebSocketClient into JSPackagerClient and ReconnectingWebSocket
Reviewed By: cwdick Differential Revision: D4495054 fbshipit-source-id: 49c634dde789317270c711370dfbdc82f70f44cd
This commit is contained in:
committed by
Facebook Github Bot
parent
0ea47424ff
commit
47616d84d8
+170
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc. All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the LICENSE file in the root
|
||||
* directory of this source tree. An additional grant of patent rights can be found in the PATENTS
|
||||
* file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.packagerconnection;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import com.facebook.common.logging.FLog;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import okhttp3.ws.WebSocket;
|
||||
import okhttp3.ws.WebSocketCall;
|
||||
import okhttp3.ws.WebSocketListener;
|
||||
import okio.Buffer;
|
||||
|
||||
/**
|
||||
* A wrapper around WebSocketClient that reconnects automatically
|
||||
*/
|
||||
final public class ReconnectingWebSocket implements WebSocketListener {
|
||||
private static final String TAG = ReconnectingWebSocket.class.getSimpleName();
|
||||
|
||||
private static final int RECONNECT_DELAY_MS = 2000;
|
||||
|
||||
static public class WebSocketSender {
|
||||
private WebSocket mWebSocket;
|
||||
|
||||
public WebSocketSender(WebSocket webSocket) {
|
||||
mWebSocket = webSocket;
|
||||
}
|
||||
|
||||
public void sendMessage(RequestBody requestBody) throws IOException {
|
||||
mWebSocket.sendMessage(requestBody);
|
||||
}
|
||||
}
|
||||
|
||||
public interface MessageCallback {
|
||||
void onMessage(@Nullable WebSocketSender webSocket, ResponseBody message);
|
||||
}
|
||||
|
||||
private final String mUrl;
|
||||
private final Handler mHandler;
|
||||
private boolean mClosed = false;
|
||||
private boolean mSuppressConnectionErrors;
|
||||
private @Nullable WebSocket mWebSocket;
|
||||
private @Nullable MessageCallback mCallback;
|
||||
|
||||
public ReconnectingWebSocket(String url, MessageCallback callback) {
|
||||
super();
|
||||
mUrl = url;
|
||||
mCallback = callback;
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
}
|
||||
|
||||
public void connect() {
|
||||
if (mClosed) {
|
||||
throw new IllegalStateException("Can't connect closed client");
|
||||
}
|
||||
|
||||
OkHttpClient httpClient = 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();
|
||||
WebSocketCall call = WebSocketCall.create(httpClient, request);
|
||||
call.enqueue(this);
|
||||
}
|
||||
|
||||
private synchronized void delayedReconnect() {
|
||||
// check that we haven't been closed in the meantime
|
||||
if (!mClosed) {
|
||||
connect();
|
||||
}
|
||||
}
|
||||
|
||||
private void reconnect() {
|
||||
if (mClosed) {
|
||||
throw new IllegalStateException("Can't reconnect closed client");
|
||||
}
|
||||
|
||||
if (!mSuppressConnectionErrors) {
|
||||
FLog.w(TAG, "Couldn't connect to \"" + mUrl + "\", will silently retry");
|
||||
mSuppressConnectionErrors = true;
|
||||
}
|
||||
|
||||
mHandler.postDelayed(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delayedReconnect();
|
||||
}
|
||||
},
|
||||
RECONNECT_DELAY_MS);
|
||||
}
|
||||
|
||||
public void closeQuietly() {
|
||||
mClosed = true;
|
||||
closeWebSocketQuietly();
|
||||
mCallback = null;
|
||||
}
|
||||
|
||||
private void closeWebSocketQuietly() {
|
||||
if (mWebSocket != null) {
|
||||
try {
|
||||
mWebSocket.close(1000, "End of session");
|
||||
} catch (IOException e) {
|
||||
// swallow, no need to handle it here
|
||||
}
|
||||
mWebSocket = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void abort(String message, Throwable cause) {
|
||||
FLog.e(TAG, "Error occurred, shutting down websocket connection: " + message, cause);
|
||||
closeWebSocketQuietly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onOpen(WebSocket webSocket, Response response) {
|
||||
mWebSocket = webSocket;
|
||||
mSuppressConnectionErrors = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onFailure(IOException e, Response response) {
|
||||
if (mWebSocket != null) {
|
||||
abort("Websocket exception", e);
|
||||
}
|
||||
if (!mClosed) {
|
||||
reconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onMessage(ResponseBody message) {
|
||||
if (mCallback != null) {
|
||||
WebSocketSender webSocketSender = mWebSocket == null
|
||||
? null
|
||||
: new WebSocketSender(mWebSocket);
|
||||
mCallback.onMessage(webSocketSender, message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onPong(Buffer payload) { }
|
||||
|
||||
@Override
|
||||
public synchronized void onClose(int code, String reason) {
|
||||
mWebSocket = null;
|
||||
if (!mClosed) {
|
||||
reconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user