Files
react-native/ReactAndroid/src/main/java/com/facebook/react/packagerconnection/ReconnectingWebSocket.java
T
Emil Sjolander 93a1d592d6 Update okhttp3
Reviewed By: bestander

Differential Revision: D5078004

fbshipit-source-id: 79c66cedeeb682d8bb4e67798b41115899fd1c81
2017-05-18 08:16:02 -07:00

198 lines
5.1 KiB
Java

/**
* 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.nio.channels.ClosedChannelException;
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.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;
/**
* A wrapper around WebSocketClient that reconnects automatically
*/
final public class ReconnectingWebSocket extends WebSocketListener {
private static final String TAG = ReconnectingWebSocket.class.getSimpleName();
private static final int RECONNECT_DELAY_MS = 2000;
public interface MessageCallback {
void onMessage(String text);
void onMessage(ByteString bytes);
}
public interface ConnectionCallback {
void onConnected();
void onDisconnected();
}
private final String mUrl;
private final Handler mHandler;
private boolean mClosed = false;
private boolean mSuppressConnectionErrors;
private @Nullable WebSocket mWebSocket;
private @Nullable MessageCallback mMessageCallback;
private @Nullable ConnectionCallback mConnectionCallback;
public ReconnectingWebSocket(
String url,
MessageCallback messageCallback,
ConnectionCallback connectionCallback) {
super();
mUrl = url;
mMessageCallback = messageCallback;
mConnectionCallback = connectionCallback;
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();
httpClient.newWebSocket(request, 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();
mMessageCallback = null;
if (mConnectionCallback != null) {
mConnectionCallback.onDisconnected();
}
}
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;
}
}
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;
if (mConnectionCallback != null) {
mConnectionCallback.onConnected();
}
}
@Override
public synchronized void onFailure(WebSocket webSocket, Throwable t, Response response) {
if (mWebSocket != null) {
abort("Websocket exception", t);
}
if (!mClosed) {
if (mConnectionCallback != null) {
mConnectionCallback.onDisconnected();
}
reconnect();
}
}
@Override
public synchronized void onMessage(WebSocket webSocket, String text) {
if (mMessageCallback != null) {
mMessageCallback.onMessage(text);
}
}
@Override
public synchronized void onMessage(WebSocket webSocket, ByteString bytes) {
if (mMessageCallback != null) {
mMessageCallback.onMessage(bytes);
}
}
@Override
public synchronized void onClosed(WebSocket webSocket, int code, String reason) {
mWebSocket = null;
if (!mClosed) {
if (mConnectionCallback != null) {
mConnectionCallback.onDisconnected();
}
reconnect();
}
}
public synchronized void sendMessage(String message) throws IOException {
if (mWebSocket != null) {
mWebSocket.send(message);
} else {
throw new ClosedChannelException();
}
}
public synchronized void sendMessage(ByteString message) throws IOException {
if (mWebSocket != null) {
mWebSocket.send(message);
} else {
throw new ClosedChannelException();
}
}
}