diff --git a/src/main/java/it/tdlight/tdlibsession/td/easy/AsyncTdEasy.java b/src/main/java/it/tdlight/tdlibsession/td/easy/AsyncTdEasy.java index 37247ac..e7afc1e 100644 --- a/src/main/java/it/tdlight/tdlibsession/td/easy/AsyncTdEasy.java +++ b/src/main/java/it/tdlight/tdlibsession/td/easy/AsyncTdEasy.java @@ -34,6 +34,7 @@ import it.tdlight.tdlibsession.FatalErrorType; import it.tdlight.tdlibsession.td.TdResult; import it.tdlight.tdlibsession.td.middle.AsyncTdMiddle; import it.tdlight.utils.MonoUtils; +import it.tdlight.utils.TdLightUtils; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -348,7 +349,6 @@ public class AsyncTdEasy { .filter(obj -> obj.getConstructor() == UpdateAuthorizationState.CONSTRUCTOR) .map(obj -> ((UpdateAuthorizationState) obj).authorizationState) .flatMap(obj -> { - this.authState.onNext(new AuthorizationStateReady()); switch (obj.getConstructor()) { case AuthorizationStateWaitTdlibParameters.CONSTRUCTOR: return MonoUtils.thenOrError(Mono.from(this.settings).map(settings -> { @@ -371,7 +371,12 @@ public class AsyncTdEasy { return new SetTdlibParameters(parameters); }).flatMap(this::sendDirectly)); case AuthorizationStateWaitEncryptionKey.CONSTRUCTOR: - return MonoUtils.thenOrError(sendDirectly(new CheckDatabaseEncryptionKey())); + return MonoUtils + .thenOrError(sendDirectly(new CheckDatabaseEncryptionKey())) + .onErrorResume((error) -> { + logger.error("Error while checking TDLib encryption key", error); + return sendDirectly(new TdApi.Close()).then(); + }); case AuthorizationStateWaitPhoneNumber.CONSTRUCTOR: return MonoUtils.thenOrError(Mono.from(this.settings).flatMap(settings -> { if (settings.isPhoneNumberSet()) { @@ -383,7 +388,10 @@ public class AsyncTdEasy { } else { return Mono.error(new IllegalArgumentException("A bot is neither an user or a bot")); } - })); + })).onErrorResume((error) -> { + logger.error("Error while waiting for phone number", error); + return sendDirectly(new TdApi.Close()).then(); + }); case AuthorizationStateWaitRegistration.CONSTRUCTOR: var authorizationStateWaitRegistration = (AuthorizationStateWaitRegistration) obj; RegisterUser registerUser = new RegisterUser(); @@ -396,7 +404,7 @@ public class AsyncTdEasy { .from(settings) .map(TdEasySettings::getParameterRequestHandler) .flatMap(handler -> { - return handler + return MonoUtils.thenOrLogRepeatError(() -> handler .onParameterRequest(Parameter.ASK_FIRST_NAME, new ParameterInfoEmpty()) .filter(Objects::nonNull) .map(String::trim) @@ -414,9 +422,8 @@ public class AsyncTdEasy { .defaultIfEmpty("") .doOnNext(lastName -> registerUser.lastName = lastName) ) - .thenReturn(handler); - }) - .then(MonoUtils.thenOrError(sendDirectly(registerUser))); + .then(sendDirectly(registerUser))); + }); case TdApi.AuthorizationStateWaitOtherDeviceConfirmation.CONSTRUCTOR: var authorizationStateWaitOtherDeviceConfirmation = (AuthorizationStateWaitOtherDeviceConfirmation) obj; return Mono @@ -433,27 +440,26 @@ public class AsyncTdEasy { .from(settings) .map(TdEasySettings::getParameterRequestHandler) .flatMap(handler -> { - return handler.onParameterRequest(Parameter.ASK_CODE, + return MonoUtils.thenOrLogRepeatError(() -> handler.onParameterRequest(Parameter.ASK_CODE, new ParameterInfoCode(authorizationStateWaitCode.codeInfo.phoneNumber, authorizationStateWaitCode.codeInfo.nextType, authorizationStateWaitCode.codeInfo.timeout, authorizationStateWaitCode.codeInfo.type ) - ); - }) - .flatMap(code -> MonoUtils.thenOrError(sendDirectly(new CheckAuthenticationCode(code)))); + ).flatMap(code -> sendDirectly(new CheckAuthenticationCode(code)))); + }); case AuthorizationStateWaitPassword.CONSTRUCTOR: var authorizationStateWaitPassword = (AuthorizationStateWaitPassword) obj; return Mono .from(settings) .map(TdEasySettings::getParameterRequestHandler) .flatMap(handler -> { - return handler.onParameterRequest(Parameter.ASK_PASSWORD, + return MonoUtils.thenOrLogRepeatError(() -> handler.onParameterRequest(Parameter.ASK_PASSWORD, new ParameterInfoPasswordHint(authorizationStateWaitPassword.passwordHint) - ); - }) - .flatMap(password -> MonoUtils.thenOrError(sendDirectly(new CheckAuthenticationPassword(password)))); + ).flatMap(password -> sendDirectly(new CheckAuthenticationPassword(password)))); + }); case AuthorizationStateReady.CONSTRUCTOR: { + this.authState.onNext(new AuthorizationStateReady()); return Mono.empty(); } case AuthorizationStateClosed.CONSTRUCTOR: diff --git a/src/main/java/it/tdlight/utils/MonoUtils.java b/src/main/java/it/tdlight/utils/MonoUtils.java index f27b57c..f09f637 100644 --- a/src/main/java/it/tdlight/utils/MonoUtils.java +++ b/src/main/java/it/tdlight/utils/MonoUtils.java @@ -8,12 +8,15 @@ import it.tdlight.jni.TdApi; import it.tdlight.jni.TdApi.Object; import it.tdlight.tdlibsession.td.TdError; import it.tdlight.tdlibsession.td.TdResult; +import it.tdlight.tdlibsession.td.middle.direct.AsyncTdMiddleDirect; import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Supplier; import org.reactivestreams.Subscription; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.warp.commonutils.concurrency.future.CompletableFutureUtils; import reactor.core.CoreSubscriber; import reactor.core.publisher.Mono; @@ -23,6 +26,8 @@ import reactor.util.context.Context; public class MonoUtils { + private static final Logger logger = LoggerFactory.getLogger(MonoUtils.class); + public static Handler> toHandler(SynchronousSink sink) { return event -> { if (event.succeeded()) { @@ -137,6 +142,26 @@ public class MonoUtils { }); } + public static Mono thenOrLogSkipError(Mono> optionalMono) { + return optionalMono.handle((optional, sink) -> { + if (optional.failed()) { + logger.error("Received TDLib error: {}", optional.cause()); + } + sink.complete(); + }); + } + + public static Mono thenOrLogRepeatError(Supplier>> optionalMono) { + return Mono.defer(() -> optionalMono.get().handle((TdResult optional, SynchronousSink sink) -> { + if (optional.succeeded()) { + sink.complete(); + } else { + logger.error("Received TDLib error: {}", optional.cause()); + sink.error(new TdError(optional.cause().code, optional.cause().message)); + } + })).retry(); + } + public static Mono fromFuture(CompletableFuture future) { return Mono.create(sink -> { future.whenComplete((result, error) -> { diff --git a/src/main/java/it/tdlight/utils/TdLightUtils.java b/src/main/java/it/tdlight/utils/TdLightUtils.java new file mode 100644 index 0000000..c95ea67 --- /dev/null +++ b/src/main/java/it/tdlight/utils/TdLightUtils.java @@ -0,0 +1,40 @@ +package it.tdlight.utils; + +import it.tdlight.jni.TdApi; +import it.tdlight.jni.TdApi.Error; +import it.tdlight.tdlibsession.td.ResponseError; +import it.tdlight.tdlibsession.td.TdError; +import org.jetbrains.annotations.Nullable; + +public class TdLightUtils { + + @SuppressWarnings("RedundantIfStatement") + public static boolean errorEquals(Throwable ex, @Nullable Integer errorCode, @Nullable String errorText) { + while (ex != null) { + TdApi.Error error = null; + if (ex instanceof TdError) { + error = ((TdError) ex).getTdError(); + } + if (ex instanceof ResponseError) { + error = new Error(((ResponseError) ex).getErrorCode(), ((ResponseError) ex).getErrorMessage()); + } + + if (error != null) { + if (errorCode != null) { + if (error.code != errorCode) { + return false; + } + } + if (errorText != null) { + if (error.message == null || !error.message.contains(errorText)) { + return false; + } + } + return true; + } + + ex = ex.getCause(); + } + return false; + } +} diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java deleted file mode 100644 index 216aaab..0000000 --- a/src/main/java/module-info.java +++ /dev/null @@ -1,28 +0,0 @@ -module it.tdlight.tdlibsessioncontainer { - requires vertx.core; - requires org.jetbrains.annotations; - requires reactor.core; - requires tdlight.java; - requires org.slf4j; - requires org.reactivestreams; - requires org.apache.logging.log4j.core; - requires org.apache.logging.log4j; - requires common.utils; - requires vertx.circuit.breaker; - requires org.apache.commons.lang3; - requires com.hazelcast.core; - requires vertx.hazelcast; - requires it.unimi.dsi.fastutil; - requires com.google.gson; - - exports it.tdlight.tdlibsession; - exports it.tdlight.tdlibsession.remoteclient; - exports it.tdlight.tdlibsession.td; - exports it.tdlight.tdlibsession.td.direct; - exports it.tdlight.tdlibsession.td.easy; - exports it.tdlight.tdlibsession.td.middle; - exports it.tdlight.tdlibsession.td.middle.client; - exports it.tdlight.tdlibsession.td.middle.direct; - exports it.tdlight.tdlibsession.td.middle.server; - exports it.tdlight.utils; -} \ No newline at end of file