Wait for readiness, update example
This commit is contained in:
parent
db8676cb6d
commit
652d116ad9
@ -26,7 +26,7 @@
|
||||
<dependency>
|
||||
<groupId>it.tdlight</groupId>
|
||||
<artifactId>tdlight-java-bom</artifactId>
|
||||
<version>3.1.0+td.1.8.16</version>
|
||||
<version>3.1.1+td.1.8.16</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
|
@ -8,8 +8,12 @@ import it.tdlight.client.TDLibSettings;
|
||||
import it.tdlight.Init;
|
||||
import it.tdlight.jni.TdApi.AuthorizationState;
|
||||
import it.tdlight.jni.TdApi.Chat;
|
||||
import it.tdlight.jni.TdApi.FormattedText;
|
||||
import it.tdlight.jni.TdApi.InputMessageText;
|
||||
import it.tdlight.jni.TdApi.MessageContent;
|
||||
import it.tdlight.jni.TdApi;
|
||||
import it.tdlight.jni.TdApi.SendMessage;
|
||||
import it.tdlight.jni.TdApi.TextEntity;
|
||||
import it.tdlight.util.UnsupportedNativeLibraryException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
@ -26,7 +30,7 @@ public final class Example {
|
||||
*/
|
||||
private static final TdApi.MessageSender ADMIN_ID = new TdApi.MessageSenderUser(667900586);
|
||||
|
||||
private static SimpleTelegramClient client;
|
||||
private static SimpleTelegramClient CLIENT;
|
||||
|
||||
public static void main(String[] args) throws UnsupportedNativeLibraryException, InterruptedException {
|
||||
// Initialize TDLight native libraries
|
||||
@ -34,7 +38,6 @@ public final class Example {
|
||||
|
||||
// Create the client factory
|
||||
try (SimpleTelegramClientFactory clientFactory = new SimpleTelegramClientFactory()) {
|
||||
|
||||
// Obtain the API token
|
||||
//
|
||||
// var apiToken = new APIToken(your-api-id-here, "your-api-hash-here");
|
||||
@ -69,10 +72,24 @@ public final class Example {
|
||||
clientBuilder.addCommandHandler("stop", new StopCommandHandler());
|
||||
|
||||
// Create and start the client
|
||||
client = clientBuilder.build(authenticationData);
|
||||
SimpleTelegramClient client = CLIENT = clientBuilder.build(authenticationData);
|
||||
try (client) {
|
||||
|
||||
// Wait for exit
|
||||
client.waitForExit();
|
||||
// Get me
|
||||
TdApi.User me = client.getMeAsync().join();
|
||||
|
||||
// Send a test message
|
||||
var req = new SendMessage();
|
||||
req.chatId = me.id;
|
||||
var txt = new InputMessageText();
|
||||
txt.text = new FormattedText("TDLight test", new TextEntity[0]);
|
||||
req.inputMessageContent = txt;
|
||||
var result = client.sendMessage(req, true).join();
|
||||
System.out.println("Sent message:" + result);
|
||||
|
||||
// Wait for exit
|
||||
client.waitForExit();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import it.tdlight.jni.TdApi.UpdateAuthorizationState;
|
||||
import it.tdlight.jni.TdApi.User;
|
||||
import it.tdlight.jni.TdApi.Error;
|
||||
import it.tdlight.jni.TdApi.UserTypeRegular;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -16,6 +17,7 @@ final class AuthorizationStateReadyGetMe implements GenericUpdateHandler<UpdateA
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuthorizationStateReadyGetMe.class);
|
||||
|
||||
private final TelegramClient client;
|
||||
private final CompletableFuture<Void> meReceived = new CompletableFuture<>();
|
||||
private final AtomicReference<User> me = new AtomicReference<>();
|
||||
private final AuthorizationStateReadyLoadChats mainChatsLoader;
|
||||
private final AuthorizationStateReadyLoadChats archivedChatsLoader;
|
||||
@ -47,4 +49,8 @@ final class AuthorizationStateReadyGetMe implements GenericUpdateHandler<UpdateA
|
||||
public User getMe() {
|
||||
return me.get();
|
||||
}
|
||||
|
||||
public CompletableFuture<User> getMeAsync() {
|
||||
return meReceived.thenApply(v -> me.get());
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package it.tdlight.client;
|
||||
|
||||
import it.tdlight.jni.TdApi.AuthorizationStateReady;
|
||||
import it.tdlight.jni.TdApi.UpdateAuthorizationState;
|
||||
|
||||
final class AuthorizationStateWaitReady implements GenericUpdateHandler<UpdateAuthorizationState> {
|
||||
|
||||
private final Runnable setReady;
|
||||
|
||||
public AuthorizationStateWaitReady(Runnable setReady) {
|
||||
this.setReady = setReady;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(UpdateAuthorizationState update) {
|
||||
if (update.authorizationState.getConstructor() == AuthorizationStateReady.CONSTRUCTOR) {
|
||||
setReady.run();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +1,22 @@
|
||||
package it.tdlight.client;
|
||||
|
||||
import static it.tdlight.util.MapUtils.addAllKeys;
|
||||
|
||||
import io.atlassian.util.concurrent.CopyOnWriteMap;
|
||||
import it.tdlight.ClientFactory;
|
||||
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.FutureSupport;
|
||||
import it.tdlight.util.UnsupportedNativeLibraryException;
|
||||
import it.tdlight.jni.TdApi;
|
||||
import it.tdlight.jni.TdApi.ChatListArchive;
|
||||
import it.tdlight.jni.TdApi.ChatListMain;
|
||||
import it.tdlight.jni.TdApi.Function;
|
||||
import it.tdlight.jni.TdApi.Message;
|
||||
import it.tdlight.jni.TdApi.Update;
|
||||
import it.tdlight.jni.TdApi.User;
|
||||
import it.tdlight.util.FutureSupport;
|
||||
import it.tdlight.util.UnsupportedNativeLibraryException;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
@ -22,20 +24,16 @@ 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 java.util.concurrent.TimeUnit;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static it.tdlight.util.MapUtils.addAllKeys;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public final class SimpleTelegramClient implements Authenticable, MutableTelegramClient {
|
||||
public final class SimpleTelegramClient implements Authenticable, MutableTelegramClient, AutoCloseable {
|
||||
|
||||
public static final Logger LOG = LoggerFactory.getLogger(SimpleTelegramClient.class);
|
||||
|
||||
@ -61,6 +59,7 @@ public final class SimpleTelegramClient implements Authenticable, MutableTelegra
|
||||
private final AuthorizationStateReadyLoadChats mainChatsLoader;
|
||||
private final AuthorizationStateReadyLoadChats archivedChatsLoader;
|
||||
|
||||
private final CompletableFuture<Void> ready = new CompletableFuture<>();
|
||||
private final CompletableFuture<Void> closed = new CompletableFuture<>();
|
||||
private final ConcurrentMap<TemporaryMessageURL, CompletableFuture<Message>> temporaryMessages = new ConcurrentHashMap<>();
|
||||
|
||||
@ -117,6 +116,7 @@ public final class SimpleTelegramClient implements Authenticable, MutableTelegra
|
||||
this::handleDefaultException
|
||||
)
|
||||
);
|
||||
this.addUpdateHandler(TdApi.UpdateAuthorizationState.class, new AuthorizationStateWaitReady(this::onReady));
|
||||
this.addUpdateHandler(TdApi.UpdateAuthorizationState.class, new AuthorizationStateWaitForExit(this::onCloseUpdate));
|
||||
this.mainChatsLoader = new AuthorizationStateReadyLoadChats(client, new ChatListMain());
|
||||
this.archivedChatsLoader = new AuthorizationStateReadyLoadChats(client, new ChatListArchive());
|
||||
@ -240,6 +240,61 @@ public final class SimpleTelegramClient implements Authenticable, MutableTelegra
|
||||
}
|
||||
}
|
||||
|
||||
private <R extends TdApi.Object> boolean shouldWaitForReadiness(Function<R> function) {
|
||||
switch (function.getConstructor()) {
|
||||
case TdApi.Close.CONSTRUCTOR:
|
||||
case TdApi.SetLogVerbosityLevel.CONSTRUCTOR:
|
||||
case TdApi.SetLogTagVerbosityLevel.CONSTRUCTOR:
|
||||
case TdApi.SetLogStream.CONSTRUCTOR:
|
||||
case TdApi.SetNetworkType.CONSTRUCTOR:
|
||||
case TdApi.SetOption.CONSTRUCTOR:
|
||||
case TdApi.GetOption.CONSTRUCTOR:
|
||||
case TdApi.GetAuthorizationState.CONSTRUCTOR:
|
||||
case TdApi.GetCurrentState.CONSTRUCTOR:
|
||||
case TdApi.GetLogStream.CONSTRUCTOR:
|
||||
case TdApi.GetLogTags.CONSTRUCTOR:
|
||||
case TdApi.GetLogVerbosityLevel.CONSTRUCTOR:
|
||||
case TdApi.GetLogTagVerbosityLevel.CONSTRUCTOR:
|
||||
case TdApi.GetNetworkStatistics.CONSTRUCTOR:
|
||||
case TdApi.AddNetworkStatistics.CONSTRUCTOR:
|
||||
case TdApi.ResetNetworkStatistics.CONSTRUCTOR:
|
||||
case TdApi.AddProxy.CONSTRUCTOR:
|
||||
case TdApi.DisableProxy.CONSTRUCTOR:
|
||||
case TdApi.EditProxy.CONSTRUCTOR:
|
||||
case TdApi.RemoveProxy.CONSTRUCTOR:
|
||||
case TdApi.PingProxy.CONSTRUCTOR:
|
||||
case TdApi.TestProxy.CONSTRUCTOR:
|
||||
case TdApi.EnableProxy.CONSTRUCTOR:
|
||||
case TdApi.GetProxyLink.CONSTRUCTOR:
|
||||
case TdApi.GetProxies.CONSTRUCTOR:
|
||||
case TdApi.LogOut.CONSTRUCTOR:
|
||||
case TdApi.SetTdlibParameters.CONSTRUCTOR:
|
||||
case TdApi.CheckAuthenticationCode.CONSTRUCTOR:
|
||||
case TdApi.CheckAuthenticationBotToken.CONSTRUCTOR:
|
||||
case TdApi.CheckAuthenticationEmailCode.CONSTRUCTOR:
|
||||
case TdApi.CheckAuthenticationPassword.CONSTRUCTOR:
|
||||
case TdApi.CheckAuthenticationPasswordRecoveryCode.CONSTRUCTOR:
|
||||
case TdApi.SetAuthenticationPhoneNumber.CONSTRUCTOR:
|
||||
case TdApi.GetCountries.CONSTRUCTOR:
|
||||
case TdApi.GetCountryCode.CONSTRUCTOR:
|
||||
case TdApi.GetDatabaseStatistics.CONSTRUCTOR:
|
||||
case TdApi.GetDeepLinkInfo.CONSTRUCTOR:
|
||||
case TdApi.ParseMarkdown.CONSTRUCTOR:
|
||||
case TdApi.ParseTextEntities.CONSTRUCTOR:
|
||||
case TdApi.GetJsonString.CONSTRUCTOR:
|
||||
case TdApi.GetJsonValue.CONSTRUCTOR:
|
||||
case TdApi.GetLoginUrl.CONSTRUCTOR:
|
||||
case TdApi.GetLoginUrlInfo.CONSTRUCTOR:
|
||||
case TdApi.GetMarkdownText.CONSTRUCTOR:
|
||||
case TdApi.GetMemoryStatistics.CONSTRUCTOR:
|
||||
case TdApi.GetRecoveryEmailAddress.CONSTRUCTOR:
|
||||
case TdApi.GetStorageStatistics.CONSTRUCTOR:
|
||||
case TdApi.GetStorageStatisticsFast.CONSTRUCTOR:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a request to TDLib and get the result.
|
||||
*
|
||||
@ -248,7 +303,7 @@ public final class SimpleTelegramClient implements Authenticable, MutableTelegra
|
||||
* @throws NullPointerException if function is null.
|
||||
*/
|
||||
public <R extends TdApi.Object> void send(TdApi.Function<R> function, GenericResultHandler<R> resultHandler) {
|
||||
client.send(function, result -> resultHandler.onResult(Result.of(result)), this::handleResultHandlingException);
|
||||
this.send(function, resultHandler, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -262,6 +317,30 @@ public final class SimpleTelegramClient implements Authenticable, MutableTelegra
|
||||
*/
|
||||
public <R extends TdApi.Object> void send(TdApi.Function<R> function, GenericResultHandler<R> resultHandler,
|
||||
ExceptionHandler resultHandlerExceptionHandler) {
|
||||
if (shouldWaitForReadiness(function)) {
|
||||
ready.whenComplete((ignored, error) -> {
|
||||
if (error != null) {
|
||||
resultHandler.onResult(Result.ofError(error));
|
||||
} else {
|
||||
this.sendUnsafe(function, resultHandler, resultHandlerExceptionHandler);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.sendUnsafe(function, resultHandler, resultHandlerExceptionHandler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a request to TDLib and get the result.
|
||||
*
|
||||
* @param function The request to TDLib.
|
||||
* @param resultHandler Result handler. If it is null, nothing will be called.
|
||||
* @param resultHandlerExceptionHandler Handle exceptions thrown inside the result handler.
|
||||
* If it is null, the default exception handler will be called.
|
||||
* @throws NullPointerException if function is null.
|
||||
*/
|
||||
public <R extends TdApi.Object> void sendUnsafe(TdApi.Function<R> function, GenericResultHandler<R> resultHandler,
|
||||
ExceptionHandler resultHandlerExceptionHandler) {
|
||||
if (resultHandlerExceptionHandler == null) {
|
||||
resultHandlerExceptionHandler = this::handleResultHandlingException;
|
||||
}
|
||||
@ -276,6 +355,22 @@ public final class SimpleTelegramClient implements Authenticable, MutableTelegra
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <R extends TdApi.Object> CompletableFuture<R> send(TdApi.Function<R> function) {
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
if (shouldWaitForReadiness(function)) {
|
||||
return ready.thenCompose(r -> this.sendUnsafe(function));
|
||||
} else {
|
||||
return this.sendUnsafe(function);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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> sendUnsafe(TdApi.Function<R> function) {
|
||||
CompletableFuture<R> future = new CompletableFuture<>();
|
||||
client.send(function, result -> {
|
||||
if (result instanceof TdApi.Error) {
|
||||
@ -296,14 +391,19 @@ public final class SimpleTelegramClient implements Authenticable, MutableTelegra
|
||||
* @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;
|
||||
});
|
||||
CompletableFuture<TdApi.Message> sendRequest = this.send(function);
|
||||
if (wait) {
|
||||
return sendRequest.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;
|
||||
});
|
||||
} else {
|
||||
return sendRequest;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -318,7 +418,7 @@ public final class SimpleTelegramClient implements Authenticable, MutableTelegra
|
||||
/**
|
||||
* Send the close signal but don't wait
|
||||
*/
|
||||
public CompletableFuture<Void> close() {
|
||||
public CompletableFuture<Void> closeAsync() {
|
||||
return this.send(new TdApi.Close()).thenCompose(x -> this.waitForExitAsync());
|
||||
}
|
||||
|
||||
@ -363,11 +463,21 @@ public final class SimpleTelegramClient implements Authenticable, MutableTelegra
|
||||
return FutureSupport.copy(closed);
|
||||
}
|
||||
|
||||
private void onReady() {
|
||||
this.ready.complete(null);
|
||||
}
|
||||
|
||||
private void onCloseUpdate() {
|
||||
this.ready.completeExceptionally(new TelegramError(new TdApi.Error(400, "Client closed")));
|
||||
this.closed.complete(null);
|
||||
this.temporaryMessages.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
this.closeAsync().get(90, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private final class SimpleTelegramClientInteraction implements ClientInteraction {
|
||||
|
||||
public SimpleTelegramClientInteraction() {
|
||||
@ -388,6 +498,10 @@ public final class SimpleTelegramClient implements Authenticable, MutableTelegra
|
||||
return meGetter.getMe();
|
||||
}
|
||||
|
||||
public CompletableFuture<User> getMeAsync() {
|
||||
return meGetter.getMeAsync();
|
||||
}
|
||||
|
||||
public boolean isMainChatsListLoaded() {
|
||||
return mainChatsLoader.isLoaded();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user