From fb5626de7a3627ecca07721fa06d4c95ed53415d Mon Sep 17 00:00:00 2001 From: rubenlagus Date: Tue, 3 Nov 2020 02:24:07 +0000 Subject: [PATCH] CompletableFuture support --- TelegramBots.wiki/Changelog.md | 1 + .../PassportElementErrorTranslationFiles.java | 10 - .../telegrambots/meta/bots/AbsSender.java | 102 +++++++ .../telegrambots/bots/DefaultAbsSender.java | 257 ++++++++++++++++-- 4 files changed, 340 insertions(+), 30 deletions(-) diff --git a/TelegramBots.wiki/Changelog.md b/TelegramBots.wiki/Changelog.md index 1358a72a..418a5d26 100644 --- a/TelegramBots.wiki/Changelog.md +++ b/TelegramBots.wiki/Changelog.md @@ -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. ### 4.9.2 ### 1. Bug fixing: #792, #801, #804, #810, #812, #813, #820 and #814 diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/passport/dataerror/PassportElementErrorTranslationFiles.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/passport/dataerror/PassportElementErrorTranslationFiles.java index f2be141f..61212a33 100644 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/passport/dataerror/PassportElementErrorTranslationFiles.java +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/api/objects/passport/dataerror/PassportElementErrorTranslationFiles.java @@ -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 + '\'' + - '}'; - } } diff --git a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/bots/AbsSender.java b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/bots/AbsSender.java index 204bb1fa..ccf9e8ae 100644 --- a/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/bots/AbsSender.java +++ b/telegrambots-meta/src/main/java/org/telegram/telegrambots/meta/bots/AbsSender.java @@ -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 > CompletableFuture executeAsync(Method method) throws TelegramApiException { + if (method == null) { + throw new TelegramApiException("Parameter method can not be null"); + } + return sendApiMethodAsync(method); + } + public > 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 getMeAsync() { + return sendApiMethodAsync(new GetMe()); + } + + public final CompletableFuture getWebhookInfoAsync() { + return sendApiMethodAsync(new GetWebhookInfo()); + } + public final void getMeAsync(SentCallback 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 executeAsync(SendDocument sendDocument); + + public abstract CompletableFuture executeAsync(SendPhoto sendPhoto); + + public abstract CompletableFuture executeAsync(SendVideo sendVideo); + + public abstract CompletableFuture executeAsync(SendVideoNote sendVideoNote); + + public abstract CompletableFuture 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 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 executeAsync(SendVoice sendVoice); + + /** + * Send a media group (https://core.telegram.org/bots/api#sendMediaGroup) + * @return If success, list of generated messages + */ + public abstract CompletableFuture> 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 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 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 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 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 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 executeAsync(EditMessageMedia editMessageMedia); + + /** + * Send animation + * @param sendAnimation Information of the animation + * @return Sent message + */ + public abstract CompletableFuture executeAsync(SendAnimation sendAnimation); + // Simplified methods protected abstract , Callback extends SentCallback> void sendApiMethodAsync(Method method, Callback callback); + protected abstract > CompletableFuture sendApiMethodAsync(Method method); + protected abstract > T sendApiMethod(Method method) throws TelegramApiException; } diff --git a/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java b/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java index 97b3c065..2f72f236 100644 --- a/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java +++ b/telegrambots/src/main/java/org/telegram/telegrambots/bots/DefaultAbsSender.java @@ -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 executeAsync(SendDocument sendDocument) { + CompletableFuture completableFuture = new CompletableFuture<>(); + exe.submit(() -> { + try { + completableFuture.complete(execute(sendDocument)); + } catch (TelegramApiException e) { + completableFuture.completeExceptionally(e); + } + }); + return completableFuture; + } + + @Override + public CompletableFuture executeAsync(SendPhoto sendPhoto) { + CompletableFuture completableFuture = new CompletableFuture<>(); + exe.submit(() -> { + try { + completableFuture.complete(execute(sendPhoto)); + } catch (TelegramApiException e) { + completableFuture.completeExceptionally(e); + } + }); + return completableFuture; + } + + @Override + public CompletableFuture executeAsync(SendVideo sendVideo) { + CompletableFuture completableFuture = new CompletableFuture<>(); + exe.submit(() -> { + try { + completableFuture.complete(execute(sendVideo)); + } catch (TelegramApiException e) { + completableFuture.completeExceptionally(e); + } + }); + return completableFuture; + } + + @Override + public CompletableFuture executeAsync(SendVideoNote sendVideoNote) { + CompletableFuture completableFuture = new CompletableFuture<>(); + exe.submit(() -> { + try { + completableFuture.complete(execute(sendVideoNote)); + } catch (TelegramApiException e) { + completableFuture.completeExceptionally(e); + } + }); + return completableFuture; + } + + @Override + public CompletableFuture executeAsync(SendSticker sendSticker) { + CompletableFuture completableFuture = new CompletableFuture<>(); + exe.submit(() -> { + try { + completableFuture.complete(execute(sendSticker)); + } catch (TelegramApiException e) { + completableFuture.completeExceptionally(e); + } + }); + return completableFuture; + } + + @Override + public CompletableFuture executeAsync(SendAudio sendAudio) { + CompletableFuture completableFuture = new CompletableFuture<>(); + exe.submit(() -> { + try { + completableFuture.complete(execute(sendAudio)); + } catch (TelegramApiException e) { + completableFuture.completeExceptionally(e); + } + }); + return completableFuture; + } + + @Override + public CompletableFuture executeAsync(SendVoice sendVoice) { + CompletableFuture completableFuture = new CompletableFuture<>(); + exe.submit(() -> { + try { + completableFuture.complete(execute(sendVoice)); + } catch (TelegramApiException e) { + completableFuture.completeExceptionally(e); + } + }); + return completableFuture; + } + + @Override + public CompletableFuture> executeAsync(SendMediaGroup sendMediaGroup) { + CompletableFuture> completableFuture = new CompletableFuture<>(); + exe.submit(() -> { + try { + completableFuture.complete(execute(sendMediaGroup)); + } catch (TelegramApiException e) { + completableFuture.completeExceptionally(e); + } + }); + return completableFuture; + } + + @Override + public CompletableFuture executeAsync(SetChatPhoto setChatPhoto) { + CompletableFuture completableFuture = new CompletableFuture<>(); + exe.submit(() -> { + try { + completableFuture.complete(execute(setChatPhoto)); + } catch (TelegramApiException e) { + completableFuture.completeExceptionally(e); + } + }); + return completableFuture; + } + + @Override + public CompletableFuture executeAsync(AddStickerToSet addStickerToSet) { + CompletableFuture completableFuture = new CompletableFuture<>(); + exe.submit(() -> { + try { + completableFuture.complete(execute(addStickerToSet)); + } catch (TelegramApiException e) { + completableFuture.completeExceptionally(e); + } + }); + return completableFuture; + } + + @Override + public CompletableFuture executeAsync(SetStickerSetThumb setStickerSetThumb) { + CompletableFuture completableFuture = new CompletableFuture<>(); + exe.submit(() -> { + try { + completableFuture.complete(execute(setStickerSetThumb)); + } catch (TelegramApiException e) { + completableFuture.completeExceptionally(e); + } + }); + return completableFuture; + } + + @Override + public CompletableFuture executeAsync(CreateNewStickerSet createNewStickerSet) { + CompletableFuture completableFuture = new CompletableFuture<>(); + exe.submit(() -> { + try { + completableFuture.complete(execute(createNewStickerSet)); + } catch (TelegramApiException e) { + completableFuture.completeExceptionally(e); + } + }); + return completableFuture; + } + + @Override + public CompletableFuture executeAsync(UploadStickerFile uploadStickerFile) { + CompletableFuture completableFuture = new CompletableFuture<>(); + exe.submit(() -> { + try { + completableFuture.complete(execute(uploadStickerFile)); + } catch (TelegramApiException e) { + completableFuture.completeExceptionally(e); + } + }); + return completableFuture; + } + + @Override + public CompletableFuture executeAsync(EditMessageMedia editMessageMedia) { + CompletableFuture completableFuture = new CompletableFuture<>(); + exe.submit(() -> { + try { + completableFuture.complete(execute(editMessageMedia)); + } catch (TelegramApiException e) { + completableFuture.completeExceptionally(e); + } + }); + return completableFuture; + } + + @Override + public CompletableFuture executeAsync(SendAnimation sendAnimation) { + CompletableFuture 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 > CompletableFuture sendApiMethodAsync(Method method) { + CompletableFuture 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 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 > 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");