导航菜单

页面标题

页面副标题

St.John's v1.0.9 - ConnectionManager.java 源代码

正在查看: St.John's v1.0.9 应用的 ConnectionManager.java JAVA 源代码文件

本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。


package io.ably.lib.transport;

import com.microsoft.identity.common.java.providers.microsoft.MicrosoftAuthorizationErrorResponse;
import cz.msebera.android.httpclient.HttpStatus;
import io.ably.lib.debug.DebugOptions;
import io.ably.lib.http.HttpHelpers;
import io.ably.lib.realtime.AblyRealtime;
import io.ably.lib.realtime.Channel;
import io.ably.lib.realtime.CompletionListener;
import io.ably.lib.realtime.Connection;
import io.ably.lib.realtime.ConnectionState;
import io.ably.lib.realtime.ConnectionStateListener;
import io.ably.lib.transport.ITransport;
import io.ably.lib.transport.NetworkConnectivity;
import io.ably.lib.types.AblyException;
import io.ably.lib.types.ClientOptions;
import io.ably.lib.types.ConnectionDetails;
import io.ably.lib.types.ErrorInfo;
import io.ably.lib.types.ProtocolMessage;
import io.ably.lib.types.ProtocolSerializer;
import io.ably.lib.util.Log;
import io.ably.lib.util.PlatformAgentProvider;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class ConnectionManager implements ITransport.ConnectListener {
    private static final long HEARTBEAT_TIMEOUT = 5000;
    private static final String INTERNET_CHECK_OK = "yes";
    private static final String INTERNET_CHECK_URL = "https://internet-up.ably-realtime.com/is-the-internet-up.txt";
    private static final String TAG = "io.ably.lib.transport.ConnectionManager";
    final AblyRealtime ably;
    private final Channels channels;
    private final Connection connection;
    private long connectionStateTtl;
    private CMConnectivityListener connectivityListener;
    private State currentState;
    private Thread handlerThread;
    private final Hosts hosts;
    private long lastActivity;
    private String lastUsedHost;
    long maxIdleInterval;
    private long msgSerial;
    private ConnectParams pendingConnect;
    private final PlatformAgentProvider platformAgentProvider;
    private final DebugOptions.RawProtocolListener protocolListener;
    private ErrorInfo stateError;
    private final Map<ConnectionState, State> states;
    private boolean suppressRetry;
    private long suspendTime;
    private ITransport transport;
    private final ITransport.Factory transportFactory;
    static ErrorInfo REASON_CLOSED = new ErrorInfo("Can't attach when not in an active state", HttpStatus.SC_OK, 10000);
    static ErrorInfo REASON_DISCONNECTED = new ErrorInfo("Connection temporarily unavailable", HttpStatus.SC_SERVICE_UNAVAILABLE, 80003);
    static ErrorInfo REASON_SUSPENDED = new ErrorInfo("Connection unavailable", HttpStatus.SC_SERVICE_UNAVAILABLE, 80002);
    static ErrorInfo REASON_FAILED = new ErrorInfo("Connection failed", 400, 80000);
    static ErrorInfo REASON_REFUSED = new ErrorInfo("Access refused", HttpStatus.SC_UNAUTHORIZED, 40100);
    static ErrorInfo REASON_TOO_BIG = new ErrorInfo("Connection closed; message too large", 400, 40000);
    private final List<QueuedMessage> queuedMessages = new ArrayList();
    private final PendingMessageQueue pendingMessages = new PendingMessageQueue(this, 0 == true ? 1 : 0);
    private final HashSet<Object> heartbeatWaiters = new HashSet<>();
    private final ActionQueue actionQueue = new ActionQueue(0 == true ? 1 : 0);

    private interface Action extends Runnable {
    }

    public interface Channels {
        void onMessage(ProtocolMessage protocolMessage);

        void suspendAll(ErrorInfo errorInfo, boolean z);

        Iterable<Channel> values();
    }

    public static class StateIndication {
        final String currentHost;
        final String fallback;
        final ErrorInfo reason;
        final ConnectionState state;

        StateIndication(ConnectionState connectionState) {
            this(connectionState, null);
        }

        public StateIndication(ConnectionState connectionState, ErrorInfo errorInfo) {
            this(connectionState, errorInfo, null, null);
        }

        StateIndication(ConnectionState connectionState, ErrorInfo errorInfo, String str, String str2) {
            this.state = connectionState;
            this.reason = errorInfo;
            this.fallback = str;
            this.currentHost = str2;
        }
    }

    public abstract class State {
        public final ErrorInfo defaultErrorInfo;
        public final boolean queueEvents;
        public final boolean sendEvents;
        public final ConnectionState state;
        final boolean terminal;
        public final long timeout;

        void enactForChannel(StateIndication stateIndication, ConnectionStateListener.ConnectionStateChange connectionStateChange, Channel channel) {
        }

        StateIndication onTimeout() {
            return null;
        }

        abstract StateIndication validateTransition(StateIndication stateIndication);

        State(ConnectionState connectionState, boolean z, boolean z2, boolean z3, long j, ErrorInfo errorInfo) {
            this.state = connectionState;
            this.queueEvents = z;
            this.sendEvents = z2;
            this.terminal = z3;
            this.timeout = j;
            this.defaultErrorInfo = errorInfo;
        }

        void enact(StateIndication stateIndication, ConnectionStateListener.ConnectionStateChange connectionStateChange) {
            if (connectionStateChange != null) {
                if (this.sendEvents) {
                    ConnectionManager.this.sendQueuedMessages();
                } else if (!this.queueEvents) {
                    ConnectionManager.this.failQueuedMessages(stateIndication.reason);
                }
                Iterator<Channel> it = ConnectionManager.this.channels.values().iterator();
                while (it.hasNext()) {
                    enactForChannel(stateIndication, connectionStateChange, it.next());
                }
            }
        }
    }

    class Initialized extends State {
        Initialized() {
            super(ConnectionState.initialized, true, false, false, 0L, null);
        }

        @Override
        StateIndication validateTransition(StateIndication stateIndication) {
            if (stateIndication.state == this.state) {
                return null;
            }
            return stateIndication;
        }
    }

    class Connecting extends State {
        @Override
        StateIndication validateTransition(StateIndication stateIndication) {
            return stateIndication;
        }

        Connecting() {
            super(ConnectionState.connecting, true, false, false, Defaults.TIMEOUT_CONNECT, null);
        }

        @Override
        StateIndication onTimeout() {
            return ConnectionManager.this.checkSuspended(null);
        }

        @Override
        void enact(StateIndication stateIndication, ConnectionStateListener.ConnectionStateChange connectionStateChange) {
            super.enact(stateIndication, connectionStateChange);
            ConnectionManager.this.connectImpl(stateIndication);
        }
    }

    class Connected extends State {
        Connected() {
            super(ConnectionState.connected, false, true, false, 0L, null);
        }

        @Override
        StateIndication validateTransition(StateIndication stateIndication) {
            if (stateIndication.state != this.state) {
                return stateIndication;
            }
            ConnectionManager connectionManager = ConnectionManager.this;
            connectionManager.addAction(connectionManager.new UpdateAction(null));
            return null;
        }

        @Override
        void enactForChannel(StateIndication stateIndication, ConnectionStateListener.ConnectionStateChange connectionStateChange, Channel channel) {
            channel.setConnected();
        }
    }

    class Disconnected extends State {
        @Override
        void enactForChannel(StateIndication stateIndication, ConnectionStateListener.ConnectionStateChange connectionStateChange, Channel channel) {
        }

        Disconnected() {
            super(ConnectionState.disconnected, true, false, false, Defaults.TIMEOUT_DISCONNECT, ConnectionManager.REASON_DISCONNECTED);
        }

        @Override
        StateIndication validateTransition(StateIndication stateIndication) {
            if (stateIndication.state == this.state) {
                return null;
            }
            return stateIndication.state == ConnectionState.closing ? new StateIndication(ConnectionState.closed) : stateIndication;
        }

        @Override
        StateIndication onTimeout() {
            return new StateIndication(ConnectionState.connecting);
        }

        @Override
        void enact(StateIndication stateIndication, ConnectionStateListener.ConnectionStateChange connectionStateChange) {
            super.enact(stateIndication, connectionStateChange);
            ConnectionManager.this.clearTransport();
            if (connectionStateChange.previous == ConnectionState.connected) {
                ConnectionManager.this.setSuspendTime();
                if (ConnectionManager.this.suppressRetry) {
                    return;
                }
                ConnectionManager.this.requestState(ConnectionState.connecting);
            }
        }
    }

    class Suspended extends State {
        Suspended() {
            super(ConnectionState.suspended, false, false, false, Defaults.connectionStateTtl, ConnectionManager.REASON_SUSPENDED);
        }

        @Override
        StateIndication validateTransition(StateIndication stateIndication) {
            if (stateIndication.state == this.state) {
                return null;
            }
            return stateIndication.state == ConnectionState.closing ? new StateIndication(ConnectionState.closed) : stateIndication;
        }

        @Override
        StateIndication onTimeout() {
            return new StateIndication(ConnectionState.connecting);
        }

        @Override
        void enactForChannel(StateIndication stateIndication, ConnectionStateListener.ConnectionStateChange connectionStateChange, Channel channel) {
            channel.setSuspended(this.defaultErrorInfo, true);
        }
    }

    class Closing extends State {
        Closing() {
            super(ConnectionState.closing, false, false, false, Defaults.TIMEOUT_CONNECT, ConnectionManager.REASON_CLOSED);
        }

        @Override
        StateIndication validateTransition(StateIndication stateIndication) {
            if (stateIndication.state == this.state) {
                return null;
            }
            return (stateIndication.state == ConnectionState.disconnected || stateIndication.state == ConnectionState.suspended) ? new StateIndication(ConnectionState.closed) : stateIndication;
        }

        @Override
        StateIndication onTimeout() {
            return new StateIndication(ConnectionState.closed);
        }

        @Override
        void enact(StateIndication stateIndication, ConnectionStateListener.ConnectionStateChange connectionStateChange) {
            super.enact(stateIndication, connectionStateChange);
            if (ConnectionManager.this.closeImpl()) {
                ConnectionManager connectionManager = ConnectionManager.this;
                connectionManager.addAction(connectionManager.new AsynchronousStateChangeAction(ConnectionState.closed));
            }
        }
    }

    class Closed extends State {
        Closed() {
            super(ConnectionState.closed, false, false, true, 0L, ConnectionManager.REASON_CLOSED);
        }

        @Override
        StateIndication validateTransition(StateIndication stateIndication) {
            if (stateIndication.state == ConnectionState.connecting) {
                return stateIndication;
            }
            return null;
        }

        @Override
        void enactForChannel(StateIndication stateIndication, ConnectionStateListener.ConnectionStateChange connectionStateChange, Channel channel) {
            channel.setConnectionClosed(ConnectionManager.REASON_CLOSED);
        }
    }

    class Failed extends State {
        Failed() {
            super(ConnectionState.failed, false, false, true, 0L, ConnectionManager.REASON_FAILED);
        }

        @Override
        StateIndication validateTransition(StateIndication stateIndication) {
            if (stateIndication.state == ConnectionState.connecting) {
                return stateIndication;
            }
            return null;
        }

        @Override
        void enactForChannel(StateIndication stateIndication, ConnectionStateListener.ConnectionStateChange connectionStateChange, Channel channel) {
            channel.setConnectionFailed(stateIndication.reason);
        }

        @Override
        void enact(StateIndication stateIndication, ConnectionStateListener.ConnectionStateChange connectionStateChange) {
            super.enact(stateIndication, connectionStateChange);
            ConnectionManager.this.clearTransport();
        }
    }

    public ErrorInfo getStateErrorInfo() {
        ErrorInfo errorInfo = this.stateError;
        return errorInfo != null ? errorInfo : this.currentState.defaultErrorInfo;
    }

    public boolean isActive() {
        return this.currentState.queueEvents || this.currentState.sendEvents;
    }

    private class ConnectionWaiter implements ConnectionStateListener {
        private ConnectionStateListener.ConnectionStateChange change;
        private boolean closed;

        ConnectionWaiter(ConnectionManager connectionManager, AnonymousClass1 anonymousClass1) {
            this();
        }

        private ConnectionWaiter() {
            this.closed = false;
            ConnectionManager.this.connection.on(this);
        }

        public synchronized ErrorInfo waitForChange() {
            ErrorInfo errorInfo;
            if (!this.closed) {
                Log.d(ConnectionManager.TAG, "ConnectionWaiter.waitFor()");
                if (this.change == null) {
                    try {
                        wait();
                    } catch (InterruptedException unused) {
                    }
                }
                Log.d(ConnectionManager.TAG, "ConnectionWaiter.waitFor done: currentState=" + ConnectionManager.this.currentState + ")");
                errorInfo = this.change.reason;
                this.change = null;
            } else {
                throw new IllegalStateException("Already closed.");
            }
            return errorInfo;
        }

        @Override
        public synchronized void onConnectionStateChanged(ConnectionStateListener.ConnectionStateChange connectionStateChange) {
            this.change = connectionStateChange;
            notify();
        }

        public void close() {
            if (this.closed) {
                return;
            }
            this.closed = true;
            ConnectionManager.this.connection.off(this);
        }
    }

    private abstract class StateChangeAction {
        protected ConnectionStateListener.ConnectionStateChange change;
        protected final StateIndication stateIndication;
        protected final ITransport transport;

        StateChangeAction(ITransport iTransport, StateIndication stateIndication) {
            this.transport = iTransport;
            this.stateIndication = stateIndication;
        }

        protected void setState() {
            this.change = ConnectionManager.this.setState(this.transport, this.stateIndication);
        }

        protected void enactState() {
            ConnectionStateListener.ConnectionStateChange connectionStateChange = this.change;
            if (connectionStateChange != null) {
                if (connectionStateChange.current != this.change.previous) {
                    ConnectionManager.this.connection.onConnectionStateChange(this.change);
                }
                ((State) ConnectionManager.this.states.get(this.stateIndication.state)).enact(this.stateIndication, this.change);
                if (ConnectionManager.this.currentState.terminal) {
                    ConnectionManager.this.clearTransport();
                }
            }
        }
    }

    private class SynchronousStateChangeAction extends StateChangeAction implements Action {
        SynchronousStateChangeAction(ITransport iTransport, StateIndication stateIndication) {
            super(iTransport, stateIndication);
            setState();
        }

        @Override
        public void run() {
            enactState();
        }
    }

    private class AsynchronousStateChangeAction extends StateChangeAction implements Action {
        AsynchronousStateChangeAction(ConnectionState connectionState) {
            super(null, new StateIndication(connectionState, null));
        }

        AsynchronousStateChangeAction(ITransport iTransport, StateIndication stateIndication) {
            super(iTransport, stateIndication);
        }

        @Override
        public void run() {
            setState();
            enactState();
        }
    }

    private class ReauthAction implements Action {
        private ReauthAction() {
        }

        ReauthAction(ConnectionManager connectionManager, AnonymousClass1 anonymousClass1) {
            this();
        }

        @Override
        public void run() {
            ConnectionManager.this.handleReauth();
        }
    }

    private class UpdateAction implements Action {
        private final ErrorInfo reason;

        UpdateAction(ErrorInfo errorInfo) {
            this.reason = errorInfo;
        }

        @Override
        public void run() {
            ConnectionManager.this.connection.emitUpdate(this.reason);
        }
    }

    private static class ActionQueue extends ArrayDeque<Action> {
        private ActionQueue() {
        }

        ActionQueue(AnonymousClass1 anonymousClass1) {
            this();
        }

        @Override
        public synchronized boolean add(Action action) {
            return super.add((ActionQueue) action);
        }

        @Override
        public synchronized Action poll() {
            return (Action) super.poll();
        }

        @Override
        public synchronized Action peek() {
            return (Action) super.peek();
        }

        @Override
        public synchronized int size() {
            return super.size();
        }
    }

    public synchronized void addAction(Action action) {
        this.actionQueue.add(action);
        notifyAll();
    }

    class ActionHandler implements Runnable {
        ActionHandler() {
        }

        @Override
        public void run() {
            StateIndication onTimeout;
            while (true) {
                synchronized (ConnectionManager.this) {
                    while (true) {
                        if (ConnectionManager.this.actionQueue.size() != 0) {
                            break;
                        }
                        if (ConnectionManager.this.currentState.terminal) {
                            ConnectionManager.this.handlerThread = null;
                            ConnectionManager.this.stopConnectivityListener();
                            return;
                        }
                        ConnectionManager connectionManager = ConnectionManager.this;
                        connectionManager.tryWait(connectionManager.currentState.timeout);
                        Action peek = ConnectionManager.this.actionQueue.peek();
                        if (peek != null) {
                            Log.d(ConnectionManager.TAG, "Wait ended by action: " + peek.toString());
                            break;
                        }
                        if (!ConnectionManager.this.suppressRetry && (onTimeout = ConnectionManager.this.currentState.onTimeout()) != null) {
                            ConnectionManager.this.requestState(onTimeout);
                        }
                    }
                }
                while (true) {
                    Action poll = ConnectionManager.this.actionQueue.poll();
                    if (poll != null) {
                        try {
                            poll.run();
                        } catch (Exception e) {
                            Log.e(ConnectionManager.TAG, "Action invocation failed with exception: action = " + poll.toString(), e);
                        }
                    }
                }
            }
        }
    }

    public ConnectionManager(AblyRealtime ablyRealtime, Connection connection, Channels channels, PlatformAgentProvider platformAgentProvider) throws AblyException {
        ITransport.Factory factory;
        DebugOptions.RawProtocolListener rawProtocolListener = null;
        HashMap hashMap = new HashMap();
        this.states = hashMap;
        this.connectionStateTtl = Defaults.connectionStateTtl;
        this.maxIdleInterval = Defaults.maxIdleInterval;
        this.ably = ablyRealtime;
        this.connection = connection;
        this.channels = channels;
        this.platformAgentProvider = platformAgentProvider;
        ClientOptions clientOptions = ablyRealtime.options;
        this.hosts = new Hosts(clientOptions.realtimeHost, Defaults.HOST_REALTIME, clientOptions);
        if (clientOptions instanceof DebugOptions) {
            DebugOptions debugOptions = (DebugOptions) clientOptions;
            rawProtocolListener = debugOptions.protocolListener;
            factory = debugOptions.transportFactory;
        } else {
            factory = null;
        }
        this.protocolListener = rawProtocolListener;
        this.transportFactory = factory == null ? Defaults.TRANSPORT : factory;
        hashMap.put(ConnectionState.initialized, new Initialized());
        hashMap.put(ConnectionState.connecting, new Connecting());
        hashMap.put(ConnectionState.connected, new Connected());
        hashMap.put(ConnectionState.disconnected, new Disconnected());
        hashMap.put(ConnectionState.suspended, new Suspended());
        hashMap.put(ConnectionState.closing, new Closing());
        hashMap.put(ConnectionState.closed, new Closed());
        hashMap.put(ConnectionState.failed, new Failed());
        this.currentState = (State) hashMap.get(ConnectionState.initialized);
        setSuspendTime();
    }

    public String getHost() {
        return this.lastUsedHost;
    }

    public synchronized State getConnectionState() {
        return this.currentState;
    }

    public synchronized void connect() {
        if (this.currentState.terminal || this.currentState.state == ConnectionState.initialized) {
            startup();
        }
        requestState(ConnectionState.connecting);
    }

    public void close() {
        requestState(ConnectionState.closing);
    }

    public void requestState(ConnectionState connectionState) {
        requestState(new StateIndication(connectionState, null));
    }

    public void requestState(StateIndication stateIndication) {
        requestState(null, stateIndication);
    }

    private synchronized void requestState(ITransport iTransport, StateIndication stateIndication) {
        Log.v(TAG, "requestState(): requesting " + stateIndication.state + "; id = " + this.connection.id);
        addAction(new AsynchronousStateChangeAction(iTransport, stateIndication));
    }

    public synchronized ConnectionStateListener.ConnectionStateChange setState(ITransport iTransport, StateIndication stateIndication) {
        if (iTransport != null) {
            if (iTransport != this.transport) {
                Log.v(TAG, "setState: action received for superseded transport; discarding");
                return null;
            }
        }
        StateIndication validateTransition = this.currentState.validateTransition(stateIndication);
        if (validateTransition == null) {
            Log.v(TAG, "setState(): not transitioning; not a valid transition " + stateIndication.state);
            return null;
        }
        ConnectionState connectionState = validateTransition.state;
        State state = this.states.get(connectionState);
        ErrorInfo errorInfo = validateTransition.reason;
        if (errorInfo == null) {
            errorInfo = state.defaultErrorInfo;
        }
        Log.v(TAG, "setState(): setting " + state.state + "; reason " + errorInfo);
        ConnectionStateListener.ConnectionStateChange connectionStateChange = new ConnectionStateListener.ConnectionStateChange(this.currentState.state, connectionState, state.timeout, errorInfo);
        this.currentState = state;
        this.stateError = errorInfo;
        return connectionStateChange;
    }

    public void ping(CompletionListener completionListener) {
        HeartbeatWaiter heartbeatWaiter = new HeartbeatWaiter(completionListener);
        if (this.currentState.state == ConnectionState.connected) {
            synchronized (this.heartbeatWaiters) {
                this.heartbeatWaiters.add(heartbeatWaiter);
                heartbeatWaiter.start();
            }
            try {
                send(new ProtocolMessage(ProtocolMessage.Action.heartbeat), false, null);
                return;
            } catch (AblyException e) {
                heartbeatWaiter.onError(e.errorInfo);
                return;
            }
        }
        heartbeatWaiter.onError(new ErrorInfo("Unable to ping service; not connected", 40000, 400));
    }

    private class HeartbeatWaiter extends Thread {
        private final CompletionListener listener;

        HeartbeatWaiter(CompletionListener completionListener) {
            this.listener = completionListener;
        }

        private void onSuccess() {
            clear();
            CompletionListener completionListener = this.listener;
            if (completionListener != null) {
                completionListener.onSuccess();
            }
        }

        public void onError(ErrorInfo errorInfo) {
            clear();
            CompletionListener completionListener = this.listener;
            if (completionListener != null) {
                completionListener.onError(errorInfo);
            }
        }

        private boolean clear() {
            boolean remove = ConnectionManager.this.heartbeatWaiters.remove(this);
            if (remove) {
                interrupt();
            }
            return remove;
        }

        @Override
        public void run() {
            boolean clear;
            synchronized (ConnectionManager.this.heartbeatWaiters) {
                try {
                    ConnectionManager.this.heartbeatWaiters.wait(ConnectionManager.HEARTBEAT_TIMEOUT);
                } catch (InterruptedException unused) {
                }
                clear = clear();
            }
            if (clear) {
                onError(new ErrorInfo("Timed out waiting for heartbeat response", 50000, 500));
            } else {
                onSuccess();
            }
        }
    }

    public void onAuthUpdated(String str, boolean z) throws AblyException {
        ConnectionWaiter connectionWaiter = new ConnectionWaiter(this, null);
        try {
            int i = AnonymousClass1.$SwitchMap$io$ably$lib$realtime$ConnectionState[this.currentState.state.ordinal()];
            if (i == 1) {
                try {
                    ProtocolMessage protocolMessage = new ProtocolMessage(ProtocolMessage.Action.auth);
                    protocolMessage.auth = new ProtocolMessage.AuthDetails(str);
                    send(protocolMessage, false, null);
                } catch (AblyException unused) {
                    Log.v(TAG, "onAuthUpdated: closing transport after send failure");
                    this.transport.close();
                }
            } else if (i == 2) {
                Log.v(TAG, "onAuthUpdated: closing connecting transport");
                requestState(new StateIndication(ConnectionState.disconnected, new ErrorInfo("Aborting incomplete connection with superseded auth params", HttpStatus.SC_SERVICE_UNAVAILABLE, 80003), null, null));
                connect();
            } else {
                connect();
            }
            if (z) {
                boolean z2 = true;
                while (z2) {
                    ErrorInfo waitForChange = connectionWaiter.waitForChange();
                    ConnectionState connectionState = this.currentState.state;
                    int i2 = AnonymousClass1.$SwitchMap$io$ably$lib$realtime$ConnectionState[connectionState.ordinal()];
                    if (i2 == 1) {
                        Log.v(TAG, "onAuthUpdated: got connected");
                        z2 = false;
                    } else {
                        if (i2 != 2 && i2 != 3) {
                            Log.v(TAG, "onAuthUpdated: throwing exception");
                            throw AblyException.fromErrorInfo(waitForChange);
                        }
                        Log.v(TAG, "onAuthUpdated: " + connectionState);
                    }
                }
            }
        } finally {
            connectionWaiter.close();
        }
    }

    public void onAuthError(ErrorInfo errorInfo) {
        Log.i(TAG, String.format("onAuthError: (%d) %s", Integer.valueOf(errorInfo.code), errorInfo.message));
        if (errorInfo.statusCode == 403) {
            this.connection.onConnectionStateChange(new ConnectionStateListener.ConnectionStateChange(this.connection.state, ConnectionState.failed, 0L, errorInfo));
            return;
        }
        int i = AnonymousClass1.$SwitchMap$io$ably$lib$realtime$ConnectionState[this.currentState.state.ordinal()];
        if (i != 1) {
            if (i == 2 && this.transport != null) {
                requestState(new StateIndication(ConnectionState.disconnected, errorInfo));
                return;
            }
            return;
        }
        addAction(new UpdateAction(errorInfo));
    }

    public void onMessage(ITransport iTransport, ProtocolMessage protocolMessage) throws AblyException {
        if (iTransport == null || this.transport == iTransport) {
            if (Log.level <= 2) {
                Log.v(TAG, "onMessage() (transport = " + iTransport + "): " + protocolMessage.action + ": " + new String(ProtocolSerializer.writeJSON(protocolMessage)));
            }
            try {
                DebugOptions.RawProtocolListener rawProtocolListener = this.protocolListener;
                if (rawProtocolListener != null) {
                    rawProtocolListener.onRawMessageRecv(protocolMessage);
                }
                switch (AnonymousClass1.$SwitchMap$io$ably$lib$types$ProtocolMessage$Action[protocolMessage.action.ordinal()]) {
                    case 1:
                        onHeartbeat(protocolMessage);
                        return;
                    case 2:
                        ErrorInfo errorInfo = protocolMessage.error;
                        if (errorInfo == null) {
                            Log.e(TAG, "onMessage(): ERROR message received (no error detail)");
                        } else {
                            Log.e(TAG, "onMessage(): ERROR message received; message = " + errorInfo.message + "; code = " + errorInfo.code);
                        }
                        if (protocolMessage.channel != null) {
                            onChannelMessage(protocolMessage);
                            return;
                        } else {
                            onError(protocolMessage);
                            return;
                        }
                    case 3:
                        onConnected(protocolMessage);
                        return;
                    case 4:
                    case 5:
                        onDisconnected(protocolMessage);
                        return;
                    case 6:
                        onClosed(protocolMessage);
                        return;
                    case 7:
                        onAck(protocolMessage);
                        return;
                    case 8:
                        onNack(protocolMessage);
                        return;
                    case 9:
                        addAction(new ReauthAction(this, null));
                        return;
                    default:
                        onChannelMessage(protocolMessage);
                        return;
                }
            } catch (Exception e) {
                throw AblyException.fromThrowable(e);
            }
        }
    }

    static class AnonymousClass1 {
        static final int[] $SwitchMap$io$ably$lib$realtime$ConnectionState;
        static final int[] $SwitchMap$io$ably$lib$types$ProtocolMessage$Action;

        static {
            int[] iArr = new int[ProtocolMessage.Action.values().length];
            $SwitchMap$io$ably$lib$types$ProtocolMessage$Action = iArr;
            try {
                iArr[ProtocolMessage.Action.heartbeat.ordinal()] = 1;
            } catch (NoSuchFieldError unused) {
            }
            try {
                $SwitchMap$io$ably$lib$types$ProtocolMessage$Action[ProtocolMessage.Action.error.ordinal()] = 2;
            } catch (NoSuchFieldError unused2) {
            }
            try {
                $SwitchMap$io$ably$lib$types$ProtocolMessage$Action[ProtocolMessage.Action.connected.ordinal()] = 3;
            } catch (NoSuchFieldError unused3) {
            }
            try {
                $SwitchMap$io$ably$lib$types$ProtocolMessage$Action[ProtocolMessage.Action.disconnect.ordinal()] = 4;
            } catch (NoSuchFieldError unused4) {
            }
            try {
                $SwitchMap$io$ably$lib$types$ProtocolMessage$Action[ProtocolMessage.Action.disconnected.ordinal()] = 5;
            } catch (NoSuchFieldError unused5) {
            }
            try {
                $SwitchMap$io$ably$lib$types$ProtocolMessage$Action[ProtocolMessage.Action.closed.ordinal()] = 6;
            } catch (NoSuchFieldError unused6) {
            }
            try {
                $SwitchMap$io$ably$lib$types$ProtocolMessage$Action[ProtocolMessage.Action.ack.ordinal()] = 7;
            } catch (NoSuchFieldError unused7) {
            }
            try {
                $SwitchMap$io$ably$lib$types$ProtocolMessage$Action[ProtocolMessage.Action.nack.ordinal()] = 8;
            } catch (NoSuchFieldError unused8) {
            }
            try {
                $SwitchMap$io$ably$lib$types$ProtocolMessage$Action[ProtocolMessage.Action.auth.ordinal()] = 9;
            } catch (NoSuchFieldError unused9) {
            }
            int[] iArr2 = new int[ConnectionState.values().length];
            $SwitchMap$io$ably$lib$realtime$ConnectionState = iArr2;
            try {
                iArr2[ConnectionState.connected.ordinal()] = 1;
            } catch (NoSuchFieldError unused10) {
            }
            try {
                $SwitchMap$io$ably$lib$realtime$ConnectionState[ConnectionState.connecting.ordinal()] = 2;
            } catch (NoSuchFieldError unused11) {
            }
            try {
                $SwitchMap$io$ably$lib$realtime$ConnectionState[ConnectionState.disconnected.ordinal()] = 3;
            } catch (NoSuchFieldError unused12) {
            }
        }
    }

    private void onChannelMessage(ProtocolMessage protocolMessage) {
        if (protocolMessage.connectionSerial != null) {
            this.connection.serial = protocolMessage.connectionSerial.longValue();
            if (this.connection.key != null) {
                this.connection.recoveryKey = this.connection.key + ":" + protocolMessage.connectionSerial;
            }
        }
        this.channels.onMessage(protocolMessage);
    }

    private synchronized void onConnected(ProtocolMessage protocolMessage) {
        ErrorInfo errorInfo = protocolMessage.error;
        if (this.connection.id != null && !protocolMessage.connectionId.equals(this.connection.id)) {
            if (errorInfo == null) {
                errorInfo = REASON_SUSPENDED;
            }
            this.channels.suspendAll(errorInfo, false);
        }
        ConnectionDetails connectionDetails = protocolMessage.connectionDetails;
        this.connection.key = connectionDetails.connectionKey;
        if (!protocolMessage.connectionId.equals(this.connection.id)) {
            this.pendingMessages.reset(this.msgSerial, new ErrorInfo("Connection resume failed", 500, 50000));
            this.msgSerial = 0L;
        }
        this.connection.id = protocolMessage.connectionId;
        if (protocolMessage.connectionSerial != null) {
            this.connection.serial = protocolMessage.connectionSerial.longValue();
            if (this.connection.key != null) {
                this.connection.recoveryKey = this.connection.key + ":" + protocolMessage.connectionSerial;
            }
        }
        this.maxIdleInterval = connectionDetails.maxIdleInterval.longValue();
        this.connectionStateTtl = connectionDetails.connectionStateTtl.longValue();
        try {
            this.ably.auth.setClientId(connectionDetails.clientId);
            setSuspendTime();
            requestState(new StateIndication(ConnectionState.connected, errorInfo));
        } catch (AblyException e) {
            requestState(this.transport, new StateIndication(ConnectionState.failed, e.errorInfo));
        }
    }

    private synchronized void onDisconnected(ProtocolMessage protocolMessage) {
        ErrorInfo errorInfo = protocolMessage.error;
        if (errorInfo != null && isTokenError(errorInfo)) {
            this.ably.auth.onAuthError(errorInfo);
        }
        requestState(new StateIndication(ConnectionState.disconnected, errorInfo));
    }

    private synchronized void onClosed(ProtocolMessage protocolMessage) {
        if (protocolMessage.error != null) {
            onError(protocolMessage);
        } else {
            this.connection.key = null;
            requestState(new StateIndication(ConnectionState.closed, null));
        }
    }

    private synchronized void onError(ProtocolMessage protocolMessage) {
        this.connection.key = null;
        ErrorInfo errorInfo = protocolMessage.error;
        if (isTokenError(errorInfo)) {
            this.ably.auth.onAuthError(errorInfo);
        }
        requestState(this.transport, new StateIndication(isFatalError(errorInfo) ? ConnectionState.failed : ConnectionState.disconnected, errorInfo));
    }

    private void onAck(ProtocolMessage protocolMessage) {
        this.pendingMessages.ack(protocolMessage.msgSerial.longValue(), protocolMessage.count, protocolMessage.error);
    }

    private void onNack(ProtocolMessage protocolMessage) {
        this.pendingMessages.nack(protocolMessage.msgSerial.longValue(), protocolMessage.count, protocolMessage.error);
    }

    private void onHeartbeat(ProtocolMessage protocolMessage) {
        synchronized (this.heartbeatWaiters) {
            this.heartbeatWaiters.clear();
            this.heartbeatWaiters.notifyAll();
        }
    }

    private synchronized void startup() {
        if (this.handlerThread == null) {
            Thread thread = new Thread(new ActionHandler());
            this.handlerThread = thread;
            thread.start();
            startConnectivityListener();
        }
    }

    private boolean checkConnectionStale() {
        if (this.lastActivity == 0 || System.currentTimeMillis() - this.lastActivity <= this.maxIdleInterval + this.connectionStateTtl) {
            return false;
        }
        if (this.connection.key == null) {
            return true;
        }
        Log.v(TAG, "Clearing stale connection key to suppress resume");
        this.connection.key = null;
        this.connection.recoveryKey = null;
        return true;
    }

    public synchronized void setSuspendTime() {
        this.suspendTime = System.currentTimeMillis() + this.connectionStateTtl;
    }

    private StateIndication checkFallback(ErrorInfo errorInfo) {
        String fallback;
        if (this.pendingConnect != null && ((errorInfo == null || errorInfo.statusCode >= 500) && checkConnectivity() && (fallback = this.hosts.getFallback(this.pendingConnect.host)) != null)) {
            Log.v(TAG, "checkFallback: fallback to " + fallback);
            return new StateIndication(ConnectionState.connecting, null, fallback, this.pendingConnect.host);
        }
        this.pendingConnect = null;
        return null;
    }

    public synchronized StateIndication checkSuspended(ErrorInfo errorInfo) {
        boolean z;
        long currentTimeMillis = this.suspendTime - System.currentTimeMillis();
        z = currentTimeMillis <= 0;
        Log.v(TAG, "checkSuspended: timeToSuspend = " + currentTimeMillis + "ms; suspendMode = " + z);
        return new StateIndication(z ? ConnectionState.suspended : ConnectionState.disconnected, errorInfo);
    }

    public void tryWait(long j) {
        try {
            if (j == 0) {
                wait();
            } else {
                wait(j);
            }
        } catch (InterruptedException unused) {
        }
    }

    public void handleReauth() {
        ErrorInfo errorInfo;
        if (this.currentState.state == ConnectionState.connected) {
            Log.v(TAG, "Server initiated reauth");
            try {
                this.ably.auth.renew();
                errorInfo = null;
            } catch (AblyException e) {
                errorInfo = e.errorInfo;
            }
            if (this.currentState.state == ConnectionState.connected) {
                this.connection.emitUpdate(errorInfo);
            }
        }
    }

    @Override
    public synchronized void onTransportAvailable(ITransport iTransport) {
        if (this.transport != iTransport) {
            Log.v(TAG, "onTransportAvailable: ignoring connection event from superseded transport");
            return;
        }
        DebugOptions.RawProtocolListener rawProtocolListener = this.protocolListener;
        if (rawProtocolListener != null) {
            rawProtocolListener.onRawConnect(iTransport.getURL());
        }
    }

    @Override
    public synchronized void onTransportUnavailable(io.ably.lib.transport.ITransport r4, io.ably.lib.types.ErrorInfo r5) {
        throw new UnsupportedOperationException("Method not decompiled: io.ably.lib.transport.ConnectionManager.onTransportUnavailable(io.ably.lib.transport.ITransport, io.ably.lib.types.ErrorInfo):void");
    }

    private class ConnectParams extends ITransport.TransportParams {
        ConnectParams(ClientOptions clientOptions, PlatformAgentProvider platformAgentProvider) {
            super(clientOptions, platformAgentProvider);
            this.connectionKey = ConnectionManager.this.connection.key;
            this.connectionSerial = String.valueOf(ConnectionManager.this.connection.serial);
            this.port = Defaults.getPort(clientOptions);
        }
    }

    public void connectImpl(StateIndication stateIndication) {
        ITransport iTransport;
        String str = stateIndication.fallback;
        if (str == null) {
            str = this.hosts.getPreferredHost();
        }
        checkConnectionStale();
        ConnectParams connectParams = new ConnectParams(this.ably.options, this.platformAgentProvider);
        this.pendingConnect = connectParams;
        connectParams.host = str;
        this.lastUsedHost = str;
        try {
            ITransport transport = this.transportFactory.getTransport(this.pendingConnect, this);
            synchronized (this) {
                iTransport = this.transport;
                this.transport = transport;
            }
            if (iTransport != null) {
                iTransport.close();
            }
            transport.connect(this);
            DebugOptions.RawProtocolListener rawProtocolListener = this.protocolListener;
            if (rawProtocolListener != null) {
                rawProtocolListener.onRawConnectRequested(transport.getURL());
            }
        } catch (Exception e) {
            Log.e(getClass().getName(), "Unable to instance transport class", e);
            throw new RuntimeException("Unable to instance transport class", e);
        }
    }

    public boolean closeImpl() {
        if (this.transport == null) {
            return true;
        }
        if (this.currentState.state == ConnectionState.connected) {
            try {
                Log.v(TAG, "Requesting connection close");
                this.transport.send(new ProtocolMessage(ProtocolMessage.Action.close));
                return false;
            } catch (AblyException unused) {
            }
        }
        Log.v(TAG, "Closing incomplete transport");
        clearTransport();
        return true;
    }

    public void clearTransport() {
        ITransport iTransport = this.transport;
        if (iTransport != null) {
            iTransport.close();
            this.transport = null;
        }
    }

    protected boolean checkConnectivity() {
        try {
            return HttpHelpers.getUrlString(this.ably.httpCore, INTERNET_CHECK_URL).contains(INTERNET_CHECK_OK);
        } catch (AblyException unused) {
            return false;
        }
    }

    protected void setLastActivity(long j) {
        this.lastActivity = j;
    }

    public static class QueuedMessage {
        public final CompletionListener listener;
        public final ProtocolMessage msg;

        public QueuedMessage(ProtocolMessage protocolMessage, CompletionListener completionListener) {
            this.msg = protocolMessage;
            this.listener = completionListener;
        }
    }

    public void send(ProtocolMessage protocolMessage, boolean z, CompletionListener completionListener) throws AblyException {
        synchronized (this) {
            State state = this.currentState;
            if (state.sendEvents) {
                sendImpl(protocolMessage, completionListener);
            } else {
                if (state.queueEvents && z) {
                    this.queuedMessages.add(new QueuedMessage(protocolMessage, completionListener));
                    return;
                }
                throw AblyException.fromErrorInfo(state.defaultErrorInfo);
            }
        }
    }

    private void sendImpl(ProtocolMessage protocolMessage, CompletionListener completionListener) throws AblyException {
        if (this.transport == null) {
            Log.v(TAG, "sendImpl(): Discarding message; transport unavailable");
            return;
        }
        if (ProtocolMessage.ackRequired(protocolMessage)) {
            long j = this.msgSerial;
            this.msgSerial = 1 + j;
            protocolMessage.msgSerial = Long.valueOf(j);
            this.pendingMessages.push(new QueuedMessage(protocolMessage, completionListener));
        }
        DebugOptions.RawProtocolListener rawProtocolListener = this.protocolListener;
        if (rawProtocolListener != null) {
            rawProtocolListener.onRawMessageSend(protocolMessage);
        }
        this.transport.send(protocolMessage);
    }

    private void sendImpl(QueuedMessage queuedMessage) throws AblyException {
        if (this.transport == null) {
            Log.v(TAG, "sendImpl(): Discarding message; transport unavailable");
            return;
        }
        ProtocolMessage protocolMessage = queuedMessage.msg;
        if (ProtocolMessage.ackRequired(protocolMessage)) {
            long j = this.msgSerial;
            this.msgSerial = 1 + j;
            protocolMessage.msgSerial = Long.valueOf(j);
            this.pendingMessages.push(queuedMessage);
        }
        DebugOptions.RawProtocolListener rawProtocolListener = this.protocolListener;
        if (rawProtocolListener != null) {
            rawProtocolListener.onRawMessageSend(protocolMessage);
        }
        this.transport.send(protocolMessage);
    }

    public void sendQueuedMessages() {
        List<QueuedMessage> list;
        synchronized (this) {
            while (this.queuedMessages.size() > 0) {
                try {
                    try {
                        sendImpl(this.queuedMessages.get(0));
                        list = this.queuedMessages;
                    } catch (Throwable th) {
                        this.queuedMessages.remove(0);
                        throw th;
                    }
                } catch (AblyException e) {
                    Log.e(TAG, "sendQueuedMessages(): Unexpected error sending queued messages", e);
                    list = this.queuedMessages;
                }
                list.remove(0);
            }
        }
    }

    public void failQueuedMessages(ErrorInfo errorInfo) {
        synchronized (this) {
            for (QueuedMessage queuedMessage : this.queuedMessages) {
                if (queuedMessage.listener != null) {
                    try {
                        queuedMessage.listener.onError(errorInfo);
                    } catch (Throwable th) {
                        Log.e(TAG, "failQueuedMessages(): Unexpected error calling listener", th);
                    }
                }
            }
            this.queuedMessages.clear();
        }
    }

    private class PendingMessageQueue {
        private ArrayList<QueuedMessage> queue;
        private long startSerial;

        private PendingMessageQueue() {
            this.startSerial = 0L;
            this.queue = new ArrayList<>();
        }

        PendingMessageQueue(ConnectionManager connectionManager, AnonymousClass1 anonymousClass1) {
            this();
        }

        public synchronized void push(QueuedMessage queuedMessage) {
            this.queue.add(queuedMessage);
        }

        public void ack(long j, int i, ErrorInfo errorInfo) {
            int i2;
            QueuedMessage[] queuedMessageArr;
            QueuedMessage[] queuedMessageArr2;
            synchronized (this) {
                long j2 = this.startSerial;
                if (j < j2) {
                    i -= (int) (j2 - j);
                    if (i < 0) {
                        i = 0;
                    }
                    j = j2;
                }
                queuedMessageArr = null;
                if (j > j2) {
                    int i3 = (int) (j - j2);
                    List<QueuedMessage> subList = this.queue.subList(0, i3);
                    queuedMessageArr2 = (QueuedMessage[]) subList.toArray(new QueuedMessage[i3]);
                    subList.clear();
                    this.startSerial = j;
                } else {
                    queuedMessageArr2 = null;
                }
                if (j == this.startSerial) {
                    List<QueuedMessage> subList2 = this.queue.subList(0, i);
                    queuedMessageArr = (QueuedMessage[]) subList2.toArray(new QueuedMessage[i]);
                    subList2.clear();
                    this.startSerial += i;
                }
            }
            if (queuedMessageArr2 != null) {
                if (errorInfo == null) {
                    errorInfo = new ErrorInfo(MicrosoftAuthorizationErrorResponse.UNKNOWN_ERROR, 500, 50000);
                }
                for (QueuedMessage queuedMessage : queuedMessageArr2) {
                    try {
                        if (queuedMessage.listener != null) {
                            queuedMessage.listener.onError(errorInfo);
                        }
                    } catch (Throwable th) {
                        Log.e(ConnectionManager.TAG, "ack(): listener exception", th);
                    }
                }
            }
            if (queuedMessageArr != null) {
                for (QueuedMessage queuedMessage2 : queuedMessageArr) {
                    try {
                        if (queuedMessage2.listener != null) {
                            queuedMessage2.listener.onSuccess();
                        }
                    } catch (Throwable th2) {
                        Log.e(ConnectionManager.TAG, "ack(): listener exception", th2);
                    }
                }
            }
        }

        public synchronized void nack(long j, int i, ErrorInfo errorInfo) {
            int i2;
            QueuedMessage[] queuedMessageArr;
            synchronized (this) {
                long j2 = this.startSerial;
                if (j != j2) {
                    i -= (int) (j2 - j);
                }
                List<QueuedMessage> subList = this.queue.subList(0, i);
                queuedMessageArr = (QueuedMessage[]) subList.toArray(new QueuedMessage[i]);
                subList.clear();
                this.startSerial += i;
            }
            if (queuedMessageArr != null) {
                if (errorInfo == null) {
                    errorInfo = new ErrorInfo(MicrosoftAuthorizationErrorResponse.UNKNOWN_ERROR, 500, 50000);
                }
                for (QueuedMessage queuedMessage : queuedMessageArr) {
                    try {
                        if (queuedMessage.listener != null) {
                            queuedMessage.listener.onError(errorInfo);
                        }
                    } catch (Throwable th) {
                        Log.e(ConnectionManager.TAG, "nack(): listener exception", th);
                    }
                }
            }
        }

        public synchronized void reset(long j, ErrorInfo errorInfo) {
            long j2 = this.startSerial;
            nack(j2, (int) (j - j2), errorInfo);
            this.startSerial = 0L;
        }
    }

    private class CMConnectivityListener implements NetworkConnectivity.NetworkConnectivityListener {
        private CMConnectivityListener() {
        }

        CMConnectivityListener(ConnectionManager connectionManager, AnonymousClass1 anonymousClass1) {
            this();
        }

        @Override
        public void onNetworkAvailable() {
            ConnectionManager connectionManager = ConnectionManager.this;
            ConnectionState connectionState = connectionManager.getConnectionState().state;
            Log.i(ConnectionManager.TAG, "onNetworkAvailable(): currentState = " + connectionState.name());
            if (connectionState == ConnectionState.disconnected || connectionState == ConnectionState.suspended) {
                Log.i(ConnectionManager.TAG, "onNetworkAvailable(): initiating reconnect");
                connectionManager.connect();
            }
        }

        @Override
        public void onNetworkUnavailable(ErrorInfo errorInfo) {
            ConnectionManager connectionManager = ConnectionManager.this;
            ConnectionState connectionState = connectionManager.getConnectionState().state;
            Log.i(ConnectionManager.TAG, "onNetworkUnavailable(); currentState = " + connectionState.name() + "; reason = " + errorInfo.toString());
            if (connectionState == ConnectionState.connected || connectionState == ConnectionState.connecting) {
                Log.i(ConnectionManager.TAG, "onNetworkUnavailable(): closing connected transport");
                connectionManager.requestState(new StateIndication(ConnectionState.disconnected, errorInfo));
            }
        }
    }

    private void startConnectivityListener() {
        this.connectivityListener = new CMConnectivityListener(this, null);
        this.ably.platform.getNetworkConnectivity().addListener(this.connectivityListener);
    }

    public void stopConnectivityListener() {
        this.ably.platform.getNetworkConnectivity().removeListener(this.connectivityListener);
        this.connectivityListener = null;
    }

    void disconnectAndSuppressRetries() {
        ITransport iTransport = this.transport;
        if (iTransport != null) {
            iTransport.close();
        }
        this.suppressRetry = true;
    }

    private boolean isTokenError(ErrorInfo errorInfo) {
        return (errorInfo.code >= 40140 && errorInfo.code < 40150) || (errorInfo.code == 80019 && errorInfo.statusCode == 401);
    }

    private boolean isFatalError(ErrorInfo errorInfo) {
        if (errorInfo.code != 0) {
            if (isTokenError(errorInfo)) {
                return false;
            }
            if (errorInfo.code >= 40000 && errorInfo.code < 50000) {
                return true;
            }
        }
        return errorInfo.statusCode != 0 && errorInfo.statusCode < 500;
    }
}