正在查看: St.John's v1.0.9 应用的 ConnectionManager.java JAVA 源代码文件
本页面展示 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;
}
}