diff --git a/README.md b/README.md
index bbe79a84..58219203 100644
--- a/README.md
+++ b/README.md
@@ -51,7 +51,7 @@ The pusher-java-client is available in Maven Central.
com.pusher
pusher-java-client
- 1.7.0
+ 1.8.0
```
@@ -60,7 +60,7 @@ The pusher-java-client is available in Maven Central.
```groovy
dependencies {
- compile 'com.pusher:pusher-java-client:1.7.0'
+ compile 'com.pusher:pusher-java-client:1.8.0'
}
```
diff --git a/build.gradle b/build.gradle
index c8e317c2..95c38923 100644
--- a/build.gradle
+++ b/build.gradle
@@ -21,7 +21,7 @@ apply plugin: 'org.ajoberstar.github-pages'
apply plugin: 'signing'
group = "com.pusher"
-version = "1.7.1-SNAPSHOT"
+version = "1.8.1-SNAPSHOT"
sourceCompatibility = "1.6"
targetCompatibility = "1.6"
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 45a4d68f..1b47c1b9 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,6 @@
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-bin.zip
+#Wed Feb 21 14:42:32 GMT 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-all.zip
diff --git a/src/main/java/com/pusher/client/PusherOptions.java b/src/main/java/com/pusher/client/PusherOptions.java
index f9b92f0d..77b525e2 100644
--- a/src/main/java/com/pusher/client/PusherOptions.java
+++ b/src/main/java/com/pusher/client/PusherOptions.java
@@ -25,6 +25,9 @@ public class PusherOptions {
private static final long DEFAULT_ACTIVITY_TIMEOUT = 120000;
private static final long DEFAULT_PONG_TIMEOUT = 30000;
+ private static final int MAX_RECONNECTION_ATTEMPTS = 6; //Taken from the Swift lib
+ private static final int MAX_RECONNECT_GAP_IN_SECONDS = 30;
+
// Note that the primary cluster lives on a different domain
// (others are subdomains of pusher.com). This is not an oversight.
// Legacy reasons.
@@ -36,6 +39,8 @@ public class PusherOptions {
private long pongTimeout = DEFAULT_PONG_TIMEOUT;
private Authorizer authorizer;
private Proxy proxy = Proxy.NO_PROXY;
+ private int maxReconnectionAttempts = MAX_RECONNECTION_ATTEMPTS;
+ private int maxReconnectGapInSeconds = MAX_RECONNECT_GAP_IN_SECONDS;
/**
* Gets whether an encrypted (SSL) connection should be used when connecting
@@ -182,7 +187,30 @@ public PusherOptions setPongTimeout(final long pongTimeout) {
return this;
}
- public long getPongTimeout() {
+ /**
+ * Number of reconnect attempts when websocket connection failed
+ * @param maxReconnectionAttempts
+ * number of max reconnection attempts, default = {@link #MAX_RECONNECTION_ATTEMPTS} 6
+ * @return this, for chaining
+ */
+ public PusherOptions setMaxReconnectionAttempts(int maxReconnectionAttempts) {
+ this.maxReconnectionAttempts = maxReconnectionAttempts;
+ return this;
+ }
+
+ /**
+ * The delay in two reconnection extends exponentially (1, 2, 4, .. seconds) This property sets the maximum in between two
+ * reconnection attempts.
+ * @param maxReconnectGapInSeconds
+ * time in seconds of the maximum gab between two reconnection attempts, default = {@link #MAX_RECONNECT_GAP_IN_SECONDS} 30s
+ * @return this, for chaining
+ */
+ public PusherOptions setMaxReconnectGapInSeconds(int maxReconnectGapInSeconds) {
+ this.maxReconnectGapInSeconds = maxReconnectGapInSeconds;
+ return this;
+ }
+
+ public long getPongTimeout() {
return pongTimeout;
}
@@ -221,7 +249,21 @@ public Proxy getProxy() {
return this.proxy;
}
- private static String readVersionFromProperties() {
+ /**
+ * @return the maximum reconnection attempts
+ */
+ public int getMaxReconnectionAttempts() {
+ return maxReconnectionAttempts;
+ }
+
+ /**
+ * @return the maximum reconnection gap in seconds
+ */
+ public int getMaxReconnectGapInSeconds() {
+ return maxReconnectGapInSeconds;
+ }
+
+ private static String readVersionFromProperties() {
InputStream inStream = null;
try {
final Properties p = new Properties();
diff --git a/src/main/java/com/pusher/client/connection/websocket/WebSocketConnection.java b/src/main/java/com/pusher/client/connection/websocket/WebSocketConnection.java
index b7db6450..199c249f 100644
--- a/src/main/java/com/pusher/client/connection/websocket/WebSocketConnection.java
+++ b/src/main/java/com/pusher/client/connection/websocket/WebSocketConnection.java
@@ -30,14 +30,14 @@ public class WebSocketConnection implements InternalConnection, WebSocketListene
private static final String INTERNAL_EVENT_PREFIX = "pusher:";
private static final String PING_EVENT_SERIALIZED = "{\"event\": \"pusher:ping\"}";
- private static final int MAX_RECONNECTION_ATTEMPTS = 6; //Taken from the Swift lib
- private static final int MAX_RECONNECT_GAP_IN_SECONDS = 30;
private final Factory factory;
private final ActivityTimer activityTimer;
private final Map> eventListeners = new ConcurrentHashMap>();
private final URI webSocketUri;
private final Proxy proxy;
+ private final int maxReconnectionAttempts;
+ private final int maxReconnectionGap;
private volatile ConnectionState state = ConnectionState.DISCONNECTED;
private WebSocketClientWrapper underlyingConnection;
@@ -49,10 +49,14 @@ public WebSocketConnection(
final String url,
final long activityTimeout,
final long pongTimeout,
+ int maxReconnectionAttempts,
+ int maxReconnectionGap,
final Proxy proxy,
final Factory factory) throws URISyntaxException {
webSocketUri = new URI(url);
activityTimer = new ActivityTimer(activityTimeout, pongTimeout);
+ this.maxReconnectionAttempts = maxReconnectionAttempts;
+ this.maxReconnectionGap = maxReconnectionGap;
this.proxy = proxy;
this.factory = factory;
@@ -270,7 +274,7 @@ public void onClose(final int code, final String reason, final boolean remote) {
//Reconnection logic
if(state == ConnectionState.CONNECTED || state == ConnectionState.CONNECTING){
- if(reconnectAttempts < MAX_RECONNECTION_ATTEMPTS){
+ if(reconnectAttempts < maxReconnectionAttempts){
tryReconnecting();
}
else{
@@ -288,7 +292,7 @@ public void onClose(final int code, final String reason, final boolean remote) {
private void tryReconnecting() {
reconnectAttempts++;
updateState(ConnectionState.RECONNECTING);
- long reconnectInterval = Math.min(MAX_RECONNECT_GAP_IN_SECONDS, reconnectAttempts * reconnectAttempts);
+ long reconnectInterval = Math.min(maxReconnectionGap, reconnectAttempts * reconnectAttempts);
factory.getTimers().schedule(new Runnable() {
@Override
diff --git a/src/main/java/com/pusher/client/util/Factory.java b/src/main/java/com/pusher/client/util/Factory.java
index ed93424b..b7622c78 100644
--- a/src/main/java/com/pusher/client/util/Factory.java
+++ b/src/main/java/com/pusher/client/util/Factory.java
@@ -50,8 +50,14 @@ public class Factory {
public synchronized InternalConnection getConnection(final String apiKey, final PusherOptions options) {
if (connection == null) {
try {
- connection = new WebSocketConnection(options.buildUrl(apiKey), options.getActivityTimeout(),
- options.getPongTimeout(), options.getProxy(), this);
+ connection = new WebSocketConnection(
+ options.buildUrl(apiKey),
+ options.getActivityTimeout(),
+ options.getPongTimeout(),
+ options.getMaxReconnectionAttempts(),
+ options.getMaxReconnectGapInSeconds(),
+ options.getProxy(),
+ this);
}
catch (final URISyntaxException e) {
throw new IllegalArgumentException("Failed to initialise connection", e);
diff --git a/src/test/java/com/pusher/client/EndToEndTest.java b/src/test/java/com/pusher/client/EndToEndTest.java
index cb1be7f1..fd042875 100644
--- a/src/test/java/com/pusher/client/EndToEndTest.java
+++ b/src/test/java/com/pusher/client/EndToEndTest.java
@@ -1,12 +1,17 @@
package com.pusher.client;
-import static org.mockito.Matchers.*;
-import static org.mockito.Mockito.*;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import java.net.Proxy;
import java.net.URI;
-import com.pusher.java_websocket.handshake.ServerHandshake;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -26,6 +31,7 @@
import com.pusher.client.connection.websocket.WebSocketListener;
import com.pusher.client.util.DoNothingExecutor;
import com.pusher.client.util.Factory;
+import com.pusher.java_websocket.handshake.ServerHandshake;
@RunWith(MockitoJUnitRunner.class)
public class EndToEndTest {
@@ -38,6 +44,7 @@ public class EndToEndTest {
+ PRIVATE_CHANNEL_NAME + "\",\"auth\":\"" + AUTH_KEY + "\"}}";
private static final long ACTIVITY_TIMEOUT = 120000;
private static final long PONG_TIMEOUT = 120000;
+
private static final Proxy proxy = Proxy.NO_PROXY;
private @Mock Authorizer mockAuthorizer;
@@ -53,7 +60,8 @@ public class EndToEndTest {
public void setUp() throws Exception {
pusherOptions = new PusherOptions().setAuthorizer(mockAuthorizer).setEncrypted(false);
- connection = new WebSocketConnection(pusherOptions.buildUrl(API_KEY), ACTIVITY_TIMEOUT, PONG_TIMEOUT, proxy, factory);
+ connection = new WebSocketConnection(pusherOptions.buildUrl(API_KEY), ACTIVITY_TIMEOUT, PONG_TIMEOUT, pusherOptions.getMaxReconnectionAttempts(),
+ pusherOptions.getMaxReconnectGapInSeconds(), proxy, factory);
doAnswer(new Answer() {
@Override
diff --git a/src/test/java/com/pusher/client/connection/websocket/WebSocketConnectionTest.java b/src/test/java/com/pusher/client/connection/websocket/WebSocketConnectionTest.java
index cf7d6c50..ca7869fb 100644
--- a/src/test/java/com/pusher/client/connection/websocket/WebSocketConnectionTest.java
+++ b/src/test/java/com/pusher/client/connection/websocket/WebSocketConnectionTest.java
@@ -32,6 +32,8 @@ public class WebSocketConnectionTest {
private static final long ACTIVITY_TIMEOUT = 500;
private static final long PONG_TIMEOUT = 500;
+ private static final int MAX_RECONNECTIONS = 6;
+ private static final int MAX_GAP = 30;
private static final String URL = "ws://ws.example.com/";
private static final String EVENT_NAME = "my-event";
private static final String CONN_ESTABLISHED_EVENT = "{\"event\":\"pusher:connection_established\",\"data\":\"{\\\"socket_id\\\":\\\"21112.816204\\\"}\"}";
@@ -65,14 +67,15 @@ public Object answer(InvocationOnMock invocation) throws Throwable {
}).when(factory).queueOnEventThread(any(Runnable.class));
when(factory.getTimers()).thenReturn(new DoNothingExecutor());
- connection = new WebSocketConnection(URL, ACTIVITY_TIMEOUT, PONG_TIMEOUT, PROXY, factory);
+ connection = new WebSocketConnection(URL, ACTIVITY_TIMEOUT, PONG_TIMEOUT, MAX_RECONNECTIONS, MAX_GAP, PROXY, factory);
connection.bind(ConnectionState.ALL, mockEventListener);
}
@Test
public void testUnbindingWhenNotAlreadyBoundReturnsFalse() throws URISyntaxException {
final ConnectionEventListener listener = mock(ConnectionEventListener.class);
- final WebSocketConnection connection = new WebSocketConnection(URL, ACTIVITY_TIMEOUT, PONG_TIMEOUT, PROXY, factory);
+ final WebSocketConnection connection = new WebSocketConnection(URL, ACTIVITY_TIMEOUT, PONG_TIMEOUT, MAX_RECONNECTIONS, MAX_GAP,
+ PROXY, factory);
final boolean unbound = connection.unbind(ConnectionState.ALL, listener);
assertEquals(false, unbound);
}
@@ -80,7 +83,8 @@ public void testUnbindingWhenNotAlreadyBoundReturnsFalse() throws URISyntaxExcep
@Test
public void testUnbindingWhenBoundReturnsTrue() throws URISyntaxException {
final ConnectionEventListener listener = mock(ConnectionEventListener.class);
- final WebSocketConnection connection = new WebSocketConnection(URL, ACTIVITY_TIMEOUT, PONG_TIMEOUT, PROXY, factory);
+ final WebSocketConnection connection = new WebSocketConnection(URL, ACTIVITY_TIMEOUT, PONG_TIMEOUT, MAX_RECONNECTIONS, MAX_GAP,
+ PROXY, factory);
connection.bind(ConnectionState.ALL, listener);
@@ -118,7 +122,8 @@ public void testConnectDoesNotCallConnectOnUnderlyingConnectionIfAlreadyInConnec
@Test
public void testListenerDoesNotReceiveConnectingEventIfItIsOnlyBoundToTheConnectedEvent() throws URISyntaxException {
- connection = new WebSocketConnection(URL, ACTIVITY_TIMEOUT, PONG_TIMEOUT, PROXY, factory);
+ connection = new WebSocketConnection(URL, ACTIVITY_TIMEOUT, PONG_TIMEOUT, MAX_RECONNECTIONS, MAX_GAP,
+ PROXY, factory);
connection.bind(ConnectionState.CONNECTED, mockEventListener);
connection.connect();
@@ -219,7 +224,8 @@ public void testOnCloseCallbackUpdatesStateToDisconnectedWhenPreviousStateIsDisc
@Test
public void testOnCloseCallbackDoesNotCallListenerIfItIsNotBoundToDisconnectedEvent() throws URISyntaxException {
- connection = new WebSocketConnection(URL, ACTIVITY_TIMEOUT, PONG_TIMEOUT, PROXY, factory);
+ connection = new WebSocketConnection(URL, ACTIVITY_TIMEOUT, PONG_TIMEOUT, MAX_RECONNECTIONS, MAX_GAP,
+ PROXY, factory);
connection.bind(ConnectionState.CONNECTED, mockEventListener);
connection.connect();