migration
This commit is contained in:
@@ -10,15 +10,14 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.3'
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
|
||||
implementation platform('com.fasterxml.jackson:jackson-bom:2.18.3')
|
||||
|
||||
|
||||
implementation 'com.fasterxml.jackson.core:jackson-core'
|
||||
implementation 'com.fasterxml.jackson.core:jackson-databind'
|
||||
|
||||
//implementation 'com.squareup.okhttp3:okhttp:4.12.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:5.2.1'
|
||||
implementation(project(":core"))
|
||||
}
|
||||
|
||||
tasks.register('fat') {
|
||||
jar {
|
||||
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import hdvtdev.telegram.core.InvokeMethod;
|
||||
import hdvtdev.telegram.core.HandlersModule;
|
||||
import hdvtdev.telegram.core.TelegramBot;
|
||||
import hdvtdev.telegram.core.UpdateConsumer;
|
||||
import hdvtdev.telegram.core.annotaions.Jsonable;
|
||||
import hdvtdev.telegram.core.UpdateExecutor;
|
||||
import hdvtdev.telegram.core.exceptions.TelegramApiException;
|
||||
import hdvtdev.telegram.core.exceptions.TelegramApiNetworkException;
|
||||
import hdvtdev.telegram.core.exceptions.TelegramMethodParsingException;
|
||||
@@ -22,14 +22,10 @@ import okhttp3.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
@@ -40,24 +36,10 @@ public class OkHttpTelegramBot implements TelegramBot {
|
||||
private final String TELEGRAM_FILE_API_URL;
|
||||
private final ObjectMapper json;
|
||||
|
||||
static {
|
||||
try {
|
||||
HttpURLConnection connection = (HttpURLConnection) URI.create("https://api.telegram.org").toURL().openConnection();
|
||||
connection.setRequestMethod("HEAD");
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setReadTimeout(5000);
|
||||
int responseCode = connection.getResponseCode();
|
||||
private ScheduledExecutorService scheduler;
|
||||
|
||||
if (responseCode != 200) {
|
||||
throw new TelegramApiNetworkException("Telegram API is unreachable. Response code: " + responseCode);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new TelegramApiNetworkException("Error checking Telegram API connectivity.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private ExecutorService thread;
|
||||
private AtomicLong lastUpdateId;
|
||||
private final UpdateExecutor updateExecutor;
|
||||
private final AtomicLong lastUpdateId = new AtomicLong(0);
|
||||
private int updateLimit = 10;
|
||||
private int updateTimeout = 25;
|
||||
private final OkHttpClient client = buildOkHttpClient();
|
||||
@@ -68,6 +50,7 @@ public class OkHttpTelegramBot implements TelegramBot {
|
||||
dispatcher.setMaxRequestsPerHost(100);
|
||||
|
||||
return new OkHttpClient.Builder()
|
||||
|
||||
.dispatcher(dispatcher)
|
||||
.connectionPool(new ConnectionPool(
|
||||
100,
|
||||
@@ -78,14 +61,37 @@ public class OkHttpTelegramBot implements TelegramBot {
|
||||
.writeTimeout(updateTimeout, TimeUnit.SECONDS)
|
||||
.connectTimeout(updateTimeout, TimeUnit.SECONDS)
|
||||
.retryOnConnectionFailure(true)
|
||||
.addInterceptor(chain -> {
|
||||
Request request = chain.request();
|
||||
|
||||
int retryDelay = 1000;
|
||||
int maxRetries = 5;
|
||||
|
||||
for (int attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
|
||||
try {
|
||||
return chain.proceed(request);
|
||||
} catch (IOException e) {
|
||||
if (attempt == maxRetries) throw e;
|
||||
try {
|
||||
TimeUnit.MILLISECONDS.sleep(retryDelay);
|
||||
} catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw e;
|
||||
}
|
||||
retryDelay *= 2;
|
||||
}
|
||||
}
|
||||
throw new TelegramApiNetworkException("Network is unreachable");
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
private UpdateConsumer updateConsumer;
|
||||
private boolean enableHandlers = false;
|
||||
|
||||
public OkHttpTelegramBot(String token) {
|
||||
this.json = new ObjectMapper();
|
||||
this.updateExecutor = (Update update) -> CompletableFuture.runAsync(() -> updateConsumer.onUpdate(update));
|
||||
this.TELEGRAM_API_URL = "https://api.telegram.org/bot" + token + "/";
|
||||
this.TELEGRAM_FILE_API_URL = "https://api.telegram.org/file/bot" + token + "/";
|
||||
}
|
||||
@@ -93,54 +99,69 @@ public class OkHttpTelegramBot implements TelegramBot {
|
||||
private OkHttpTelegramBot(Builder builder) {
|
||||
updateLimit = builder.updateLimit;
|
||||
updateTimeout = builder.updateTimeout;
|
||||
enableHandlers = builder.enableHandlers;
|
||||
json = builder.objectMapper == null ? new ObjectMapper() : builder.objectMapper;
|
||||
/*
|
||||
if (false) {
|
||||
Class<? extends UpdateConsumer> updateConsumerClass = builder.updateConsumer == null ? UpdateConsumer.class : builder.updateConsumer.getClass();
|
||||
Map<Class<?>, Map<String, InvokeMethod>> handlers = builder.enableScan ? ClassFinder.getClasses() : ClassFinder.localScan(updateConsumerClass);
|
||||
this.messageHandlers = Collections.unmodifiableMap(handlers.get(TextMessageHandler.class));
|
||||
this.callbackQueryHandlers = Collections.unmodifiableMap(handlers.get(CallbackQueryHandler.class));
|
||||
}
|
||||
|
||||
*/
|
||||
ExecutorService pool = builder.pool;
|
||||
|
||||
this.updateExecutor = pool == null ? (Update update) -> CompletableFuture.runAsync(() -> updateConsumer.onUpdate(update))
|
||||
: (Update update) -> pool.execute(() -> updateConsumer.onUpdate(update));
|
||||
this.TELEGRAM_API_URL = "https://api.telegram.org/bot" + builder.token + "/";
|
||||
this.TELEGRAM_FILE_API_URL = "https://api.telegram.org/file/bot" + builder.token + "/";
|
||||
if (builder.updateConsumer != null) setUpdateConsumer(builder.updateConsumer);
|
||||
if (builder.updateConsumer != null) start(builder.updateConsumer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables a long polling update consumer. If {@link #enableHandlers} is {@code true},
|
||||
* the specified handlers will be invoked for each received update.
|
||||
*
|
||||
* @param updateConsumer class that implements {@code UpdateConsumer}
|
||||
* @throws IllegalStateException if an {@code UpdateConsumer} is already defined
|
||||
* @see #enableHandlers
|
||||
* @since 0.0.1
|
||||
*/
|
||||
private void setUpdateConsumer(UpdateConsumer updateConsumer) throws IllegalStateException {
|
||||
if (thread != null) throw new IllegalStateException("Update Consumer is already defined. You must first stop the previous");
|
||||
this.updateConsumer = updateConsumer;
|
||||
this.lastUpdateId = new AtomicLong(0);
|
||||
thread = Executors.newSingleThreadExecutor();
|
||||
thread.execute(this::getUpdates);
|
||||
@Override
|
||||
public void start(UpdateConsumer updateConsumer) throws IllegalStateException {
|
||||
if (scheduler != null && !scheduler.isShutdown()) {
|
||||
throw new IllegalStateException("Long polling is already running. You must stop it first.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
boolean moduleEnabled = true;
|
||||
|
||||
try {
|
||||
Class<?> handlersModule = Class.forName("Handlers");
|
||||
HandlersModule module = (HandlersModule) handlersModule.getDeclaredConstructor().newInstance();
|
||||
//this.updateConsumer = module.enable(updateConsumer);
|
||||
} catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException | IllegalArgumentException | NoSuchMethodException | InstantiationException e) {
|
||||
moduleEnabled = false;
|
||||
}
|
||||
|
||||
if (!moduleEnabled) this.updateConsumer = updateConsumer;
|
||||
scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||
scheduler.scheduleWithFixedDelay(this::getUpdates, 0, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
|
||||
public void stop() {
|
||||
if (scheduler == null || scheduler.isShutdown()) {
|
||||
return;
|
||||
}
|
||||
scheduler.shutdown();
|
||||
try {
|
||||
if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
|
||||
scheduler.shutdownNow();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
scheduler.shutdownNow();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
private void getUpdates() {
|
||||
|
||||
List<Update> updates = List.of(awaitExecute(new GetUpdates(lastUpdateId.get() + 1, updateLimit, updateTimeout)));
|
||||
try {
|
||||
if (!updates.isEmpty()) {
|
||||
if (updateConsumer != null) CompletableFuture.runAsync(() -> updateConsumer.onUpdates(updates));
|
||||
lastUpdateId.set(updates.getLast().updateId());
|
||||
if (!updates.isEmpty()) {
|
||||
for (Update update : updates) {
|
||||
updateExecutor.execute(update);
|
||||
}
|
||||
} finally {
|
||||
if (!thread.isShutdown()) getUpdates();
|
||||
lastUpdateId.set(updates.getLast().updateId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
this.thread.close();
|
||||
stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -151,7 +172,7 @@ public class OkHttpTelegramBot implements TelegramBot {
|
||||
Request.Builder request = new Request.Builder()
|
||||
.url(TELEGRAM_API_URL + telegramApiMethod.getMethodName());
|
||||
if (body == null) {
|
||||
if (telegramApiMethod.getClass().isAnnotationPresent(Jsonable.class)) {
|
||||
if (telegramApiMethod.isJsonable()) {
|
||||
try {
|
||||
request.post(RequestBody.create(json.writeValueAsString(telegramApiMethod), MediaType.get("application/json; charset=utf-8")));
|
||||
} catch (JsonProcessingException e) {
|
||||
@@ -168,24 +189,24 @@ public class OkHttpTelegramBot implements TelegramBot {
|
||||
}
|
||||
|
||||
try (Response response = client.newCall(request.build()).execute()) {
|
||||
String responseBody = Objects.requireNonNull(response.body()).string();
|
||||
ResponseBody responseBody = response.body();
|
||||
String responseBodyString = responseBody.string();
|
||||
if (response.isSuccessful()) {
|
||||
JsonNode rootNode = json.readTree(responseBody);
|
||||
JsonNode rootNode = json.readTree(responseBodyString);
|
||||
JsonNode resultNode = rootNode.path("result");
|
||||
return json.treeToValue(resultNode, telegramApiMethod.getResponseClass());
|
||||
} else {
|
||||
throw new TelegramApiException(json.readValue(responseBody, TelegramApiException.ErrorResponse.class));
|
||||
throw new TelegramApiException(json.readValue(responseBodyString, TelegramApiException.ErrorResponse.class));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new TelegramApiNetworkException(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private File getFile(TelegramFile telegramFile, Path targetDirectory) {
|
||||
try (Response response = client.newCall(new Request.Builder().url(TELEGRAM_FILE_API_URL + telegramFile.filePath()).build()).execute()) {
|
||||
ResponseBody responseBody = Objects.requireNonNull(response.body());
|
||||
ResponseBody responseBody = response.body();
|
||||
if (!response.isSuccessful())
|
||||
throw new TelegramApiException(json.readValue(responseBody.string(), TelegramApiException.ErrorResponse.class));
|
||||
Path filePath = Files.isDirectory(targetDirectory) ? targetDirectory.resolve(Path.of(telegramFile.filePath()).getFileName()) : targetDirectory;
|
||||
@@ -203,16 +224,21 @@ public class OkHttpTelegramBot implements TelegramBot {
|
||||
public static final class Builder {
|
||||
private int updateLimit = 10;
|
||||
private int updateTimeout = 25;
|
||||
private boolean enableHandlers = false;
|
||||
private boolean enableScan = false;
|
||||
private final String token;
|
||||
private UpdateConsumer updateConsumer;
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
private ExecutorService pool;
|
||||
|
||||
public Builder(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
|
||||
public Builder threadPool(ExecutorService pool) {
|
||||
this.pool = pool;
|
||||
return this;
|
||||
}
|
||||
public Builder objectMapper(ObjectMapper objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
return this;
|
||||
@@ -233,17 +259,6 @@ public class OkHttpTelegramBot implements TelegramBot {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder enableHandlers() {
|
||||
this.enableHandlers = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder enableHandlers(boolean enableScan) {
|
||||
this.enableHandlers = true;
|
||||
this.enableScan = enableScan;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OkHttpTelegramBot build() {
|
||||
return new OkHttpTelegramBot(this);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user