Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reconnect OkHttp websocket when internet disconnects

I have the following class. I'm trying to have the WebSocket reconnect in case of failure

public class WebSocketClient extends WebSocketListener {
    volatile OkHttpClient client;
    volatile WebSocket webSocket;
    volatile Boolean isConnected = false;

    public WebSocketClient() {
        Proxy proxy = null;

        if (Main.useProxy) {
            tinder.CustomProxy proxyCustom = ProxyManager.GetStaticProxy(ThreadLocalManager.account.get().getProxyId());
            proxy = new Proxy(Proxy.Type.HTTP,
                    new InetSocketAddress(proxyCustom.getProxyIp(), proxyCustom.getProxyPort()));
        }

        client = new OkHttpClient.Builder().proxy(proxy).readTimeout(2, TimeUnit.SECONDS)
                .connectTimeout(2, TimeUnit.SECONDS).build();


        Request request = new Request.Builder().url("wss://echo.com/ws")
                .addHeader("Accept-Language", "en").build();
        webSocket = client.newWebSocket(request, this);
    }

    @Override
    public void onOpen(WebSocket webSocket, Response response) {
        AnsiConsole.out.println(Ansi.ansi().fg(Ansi.Color.GREEN).a("Socket connection successful").reset());
        isConnected = true;
    }

    @Override
    public void onMessage(WebSocket webSocket, String text) {
        System.out.println("Text MESSAGE: " + text);
    }

    @Override
    public void onMessage(WebSocket webSocket, ByteString bytes) {

    }

    @Override
    public void onClosing(WebSocket webSocket, int code, String reason) {
        webSocket.close(1000, null);
        System.out.println("CLOSE: " + code + " " + reason);
        isConnected = false;
    }

    @Override
    public void onFailure(WebSocket webSocket, Throwable t, Response response) {
        isConnected = false;
        AnsiConsole.out
                .println(Ansi.ansi().fg(Ansi.Color.RED).a("Socket connection failed! will try to reconnect").reset());

        while (!isConnected) {
            try {
                AnsiConsole.out
                        .println(Ansi.ansi().fg(Ansi.Color.YELLOW).a("Waiting to try socket connection!").reset());
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            Request request = new Request.Builder().url("wss://echo.com/ws")
                    .addHeader("Accept-Language", "en").build();
            webSocket = client.newWebSocket(request, this);
        }

        if (isConnected) {
            AnsiConsole.out.println(Ansi.ansi().fg(Ansi.Color.GREEN).a("Socket connection successful").reset());
        }
    }

    public void close() {
        if (webSocket != null) {
            webSocket.close(1000, "Connection closed");
        }
        client.dispatcher().executorService().shutdown();
    }

}

The problem is if it takes a few attempts to reconnect, then the onFailure method will get called multiple times. Causing multiple web socket connections instead of one.

How can I have the single connection reconnect when the websocket disconnects?

like image 329
Arya Avatar asked Jan 08 '19 08:01

Arya


2 Answers

public class WebSocketClient extends WebSocketListener {
    volatile OkHttpClient client;
    volatile WebSocket webSocket;
    volatile Boolean isConnected = false;

    public WebSocketClient() {
        Proxy proxy = null;

        if (Main.useProxy) {
            tinder.CustomProxy proxyCustom = ProxyManager.GetStaticProxy(ThreadLocalManager.account.get().getProxyId());
            proxy = new Proxy(Proxy.Type.HTTP,
                    new InetSocketAddress(proxyCustom.getProxyIp(), proxyCustom.getProxyPort()));
        }

        client = new OkHttpClient.Builder().proxy(proxy).readTimeout(2, TimeUnit.SECONDS)
                .connectTimeout(2, TimeUnit.SECONDS).build();

        Request request = new Request.Builder().url("wss://echo.com/ws")
                .addHeader("Accept-Language", "en").build();
        webSocket = client.newWebSocket(request, this);

        // First Change
        client.connectionPool.evictAll();
    }

    @Override
    public void onOpen(WebSocket webSocket, Response response) {
        AnsiConsole.out.println(Ansi.ansi().fg(Ansi.Color.GREEN).a("Socket connection successful").reset());
        isConnected = true;
    }

    @Override
    public void onMessage(WebSocket webSocket, String text) {
        System.out.println("Text MESSAGE: " + text);
    }

    @Override
    public void onMessage(WebSocket webSocket, ByteString bytes) {

    }

    @Override
    public void onClosing(WebSocket webSocket, int code, String reason) {
        webSocket.close(1000, null);
        System.out.println("CLOSE: " + code + " " + reason);
        isConnected = false;
    }

    @Override
    public void onFailure(WebSocket webSocket, Throwable t, Response response) {
        // Second Change
        webSocket.close(1000, null);
        close();
        Thread.sleep(10000);

        Request request = new Request.Builder().url("wss://echo.com/ws")
                .addHeader("Accept-Language", "en").build();
        webSocket = client.newWebSocket(request, this);
    }

    public void close() {
        if (webSocket != null) {
            webSocket.close(1000, "Connection closed");
        }
    }
}
like image 140
JsonX Avatar answered Sep 18 '22 03:09

JsonX


For multiple idle connection client provide a connectionPool

client.connectionPool().evictAll();

the evictAll() method evicts all the connections.

like image 24
Deepak Avatar answered Sep 17 '22 03:09

Deepak