Use interactive console login in the example, print exceptions only once

This commit is contained in:
Andrea Cavalli 2021-09-27 21:44:24 +02:00
parent 688076ff00
commit f2ba9773f5
13 changed files with 194 additions and 125 deletions

View File

@ -67,7 +67,7 @@ public final class Example {
SimpleTelegramClient client = new SimpleTelegramClient(settings); SimpleTelegramClient client = new SimpleTelegramClient(settings);
// Configure the authentication info // Configure the authentication info
AuthenticationData authenticationData = AuthenticationData.bot("124:1999"); AuthenticationData authenticationData = AuthenticationData.consoleLogin();
// Add an example update handler that prints when the bot is started // Add an example update handler that prints when the bot is started
client.addUpdateHandler(UpdateAuthorizationState.class, update -> printStatus(update.authorizationState)); client.addUpdateHandler(UpdateAuthorizationState.class, update -> printStatus(update.authorizationState));

View File

@ -4,7 +4,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://logging.apache.org/log4j/2.0/config xsi:schemaLocation="http://logging.apache.org/log4j/2.0/config
https://raw.githubusercontent.com/apache/logging-log4j2/log4j-2.14.1/log4j-core/src/main/resources/Log4j-config.xsd" https://raw.githubusercontent.com/apache/logging-log4j2/log4j-2.14.1/log4j-core/src/main/resources/Log4j-config.xsd"
status="ALL"> status="INFO">
<Appenders> <Appenders>
<Console name="Console" target="SYSTEM_OUT"> <Console name="Console" target="SYSTEM_OUT">
<PatternLayout <PatternLayout
@ -13,7 +13,7 @@
</Appenders> </Appenders>
<Loggers> <Loggers>
<Root level="ALL"> <Root level="INFO">
<AppenderRef ref="Console"/> <AppenderRef ref="Console"/>
</Root> </Root>
</Loggers> </Loggers>

View File

@ -1,75 +1,22 @@
package it.tdlight.client; package it.tdlight.client;
import java.util.Objects; public interface AuthenticationData {
import java.util.StringJoiner;
@SuppressWarnings("unused") boolean isBot();
public final class AuthenticationData {
private final Long userPhoneNumber;
private final String botToken;
private AuthenticationData(Long userPhoneNumber, String botToken) { long getUserPhoneNumber();
if ((userPhoneNumber == null) == (botToken == null)) {
throw new IllegalArgumentException("Please use either a bot token or a phone number"); String getBotToken();
}
if (botToken != null) { static AuthenticationData user(long userPhoneNumber) {
if (botToken.length() < 5 || botToken.length() > 200) { return new AuthenticationDataImpl(userPhoneNumber, null);
throw new IllegalArgumentException("Bot token is invalid: " + botToken);
}
}
this.userPhoneNumber = userPhoneNumber;
this.botToken = botToken;
} }
public static AuthenticationData user(long userPhoneNumber) { static AuthenticationData bot(String botToken) {
return new AuthenticationData(userPhoneNumber, null); return new AuthenticationDataImpl(null, botToken);
} }
public static AuthenticationData bot(String botToken) { static AuthenticationData consoleLogin() {
return new AuthenticationData(null, botToken); return new ConsoleInteractiveAuthenticationData();
}
public boolean isBot() {
return botToken != null;
}
public Long getUserPhoneNumber() {
if (userPhoneNumber == null) {
throw new UnsupportedOperationException("This is not a user");
}
return userPhoneNumber;
}
public String getBotToken() {
if (botToken == null) {
throw new UnsupportedOperationException("This is not a bot");
}
return botToken;
}
@Override
public String toString() {
if (userPhoneNumber != null) {
return "+" + userPhoneNumber;
} else {
return "\"" + botToken + "\"";
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AuthenticationData that = (AuthenticationData) o;
return Objects.equals(userPhoneNumber, that.userPhoneNumber) && Objects.equals(botToken, that.botToken);
}
@Override
public int hashCode() {
return Objects.hash(userPhoneNumber, botToken);
} }
} }

View File

@ -0,0 +1,69 @@
package it.tdlight.client;
import java.util.Objects;
@SuppressWarnings("unused")
final class AuthenticationDataImpl implements AuthenticationData {
private final Long userPhoneNumber;
private final String botToken;
AuthenticationDataImpl(Long userPhoneNumber, String botToken) {
if ((userPhoneNumber == null) == (botToken == null)) {
throw new IllegalArgumentException("Please use either a bot token or a phone number");
}
if (botToken != null) {
if (botToken.length() < 5 || botToken.length() > 200) {
throw new IllegalArgumentException("Bot token is invalid: " + botToken);
}
}
this.userPhoneNumber = userPhoneNumber;
this.botToken = botToken;
}
@Override
public boolean isBot() {
return botToken != null;
}
@Override
public long getUserPhoneNumber() {
if (userPhoneNumber == null) {
throw new UnsupportedOperationException("This is not a user");
}
return userPhoneNumber;
}
@Override
public String getBotToken() {
if (botToken == null) {
throw new UnsupportedOperationException("This is not a bot");
}
return botToken;
}
@Override
public String toString() {
if (userPhoneNumber != null) {
return "+" + userPhoneNumber;
} else {
return "\"" + botToken + "\"";
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AuthenticationDataImpl that = (AuthenticationDataImpl) o;
return Objects.equals(userPhoneNumber, that.userPhoneNumber) && Objects.equals(botToken, that.botToken);
}
@Override
public int hashCode() {
return Objects.hash(userPhoneNumber, botToken);
}
}

View File

@ -16,8 +16,6 @@ package it.tdlight.client;
final class AuthorizationStateWaitAuthenticationDataHandler implements GenericUpdateHandler<UpdateAuthorizationState> { final class AuthorizationStateWaitAuthenticationDataHandler implements GenericUpdateHandler<UpdateAuthorizationState> {
private static final Logger logger = LoggerFactory.getLogger(AuthorizationStateWaitAuthenticationDataHandler.class);
private final TelegramClient client; private final TelegramClient client;
private final Authenticable authenticable; private final Authenticable authenticable;
private final ExceptionHandler exceptionHandler; private final ExceptionHandler exceptionHandler;
@ -41,10 +39,7 @@ final class AuthorizationStateWaitAuthenticationDataHandler implements GenericUp
if (ok.getConstructor() == Error.CONSTRUCTOR) { if (ok.getConstructor() == Error.CONSTRUCTOR) {
throw new TelegramError((Error) ok); throw new TelegramError((Error) ok);
} }
}, ex -> { }, exceptionHandler);
logger.error("Failed to set TDLight phone number or bot token!", ex);
exceptionHandler.onException(ex);
});
} else { } else {
PhoneNumberAuthenticationSettings phoneSettings = new PhoneNumberAuthenticationSettings(false, false, false); PhoneNumberAuthenticationSettings phoneSettings = new PhoneNumberAuthenticationSettings(false, false, false);
@ -54,10 +49,7 @@ final class AuthorizationStateWaitAuthenticationDataHandler implements GenericUp
if (ok.getConstructor() == Error.CONSTRUCTOR) { if (ok.getConstructor() == Error.CONSTRUCTOR) {
throw new TelegramError((Error) ok); throw new TelegramError((Error) ok);
} }
}, ex -> { }, exceptionHandler);
logger.error("Failed to set TDLight phone number!", ex);
exceptionHandler.onException(ex);
});
} }
} }
} }

View File

@ -14,8 +14,6 @@ import org.slf4j.LoggerFactory;
final class AuthorizationStateWaitCodeHandler implements GenericUpdateHandler<UpdateAuthorizationState> { final class AuthorizationStateWaitCodeHandler implements GenericUpdateHandler<UpdateAuthorizationState> {
private static final Logger logger = LoggerFactory.getLogger(AuthorizationStateWaitCodeHandler.class);
private final TelegramClient client; private final TelegramClient client;
private final ClientInteraction clientInteraction; private final ClientInteraction clientInteraction;
private final ExceptionHandler exceptionHandler; private final ExceptionHandler exceptionHandler;
@ -44,10 +42,7 @@ final class AuthorizationStateWaitCodeHandler implements GenericUpdateHandler<Up
if (ok.getConstructor() == Error.CONSTRUCTOR) { if (ok.getConstructor() == Error.CONSTRUCTOR) {
throw new TelegramError((Error) ok); throw new TelegramError((Error) ok);
} }
}, ex -> { }, exceptionHandler);
logger.error("Failed to check authentication code", ex);
exceptionHandler.onException(ex);
});
} }
} }
} }

View File

@ -14,8 +14,6 @@ import org.slf4j.LoggerFactory;
final class AuthorizationStateWaitEncryptionKeyHandler implements GenericUpdateHandler<UpdateAuthorizationState> { final class AuthorizationStateWaitEncryptionKeyHandler implements GenericUpdateHandler<UpdateAuthorizationState> {
private static final Logger logger = LoggerFactory.getLogger(AuthorizationStateWaitEncryptionKeyHandler.class);
private final TelegramClient client; private final TelegramClient client;
private final ExceptionHandler exceptionHandler; private final ExceptionHandler exceptionHandler;
@ -31,10 +29,7 @@ final class AuthorizationStateWaitEncryptionKeyHandler implements GenericUpdateH
if (ok.getConstructor() == Error.CONSTRUCTOR) { if (ok.getConstructor() == Error.CONSTRUCTOR) {
throw new TelegramError((Error) ok); throw new TelegramError((Error) ok);
} }
}, ex -> { }, exceptionHandler);
logger.error("Failed to manage TDLight database encryption key!", ex);
exceptionHandler.onException(ex);
});
} }
} }
} }

View File

@ -8,16 +8,10 @@ import it.tdlight.jni.TdApi.UpdateAuthorizationState;
final class AuthorizationStateWaitOtherDeviceConfirmationHandler final class AuthorizationStateWaitOtherDeviceConfirmationHandler
implements GenericUpdateHandler<UpdateAuthorizationState> { implements GenericUpdateHandler<UpdateAuthorizationState> {
private final TelegramClient client;
private final ClientInteraction clientInteraction; private final ClientInteraction clientInteraction;
private final ExceptionHandler exceptionHandler;
public AuthorizationStateWaitOtherDeviceConfirmationHandler(TelegramClient client, public AuthorizationStateWaitOtherDeviceConfirmationHandler(ClientInteraction clientInteraction) {
ClientInteraction clientInteraction,
ExceptionHandler exceptionHandler) {
this.client = client;
this.clientInteraction = clientInteraction; this.clientInteraction = clientInteraction;
this.exceptionHandler = exceptionHandler;
} }
@Override @Override

View File

@ -14,8 +14,6 @@ import org.slf4j.LoggerFactory;
final class AuthorizationStateWaitPasswordHandler implements GenericUpdateHandler<UpdateAuthorizationState> { final class AuthorizationStateWaitPasswordHandler implements GenericUpdateHandler<UpdateAuthorizationState> {
private static final Logger logger = LoggerFactory.getLogger(AuthorizationStateWaitPasswordHandler.class);
private final TelegramClient client; private final TelegramClient client;
private final ClientInteraction clientInteraction; private final ClientInteraction clientInteraction;
private final ExceptionHandler exceptionHandler; private final ExceptionHandler exceptionHandler;
@ -43,10 +41,7 @@ final class AuthorizationStateWaitPasswordHandler implements GenericUpdateHandle
if (ok.getConstructor() == Error.CONSTRUCTOR) { if (ok.getConstructor() == Error.CONSTRUCTOR) {
throw new TelegramError((Error) ok); throw new TelegramError((Error) ok);
} }
}, ex -> { }, exceptionHandler);
logger.error("Failed to check authentication password", ex);
exceptionHandler.onException(ex);
});
} }
} }
} }

View File

@ -12,8 +12,6 @@ import org.slf4j.LoggerFactory;
final class AuthorizationStateWaitRegistrationHandler implements GenericUpdateHandler<UpdateAuthorizationState> { final class AuthorizationStateWaitRegistrationHandler implements GenericUpdateHandler<UpdateAuthorizationState> {
private static final Logger logger = LoggerFactory.getLogger(AuthorizationStateWaitRegistrationHandler.class);
private final TelegramClient client; private final TelegramClient client;
private final ClientInteraction clientInteraction; private final ClientInteraction clientInteraction;
private final ExceptionHandler exceptionHandler; private final ExceptionHandler exceptionHandler;
@ -55,10 +53,7 @@ final class AuthorizationStateWaitRegistrationHandler implements GenericUpdateHa
if (ok.getConstructor() == Error.CONSTRUCTOR) { if (ok.getConstructor() == Error.CONSTRUCTOR) {
throw new TelegramError((Error) ok); throw new TelegramError((Error) ok);
} }
}, ex -> { }, exceptionHandler);
logger.error("Failed to register user", ex);
exceptionHandler.onException(ex);
});
} }
} }
} }

View File

@ -12,8 +12,6 @@ import org.slf4j.LoggerFactory;
final class AuthorizationStateWaitTdlibParametersHandler implements GenericUpdateHandler<UpdateAuthorizationState> { final class AuthorizationStateWaitTdlibParametersHandler implements GenericUpdateHandler<UpdateAuthorizationState> {
private static final Logger logger = LoggerFactory.getLogger(AuthorizationStateWaitEncryptionKeyHandler.class);
private final TelegramClient client; private final TelegramClient client;
private final TDLibSettings settings; private final TDLibSettings settings;
private final ExceptionHandler exceptionHandler; private final ExceptionHandler exceptionHandler;
@ -49,10 +47,7 @@ final class AuthorizationStateWaitTdlibParametersHandler implements GenericUpdat
if (ok.getConstructor() == Error.CONSTRUCTOR) { if (ok.getConstructor() == Error.CONSTRUCTOR) {
throw new TelegramError((Error) ok); throw new TelegramError((Error) ok);
} }
}, ex -> { }, exceptionHandler);
logger.error("Failed to set TDLight parameters!", ex);
exceptionHandler.onException(ex);
});
} }
} }
} }

View File

@ -0,0 +1,101 @@
package it.tdlight.client;
import it.tdlight.common.utils.ScannerUtils;
import java.util.Locale;
import java.util.stream.Collector;
final class ConsoleInteractiveAuthenticationData implements AuthenticationData {
private static final Object LOCK = new Object();
private boolean initialized = false;
private boolean isBot;
private String botToken;
private long phoneNumber;
public ConsoleInteractiveAuthenticationData() {
}
public void askData() {
initializeIfNeeded();
}
@Override
public boolean isBot() {
initializeIfNeeded();
return isBot;
}
@Override
public long getUserPhoneNumber() {
initializeIfNeeded();
if (isBot) {
throw new UnsupportedOperationException("This is not a user");
}
return phoneNumber;
}
@Override
public String getBotToken() {
initializeIfNeeded();
if (!isBot) {
throw new UnsupportedOperationException("This is not a bot");
}
return botToken;
}
private void initializeIfNeeded() {
if (initialized) return;
synchronized (LOCK) {
if (initialized) return;
String choice;
// Choose login type
Boolean useBotToken;
do {
choice = ScannerUtils
.askParameter("login", "Do you want to login using a bot [token] or a [phone] number? [token/phone]")
.trim()
.toLowerCase(Locale.ROOT);
if ("phone".equals(choice)) {
useBotToken = false;
} else if ("token".equals(choice)) {
useBotToken = true;
} else {
useBotToken = null;
}
} while (useBotToken == null);
if (useBotToken) {
String token;
do {
token = ScannerUtils.askParameter("login", "Please type the bot token");
} while (token.length() < 5 || !token.contains(":"));
this.isBot = true;
this.phoneNumber = -1;
this.botToken = token;
} else {
String phoneNumber;
do {
phoneNumber = ScannerUtils.askParameter("login", "Please type your phone number");
} while (phoneNumber.length() < 3);
long phoneNumberLong = Long.parseLong(phoneNumber.chars().filter(Character::isDigit).boxed().collect(Collector.of(
StringBuilder::new,
StringBuilder::append,
StringBuilder::append,
StringBuilder::toString)));
this.isBot = false;
this.phoneNumber = phoneNumberLong;
this.botToken = null;
}
initialized = true;
}
}
}

View File

@ -10,24 +10,16 @@ import it.tdlight.common.internal.CommonClientManager;
import it.tdlight.common.utils.CantLoadLibrary; import it.tdlight.common.utils.CantLoadLibrary;
import it.tdlight.common.utils.LibraryVersion; import it.tdlight.common.utils.LibraryVersion;
import it.tdlight.jni.TdApi; import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.Chat;
import it.tdlight.jni.TdApi.Error; import it.tdlight.jni.TdApi.Error;
import it.tdlight.jni.TdApi.Function; import it.tdlight.jni.TdApi.Function;
import it.tdlight.jni.TdApi.Message;
import it.tdlight.jni.TdApi.MessageText;
import it.tdlight.jni.TdApi.UpdateNewMessage;
import it.tdlight.jni.TdApi.User; import it.tdlight.jni.TdApi.User;
import java.io.IOException; import java.io.IOException;
import java.io.UncheckedIOException; import java.io.UncheckedIOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -83,8 +75,7 @@ public final class SimpleTelegramClient implements Authenticable {
new AuthorizationStateWaitPasswordHandler(client, new SimpleTelegramClientInteraction(), new AuthorizationStateWaitPasswordHandler(client, new SimpleTelegramClientInteraction(),
this::handleDefaultException)); this::handleDefaultException));
this.addUpdateHandler(TdApi.UpdateAuthorizationState.class, this.addUpdateHandler(TdApi.UpdateAuthorizationState.class,
new AuthorizationStateWaitOtherDeviceConfirmationHandler(client, new SimpleTelegramClientInteraction(), new AuthorizationStateWaitOtherDeviceConfirmationHandler(new SimpleTelegramClientInteraction()));
this::handleDefaultException));
this.addUpdateHandler(TdApi.UpdateAuthorizationState.class, this.addUpdateHandler(TdApi.UpdateAuthorizationState.class,
new AuthorizationStateWaitCodeHandler(client, new SimpleTelegramClientInteraction(), new AuthorizationStateWaitCodeHandler(client, new SimpleTelegramClientInteraction(),
this::handleDefaultException)); this::handleDefaultException));