This commit is contained in:
Andrea Cavalli 2021-10-24 01:03:16 +02:00
parent d79cf305cb
commit 4f3c8cb6b7
12 changed files with 224 additions and 182 deletions

View File

@ -26,7 +26,7 @@
<dependency>
<groupId>it.tdlight</groupId>
<artifactId>tdlight-java</artifactId>
<version>2.7.8.38</version>
<version>2.7.8.39</version>
</dependency>
<!-- TDLight natives -->

View File

@ -43,7 +43,7 @@ public final class Example {
client = new SimpleTelegramClient(settings);
// Configure the authentication info
var authenticationData = AuthenticationData.consoleLogin().askAuthData();
var authenticationData = AuthenticationData.consoleLogin();
// Add an example update handler that prints when the bot is started
client.addUpdateHandler(TdApi.UpdateAuthorizationState.class, Example::onUpdateAuthorizationState);

View File

@ -1,6 +1,8 @@
package it.tdlight.client;
import java.util.function.Consumer;
public interface Authenticable {
AuthenticationData getAuthenticationData();
void getAuthenticationData(Consumer<AuthenticationData> result);
}

View File

@ -3,7 +3,6 @@ package it.tdlight.client;
import it.tdlight.common.ExceptionHandler;
import it.tdlight.common.TelegramClient;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.AuthorizationStateWaitPhoneNumber;
import it.tdlight.jni.TdApi.PhoneNumberAuthenticationSettings;
import it.tdlight.jni.TdApi.SetAuthenticationPhoneNumber;
import it.tdlight.jni.TdApi.UpdateAuthorizationState;
@ -25,13 +24,11 @@ final class AuthorizationStateWaitAuthenticationDataHandler implements GenericUp
@Override
public void onUpdate(UpdateAuthorizationState update) {
if (update.authorizationState.getConstructor() == TdApi.AuthorizationStateWaitPhoneNumber.CONSTRUCTOR) {
AuthenticationData authenticationData = authenticable.getAuthenticationData();
// Ask login parameters
if (authenticationData instanceof ConsoleInteractiveAuthenticationData) {
((ConsoleInteractiveAuthenticationData) authenticationData).askData();
authenticable.getAuthenticationData(this::onAuthData);
}
}
public void onAuthData(AuthenticationData authenticationData) {
if (authenticationData.isBot()) {
String botToken = authenticationData.getBotToken();
TdApi.CheckAuthenticationBotToken response = new TdApi.CheckAuthenticationBotToken(botToken);
@ -59,5 +56,4 @@ final class AuthorizationStateWaitAuthenticationDataHandler implements GenericUp
}, exceptionHandler);
}
}
}
}

View File

@ -30,13 +30,14 @@ final class AuthorizationStateWaitCodeHandler implements GenericUpdateHandler<Up
authorizationState.codeInfo.timeout,
authorizationState.codeInfo.type
);
String code = clientInteraction.onParameterRequest(InputParameter.ASK_CODE, parameterInfo);
clientInteraction.onParameterRequest(InputParameter.ASK_CODE, parameterInfo, code -> {
CheckAuthenticationCode response = new CheckAuthenticationCode(code);
client.send(response, ok -> {
if (ok.getConstructor() == TdApi.Error.CONSTRUCTOR) {
throw new TelegramError((TdApi.Error) ok);
}
}, exceptionHandler);
});
}
}
}

View File

@ -17,7 +17,9 @@ final class AuthorizationStateWaitOtherDeviceConfirmationHandler implements
if (update.authorizationState.getConstructor() == AuthorizationStateWaitOtherDeviceConfirmation.CONSTRUCTOR) {
AuthorizationStateWaitOtherDeviceConfirmation authorizationState = (AuthorizationStateWaitOtherDeviceConfirmation) update.authorizationState;
ParameterInfo parameterInfo = new ParameterInfoNotifyLink(authorizationState.link);
clientInteraction.onParameterRequest(InputParameter.NOTIFY_LINK, parameterInfo);
clientInteraction.onParameterRequest(InputParameter.NOTIFY_LINK, parameterInfo, ignored -> {
});
}
}
}

View File

@ -29,13 +29,14 @@ final class AuthorizationStateWaitPasswordHandler implements GenericUpdateHandle
authorizationState.hasRecoveryEmailAddress,
authorizationState.recoveryEmailAddressPattern
);
String password = clientInteraction.onParameterRequest(InputParameter.ASK_PASSWORD, parameterInfo);
clientInteraction.onParameterRequest(InputParameter.ASK_PASSWORD, parameterInfo, password -> {
CheckAuthenticationPassword response = new CheckAuthenticationPassword(password);
client.send(response, ok -> {
if (ok.getConstructor() == TdApi.Error.CONSTRUCTOR) {
throw new TelegramError((TdApi.Error) ok);
}
}, exceptionHandler);
});
}
}
}

View File

@ -25,11 +25,10 @@ final class AuthorizationStateWaitRegistrationHandler implements GenericUpdateHa
public void onUpdate(UpdateAuthorizationState update) {
if (update.authorizationState.getConstructor() == AuthorizationStateWaitRegistration.CONSTRUCTOR) {
TdApi.AuthorizationStateWaitRegistration authorizationState = (TdApi.AuthorizationStateWaitRegistration) update.authorizationState;
clientInteraction.onParameterRequest(InputParameter.TERMS_OF_SERVICE,
new ParameterInfoTermsOfService(authorizationState.termsOfService)
);
String firstName = clientInteraction.onParameterRequest(InputParameter.ASK_FIRST_NAME, new EmptyParameterInfo());
String lastName = clientInteraction.onParameterRequest(InputParameter.ASK_LAST_NAME, new EmptyParameterInfo());
ParameterInfoTermsOfService tos = new ParameterInfoTermsOfService(authorizationState.termsOfService);
clientInteraction.onParameterRequest(InputParameter.TERMS_OF_SERVICE, tos, ignored -> {
clientInteraction.onParameterRequest(InputParameter.ASK_FIRST_NAME, new EmptyParameterInfo(), firstName -> {
clientInteraction.onParameterRequest(InputParameter.ASK_LAST_NAME, new EmptyParameterInfo(), lastName -> {
if (firstName == null || firstName.isEmpty()) {
exceptionHandler.onException(new IllegalArgumentException("First name must not be null or empty"));
return;
@ -52,6 +51,9 @@ final class AuthorizationStateWaitRegistrationHandler implements GenericUpdateHa
throw new TelegramError((TdApi.Error) ok);
}
}, exceptionHandler);
});
});
});
}
}
}

View File

@ -1,6 +1,8 @@
package it.tdlight.client;
import java.util.function.Consumer;
public interface ClientInteraction {
String onParameterRequest(InputParameter parameter, ParameterInfo parameterInfo);
void onParameterRequest(InputParameter parameter, ParameterInfo parameterInfo, Consumer<String> result);
}

View File

@ -55,11 +55,6 @@ public final class ConsoleInteractiveAuthenticationData implements Authenticatio
return botToken;
}
public ConsoleInteractiveAuthenticationData askAuthData() {
initializeIfNeeded();
return this;
}
private void initializeIfNeeded() {
if (initialized) {
return;

View File

@ -2,18 +2,23 @@ package it.tdlight.client;
import it.tdlight.common.utils.ScannerUtils;
import it.tdlight.jni.TdApi.TermsOfService;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
final class ScannerClientInteraction implements ClientInteraction {
private final ExecutorService blockingExecutor;
private final Authenticable authenticable;
public ScannerClientInteraction(Authenticable authenticable) {
public ScannerClientInteraction(ExecutorService blockingExecutor, Authenticable authenticable) {
this.blockingExecutor = blockingExecutor;
this.authenticable = authenticable;
}
@Override
public String onParameterRequest(InputParameter parameter, ParameterInfo parameterInfo) {
AuthenticationData authenticationData = authenticable.getAuthenticationData();
public void onParameterRequest(InputParameter parameter, ParameterInfo parameterInfo, Consumer<String> resultCons) {
authenticable.getAuthenticationData(authenticationData -> {
blockingExecutor.execute(() -> {
String who;
boolean useRealWho;
if (authenticationData instanceof ConsoleInteractiveAuthenticationData) {
@ -46,8 +51,8 @@ final class ScannerClientInteraction implements ClientInteraction {
ParameterInfoCode codeInfo = ((ParameterInfoCode) parameterInfo);
question += "\n\tPhone number: " + codeInfo.getPhoneNumber();
question += "\n\tTimeout: " + codeInfo.getTimeout() + " seconds";
question +=
"\n\tCode type: " + codeInfo.getType().getClass().getSimpleName().replace("AuthenticationCodeType", "");
question += "\n\tCode type: " + codeInfo.getType().getClass().getSimpleName()
.replace("AuthenticationCodeType", "");
if (codeInfo.getNextType() != null) {
question += "\n\tNext code type: " + codeInfo
.getNextType()
@ -64,9 +69,11 @@ final class ScannerClientInteraction implements ClientInteraction {
if (hint != null && !hint.isEmpty()) {
passwordMessage += "\n\tHint: " + hint;
}
boolean hasRecoveryEmailAddress = ((ParameterInfoPasswordHint) parameterInfo).hasRecoveryEmailAddress();
boolean hasRecoveryEmailAddress = ((ParameterInfoPasswordHint) parameterInfo)
.hasRecoveryEmailAddress();
passwordMessage += "\n\tHas recovery email: " + hasRecoveryEmailAddress;
String recoveryEmailAddressPattern = ((ParameterInfoPasswordHint) parameterInfo).getRecoveryEmailAddressPattern();
String recoveryEmailAddressPattern = ((ParameterInfoPasswordHint) parameterInfo)
.getRecoveryEmailAddressPattern();
if (recoveryEmailAddressPattern != null && !recoveryEmailAddressPattern.isEmpty()) {
passwordMessage += "\n\tRecovery email address pattern: " + recoveryEmailAddressPattern;
}
@ -78,7 +85,7 @@ final class ScannerClientInteraction implements ClientInteraction {
System.out.println();
System.out.println(QrCodeTerminal.getQr(link));
System.out.println();
return "";
resultCons.accept("");
case TERMS_OF_SERVICE:
TermsOfService tos = ((ParameterInfoTermsOfService) parameterInfo).getTermsOfService();
question = "Terms of service:\n\t" + tos.text.text;
@ -90,7 +97,7 @@ final class ScannerClientInteraction implements ClientInteraction {
trim = true;
} else {
System.out.println(question);
return "";
resultCons.accept("");
}
break;
default:
@ -99,9 +106,11 @@ final class ScannerClientInteraction implements ClientInteraction {
}
String result = ScannerUtils.askParameter(who, question);
if (trim) {
return result.trim();
resultCons.accept(result.trim());
} else {
return result;
resultCons.accept(result);
}
});
});
}
}

View File

@ -19,7 +19,13 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -27,6 +33,7 @@ import org.slf4j.LoggerFactory;
public final class SimpleTelegramClient implements Authenticable {
public static final Logger LOG = LoggerFactory.getLogger(SimpleTelegramClient.class);
public static ExecutorService blockingExecutor = Executors.newSingleThreadExecutor();
static {
try {
@ -37,7 +44,7 @@ public final class SimpleTelegramClient implements Authenticable {
}
private final TelegramClient client;
private ClientInteraction clientInteraction = new ScannerClientInteraction(this);
private ClientInteraction clientInteraction = new ScannerClientInteraction(blockingExecutor, this);
private final TDLibSettings settings;
private AuthenticationData authenticationData;
@ -65,22 +72,22 @@ public final class SimpleTelegramClient implements Authenticable {
);
this.addUpdateHandler(TdApi.UpdateAuthorizationState.class,
new AuthorizationStateWaitRegistrationHandler(client,
new SimpleTelegramClientInteraction(),
new SimpleTelegramClientInteraction(blockingExecutor),
this::handleDefaultException
)
);
this.addUpdateHandler(TdApi.UpdateAuthorizationState.class,
new AuthorizationStateWaitPasswordHandler(client,
new SimpleTelegramClientInteraction(),
new SimpleTelegramClientInteraction(blockingExecutor),
this::handleDefaultException
)
);
this.addUpdateHandler(TdApi.UpdateAuthorizationState.class,
new AuthorizationStateWaitOtherDeviceConfirmationHandler(new SimpleTelegramClientInteraction())
new AuthorizationStateWaitOtherDeviceConfirmationHandler(new SimpleTelegramClientInteraction(blockingExecutor))
);
this.addUpdateHandler(TdApi.UpdateAuthorizationState.class,
new AuthorizationStateWaitCodeHandler(client,
new SimpleTelegramClientInteraction(),
new SimpleTelegramClientInteraction(blockingExecutor),
this::handleDefaultException
)
);
@ -128,8 +135,22 @@ public final class SimpleTelegramClient implements Authenticable {
}
@Override
public AuthenticationData getAuthenticationData() {
return authenticationData;
public void getAuthenticationData(Consumer<AuthenticationData> result) {
if (authenticationData instanceof ConsoleInteractiveAuthenticationData) {
ConsoleInteractiveAuthenticationData consoleInteractiveAuthenticationData
= (ConsoleInteractiveAuthenticationData) authenticationData;
try {
blockingExecutor.execute(() -> {
consoleInteractiveAuthenticationData.askData();
result.accept(consoleInteractiveAuthenticationData);
});
} catch (RejectedExecutionException | NullPointerException ex) {
LOG.error("Failed to execute askData. Returning an empty string", ex);
result.accept(consoleInteractiveAuthenticationData);
}
} else {
result.accept(authenticationData);
}
}
public void setClientInteraction(ClientInteraction clientInteraction) {
@ -259,9 +280,20 @@ public final class SimpleTelegramClient implements Authenticable {
private final class SimpleTelegramClientInteraction implements ClientInteraction {
private final ExecutorService blockingExecutor;
public SimpleTelegramClientInteraction(ExecutorService blockingExecutor) {
this.blockingExecutor = blockingExecutor;
}
@Override
public String onParameterRequest(InputParameter parameter, ParameterInfo parameterInfo) {
return clientInteraction.onParameterRequest(parameter, parameterInfo);
public void onParameterRequest(InputParameter parameter, ParameterInfo parameterInfo, Consumer<String> result) {
try {
blockingExecutor.execute(() -> clientInteraction.onParameterRequest(parameter, parameterInfo, result));
} catch (RejectedExecutionException | NullPointerException ex) {
LOG.error("Failed to execute onParameterRequest. Returning an empty string", ex);
result.accept("");
}
}
}
}