diff --git a/.github/workflows/maven-publish.yml b/.github/workflows/maven-publish.yml
index 023e679..cd3bd65 100644
--- a/.github/workflows/maven-publish.yml
+++ b/.github/workflows/maven-publish.yml
@@ -27,11 +27,11 @@ jobs:
export REVISION=${{ github.run_number }}
echo "REVISION=$REVISION" >> $GITHUB_ENV
- - name: Set up JDK 15
+ - name: Set up JDK 17
if: github.ref == 'refs/heads/master'
uses: actions/setup-java@v1
with:
- java-version: 15
+ java-version: 17
server-id: mchv-release-distribution
server-username: MAVEN_USERNAME
server-password: MAVEN_PASSWORD
diff --git a/pom.xml b/pom.xml
index 4b342ca..dae3925 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
UTF-8
0-SNAPSHOT
- 3.1.10
+ 3.1.12
33
@@ -159,6 +159,11 @@
jackson-dataformat-yaml
2.13.2
+
+ jakarta.xml.bind
+ jakarta.xml.bind-api
+ 4.0.0
+
net.minecrell
terminalconsoleappender
diff --git a/src/main/java/it/tdlight/reactiveapi/AtomixReactiveApiMultiClient.java b/src/main/java/it/tdlight/reactiveapi/AtomixReactiveApiMultiClient.java
index 52d4d93..b78f069 100644
--- a/src/main/java/it/tdlight/reactiveapi/AtomixReactiveApiMultiClient.java
+++ b/src/main/java/it/tdlight/reactiveapi/AtomixReactiveApiMultiClient.java
@@ -6,7 +6,7 @@ import io.atomix.cluster.messaging.ClusterEventService;
import io.atomix.cluster.messaging.MessagingException;
import it.tdlight.jni.TdApi;
import it.tdlight.reactiveapi.Event.ClientBoundEvent;
-import it.tdlight.reactiveapi.Event.Request;
+import it.tdlight.reactiveapi.Event.OnRequest.Request;
import java.net.ConnectException;
import java.time.Duration;
import java.time.Instant;
diff --git a/src/main/java/it/tdlight/reactiveapi/BaseAtomixReactiveApiClient.java b/src/main/java/it/tdlight/reactiveapi/BaseAtomixReactiveApiClient.java
index 57efdb8..6543f65 100644
--- a/src/main/java/it/tdlight/reactiveapi/BaseAtomixReactiveApiClient.java
+++ b/src/main/java/it/tdlight/reactiveapi/BaseAtomixReactiveApiClient.java
@@ -1,30 +1,39 @@
package it.tdlight.reactiveapi;
+import static it.tdlight.reactiveapi.Event.SERIAL_VERSION;
+
import io.atomix.cluster.messaging.ClusterEventService;
import io.atomix.cluster.messaging.MessagingException;
import io.atomix.core.Atomix;
+import it.tdlight.common.utils.LibraryVersion;
import it.tdlight.jni.TdApi;
import it.tdlight.reactiveapi.Event.ClientBoundEvent;
+import it.tdlight.reactiveapi.Event.Ignored;
import it.tdlight.reactiveapi.Event.OnBotLoginCodeRequested;
import it.tdlight.reactiveapi.Event.OnOtherDeviceLoginRequested;
import it.tdlight.reactiveapi.Event.OnPasswordRequested;
+import it.tdlight.reactiveapi.Event.OnRequest.Request;
import it.tdlight.reactiveapi.Event.OnUpdateData;
import it.tdlight.reactiveapi.Event.OnUpdateError;
import it.tdlight.reactiveapi.Event.OnUserLoginCodeRequested;
-import it.tdlight.reactiveapi.Event.Request;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ConnectException;
+import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletionException;
import java.util.concurrent.TimeoutException;
+import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.SerializationException;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.Disposable;
@@ -119,7 +128,12 @@ abstract class BaseAtomixReactiveApiClient implements ReactiveApiClient, AutoClo
if (bytes == null || bytes.length == 0) {
return null;
}
- return TdApi.Deserializer.deserialize(new DataInputStream(new ByteArrayInputStream(bytes)));
+ var dis = new DataInputStream(new ByteArrayInputStream(bytes));
+ var serialVersion = dis.readInt();
+ if (serialVersion != SERIAL_VERSION) {
+ return new TdApi.Error(400, "Conflicting protocol version");
+ }
+ return TdApi.Deserializer.deserialize(dis);
} catch (IOException ex) {
throw new SerializationException(ex);
}
@@ -129,6 +143,7 @@ abstract class BaseAtomixReactiveApiClient implements ReactiveApiClient, AutoClo
try (var byteArrayOutputStream = new ByteArrayOutputStream()) {
try (var dataOutputStream = new DataOutputStream(byteArrayOutputStream)) {
dataOutputStream.writeLong(request.liveId());
+ dataOutputStream.writeInt(SERIAL_VERSION);
dataOutputStream.writeLong(request.timeout().toEpochMilli());
request.request().serialize(dataOutputStream);
dataOutputStream.flush();
@@ -164,9 +179,13 @@ abstract class BaseAtomixReactiveApiClient implements ReactiveApiClient, AutoClo
}
}
- static ClientBoundEvent deserializeEvent(DataInputStream is) throws IOException {
+ static @NotNull ClientBoundEvent deserializeEvent(DataInputStream is) throws IOException {
var liveId = is.readLong();
var userId = is.readLong();
+ var dataVersion = is.readInt();
+ if (dataVersion != SERIAL_VERSION) {
+ return new Ignored(liveId, userId);
+ }
return switch (is.readByte()) {
case 0x01 -> new OnUpdateData(liveId, userId, (TdApi.Update) TdApi.Deserializer.deserialize(is));
case 0x02 -> new OnUpdateError(liveId, userId, (TdApi.Error) TdApi.Deserializer.deserialize(is));
diff --git a/src/main/java/it/tdlight/reactiveapi/Event.java b/src/main/java/it/tdlight/reactiveapi/Event.java
index f15c6b2..385aec0 100644
--- a/src/main/java/it/tdlight/reactiveapi/Event.java
+++ b/src/main/java/it/tdlight/reactiveapi/Event.java
@@ -1,17 +1,25 @@
package it.tdlight.reactiveapi;
+import it.tdlight.common.utils.LibraryVersion;
import it.tdlight.jni.TdApi;
import it.tdlight.reactiveapi.Event.ClientBoundEvent;
+import it.tdlight.reactiveapi.Event.OnRequest.InvalidRequest;
+import it.tdlight.reactiveapi.Event.OnRequest.Request;
import it.tdlight.reactiveapi.Event.ServerBoundEvent;
import java.io.DataInput;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.time.Instant;
+import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.SerializationException;
+import org.jetbrains.annotations.Nullable;
/**
* Any event received from a session
*/
-public sealed interface Event permits ClientBoundEvent, ServerBoundEvent {
+public sealed interface Event {
+
+ int SERIAL_VERSION = ArrayUtils.hashCode(LibraryVersion.VERSION.getBytes(StandardCharsets.US_ASCII));
/**
*
@@ -22,8 +30,7 @@ public sealed interface Event permits ClientBoundEvent, ServerBoundEvent {
/**
* Event received after choosing the user id of the session
*/
- sealed interface ClientBoundEvent extends Event permits OnLoginCodeRequested, OnOtherDeviceLoginRequested,
- OnPasswordRequested, OnUpdate {
+ sealed interface ClientBoundEvent extends Event {
/**
*
@@ -32,13 +39,12 @@ public sealed interface Event permits ClientBoundEvent, ServerBoundEvent {
long userId();
}
- sealed interface ServerBoundEvent extends Event permits Request {}
+ sealed interface ServerBoundEvent extends Event {}
/**
* TDLib is asking for an authorization code
*/
- sealed interface OnLoginCodeRequested extends ClientBoundEvent
- permits OnBotLoginCodeRequested, OnUserLoginCodeRequested {}
+ sealed interface OnLoginCodeRequested extends ClientBoundEvent {}
record OnUserLoginCodeRequested(long liveId, long userId, long phoneNumber) implements OnLoginCodeRequested {}
@@ -49,21 +55,32 @@ public sealed interface Event permits ClientBoundEvent, ServerBoundEvent {
record OnPasswordRequested(long liveId, long userId, String passwordHint, boolean hasRecoveryEmail,
String recoveryEmailPattern) implements ClientBoundEvent {}
+ record Ignored(long liveId, long userId) implements ClientBoundEvent {}
+
/**
* Event received from TDLib
*/
- sealed interface OnUpdate extends ClientBoundEvent permits OnUpdateData, OnUpdateError {}
+ sealed interface OnUpdate extends ClientBoundEvent {}
record OnUpdateData(long liveId, long userId, TdApi.Update update) implements OnUpdate {}
record OnUpdateError(long liveId, long userId, TdApi.Error error) implements OnUpdate {}
- record Request(long liveId, TdApi.Function request, Instant timeout) implements
- ServerBoundEvent {
+ sealed interface OnRequest extends ServerBoundEvent {
- public static Request deserialize(DataInput dataInput) {
+ record Request(long liveId, TdApi.Function request, Instant timeout)
+ implements OnRequest {}
+
+ record InvalidRequest(long liveId) implements OnRequest {}
+
+ static Event.OnRequest deserialize(DataInput dataInput) {
try {
var liveId = dataInput.readLong();
+ var dataVersion = dataInput.readInt();
+ if (dataVersion != SERIAL_VERSION) {
+ // Deprecated request
+ return new InvalidRequest<>(liveId);
+ }
long millis = dataInput.readLong();
var timeout = Instant.ofEpochMilli(millis);
@SuppressWarnings("unchecked")
diff --git a/src/main/java/it/tdlight/reactiveapi/ReactiveApiPublisher.java b/src/main/java/it/tdlight/reactiveapi/ReactiveApiPublisher.java
index 12d0f30..e58ed45 100644
--- a/src/main/java/it/tdlight/reactiveapi/ReactiveApiPublisher.java
+++ b/src/main/java/it/tdlight/reactiveapi/ReactiveApiPublisher.java
@@ -2,6 +2,7 @@ package it.tdlight.reactiveapi;
import static it.tdlight.reactiveapi.AuthPhase.LOGGED_IN;
import static it.tdlight.reactiveapi.AuthPhase.LOGGED_OUT;
+import static it.tdlight.reactiveapi.Event.SERIAL_VERSION;
import static java.util.Objects.requireNonNull;
import static java.util.concurrent.CompletableFuture.completedFuture;
@@ -30,10 +31,12 @@ import it.tdlight.reactiveapi.Event.ClientBoundEvent;
import it.tdlight.reactiveapi.Event.OnBotLoginCodeRequested;
import it.tdlight.reactiveapi.Event.OnOtherDeviceLoginRequested;
import it.tdlight.reactiveapi.Event.OnPasswordRequested;
+import it.tdlight.reactiveapi.Event.OnRequest;
+import it.tdlight.reactiveapi.Event.OnRequest.InvalidRequest;
+import it.tdlight.reactiveapi.Event.OnRequest.Request;
import it.tdlight.reactiveapi.Event.OnUpdateData;
import it.tdlight.reactiveapi.Event.OnUpdateError;
import it.tdlight.reactiveapi.Event.OnUserLoginCodeRequested;
-import it.tdlight.reactiveapi.Event.Request;
import it.tdlight.reactiveapi.ResultingEvent.ClientBoundResultingEvent;
import it.tdlight.reactiveapi.ResultingEvent.ClusterBoundResultingEvent;
import it.tdlight.reactiveapi.ResultingEvent.ResultingEventPublisherClosed;
@@ -439,6 +442,7 @@ public abstract class ReactiveApiPublisher {
throws IOException {
dataOutputStream.writeLong(clientBoundEvent.liveId());
dataOutputStream.writeLong(clientBoundEvent.userId());
+ dataOutputStream.writeInt(SERIAL_VERSION);
if (clientBoundEvent instanceof OnUpdateData onUpdateData) {
dataOutputStream.writeByte(0x1);
onUpdateData.update().serialize(dataOutputStream);
@@ -485,6 +489,7 @@ public abstract class ReactiveApiPublisher {
var object = response.getObject();
try (var byteArrayOutputStream = new ByteArrayOutputStream()) {
try (var dataOutputStream = new DataOutputStream(byteArrayOutputStream)) {
+ dataOutputStream.writeInt(SERIAL_VERSION);
//dataOutputStream.writeLong(id);
object.serialize(dataOutputStream);
return byteArrayOutputStream.toByteArray();
@@ -494,7 +499,11 @@ public abstract class ReactiveApiPublisher {
}
}
- private CompletableFuture handleRequest(Request