From 41e83aa950c6a5f06d4f5c708a7ea815b1e6024b Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Wed, 30 Aug 2023 11:47:48 +0200 Subject: [PATCH] Update dependencies, add sendMessage, add CompletableFuture variants to SimpleClient methods. --- README.md | 25 +++--- bom/pom.xml | 36 ++++++--- example/pom.xml | 11 +-- .../client/AuthorizationStateWaitForExit.java | 8 +- .../tdlight/client/MutableTelegramClient.java | 2 +- .../tdlight/client/SimpleResultHandler.java | 4 +- .../tdlight/client/SimpleTelegramClient.java | 79 ++++++++++++++++++- .../client/SimpleTelegramClientBuilder.java | 2 +- .../client/TemporaryMessageHandler.java | 59 ++++++++++++++ .../tdlight/client/TemporaryMessageURL.java | 46 +++++++++++ .../src/main/java/it/tdlight/util/Native.java | 8 +- 11 files changed, 237 insertions(+), 43 deletions(-) create mode 100644 tdlight-java/src/main/java/it/tdlight/client/TemporaryMessageHandler.java create mode 100644 tdlight-java/src/main/java/it/tdlight/client/TemporaryMessageURL.java diff --git a/README.md b/README.md index fd9f4e9..9fc57fa 100644 --- a/README.md +++ b/README.md @@ -86,11 +86,11 @@ If you are using Maven, edit your `pom.xml` file as below: - + it.tdlight tdlight-natives - linux_amd64_gcc_ssl1 + linux_amd64_gnu_ssl1 @@ -124,8 +124,8 @@ dependencies { // do not specify the versions on the dependencies below! implementation group: 'it.tdlight', name: 'tdlight-java' // Java 8 is supported if you use the following dependency classifier: `jdk8` - implementation group: 'it.tdlight', name: 'tdlight-natives', classifier: 'linux_amd64_gcc_ssl1' - // Include other native classifiers, for example linux_amd64_ssl1, linux_amd64_ssl3, macos_amd64, ... --> + implementation group: 'it.tdlight', name: 'tdlight-natives', classifier: 'linux_amd64_gnu_ssl1' + // Include other native classifiers, for example linux_amd64_clang_ssl3, macos_amd64, ... --> } ``` @@ -136,13 +136,16 @@ it [here](https://github.com/tdlight-team/tdlight-java/releases). To use TDLight Java you need to include the native libraries, by specifying one of the following classifier for each tdlight-natives dependency: -- `linux_amd64_ssl1` -- `linux_amd64_ssl3` -- `linux_amd64_gcc_ssl1` -- `linux_amd64_gcc_ssl3` -- `linux_arm64_ssl1` -- `linux_arm64_ssl3` -- `linux_ppc64le_ssl3` +- `linux_amd64_clang_ssl3` +- `linux_amd64_gnu_ssl1` +- `linux_amd64_gnu_ssl3` +- `linux_arm64_clang_ssl3` +- `linux_arm64_gnu_ssl1` +- `linux_arm64_gnu_ssl3` +- `linux_armhf_gnu_ssl1` +- `linux_armhf_gnu_ssl3` +- `linux_ppc64el_gnu_ssl3` +- `linux_riscv64_gnu_ssl3` - `windows_amd64` - `macos_amd64` diff --git a/bom/pom.xml b/bom/pom.xml index d3b70b3..9f31e8e 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -8,8 +8,8 @@ TDLight Java BOM 3.0.0.0-SNAPSHOT - 4.0.440 - 4.0.410 + 4.0.480 + 4.0.450 1.8 1.8 @@ -82,43 +82,61 @@ it.tdlight tdlight-natives ${tdlight.natives.version} - linux_amd64_ssl1 + linux_amd64_clang_ssl3 it.tdlight tdlight-natives ${tdlight.natives.version} - linux_amd64_ssl3 + linux_amd64_gnu_ssl1 it.tdlight tdlight-natives ${tdlight.natives.version} - linux_amd64_gcc_ssl1 + linux_amd64_gnu_ssl3 it.tdlight tdlight-natives ${tdlight.natives.version} - linux_amd64_gcc_ssl3 + linux_arm64_clang_ssl3 it.tdlight tdlight-natives ${tdlight.natives.version} - linux_arm64_ssl1 + linux_arm64_gnu_ssl1 it.tdlight tdlight-natives ${tdlight.natives.version} - linux_arm64_ssl3 + linux_arm64_gnu_ssl3 it.tdlight tdlight-natives ${tdlight.natives.version} - linux_ppc64le_ssl3 + linux_armhf_gnu_ssl1 + + + it.tdlight + tdlight-natives + ${tdlight.natives.version} + linux_armhf_gnu_ssl3 + + + it.tdlight + tdlight-natives + ${tdlight.natives.version} + linux_ppc64el_gnu_ssl3 + + + it.tdlight + tdlight-natives + ${tdlight.natives.version} + linux_riscv64_gnu_ssl3 it.tdlight diff --git a/example/pom.xml b/example/pom.xml index c46c78c..34ffd09 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -44,22 +44,17 @@ it.tdlight tdlight-natives - linux_amd64_ssl1 + linux_amd64_gnu_ssl1 it.tdlight tdlight-natives - linux_amd64_gcc_ssl1 + linux_amd64_clang_ssl3 it.tdlight tdlight-natives - linux_amd64_ssl3 - - - it.tdlight - tdlight-natives - linux_amd64_gcc_ssl3 + linux_amd64_gnu_ssl3 it.tdlight diff --git a/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitForExit.java b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitForExit.java index fd6fef3..4cf324a 100644 --- a/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitForExit.java +++ b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitForExit.java @@ -7,16 +7,16 @@ import java.util.concurrent.CountDownLatch; final class AuthorizationStateWaitForExit implements GenericUpdateHandler { - private final CountDownLatch closed; + private final Runnable setClosed; - public AuthorizationStateWaitForExit(CountDownLatch closed) { - this.closed = closed; + public AuthorizationStateWaitForExit(Runnable setClosed) { + this.setClosed = setClosed; } @Override public void onUpdate(UpdateAuthorizationState update) { if (update.authorizationState.getConstructor() == AuthorizationStateClosed.CONSTRUCTOR) { - closed.countDown(); + setClosed.run(); } } } diff --git a/tdlight-java/src/main/java/it/tdlight/client/MutableTelegramClient.java b/tdlight-java/src/main/java/it/tdlight/client/MutableTelegramClient.java index 7fb8a1f..a7b5737 100644 --- a/tdlight-java/src/main/java/it/tdlight/client/MutableTelegramClient.java +++ b/tdlight-java/src/main/java/it/tdlight/client/MutableTelegramClient.java @@ -9,7 +9,7 @@ public interface MutableTelegramClient { void addCommandHandler(String commandName, CommandHandler handler); - void addUpdateHandler(Class updateType, GenericUpdateHandler handler); + void addUpdateHandler(Class updateType, GenericUpdateHandler handler); void addUpdatesHandler(GenericUpdateHandler handler); diff --git a/tdlight-java/src/main/java/it/tdlight/client/SimpleResultHandler.java b/tdlight-java/src/main/java/it/tdlight/client/SimpleResultHandler.java index 479d513..b624ad2 100644 --- a/tdlight-java/src/main/java/it/tdlight/client/SimpleResultHandler.java +++ b/tdlight-java/src/main/java/it/tdlight/client/SimpleResultHandler.java @@ -8,9 +8,9 @@ import it.tdlight.jni.TdApi.Update; class SimpleResultHandler implements ResultHandler { private final int updateConstructor; - private final GenericUpdateHandler handler; + private final GenericUpdateHandler handler; - public SimpleResultHandler(Class type, GenericUpdateHandler handler) { + public SimpleResultHandler(Class type, GenericUpdateHandler handler) { this.updateConstructor = ConstructorDetector.getConstructor(type); this.handler = handler; } diff --git a/tdlight-java/src/main/java/it/tdlight/client/SimpleTelegramClient.java b/tdlight-java/src/main/java/it/tdlight/client/SimpleTelegramClient.java index 0575100..41f359f 100644 --- a/tdlight-java/src/main/java/it/tdlight/client/SimpleTelegramClient.java +++ b/tdlight-java/src/main/java/it/tdlight/client/SimpleTelegramClient.java @@ -6,6 +6,7 @@ import it.tdlight.ExceptionHandler; import it.tdlight.Init; import it.tdlight.ResultHandler; import it.tdlight.TelegramClient; +import it.tdlight.jni.TdApi.Message; import it.tdlight.jni.TdApi.Update; import it.tdlight.util.UnsupportedNativeLibraryException; import it.tdlight.jni.TdApi; @@ -20,7 +21,12 @@ import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; import java.util.concurrent.RejectedExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,7 +60,8 @@ public final class SimpleTelegramClient implements Authenticable, MutableTelegra private final AuthorizationStateReadyLoadChats mainChatsLoader; private final AuthorizationStateReadyLoadChats archivedChatsLoader; - private final CountDownLatch closed = new CountDownLatch(1); + private final CompletableFuture closed = new CompletableFuture<>(); + private final ConcurrentMap> temporaryMessages = new ConcurrentHashMap<>(); SimpleTelegramClient(ClientFactory clientFactory, TDLibSettings settings, @@ -109,12 +116,15 @@ public final class SimpleTelegramClient implements Authenticable, MutableTelegra this::handleDefaultException ) ); - this.addUpdateHandler(TdApi.UpdateAuthorizationState.class, new AuthorizationStateWaitForExit(this.closed)); + this.addUpdateHandler(TdApi.UpdateAuthorizationState.class, new AuthorizationStateWaitForExit(this::onCloseUpdate)); this.mainChatsLoader = new AuthorizationStateReadyLoadChats(client, new ChatListMain()); this.archivedChatsLoader = new AuthorizationStateReadyLoadChats(client, new ChatListArchive()); this.addUpdateHandler(TdApi.UpdateAuthorizationState.class, this.meGetter = new AuthorizationStateReadyGetMe(client, mainChatsLoader, archivedChatsLoader)); this.addUpdateHandler(TdApi.UpdateNewMessage.class, new CommandsHandler(client, this.commandHandlers, this::getMe)); + var temporaryMessageHandler = new TemporaryMessageHandler(this.temporaryMessages); + this.addUpdateHandler(TdApi.UpdateMessageSendSucceeded.class, temporaryMessageHandler); + this.addUpdateHandler(TdApi.UpdateMessageSendFailed.class, temporaryMessageHandler); this.authenticationData = authenticationData; createDirectories(); client.initialize(this::handleUpdate, this::handleUpdateException, this::handleDefaultException); @@ -191,7 +201,7 @@ public final class SimpleTelegramClient implements Authenticable, MutableTelegra } @Override - public void addUpdateHandler(Class updateType, GenericUpdateHandler handler) { + public void addUpdateHandler(Class updateType, GenericUpdateHandler handler) { this.updateHandlers.put(new SimpleResultHandler<>(updateType, handler), null); } @@ -257,6 +267,44 @@ public final class SimpleTelegramClient implements Authenticable, MutableTelegra client.send(function, result -> resultHandler.onResult(Result.of(result)), resultHandlerExceptionHandler); } + /** + * Sends a request to TDLib and get the result. + * + * @param function The request to TDLib. + * @throws NullPointerException if function is null. + */ + @SuppressWarnings("unchecked") + public CompletableFuture send(TdApi.Function function) { + CompletableFuture future = new CompletableFuture<>(); + client.send(function, result -> { + if (result instanceof TdApi.Error) { + future.completeExceptionally(new TelegramError((TdApi.Error) result)); + } else { + future.complete((R) result); + } + }, future::completeExceptionally); + return future; + } + + /** + * Sends a message + * + * @param function The request to TDLib. + * @param wait Wait until the message has been sent. + * If false, the returned message will not represent the real message, but it will be a temporary message. + * @throws NullPointerException if function is null. + */ + public CompletableFuture sendMessage(TdApi.SendMessage function, boolean wait) { + return this.send(function).thenCompose(msg -> { + CompletableFuture future = new CompletableFuture<>(); + CompletableFuture prev = temporaryMessages.put(new TemporaryMessageURL(msg.chatId, msg.id), future); + if (prev != null) { + prev.completeExceptionally(new IllegalStateException("Another temporary message has the same id")); + } + return future; + }); + } + /** * Execute a synchronous function. * Please note that only some functions can be executed using this method. @@ -266,6 +314,13 @@ public final class SimpleTelegramClient implements Authenticable, MutableTelegra return Result.of(client.execute(function)); } + /** + * Send the close signal but don't wait + */ + public CompletableFuture close() { + return this.send(new TdApi.Close()).thenCompose(x -> this.waitForExitAsync()); + } + /** * Send the close signal but don't wait */ @@ -293,7 +348,23 @@ public final class SimpleTelegramClient implements Authenticable, MutableTelegra * Wait until TDLight is closed */ public void waitForExit() throws InterruptedException { - closed.await(); + try { + closed.get(); + } catch (ExecutionException e) { + throw new RuntimeException(e); + } + } + + /** + * Wait until TDLight is closed + */ + public CompletableFuture waitForExitAsync() { + return closed.copy(); + } + + private void onCloseUpdate() { + this.closed.complete(null); + this.temporaryMessages.clear(); } private final class SimpleTelegramClientInteraction implements ClientInteraction { diff --git a/tdlight-java/src/main/java/it/tdlight/client/SimpleTelegramClientBuilder.java b/tdlight-java/src/main/java/it/tdlight/client/SimpleTelegramClientBuilder.java index e3586f8..10bc836 100644 --- a/tdlight-java/src/main/java/it/tdlight/client/SimpleTelegramClientBuilder.java +++ b/tdlight-java/src/main/java/it/tdlight/client/SimpleTelegramClientBuilder.java @@ -39,7 +39,7 @@ public final class SimpleTelegramClientBuilder implements MutableTelegramClient } @Override - public void addUpdateHandler(Class updateType, GenericUpdateHandler handler) { + public void addUpdateHandler(Class updateType, GenericUpdateHandler handler) { this.updateHandlers.add(new SimpleResultHandler<>(updateType, handler)); } diff --git a/tdlight-java/src/main/java/it/tdlight/client/TemporaryMessageHandler.java b/tdlight-java/src/main/java/it/tdlight/client/TemporaryMessageHandler.java new file mode 100644 index 0000000..cbc11e5 --- /dev/null +++ b/tdlight-java/src/main/java/it/tdlight/client/TemporaryMessageHandler.java @@ -0,0 +1,59 @@ +package it.tdlight.client; + +import it.tdlight.jni.TdApi; +import it.tdlight.jni.TdApi.Message; +import it.tdlight.jni.TdApi.Update; +import it.tdlight.jni.TdApi.UpdateMessageSendFailed; +import it.tdlight.jni.TdApi.UpdateMessageSendSucceeded; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentMap; + +class TemporaryMessageHandler implements GenericUpdateHandler { + + private static final Logger LOG = LoggerFactory.getLogger(TemporaryMessageHandler.class); + + private final ConcurrentMap> temporaryMessages; + + public TemporaryMessageHandler(ConcurrentMap> temporaryMessages) { + this.temporaryMessages = temporaryMessages; + } + + @Override + public void onUpdate(Update update) { + switch (update.getConstructor()) { + case TdApi.UpdateMessageSendSucceeded.CONSTRUCTOR: onUpdateSuccess(((TdApi.UpdateMessageSendSucceeded) update)); + break; + case TdApi.UpdateMessageSendFailed.CONSTRUCTOR: onUpdateFailed(((TdApi.UpdateMessageSendFailed) update)); + break; + } + } + + private void onUpdateSuccess(UpdateMessageSendSucceeded updateMessageSendSucceeded) { + TemporaryMessageURL tempUrl + = new TemporaryMessageURL(updateMessageSendSucceeded.message.chatId, updateMessageSendSucceeded.oldMessageId); + CompletableFuture future = temporaryMessages.remove(tempUrl); + if (future == null) { + logNotHandled(tempUrl); + } else { + future.complete(updateMessageSendSucceeded.message); + } + } + + private void onUpdateFailed(UpdateMessageSendFailed updateMessageSendFailed) { + TemporaryMessageURL tempUrl + = new TemporaryMessageURL(updateMessageSendFailed.message.chatId, updateMessageSendFailed.oldMessageId); + CompletableFuture future = temporaryMessages.remove(tempUrl); + if (future == null) { + logNotHandled(tempUrl); + } else { + TdApi.Error error = new TdApi.Error(updateMessageSendFailed.errorCode, updateMessageSendFailed.errorMessage); + future.completeExceptionally(new TelegramError(error)); + } + } + + private void logNotHandled(TemporaryMessageURL tempUrl) { + LOG.debug("The message {} is not being handled by the client", tempUrl); + } +} diff --git a/tdlight-java/src/main/java/it/tdlight/client/TemporaryMessageURL.java b/tdlight-java/src/main/java/it/tdlight/client/TemporaryMessageURL.java new file mode 100644 index 0000000..857e3a6 --- /dev/null +++ b/tdlight-java/src/main/java/it/tdlight/client/TemporaryMessageURL.java @@ -0,0 +1,46 @@ +package it.tdlight.client; + +import java.util.Objects; + +final class TemporaryMessageURL { + + private final long chatId; + private final long messageId; + + TemporaryMessageURL(long chatId, long messageId) { + this.chatId = chatId; + this.messageId = messageId; + } + + public long chatId() { + return chatId; + } + + public long messageId() { + return messageId; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj == null || obj.getClass() != this.getClass()) { + return false; + } + var that = (TemporaryMessageURL) obj; + return this.chatId == that.chatId && this.messageId == that.messageId; + } + + @Override + public int hashCode() { + return Objects.hash(chatId, messageId); + } + + @Override + public String toString() { + return "TemporaryMessageURL[" + "chatId=" + chatId + ", " + "messageId=" + messageId + ']'; + } + + +} diff --git a/tdlight-java/src/main/java/it/tdlight/util/Native.java b/tdlight-java/src/main/java/it/tdlight/util/Native.java index 08151a6..cc1cf12 100644 --- a/tdlight-java/src/main/java/it/tdlight/util/Native.java +++ b/tdlight-java/src/main/java/it/tdlight/util/Native.java @@ -80,7 +80,7 @@ public final class Native { private static Stream getAllNormalizedArchitectures() { Set all = new LinkedHashSet<>(); for (String os : new String[]{"windows"}) { - for (String arch : new String[]{"arm64", "amd64", "armhf", "i386", "s390x", "ppc64le"}) { + for (String arch : new String[]{"arm64", "amd64", "armhf", "i386", "s390x", "ppc64el", "riscv64"}) { getNormalizedArchitectures(os, arch).forEach(all::add); } } @@ -90,7 +90,7 @@ public final class Native { private static Stream getNormalizedArchitectures(String os, String arch) { switch (os) { case "linux": { - return Stream.of("linux_" + arch + "_ssl1", "linux_" + arch + "_ssl3", "linux_" + arch + "_gcc_ssl1", "linux_" + arch + "_gcc_ssl3"); + return Stream.of("linux_" + arch + "_clang_ssl1", "linux_" + arch + "_clang_ssl3", "linux_" + arch + "_gnu_ssl1", "linux_" + arch + "_gnu_ssl3"); } case "windows": { return Stream.of("windows_" + arch); @@ -130,6 +130,8 @@ public final class Native { return "arm64"; case "s390x": return "s390x"; + case "riscv64": + return "riscv64"; case "powerpc": case "powerpc64": case "powerpc64le": @@ -142,7 +144,7 @@ public final class Native { .nativeOrder() .equals(ByteOrder.LITTLE_ENDIAN)) // Java always returns ppc64 for all 64-bit powerpc but { - return "ppc64le"; // powerpc64le (our target) is very different, it uses this condition to accurately identify the architecture + return "ppc64el"; // powerpc64le (our target) is very different, it uses this condition to accurately identify the architecture } else { return "unknown"; }