CompletableFuture support

This commit is contained in:
rubenlagus 2020-11-03 02:24:07 +00:00 committed by Ruben Bermudez
parent 447c9d3f92
commit fb5626de7a
4 changed files with 340 additions and 30 deletions

View File

@ -6,6 +6,7 @@
5. Locations now use Double instead of Float to avoid rounding.
6. When registering a Webhook Bot, a SetWebhook object must be provided.
7. When using Webhook with Spring, extends class SpringWebhookBot instead of WebhookBot
8. New Async methods returning CompletableFutures.
### <a id="4.9.2"></a>4.9.2 ###
1. Bug fixing: #792, #801, #804, #810, #812, #813, #820 and #814

View File

@ -66,14 +66,4 @@ public class PassportElementErrorTranslationFiles implements PassportElementErro
throw new TelegramApiValidationException("Type parameter can't be empty", this);
}
}
@Override
public String toString() {
return "PassportElementErrorTranslationFiles{" +
"source='" + source + '\'' +
", type='" + type + '\'' +
", fileHashes=" + fileHashes +
", message='" + message + '\'' +
'}';
}
}

View File

@ -27,6 +27,7 @@ import org.telegram.telegrambots.meta.updateshandlers.SentCallback;
import java.io.Serializable;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* @author Ruben Bermudez
@ -49,6 +50,13 @@ public abstract class AbsSender {
sendApiMethodAsync(method, callback);
}
public <T extends Serializable, Method extends BotApiMethod<T>> CompletableFuture<T> executeAsync(Method method) throws TelegramApiException {
if (method == null) {
throw new TelegramApiException("Parameter method can not be null");
}
return sendApiMethodAsync(method);
}
public <T extends Serializable, Method extends BotApiMethod<T>> T execute(Method method) throws TelegramApiException {
if (method == null) {
throw new TelegramApiException("Parameter method can not be null");
@ -70,6 +78,15 @@ public abstract class AbsSender {
// Send Requests Async
public final CompletableFuture<User> getMeAsync() {
return sendApiMethodAsync(new GetMe());
}
public final CompletableFuture<WebhookInfo> getWebhookInfoAsync() {
return sendApiMethodAsync(new GetWebhookInfo());
}
public final void getMeAsync(SentCallback<User> sentCallback) throws TelegramApiException {
if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be null");
@ -175,9 +192,94 @@ public abstract class AbsSender {
*/
public abstract Message execute(SendAnimation sendAnimation) throws TelegramApiException;
// Specific Send Requests Async
public abstract CompletableFuture<Message> executeAsync(SendDocument sendDocument);
public abstract CompletableFuture<Message> executeAsync(SendPhoto sendPhoto);
public abstract CompletableFuture<Message> executeAsync(SendVideo sendVideo);
public abstract CompletableFuture<Message> executeAsync(SendVideoNote sendVideoNote);
public abstract CompletableFuture<Message> executeAsync(SendSticker sendSticker);
/**
* Sends a file using Send Audio method (https://core.telegram.org/bots/api#sendaudio)
* @param sendAudio Information to send
* @return If success, the sent Message is returned
*/
public abstract CompletableFuture<Message> executeAsync(SendAudio sendAudio);
/**
* Sends a voice note using Send Voice method (https://core.telegram.org/bots/api#sendvoice)
* For this to work, your audio must be in an .ogg file encoded with OPUS
* @param sendVoice Information to send
* @return If success, the sent Message is returned
*/
public abstract CompletableFuture<Message> executeAsync(SendVoice sendVoice);
/**
* Send a media group (https://core.telegram.org/bots/api#sendMediaGroup)
* @return If success, list of generated messages
*/
public abstract CompletableFuture<List<Message>> executeAsync(SendMediaGroup sendMediaGroup);
/**
* Set chat profile photo (https://core.telegram.org/bots/api#setChatPhoto)
* @param setChatPhoto Information to set the photo
* @return If success, true is returned
*/
public abstract CompletableFuture<Boolean> executeAsync(SetChatPhoto setChatPhoto);
/**
* Adds a new sticker to a set (https://core.telegram.org/bots/api#addStickerToSet)
* @param addStickerToSet Information of the sticker to set
* @return If success, true is returned
*/
public abstract CompletableFuture<Boolean> executeAsync(AddStickerToSet addStickerToSet);
/**
* Set sticker set thumb (https://core.telegram.org/bots/api#setStickerSetThumb)
* @param setStickerSetThumb Information of the sticker to set
* @return If success, true is returned
*/
public abstract CompletableFuture<Boolean> executeAsync(SetStickerSetThumb setStickerSetThumb);
/**
* Creates a new sticker set (https://core.telegram.org/bots/api#createNewStickerSet)
* @param createNewStickerSet Information of the sticker set to create
* @return If success, true is returned
*/
public abstract CompletableFuture<Boolean> executeAsync(CreateNewStickerSet createNewStickerSet);
/**
* Upload a new file as sticker (https://core.telegram.org/bots/api#uploadStickerFile)
* @param uploadStickerFile Information of the file to upload as sticker
* @return If success, true is returned
*/
public abstract CompletableFuture<File> executeAsync(UploadStickerFile uploadStickerFile);
/**
* Edit media in a message
* @param editMessageMedia Information of the new media
* @return If the edited message is not an inline message, the edited Message is returned, otherwise True is returned
*/
public abstract CompletableFuture<Serializable> executeAsync(EditMessageMedia editMessageMedia);
/**
* Send animation
* @param sendAnimation Information of the animation
* @return Sent message
*/
public abstract CompletableFuture<Message> executeAsync(SendAnimation sendAnimation);
// Simplified methods
protected abstract <T extends Serializable, Method extends BotApiMethod<T>, Callback extends SentCallback<T>> void sendApiMethodAsync(Method method, Callback callback);
protected abstract <T extends Serializable, Method extends BotApiMethod<T>> CompletableFuture<T> sendApiMethodAsync(Method method);
protected abstract <T extends Serializable, Method extends BotApiMethod<T>> T sendApiMethod(Method method) throws TelegramApiException;
}

View File

@ -2,6 +2,7 @@ package org.telegram.telegrambots.bots;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
@ -50,6 +51,7 @@ import java.io.Serializable;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@ -61,6 +63,7 @@ import static org.telegram.telegrambots.Constants.SOCKET_TIMEOUT;
* Implementation of all the methods needed to interact with Telegram Servers
*/
@SuppressWarnings({"unused"})
@Slf4j
public abstract class DefaultAbsSender extends AbsSender {
private static final ContentType TEXT_PLAIN_CONTENT_TYPE = ContentType.create("text/plain", StandardCharsets.UTF_8);
@ -92,22 +95,6 @@ public abstract class DefaultAbsSender extends AbsSender {
}
}
private void configureHttpContext() {
if (options.getProxyType() != DefaultBotOptions.ProxyType.NO_PROXY) {
InetSocketAddress socksaddr = new InetSocketAddress(options.getProxyHost(), options.getProxyPort());
options.getHttpContext().setAttribute("socketAddress", socksaddr);
}
if (options.getProxyType() == DefaultBotOptions.ProxyType.SOCKS4) {
options.getHttpContext().setAttribute("socksVersion", 4);
}
if (options.getProxyType() == DefaultBotOptions.ProxyType.SOCKS5) {
options.getHttpContext().setAttribute("socksVersion", 5);
}
}
/**
* Returns the token of the bot to be able to perform Telegram Api Requests
* @return Token of the bot
@ -118,6 +105,10 @@ public abstract class DefaultAbsSender extends AbsSender {
return options;
}
public String getBaseUrl() {
return options.getBaseUrl() + getBotToken() + "/";
}
// Send Requests
public final java.io.File downloadFile(String filePath) throws TelegramApiException {
@ -776,6 +767,204 @@ public abstract class DefaultAbsSender extends AbsSender {
}
}
// Async Methods
@Override
public CompletableFuture<Message> executeAsync(SendDocument sendDocument) {
CompletableFuture<Message> completableFuture = new CompletableFuture<>();
exe.submit(() -> {
try {
completableFuture.complete(execute(sendDocument));
} catch (TelegramApiException e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
@Override
public CompletableFuture<Message> executeAsync(SendPhoto sendPhoto) {
CompletableFuture<Message> completableFuture = new CompletableFuture<>();
exe.submit(() -> {
try {
completableFuture.complete(execute(sendPhoto));
} catch (TelegramApiException e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
@Override
public CompletableFuture<Message> executeAsync(SendVideo sendVideo) {
CompletableFuture<Message> completableFuture = new CompletableFuture<>();
exe.submit(() -> {
try {
completableFuture.complete(execute(sendVideo));
} catch (TelegramApiException e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
@Override
public CompletableFuture<Message> executeAsync(SendVideoNote sendVideoNote) {
CompletableFuture<Message> completableFuture = new CompletableFuture<>();
exe.submit(() -> {
try {
completableFuture.complete(execute(sendVideoNote));
} catch (TelegramApiException e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
@Override
public CompletableFuture<Message> executeAsync(SendSticker sendSticker) {
CompletableFuture<Message> completableFuture = new CompletableFuture<>();
exe.submit(() -> {
try {
completableFuture.complete(execute(sendSticker));
} catch (TelegramApiException e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
@Override
public CompletableFuture<Message> executeAsync(SendAudio sendAudio) {
CompletableFuture<Message> completableFuture = new CompletableFuture<>();
exe.submit(() -> {
try {
completableFuture.complete(execute(sendAudio));
} catch (TelegramApiException e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
@Override
public CompletableFuture<Message> executeAsync(SendVoice sendVoice) {
CompletableFuture<Message> completableFuture = new CompletableFuture<>();
exe.submit(() -> {
try {
completableFuture.complete(execute(sendVoice));
} catch (TelegramApiException e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
@Override
public CompletableFuture<List<Message>> executeAsync(SendMediaGroup sendMediaGroup) {
CompletableFuture<List<Message>> completableFuture = new CompletableFuture<>();
exe.submit(() -> {
try {
completableFuture.complete(execute(sendMediaGroup));
} catch (TelegramApiException e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
@Override
public CompletableFuture<Boolean> executeAsync(SetChatPhoto setChatPhoto) {
CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();
exe.submit(() -> {
try {
completableFuture.complete(execute(setChatPhoto));
} catch (TelegramApiException e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
@Override
public CompletableFuture<Boolean> executeAsync(AddStickerToSet addStickerToSet) {
CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();
exe.submit(() -> {
try {
completableFuture.complete(execute(addStickerToSet));
} catch (TelegramApiException e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
@Override
public CompletableFuture<Boolean> executeAsync(SetStickerSetThumb setStickerSetThumb) {
CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();
exe.submit(() -> {
try {
completableFuture.complete(execute(setStickerSetThumb));
} catch (TelegramApiException e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
@Override
public CompletableFuture<Boolean> executeAsync(CreateNewStickerSet createNewStickerSet) {
CompletableFuture<Boolean> completableFuture = new CompletableFuture<>();
exe.submit(() -> {
try {
completableFuture.complete(execute(createNewStickerSet));
} catch (TelegramApiException e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
@Override
public CompletableFuture<File> executeAsync(UploadStickerFile uploadStickerFile) {
CompletableFuture<File> completableFuture = new CompletableFuture<>();
exe.submit(() -> {
try {
completableFuture.complete(execute(uploadStickerFile));
} catch (TelegramApiException e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
@Override
public CompletableFuture<Serializable> executeAsync(EditMessageMedia editMessageMedia) {
CompletableFuture<Serializable> completableFuture = new CompletableFuture<>();
exe.submit(() -> {
try {
completableFuture.complete(execute(editMessageMedia));
} catch (TelegramApiException e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
@Override
public CompletableFuture<Message> executeAsync(SendAnimation sendAnimation) {
CompletableFuture<Message> completableFuture = new CompletableFuture<>();
exe.submit(() -> {
try {
completableFuture.complete(execute(sendAnimation));
} catch (TelegramApiException e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
// Simplified methods
@Override
@ -799,6 +988,20 @@ public abstract class DefaultAbsSender extends AbsSender {
});
}
@Override
protected <T extends Serializable, Method extends BotApiMethod<T>> CompletableFuture<T> sendApiMethodAsync(Method method) {
CompletableFuture<T> completableFuture = new CompletableFuture<>();
exe.submit(() -> {
try {
String responseContent = sendMethodRequest(method);
completableFuture.complete(method.deserializeResponse(responseContent));
} catch (IOException | TelegramApiValidationException | TelegramApiRequestException e) {
completableFuture.completeExceptionally(e);
}
});
return completableFuture;
}
@Override
protected final <T extends Serializable, Method extends BotApiMethod<T>> T sendApiMethod(Method method) throws TelegramApiException {
try {
@ -809,6 +1012,24 @@ public abstract class DefaultAbsSender extends AbsSender {
}
}
// Private methods
private void configureHttpContext() {
if (options.getProxyType() != DefaultBotOptions.ProxyType.NO_PROXY) {
InetSocketAddress socksaddr = new InetSocketAddress(options.getProxyHost(), options.getProxyPort());
options.getHttpContext().setAttribute("socketAddress", socksaddr);
}
if (options.getProxyType() == DefaultBotOptions.ProxyType.SOCKS4) {
options.getHttpContext().setAttribute("socksVersion", 4);
}
if (options.getProxyType() == DefaultBotOptions.ProxyType.SOCKS5) {
options.getHttpContext().setAttribute("socksVersion", 5);
}
}
private <T extends Serializable, Method extends BotApiMethod<T>> String sendMethodRequest(Method method) throws TelegramApiValidationException, IOException {
method.validate();
String url = getBaseUrl() + method.getMethod();
@ -888,10 +1109,6 @@ public abstract class DefaultAbsSender extends AbsSender {
}
}
public String getBaseUrl() {
return options.getBaseUrl() + getBotToken() + "/";
}
private void assertParamNotNull(Object param, String paramName) throws TelegramApiException {
if (param == null) {
throw new TelegramApiException("Parameter " + paramName + " can not be null");