diff --git a/jtelegrambotapi-core/pom.xml b/jtelegrambotapi-core/pom.xml index 2abf92482..db847080f 100644 --- a/jtelegrambotapi-core/pom.xml +++ b/jtelegrambotapi-core/pom.xml @@ -24,11 +24,6 @@ lombok - - com.squareup.okhttp3 - okhttp - - diff --git a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/TelegramBot.java b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/TelegramBot.java index 39c76973e..b59f2390b 100644 --- a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/TelegramBot.java +++ b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/TelegramBot.java @@ -9,11 +9,12 @@ import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; -import okhttp3.Request; -import okhttp3.ResponseBody; import java.io.IOException; import java.io.InputStream; +import java.net.URI; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; @Getter @EqualsAndHashCode(of = {"apiKey", "botInfo"}) @@ -45,13 +46,17 @@ public InputStream downloadFile(TelegramFile file) throws IOException { } public InputStream downloadFile(String filePath) throws IOException { - ResponseBody body = registry.getClient().newCall( - new Request.Builder() - .url(registry.getFileApiUrl() + apiKey + "/" + filePath) - .get() - .build() - ).execute().body(); - - return body == null ? null : body.byteStream(); + URI uri = URI.create(registry.getFileApiUrl() + apiKey + "/" + filePath); + HttpResponse body; + try { + body = registry.getClient().send( + HttpRequest.newBuilder() + .uri(uri) + .GET().build(), HttpResponse.BodyHandlers.ofInputStream()); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } + + return body == null ? null : body.body(); } } diff --git a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/TelegramBotRegistry.java b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/TelegramBotRegistry.java index 801e972cc..910dd04f4 100644 --- a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/TelegramBotRegistry.java +++ b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/TelegramBotRegistry.java @@ -24,9 +24,9 @@ import com.jtelegram.api.requests.GetMe; import lombok.Builder; import lombok.Getter; -import okhttp3.OkHttpClient; import java.lang.reflect.Modifier; +import java.net.http.HttpClient; import java.util.HashSet; import java.util.Set; import java.util.function.BiConsumer; @@ -55,7 +55,7 @@ public class TelegramBotRegistry { private final UpdateProvider updateProvider; private String apiUrl = "https://api.telegram.org/bot"; private String fileApiUrl = "https://api.telegram.org/file/bot"; - private OkHttpClient client = new OkHttpClient(); + private HttpClient client = HttpClient.newHttpClient(); // <1 is a dynamic thread pool // 1 is a single thread pool // >1 is a multi thread pool @@ -63,7 +63,7 @@ public class TelegramBotRegistry { private final Set bots = new HashSet<>(); @Builder - private TelegramBotRegistry(UpdateProvider updateProvider, String apiUrl, OkHttpClient client, Integer eventThreadCount) { + private TelegramBotRegistry(UpdateProvider updateProvider, String apiUrl, HttpClient client, Integer eventThreadCount) { this.updateProvider = updateProvider; if (apiUrl != null) { @@ -79,7 +79,7 @@ private TelegramBotRegistry(UpdateProvider updateProvider, String apiUrl, OkHttp } } - public void setHttpClient(OkHttpClient client) { + public void setHttpClient(HttpClient client) { this.client = client; bots.forEach((bot) -> bot.getRequestQueue().setClient(client)); } diff --git a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/message/input/file/InputFile.java b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/message/input/file/InputFile.java index 72960fd83..1062cacb0 100644 --- a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/message/input/file/InputFile.java +++ b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/message/input/file/InputFile.java @@ -4,7 +4,7 @@ import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; -import okhttp3.MultipartBody; +import com.jtelegram.api.util.MultipartBodyPublisher; import java.lang.reflect.Type; @@ -23,7 +23,7 @@ default boolean isAttachable() { return getIdentifier() != null; } - default void attachTo(MultipartBody.Builder builder) {} + default void attachTo(MultipartBodyPublisher.Builder builder) {} class Serializer implements JsonSerializer { @Override diff --git a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/message/input/file/InputFileRequest.java b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/message/input/file/InputFileRequest.java index afdc5b64e..860602396 100644 --- a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/message/input/file/InputFileRequest.java +++ b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/message/input/file/InputFileRequest.java @@ -4,22 +4,19 @@ import com.google.gson.JsonObject; import com.jtelegram.api.TelegramBot; import com.jtelegram.api.TelegramBotRegistry; -import okhttp3.MediaType; -import okhttp3.MultipartBody; -import okhttp3.Request; -import okhttp3.RequestBody; +import com.jtelegram.api.util.MultipartBodyPublisher; -import java.io.File; +import java.net.http.HttpRequest; import java.util.List; public interface InputFileRequest { - MediaType OCTET_STREAM_TYPE = MediaType.parse("application/octet-stream"); + String OCTET_STREAM_TYPE = "application/octet-stream"; List getInputFiles(); - Request.Builder superBuild(TelegramBot bot); + HttpRequest.Builder superBuild(TelegramBot bot); - default Request.Builder getBuilder(TelegramBot bot) { + default HttpRequest.Builder getBuilder(TelegramBot bot) { List inputFiles = getInputFiles(); if (inputFiles.stream().noneMatch(InputFile::isAttachable)) { @@ -27,8 +24,7 @@ default Request.Builder getBuilder(TelegramBot bot) { } JsonObject obj = TelegramBotRegistry.GSON.toJsonTree(this).getAsJsonObject(); - MultipartBody.Builder bodyBuilder = new MultipartBody.Builder() - .setType(MultipartBody.FORM); + MultipartBodyPublisher.Builder bodyBuilder = new MultipartBodyPublisher.Builder(); obj.keySet().forEach((key) -> { JsonElement e = obj.get(key); @@ -40,10 +36,10 @@ default Request.Builder getBuilder(TelegramBot bot) { val = e.toString(); } - bodyBuilder.addFormDataPart(key, val); + bodyBuilder.addPart(MultipartBodyPublisher.Part.forFormData(key, val)); }); inputFiles.stream().filter(InputFile::isAttachable).forEach((inputFile) -> inputFile.attachTo(bodyBuilder)); - return superBuild(bot).post(bodyBuilder.build()); + return superBuild(bot).header("Content-Type", "multipart/form-data").POST(bodyBuilder.build()); } } diff --git a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/message/input/file/LocalInputFile.java b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/message/input/file/LocalInputFile.java index 77917af46..e623c1e29 100644 --- a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/message/input/file/LocalInputFile.java +++ b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/message/input/file/LocalInputFile.java @@ -1,12 +1,14 @@ package com.jtelegram.api.message.input.file; +import com.jtelegram.api.util.MultipartBodyPublisher; import lombok.AllArgsConstructor; import lombok.Getter; import java.io.File; +import java.io.FileNotFoundException; +import java.net.http.HttpRequest; + import lombok.ToString; -import okhttp3.MultipartBody; -import okhttp3.RequestBody; @Getter @ToString @@ -20,8 +22,15 @@ public String getIdentifier() { } @Override - public void attachTo(MultipartBody.Builder builder) { + public void attachTo(MultipartBodyPublisher.Builder builder) { + HttpRequest.BodyPublisher filePublisher; + try { + filePublisher = HttpRequest.BodyPublishers.ofFile(data.toPath()); + } catch (FileNotFoundException ex) { + throw new IllegalArgumentException("Local file not found", ex); + } String identifier = getIdentifier(); - builder.addFormDataPart(identifier, identifier, RequestBody.create(InputFileRequest.OCTET_STREAM_TYPE, data)); + builder.addPart( + MultipartBodyPublisher.Part.forBodyPublisher(identifier, identifier, InputFileRequest.OCTET_STREAM_TYPE, filePublisher)); } } diff --git a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/AbstractTelegramRequest.java b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/AbstractTelegramRequest.java index 6260e1918..94aff3974 100644 --- a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/AbstractTelegramRequest.java +++ b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/AbstractTelegramRequest.java @@ -8,21 +8,21 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; -import okhttp3.Response; import java.io.IOException; +import java.net.http.HttpResponse; import java.util.function.Consumer; @EqualsAndHashCode @AllArgsConstructor(access = AccessLevel.PROTECTED) -public abstract class AbstractTelegramRequest implements TelegramRequest { +public abstract class AbstractTelegramRequest implements TelegramRequest { // utility field protected transient static Gson gson = TelegramBotRegistry.GSON; private transient final String endPoint; protected transient final Consumer errorHandler; - protected String getBody(Response response) throws IOException { - return response == null ? null : response.body().string(); + protected T getBody(HttpResponse response) throws IOException { + return response == null ? null : response.body(); } protected JsonElement validate(String response) throws IOException { diff --git a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/BotRequestQueue.java b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/BotRequestQueue.java index 2ec1902a7..441e482a8 100644 --- a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/BotRequestQueue.java +++ b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/BotRequestQueue.java @@ -2,14 +2,14 @@ import lombok.Getter; import lombok.Setter; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; import java.io.IOException; -import java.util.Queue; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutionException; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; @@ -21,9 +21,9 @@ public class BotRequestQueue extends Thread { // 0 for instantaneous, negative numbers // will result in an error private long interval = 100; - private OkHttpClient client; + private HttpClient client; - public BotRequestQueue(OkHttpClient client) { + public BotRequestQueue(HttpClient client) { super("Bot Request Queue"); this.client = client; } @@ -44,12 +44,18 @@ public void run() { } try { - Request httpRequest = request.getRequest().build(request.getBot()).build(); - Response response = client.newCall(httpRequest).execute(); + + HttpRequest httpRequest = request.getRequest().build(request.getBot()).build(); + HttpResponse response = client.send(httpRequest, + HttpResponse.BodyHandlers.ofString( + StandardCharsets.UTF_8)); request.getRequest().handleResponse(response); } catch (IOException ex) { request.getRequest().handleException(ex); + } catch (InterruptedException e) { + e.printStackTrace(); + return; } try { diff --git a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/QueryTelegramRequest.java b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/QueryTelegramRequest.java index 3468192d6..dc5a2a63f 100644 --- a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/QueryTelegramRequest.java +++ b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/QueryTelegramRequest.java @@ -3,9 +3,9 @@ import com.google.gson.JsonElement; import com.jtelegram.api.ex.TelegramException; import lombok.EqualsAndHashCode; -import okhttp3.Response; import java.io.IOException; +import java.net.http.HttpResponse; import java.util.function.Consumer; /** @@ -13,7 +13,7 @@ * has a response beyond "OK" */ @EqualsAndHashCode(callSuper = true) -public abstract class QueryTelegramRequest extends AbstractTelegramRequest { +public abstract class QueryTelegramRequest extends AbstractTelegramRequest { private transient final Consumer callback; private transient final Class callbackType; @@ -24,8 +24,9 @@ protected QueryTelegramRequest(String endPoint, Class callbackType, Consumer< } @Override - public void handleResponse(Response response) throws IOException { + public void handleResponse(HttpResponse response) throws IOException { String body = getBody(response); + response.body(); JsonElement result; if (body != null && (result = validate(body)) != null) { diff --git a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/TelegramRequest.java b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/TelegramRequest.java index bc29f5976..a87f125fb 100644 --- a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/TelegramRequest.java +++ b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/TelegramRequest.java @@ -1,16 +1,15 @@ package com.jtelegram.api.requests.framework; +import com.google.gson.JsonElement; import com.jtelegram.api.TelegramBot; -import okhttp3.MediaType; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; import java.io.IOException; +import java.net.URI; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; -public interface TelegramRequest { - MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8"); - +public interface TelegramRequest { /** * Use GSON to properly serialize the request * to send to Telegram's servers. This method @@ -21,10 +20,12 @@ public interface TelegramRequest { */ String serialize(); - default Request.Builder build(TelegramBot bot) { - return new Request.Builder() - .url(bot.getRegistry().getApiUrl() + bot.getApiKey() + "/" + getEndPoint()) - .post(RequestBody.create(JSON_MEDIA_TYPE, serialize())); + default HttpRequest.Builder build(TelegramBot bot) { + + return HttpRequest.newBuilder() + .uri(URI.create(bot.getRegistry().getApiUrl() + bot.getApiKey() + "/" + getEndPoint())) + .header("Content-Type", "application/json; charset=utf-8") + .POST(HttpRequest.BodyPublishers.ofString(serialize(), StandardCharsets.UTF_8)); } /** @@ -42,7 +43,7 @@ default Request.Builder build(TelegramBot bot) { * * @throws IOException If any I/O error occurred */ - void handleResponse(Response response) throws IOException; + void handleResponse(HttpResponse response) throws IOException; /** * Handle an exception in the case that an I/O error occured diff --git a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/UpdateTelegramRequest.java b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/UpdateTelegramRequest.java index 2eb357af3..78a67d336 100644 --- a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/UpdateTelegramRequest.java +++ b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/framework/UpdateTelegramRequest.java @@ -1,9 +1,9 @@ package com.jtelegram.api.requests.framework; import com.jtelegram.api.ex.TelegramException; -import okhttp3.Response; import java.io.IOException; +import java.net.http.HttpResponse; import java.util.function.Consumer; /** @@ -13,7 +13,7 @@ * the request was successful or there was an error. * */ -public abstract class UpdateTelegramRequest extends AbstractTelegramRequest { +public abstract class UpdateTelegramRequest extends AbstractTelegramRequest { protected transient Runnable callback; protected UpdateTelegramRequest(String endPoint, Consumer errorHandler, Runnable callback) { @@ -22,7 +22,7 @@ protected UpdateTelegramRequest(String endPoint, Consumer err } @Override - public void handleResponse(Response response) throws IOException { + public void handleResponse(HttpResponse response) throws IOException { String body = getBody(response); if (body != null && validate(body) != null) { diff --git a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/message/framework/req/InputFileMessageRequest.java b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/message/framework/req/InputFileMessageRequest.java index e669f2615..a70623c47 100644 --- a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/message/framework/req/InputFileMessageRequest.java +++ b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/message/framework/req/InputFileMessageRequest.java @@ -5,8 +5,8 @@ import com.jtelegram.api.ex.TelegramException; import com.jtelegram.api.message.input.file.InputFileRequest; import com.jtelegram.api.requests.message.framework.ReplyMarkup; -import okhttp3.Request; +import java.net.http.HttpRequest; import java.util.function.Consumer; public abstract class InputFileMessageRequest extends SendableMessageRequest implements InputFileRequest { @@ -15,12 +15,12 @@ protected InputFileMessageRequest(String endPoint, Class callbackType, Consum } @Override - public Request.Builder build(TelegramBot bot) { + public HttpRequest.Builder build(TelegramBot bot) { return getBuilder(bot); } @Override - public Request.Builder superBuild(TelegramBot bot) { + public HttpRequest.Builder superBuild(TelegramBot bot) { return super.build(bot); } } diff --git a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/message/framework/req/InputFileMessageUpdate.java b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/message/framework/req/InputFileMessageUpdate.java index 21d8f0448..dcbacf5c8 100644 --- a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/message/framework/req/InputFileMessageUpdate.java +++ b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/message/framework/req/InputFileMessageUpdate.java @@ -4,8 +4,8 @@ import com.jtelegram.api.requests.framework.UpdateTelegramRequest; import com.jtelegram.api.TelegramBot; import com.jtelegram.api.ex.TelegramException; -import okhttp3.Request; +import java.net.http.HttpRequest; import java.util.function.Consumer; public abstract class InputFileMessageUpdate extends UpdateTelegramRequest implements InputFileRequest { @@ -14,12 +14,12 @@ protected InputFileMessageUpdate(String endPoint, Consumer er } @Override - public Request.Builder build(TelegramBot bot) { + public HttpRequest.Builder build(TelegramBot bot) { return getBuilder(bot); } @Override - public Request.Builder superBuild(TelegramBot bot) { + public HttpRequest.Builder superBuild(TelegramBot bot) { return super.build(bot); } } diff --git a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/message/framework/req/SendableInputFileInlineRequest.java b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/message/framework/req/SendableInputFileInlineRequest.java index 26f14676c..8bd2186ac 100644 --- a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/message/framework/req/SendableInputFileInlineRequest.java +++ b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/message/framework/req/SendableInputFileInlineRequest.java @@ -4,8 +4,8 @@ import com.jtelegram.api.chat.id.ChatId; import com.jtelegram.api.ex.TelegramException; import com.jtelegram.api.message.input.file.InputFileRequest; -import okhttp3.Request; +import java.net.http.HttpRequest; import java.util.function.Consumer; public abstract class SendableInputFileInlineRequest extends SendableInlineRequest implements InputFileRequest { @@ -15,7 +15,7 @@ public SendableInputFileInlineRequest(String endPoint, Class callbackType, Co } @Override - public Request.Builder superBuild(TelegramBot bot) { + public HttpRequest.Builder superBuild(TelegramBot bot) { return super.build(bot); } } diff --git a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/webhooks/SetWebhook.java b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/webhooks/SetWebhook.java index d02cd757a..91166eee0 100644 --- a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/webhooks/SetWebhook.java +++ b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/requests/webhooks/SetWebhook.java @@ -1,19 +1,19 @@ package com.jtelegram.api.requests.webhooks; +import com.jtelegram.api.TelegramBot; import com.jtelegram.api.ex.TelegramException; import com.jtelegram.api.message.input.file.InputFileRequest; import com.jtelegram.api.message.input.file.LocalInputFile; import com.jtelegram.api.requests.framework.UpdateTelegramRequest; import com.jtelegram.api.update.UpdateType; -import com.jtelegram.api.TelegramBot; +import com.jtelegram.api.util.MultipartBodyPublisher; import lombok.Builder; import lombok.Getter; import lombok.ToString; -import okhttp3.MultipartBody; -import okhttp3.Request; -import okhttp3.RequestBody; +import java.io.FileNotFoundException; import java.net.URL; +import java.net.http.HttpRequest; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; @@ -37,25 +37,37 @@ private SetWebhook(Consumer errorHandler, Runnable callback, } @Override - public Request.Builder build(TelegramBot bot) { - MultipartBody.Builder bodyBuilder = new MultipartBody.Builder() - .setType(MultipartBody.FORM); + public HttpRequest.Builder build(TelegramBot bot) { + MultipartBodyPublisher.Builder bodyBuilder = new MultipartBodyPublisher.Builder(); - bodyBuilder.addFormDataPart("url", url.toString()); + bodyBuilder.addPart(MultipartBodyPublisher.Part.forFormData("url", url.toString())); if (certificate != null) { - bodyBuilder.addFormDataPart("certificate", certificate.getData().getName(), RequestBody.create(InputFileRequest.OCTET_STREAM_TYPE, certificate.getData())); + HttpRequest.BodyPublisher certificatePublisher; + try { + certificatePublisher = HttpRequest.BodyPublishers.ofFile(certificate.getData().toPath()); + } catch (FileNotFoundException ex) { + throw new IllegalArgumentException("Certificate not found", ex); + } + bodyBuilder.addPart( + MultipartBodyPublisher.Part.forBodyPublisher( + "certificate", + certificate.getData().getName(), + InputFileRequest.OCTET_STREAM_TYPE, + certificatePublisher)); } if (maxConnections != null) { - bodyBuilder.addFormDataPart("max_connections", String.valueOf(maxConnections)); + bodyBuilder.addPart( + MultipartBodyPublisher.Part.forFormData("max_connections", String.valueOf(maxConnections)) + ); } if (allowedTypes != null) { - bodyBuilder.addFormDataPart("allowedTypes", gson.toJson(allowedTypes)); + bodyBuilder.addPart(MultipartBodyPublisher.Part.forFormData("allowedTypes", gson.toJson(allowedTypes))); } - return super.build(bot).post(bodyBuilder.build()); + return super.build(bot).header("Content-Type", "multipart/form-data").POST(bodyBuilder.build()); } @Override diff --git a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/update/PollingUpdateRunnable.java b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/update/PollingUpdateRunnable.java index 6dcaf3f8d..1a40d250a 100644 --- a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/update/PollingUpdateRunnable.java +++ b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/update/PollingUpdateRunnable.java @@ -4,9 +4,10 @@ import com.jtelegram.api.requests.GetUpdates; import com.jtelegram.api.requests.framework.TelegramRequest; import lombok.RequiredArgsConstructor; -import okhttp3.Response; import java.io.IOException; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; import java.util.stream.Stream; @RequiredArgsConstructor @@ -26,11 +27,17 @@ public void run() { .build(); try { - Response response = bot.getRegistry().getClient().newCall(request.build(bot).build()).execute(); + HttpResponse + response = bot.getRegistry().getClient().send(request.build(bot).build(), + HttpResponse.BodyHandlers.ofString( + StandardCharsets.UTF_8)); request.handleResponse(response); } catch (IOException e) { request.handleException(e); + } catch (InterruptedException e) { + e.printStackTrace(); + return; } try { diff --git a/jtelegrambotapi-core/src/main/java/com/jtelegram/api/util/MultipartBodyPublisher.java b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/util/MultipartBodyPublisher.java new file mode 100644 index 000000000..00b91ab84 --- /dev/null +++ b/jtelegrambotapi-core/src/main/java/com/jtelegram/api/util/MultipartBodyPublisher.java @@ -0,0 +1,207 @@ +package com.jtelegram.api.util; + +import java.net.http.HttpRequest; +import java.net.http.HttpRequest.BodyPublishers; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.Flow; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +// TODO: replace with an actual proper implementation if Oracle ever gets to it +public class MultipartBodyPublisher implements HttpRequest.BodyPublisher { + + // HEADERS\r\n + //\r\n + //--boundary\r\n + //SUBHEADERS\r\n + //\r\n + //stuff\r\n + //--boundary-- + + private static final String CRLF = "\r\n"; + + private long contentLength; + + private List bodyPublishers; + + private Flow.Subscriber subscriber; + + private Flow.Subscription currentSubscription; + + private long requested = 0L; + + private boolean currentlySubscribed; + + public MultipartBodyPublisher(String boundaryDelimiter, List parts) { + this.contentLength = parts.stream().mapToLong(Part::contentLength).sum() + + (boundaryDelimiter.length() + CRLF.length()) * (parts.size() + 1); + String boundary = "--" + boundaryDelimiter + CRLF; + List publishers = parts.stream() + .flatMap(part -> { + String headers = CRLF; + if (!part.headers.isEmpty()) { + headers = String.join(CRLF, part.headers) + CRLF + CRLF; + } + return Stream.of( + BodyPublishers.ofString(boundary, StandardCharsets.UTF_8), + BodyPublishers.ofString(headers, StandardCharsets.UTF_8), + part.publisher, + BodyPublishers.ofString(CRLF, StandardCharsets.UTF_8) + ); + }).collect(Collectors.toList()); + publishers.add(BodyPublishers.ofString(boundary + "--", StandardCharsets.UTF_8)); + this.bodyPublishers = publishers; + } + + @Override + public long contentLength() { + return this.contentLength; + } + + @Override + public void subscribe(Flow.Subscriber subscriber) { + if (this.subscriber != null) { + throw new IllegalStateException("A subscriber already subscribed to this publisher."); + } + this.subscriber = subscriber; + this.subscriber.onSubscribe(new Flow.Subscription() { + @Override + public void request(long n) { + if (n <= 0) { + throw new IllegalArgumentException("Expected at least 1 requested items"); + } + boolean paused = requested == 0; + requested += n; + if (paused) { + requestNext(subscriber); + } + } + + @Override + public void cancel() { + requested = -1; + currentSubscription.cancel(); + } + }); + } + + private void requestNext(Flow.Subscriber subscriber) { + if (this.subscriber == null) { + throw new IllegalStateException("No subscriber present"); + } + + if (currentlySubscribed) { + if (this.currentSubscription != null) { + currentSubscription.request(1); + } + return; + } + + if (this.bodyPublishers.isEmpty()) { + this.subscriber.onComplete(); + return; + } + this.bodyPublishers.get(0).subscribe(new Flow.Subscriber<>() { + private Flow.Subscription subscription; + @Override + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + currentSubscription = subscription; + if (requested-- > 0) { + this.subscription.request(1); + } + } + + @Override + public void onNext(ByteBuffer item) { + subscriber.onNext(item); + if (requested-- > 0) { + this.subscription.request(1); + } + } + + @Override + public void onError(Throwable throwable) { + subscriber.onError(throwable); + } + + @Override + public void onComplete() { + currentlySubscribed = false; + bodyPublishers.remove(0); + requestNext(subscriber); + } + }); + this.currentlySubscribed = true; + } + + public Builder newBuilder() { + return new Builder(); + } + + public static class Part { + private List headers = new ArrayList<>(); + + private final HttpRequest.BodyPublisher publisher; + + Part(HttpRequest.BodyPublisher publisher) { + this.publisher = publisher; + } + + private long getHeadersLength() { + return this.headers.stream().mapToLong(String::length).sum() + CRLF.length() * this.headers.size(); + } + + private long contentLength() { + return this.getHeadersLength() + CRLF.length() + this.publisher.contentLength() + CRLF.length(); + } + + private Part addHeader(String key, String value) { + this.headers.add(key + ": " + value); + return this; + } + + public static Part forFormData(String key, String value) { + return new Part(BodyPublishers.ofString(value, StandardCharsets.UTF_8)) + .addHeader("Content-Disposition", "form-data; name=" + key); + } + + public static Part forBodyPublisher(String key, String contentType, HttpRequest.BodyPublisher bodyPublisher) { + return forBodyPublisher(key, null, contentType, bodyPublisher); + } + + public static Part forBodyPublisher(String key, String filename, String contentType, HttpRequest.BodyPublisher bodyPublisher) { + String disposition = "form-data; name=" + key; + if (filename != null) { + disposition += "; filename=" + filename; + } + return new Part(bodyPublisher) + .addHeader("Content-Disposition", disposition) + .addHeader("Content-Type", contentType); + } + } + + public static class Builder { + private String boundaryDelimiter = UUID.randomUUID().toString(); + + private List part = new ArrayList<>(); + + public Builder addPart(Part part) { + this.part.add(part); + return this; + } + + public Builder setBoundaryDelimiter(String boundaryDelimiter) { + this.boundaryDelimiter = boundaryDelimiter; + return this; + } + + public MultipartBodyPublisher build() { + return new MultipartBodyPublisher(this.boundaryDelimiter, this.part); + } + } +} diff --git a/pom.xml b/pom.xml index 0b71248d5..b795c8bdb 100644 --- a/pom.xml +++ b/pom.xml @@ -91,16 +91,10 @@ compile - - com.squareup.okhttp3 - okhttp - 3.9.0 - compile - org.projectlombok lombok - 1.16.18 + 1.18.10 provided @@ -158,10 +152,9 @@ org.apache.maven.plugins maven-compiler-plugin - 3.7.0 + 3.8.1 - 1.8 - 1.8 + 11 @@ -198,7 +191,7 @@ org.projectlombok lombok-maven-plugin - 1.16.18.1 + 1.18.10.0 ${project.basedir}/src/main/java ${project.basedir}/src/main/delombok