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. 5. Locations now use Double instead of Float to avoid rounding.
6. When registering a Webhook Bot, a SetWebhook object must be provided. 6. When registering a Webhook Bot, a SetWebhook object must be provided.
7. When using Webhook with Spring, extends class SpringWebhookBot instead of WebhookBot 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 ### ### <a id="4.9.2"></a>4.9.2 ###
1. Bug fixing: #792, #801, #804, #810, #812, #813, #820 and #814 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); 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.io.Serializable;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
/** /**
* @author Ruben Bermudez * @author Ruben Bermudez
@ -49,6 +50,13 @@ public abstract class AbsSender {
sendApiMethodAsync(method, callback); 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 { public <T extends Serializable, Method extends BotApiMethod<T>> T execute(Method method) throws TelegramApiException {
if (method == null) { if (method == null) {
throw new TelegramApiException("Parameter method can not be null"); throw new TelegramApiException("Parameter method can not be null");
@ -70,6 +78,15 @@ public abstract class AbsSender {
// Send Requests Async // 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 { public final void getMeAsync(SentCallback<User> sentCallback) throws TelegramApiException {
if (sentCallback == null) { if (sentCallback == null) {
throw new TelegramApiException("Parameter sentCallback can not be 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; 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 // 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>, 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; 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.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig; import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
@ -50,6 +51,7 @@ import java.io.Serializable;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; 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 * Implementation of all the methods needed to interact with Telegram Servers
*/ */
@SuppressWarnings({"unused"}) @SuppressWarnings({"unused"})
@Slf4j
public abstract class DefaultAbsSender extends AbsSender { public abstract class DefaultAbsSender extends AbsSender {
private static final ContentType TEXT_PLAIN_CONTENT_TYPE = ContentType.create("text/plain", StandardCharsets.UTF_8); 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 * Returns the token of the bot to be able to perform Telegram Api Requests
* @return Token of the bot * @return Token of the bot
@ -118,6 +105,10 @@ public abstract class DefaultAbsSender extends AbsSender {
return options; return options;
} }
public String getBaseUrl() {
return options.getBaseUrl() + getBotToken() + "/";
}
// Send Requests // Send Requests
public final java.io.File downloadFile(String filePath) throws TelegramApiException { 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 // Simplified methods
@Override @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 @Override
protected final <T extends Serializable, Method extends BotApiMethod<T>> T sendApiMethod(Method method) throws TelegramApiException { protected final <T extends Serializable, Method extends BotApiMethod<T>> T sendApiMethod(Method method) throws TelegramApiException {
try { 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 { private <T extends Serializable, Method extends BotApiMethod<T>> String sendMethodRequest(Method method) throws TelegramApiValidationException, IOException {
method.validate(); method.validate();
String url = getBaseUrl() + method.getMethod(); 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 { private void assertParamNotNull(Object param, String paramName) throws TelegramApiException {
if (param == null) { if (param == null) {
throw new TelegramApiException("Parameter " + paramName + " can not be null"); throw new TelegramApiException("Parameter " + paramName + " can not be null");