Update dependencies, add sendMessage, add CompletableFuture variants to SimpleClient methods.

This commit is contained in:
Andrea Cavalli 2023-08-30 11:47:48 +02:00
parent 6de20e1a31
commit 41e83aa950
11 changed files with 237 additions and 43 deletions

View File

@ -86,11 +86,11 @@ If you are using Maven, edit your `pom.xml` file as below:
<!-- Java 8 is supported if you use the following dependency classifier: <classifier>jdk8</classifier> -->
<!-- don't specify the version here -->
</dependency>
<!-- Example linux amd64 (GCC) ssl1 natives -->
<!-- Example linux amd64 (GNU GCC) ssl1 natives -->
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-natives</artifactId>
<classifier>linux_amd64_gcc_ssl1</classifier>
<classifier>linux_amd64_gnu_ssl1</classifier>
<!-- don't specify the version here -->
</dependency>
<!-- Example windows amd64 natives -->
@ -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`

View File

@ -8,8 +8,8 @@
<name>TDLight Java BOM</name>
<properties>
<revision>3.0.0.0-SNAPSHOT</revision>
<tdlight.natives.version>4.0.440</tdlight.natives.version>
<tdlight.api.version>4.0.410</tdlight.api.version>
<tdlight.natives.version>4.0.480</tdlight.natives.version>
<tdlight.api.version>4.0.450</tdlight.api.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
@ -82,43 +82,61 @@
<groupId>it.tdlight</groupId>
<artifactId>tdlight-natives</artifactId>
<version>${tdlight.natives.version}</version>
<classifier>linux_amd64_ssl1</classifier>
<classifier>linux_amd64_clang_ssl3</classifier>
</dependency>
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-natives</artifactId>
<version>${tdlight.natives.version}</version>
<classifier>linux_amd64_ssl3</classifier>
<classifier>linux_amd64_gnu_ssl1</classifier>
</dependency>
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-natives</artifactId>
<version>${tdlight.natives.version}</version>
<classifier>linux_amd64_gcc_ssl1</classifier>
<classifier>linux_amd64_gnu_ssl3</classifier>
</dependency>
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-natives</artifactId>
<version>${tdlight.natives.version}</version>
<classifier>linux_amd64_gcc_ssl3</classifier>
<classifier>linux_arm64_clang_ssl3</classifier>
</dependency>
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-natives</artifactId>
<version>${tdlight.natives.version}</version>
<classifier>linux_arm64_ssl1</classifier>
<classifier>linux_arm64_gnu_ssl1</classifier>
</dependency>
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-natives</artifactId>
<version>${tdlight.natives.version}</version>
<classifier>linux_arm64_ssl3</classifier>
<classifier>linux_arm64_gnu_ssl3</classifier>
</dependency>
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-natives</artifactId>
<version>${tdlight.natives.version}</version>
<classifier>linux_ppc64le_ssl3</classifier>
<classifier>linux_armhf_gnu_ssl1</classifier>
</dependency>
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-natives</artifactId>
<version>${tdlight.natives.version}</version>
<classifier>linux_armhf_gnu_ssl3</classifier>
</dependency>
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-natives</artifactId>
<version>${tdlight.natives.version}</version>
<classifier>linux_ppc64el_gnu_ssl3</classifier>
</dependency>
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-natives</artifactId>
<version>${tdlight.natives.version}</version>
<classifier>linux_riscv64_gnu_ssl3</classifier>
</dependency>
<dependency>
<groupId>it.tdlight</groupId>

View File

@ -44,22 +44,17 @@
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-natives</artifactId>
<classifier>linux_amd64_ssl1</classifier>
<classifier>linux_amd64_gnu_ssl1</classifier>
</dependency>
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-natives</artifactId>
<classifier>linux_amd64_gcc_ssl1</classifier>
<classifier>linux_amd64_clang_ssl3</classifier>
</dependency>
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-natives</artifactId>
<classifier>linux_amd64_ssl3</classifier>
</dependency>
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-natives</artifactId>
<classifier>linux_amd64_gcc_ssl3</classifier>
<classifier>linux_amd64_gnu_ssl3</classifier>
</dependency>
<dependency>
<groupId>it.tdlight</groupId>

View File

@ -7,16 +7,16 @@ import java.util.concurrent.CountDownLatch;
final class AuthorizationStateWaitForExit implements GenericUpdateHandler<TdApi.UpdateAuthorizationState> {
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();
}
}
}

View File

@ -9,7 +9,7 @@ public interface MutableTelegramClient {
<T extends TdApi.Update> void addCommandHandler(String commandName, CommandHandler handler);
<T extends TdApi.Update> void addUpdateHandler(Class<T> updateType, GenericUpdateHandler<T> handler);
<T extends TdApi.Update> void addUpdateHandler(Class<T> updateType, GenericUpdateHandler<? super T> handler);
void addUpdatesHandler(GenericUpdateHandler<TdApi.Update> handler);

View File

@ -8,9 +8,9 @@ import it.tdlight.jni.TdApi.Update;
class SimpleResultHandler<T extends Update> implements ResultHandler<Update> {
private final int updateConstructor;
private final GenericUpdateHandler<T> handler;
private final GenericUpdateHandler<? super T> handler;
public SimpleResultHandler(Class<T> type, GenericUpdateHandler<T> handler) {
public SimpleResultHandler(Class<T> type, GenericUpdateHandler<? super T> handler) {
this.updateConstructor = ConstructorDetector.getConstructor(type);
this.handler = handler;
}

View File

@ -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<Void> closed = new CompletableFuture<>();
private final ConcurrentMap<TemporaryMessageURL, CompletableFuture<Message>> 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 <T extends TdApi.Update> void addUpdateHandler(Class<T> updateType, GenericUpdateHandler<T> handler) {
public <T extends TdApi.Update> void addUpdateHandler(Class<T> updateType, GenericUpdateHandler<? super T> 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 <R extends TdApi.Object> CompletableFuture<R> send(TdApi.Function<R> function) {
CompletableFuture<R> 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<TdApi.Message> sendMessage(TdApi.SendMessage function, boolean wait) {
return this.send(function).thenCompose(msg -> {
CompletableFuture<TdApi.Message> 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.
* <strong>Please note that only some functions can be executed using this method.</strong>
@ -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<Void> 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<Void> waitForExitAsync() {
return closed.copy();
}
private void onCloseUpdate() {
this.closed.complete(null);
this.temporaryMessages.clear();
}
private final class SimpleTelegramClientInteraction implements ClientInteraction {

View File

@ -39,7 +39,7 @@ public final class SimpleTelegramClientBuilder implements MutableTelegramClient
}
@Override
public <T extends Update> void addUpdateHandler(Class<T> updateType, GenericUpdateHandler<T> handler) {
public <T extends Update> void addUpdateHandler(Class<T> updateType, GenericUpdateHandler<? super T> handler) {
this.updateHandlers.add(new SimpleResultHandler<>(updateType, handler));
}

View File

@ -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<TdApi.Update> {
private static final Logger LOG = LoggerFactory.getLogger(TemporaryMessageHandler.class);
private final ConcurrentMap<TemporaryMessageURL, CompletableFuture<Message>> temporaryMessages;
public TemporaryMessageHandler(ConcurrentMap<TemporaryMessageURL, CompletableFuture<Message>> 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<TdApi.Message> 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<TdApi.Message> 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);
}
}

View File

@ -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 + ']';
}
}

View File

@ -80,7 +80,7 @@ public final class Native {
private static Stream<String> getAllNormalizedArchitectures() {
Set<String> 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<String> 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";
}