diff --git a/.pubnub.yml b/.pubnub.yml
index 3b8c360fb..2103b5e49 100644
--- a/.pubnub.yml
+++ b/.pubnub.yml
@@ -1,9 +1,9 @@
name: java
-version: v5.2.3
+version: v5.2.4
schema: 1
scm: github.com/pubnub/java
files:
- - build/libs/pubnub-gson-5.2.3-all.jar
+ - build/libs/pubnub-gson-5.2.4-all.jar
sdks:
-
type: library
@@ -23,8 +23,8 @@ sdks:
-
distribution-type: library
distribution-repository: git release
- package-name: pubnub-gson-5.2.3
- location: https://github.com/pubnub/java/releases/download/v5.2.3/pubnub-gson-5.2.3-all.jar
+ package-name: pubnub-gson-5.2.4
+ location: https://github.com/pubnub/java/releases/download/v5.2.4/pubnub-gson-5.2.4-all.jar
supported-platforms:
supported-operating-systems:
Android:
@@ -135,8 +135,8 @@ sdks:
-
distribution-type: library
distribution-repository: maven
- package-name: pubnub-gson-5.2.3
- location: https://repo.maven.apache.org/maven2/com/pubnub/pubnub-gson/5.2.3/pubnub-gson-5.2.3.jar
+ package-name: pubnub-gson-5.2.4
+ location: https://repo.maven.apache.org/maven2/com/pubnub/pubnub-gson/5.2.4/pubnub-gson-5.2.4.jar
supported-platforms:
supported-operating-systems:
Android:
@@ -234,6 +234,11 @@ sdks:
is-required: Required
changelog:
+ - date: 2021-12-09
+ version: v5.2.4
+ changes:
+ - type: bug
+ text: "Emit PNReconnectedCategory in case of successful manual reconnection."
- date: 2021-11-17
version: v5.2.3
changes:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b36492216..887e65da5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## v5.2.4
+December 09 2021
+
+#### Fixed
+- Emit PNReconnectedCategory in case of successful manual reconnection.
+
## v5.2.3
November 17 2021
diff --git a/README.md b/README.md
index c80592f3e..054a3b666 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,7 @@ You will need the publish and subscribe keys to authenticate your app. Get your
com.pubnub
pubnub-gson
- 5.2.3
+ 5.2.4
```
diff --git a/build.gradle b/build.gradle
index f69148076..465fed364 100644
--- a/build.gradle
+++ b/build.gradle
@@ -12,7 +12,7 @@ plugins {
}
group = 'com.pubnub'
-version = '5.2.3'
+version = '5.2.4'
description = """"""
diff --git a/src/main/java/com/pubnub/api/PubNub.java b/src/main/java/com/pubnub/api/PubNub.java
index af492497c..fff93e9e5 100644
--- a/src/main/java/com/pubnub/api/PubNub.java
+++ b/src/main/java/com/pubnub/api/PubNub.java
@@ -103,7 +103,7 @@ public class PubNub {
private static final int TIMESTAMP_DIVIDER = 1000;
private static final int MAX_SEQUENCE = 65535;
- private static final String SDK_VERSION = "5.2.3";
+ private static final String SDK_VERSION = "5.2.4";
private final ListenerManager listenerManager;
private final StateManager stateManager;
diff --git a/src/main/java/com/pubnub/api/managers/StateManager.java b/src/main/java/com/pubnub/api/managers/StateManager.java
index 1c7c6fe04..f4df37ccb 100644
--- a/src/main/java/com/pubnub/api/managers/StateManager.java
+++ b/src/main/java/com/pubnub/api/managers/StateManager.java
@@ -8,6 +8,7 @@
import com.pubnub.api.builder.dto.SubscribeOperation;
import com.pubnub.api.builder.dto.TimetokenAndRegionOperation;
import com.pubnub.api.builder.dto.UnsubscribeOperation;
+import com.pubnub.api.enums.PNStatusCategory;
import com.pubnub.api.models.SubscriptionItem;
import lombok.AllArgsConstructor;
import lombok.Data;
@@ -67,7 +68,7 @@ private static class TemporaryUnavailableItem {
private String region = null;
private final PNConfiguration configuration;
- private boolean shouldAnnounce = false;
+ private PNStatusCategory announceStatus = null;
public StateManager(final PNConfiguration configuration) {
this.configuration = configuration;
@@ -79,12 +80,12 @@ public synchronized boolean handleOperation(final PubSubOperation... pubSubOpera
if (pubSubOperation instanceof SubscribeOperation) {
if (adaptSubscribeBuilder((SubscribeOperation) pubSubOperation)) {
stateChanged = true;
- shouldAnnounce = true;
+ announceStatus = PNStatusCategory.PNConnectedCategory;
}
} else if (pubSubOperation instanceof UnsubscribeOperation) {
unsubscribe((UnsubscribeOperation) pubSubOperation);
stateChanged = true;
- shouldAnnounce = true;
+ announceStatus = PNStatusCategory.PNConnectedCategory;
} else if (pubSubOperation instanceof StateOperation) {
adaptStateBuilder((StateOperation) pubSubOperation);
} else if (pubSubOperation instanceof PresenceOperation) {
@@ -98,9 +99,12 @@ public synchronized boolean handleOperation(final PubSubOperation... pubSubOpera
} else if (pubSubOperation instanceof ChangeTemporaryUnavailableOperation) {
changeTemporary((ChangeTemporaryUnavailableOperation) pubSubOperation);
} else if (pubSubOperation instanceof PubSubOperation.ConnectedStatusAnnouncedOperation) {
- shouldAnnounce = false;
+ announceStatus = null;
} else if (pubSubOperation instanceof PubSubOperation.ReconnectOperation) {
stateChanged = true;
+ announceStatus = PNStatusCategory.PNReconnectedCategory;
+ storedTimetoken = timetoken;
+ timetoken = 0L;
}
}
return stateChanged;
@@ -129,7 +133,7 @@ public synchronized SubscriptionStateData subscriptionStateData(Boolean includeP
region,
hasAnythingToSubscribe(),
subscribedToOnlyTemporaryUnavailable(),
- shouldAnnounce
+ announceStatus
);
}
@@ -474,7 +478,10 @@ public static class SubscriptionStateData {
private final String region;
private final boolean anythingToSubscribe;
private final boolean subscribedToOnlyTemporaryUnavailable;
- private final boolean shouldAnnounce;
+ private final PNStatusCategory announceStatus;
+ public boolean isShouldAnnounce() {
+ return announceStatus != null;
+ }
}
@Data
diff --git a/src/main/java/com/pubnub/api/managers/SubscriptionManager.java b/src/main/java/com/pubnub/api/managers/SubscriptionManager.java
index 695b57146..71052d5ad 100644
--- a/src/main/java/com/pubnub/api/managers/SubscriptionManager.java
+++ b/src/main/java/com/pubnub/api/managers/SubscriptionManager.java
@@ -325,7 +325,7 @@ synchronized void startSubscribeLoop(final PubSubOperation... pubSubOperations)
final PubSubOperation statusAnnouncedOperation;
if (subscriptionStateData.isShouldAnnounce()) {
PNStatus pnStatus = createPublicStatus(status)
- .category(PNStatusCategory.PNConnectedCategory)
+ .category(subscriptionStateData.getAnnounceStatus())
.error(false)
.build();
listenerManager.announce(pnStatus);
diff --git a/src/test/java/com/pubnub/api/PubNubTest.java b/src/test/java/com/pubnub/api/PubNubTest.java
index 539af9092..f70bbe495 100644
--- a/src/test/java/com/pubnub/api/PubNubTest.java
+++ b/src/test/java/com/pubnub/api/PubNubTest.java
@@ -99,7 +99,7 @@ public void getVersionAndTimeStamp() {
pubnub = new PubNub(pnConfiguration);
String version = pubnub.getVersion();
int timeStamp = pubnub.getTimestamp();
- Assert.assertEquals("5.2.3", version);
+ Assert.assertEquals("5.2.4", version);
Assert.assertTrue(timeStamp > 0);
}
diff --git a/src/test/java/com/pubnub/api/managers/FastSubscriptionManagerTest.java b/src/test/java/com/pubnub/api/managers/FastSubscriptionManagerTest.java
index fdb149e54..19c0d67fe 100644
--- a/src/test/java/com/pubnub/api/managers/FastSubscriptionManagerTest.java
+++ b/src/test/java/com/pubnub/api/managers/FastSubscriptionManagerTest.java
@@ -4,34 +4,45 @@
import com.pubnub.api.builder.dto.ChangeTemporaryUnavailableOperation;
import com.pubnub.api.builder.dto.PubSubOperation;
import com.pubnub.api.builder.dto.SubscribeOperation;
+import com.pubnub.api.enums.PNStatusCategory;
import com.pubnub.api.managers.subscription.utils.RequestDetails;
import com.pubnub.api.managers.subscription.utils.ResponseHolder;
import com.pubnub.api.managers.subscription.utils.ResponseSupplier;
import com.pubnub.api.managers.token_manager.TokenManager;
+import com.pubnub.api.models.consumer.PNStatus;
import com.pubnub.api.models.server.SubscribeEnvelope;
import com.pubnub.api.models.server.SubscribeMetadata;
import com.pubnub.api.services.SubscribeService;
import okhttp3.MediaType;
import okhttp3.ResponseBody;
import org.awaitility.core.ThrowingRunnable;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import retrofit2.Response;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
+import java.util.List;
+import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
import static com.pubnub.api.managers.subscription.utils.SubscriptionTestUtils.pubnub;
import static com.pubnub.api.managers.subscription.utils.SubscriptionTestUtils.retrofitManagerMock;
import static com.pubnub.api.managers.subscription.utils.SubscriptionTestUtils.telemetryManager;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.awaitility.Awaitility.await;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
@@ -253,6 +264,76 @@ public void run() throws Throwable {
});
}
+ @Test
+ public void sendReconnectedOnManualReconnect() {
+ long timeToken = System.currentTimeMillis();
+ final ResponseSupplier responseSupplier = new ResponseSupplier() {
+ private boolean first = true;
+
+ @Override
+ public ResponseHolder get(final RequestDetails requestDetails) {
+ try {
+ MILLISECONDS.sleep(100);
+ } catch (InterruptedException e) {
+ }
+ if (first) {
+ first = false;
+ return new ResponseHolder<>(Response.error(500, ResponseBody.create(MediaType.parse("application/json"), "{}")));
+ }
+ final SubscribeEnvelope subscribeEnvelope = new SubscribeEnvelope(emptyList(),
+ new SubscribeMetadata(timeToken, FAKE_REGION));
+ return new ResponseHolder<>(Response.success(200, subscribeEnvelope));
+ }
+ };
+ final RetrofitManager retrofitManagerMock = retrofitManagerMock(responseSupplier);
+ final SubscriptionManager subscriptionManager = subscriptionManagerUnderTest(retrofitManagerMock);
+
+ final SubscribeOperation subscribeOperation = SubscribeOperation.builder()
+ .channels(singletonList("ch2"))
+ .channelGroups(singletonList("group2"))
+ .build();
+
+ subscriptionManager.adaptSubscribeBuilder(subscribeOperation);
+ subscriptionManager.reconnect();
+ ArgumentCaptor statusArgumentCaptor = ArgumentCaptor.forClass(PNStatus.class);
+ await().atMost(1, SECONDS).untilAsserted(() -> verify(listenerManagerMock, times(2)).announce(statusArgumentCaptor.capture()));
+
+ List statusCategories = statusArgumentCaptor.getAllValues().stream().map(PNStatus::getCategory).collect(Collectors.toList());
+ MatcherAssert.assertThat(statusCategories, Matchers.hasItem(PNStatusCategory.PNReconnectedCategory));
+ }
+
+ @Test
+ public void reconnectUsesTT0ForFastUserNotification() {
+ final ResponseSupplier responseSupplier = requestDetails -> {
+ final SubscribeEnvelope subscribeEnvelope = new SubscribeEnvelope(emptyList(),
+ new SubscribeMetadata(System.currentTimeMillis(), FAKE_REGION));
+ try {
+ MILLISECONDS.sleep(100);
+ } catch (InterruptedException e) {
+ }
+ return new ResponseHolder<>(Response.success(200, subscribeEnvelope));
+ };
+
+ final RetrofitManager retrofitManagerMock = retrofitManagerMock(responseSupplier);
+ final SubscribeService spiedSubscribeService = retrofitManagerMock.getSubscribeService();
+ final SubscriptionManager subscriptionManager = subscriptionManagerUnderTest(retrofitManagerMock);
+
+ final SubscribeOperation subscribeOperation = SubscribeOperation.builder()
+ .channels(singletonList("ch2"))
+ .channelGroups(singletonList("group2"))
+ .timetoken(42L)
+ .build();
+
+ subscriptionManager.adaptSubscribeBuilder(subscribeOperation);
+ await().atMost(1, SECONDS).untilAsserted(() -> verify(spiedSubscribeService, atLeast(2)).subscribe(any(), any(), any()));
+ subscriptionManager.reconnect();
+ ArgumentCaptor