diff --git a/README.md b/README.md
index 9506a43..67ba9cb 100644
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@
## 💻 Supported platforms
-**Java versions**: from Java 17 to Java 19+ (Legacy Java 8+ support with `tdlight-java-8`)
+**Java versions**: from Java 17 to Java 19+ (Java 8 is supported if you use the following dependency classifier: `jdk8`)
**Operating systems**: Linux, Windows, MacOS
@@ -84,7 +84,7 @@ If you are using Maven, edit your `pom.xml` file as below:
it.tdlight
- tdlight-java
+ tdlight-java
@@ -114,7 +114,7 @@ dependencies {
implementation platform('it.tdlight:tdlight-java-bom:VERSION')
// do not specify the versions on the dependencies below!
- implementation 'it.tdlight:tdlight-java' // Use tdlight-java-8 if you are using java 8 to 16
+ implementation 'it.tdlight:tdlight-java' // Java 8 is supported if you use the following dependency classifier: `jdk8`
implementation 'it.tdlight:tdlight-natives-linux-amd64'
// Include other native versions that you want, for example for windows, osx, ...
}
diff --git a/bom/pom.xml b/bom/pom.xml
index 057c36c..c5ff9cb 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -7,7 +7,7 @@
pom
TDLight Java BOM
- 1.1.0.0-SNAPSHOT
+ 3.0.0.0-SNAPSHOT
307
305
@@ -81,8 +81,9 @@
it.tdlight
- tdlight-java-8
+ tdlight-java
${revision}
+ jdk8
it.tdlight
@@ -137,7 +138,7 @@
- ../parent
+ ../
diff --git a/example/pom.xml b/example/pom.xml
index 8037185..ed0e4ab 100644
--- a/example/pom.xml
+++ b/example/pom.xml
@@ -3,7 +3,7 @@
4.0.0
it.tdlight
example-java
- 1.1.0.0-SNAPSHOT
+ 3.0.0.0-SNAPSHOT
TDLight Java Example
jar
@@ -26,7 +26,7 @@
it.tdlight
tdlight-java-bom
- 2.8.10.4
+ 3.0.0.0-SNAPSHOT
pom
import
@@ -36,7 +36,8 @@
it.tdlight
- tdlight-java
+ tdlight-java
+ jdk8
diff --git a/example/src/main/java/it/tdlight/example/AdvancedExample.java b/example/src/main/java/it/tdlight/example/AdvancedExample.java
index 94bcf26..393f788 100644
--- a/example/src/main/java/it/tdlight/example/AdvancedExample.java
+++ b/example/src/main/java/it/tdlight/example/AdvancedExample.java
@@ -1,10 +1,10 @@
package it.tdlight.example;
-import it.tdlight.common.Init;
-import it.tdlight.common.TelegramClient;
-import it.tdlight.common.utils.CantLoadLibrary;
+import it.tdlight.Init;
+import it.tdlight.TelegramClient;
+import it.tdlight.utils.CantLoadLibrary;
import it.tdlight.jni.TdApi;
-import it.tdlight.tdlight.ClientManager;
+import it.tdlight.ClientFactory;
/**
* This is an advanced example that uses directly the native client without using the SimpleClient implementation
@@ -15,8 +15,11 @@ public class AdvancedExample {
// Initialize TDLight native libraries
Init.start();
- // Create a client
- TelegramClient client = ClientManager.create();
+ // Create a client manager, it should be closed before shutdown
+ ClientFactory clientManager = new ClientFactory();
+
+ // Create a client, it should be closed before shutdown
+ TelegramClient client = clientManager.createClient();
// Initialize the client
client.initialize(AdvancedExample::onUpdate, AdvancedExample::onUpdateError, AdvancedExample::onError);
diff --git a/example/src/main/java/it/tdlight/example/Example.java b/example/src/main/java/it/tdlight/example/Example.java
index 029b941..c2a7a1d 100644
--- a/example/src/main/java/it/tdlight/example/Example.java
+++ b/example/src/main/java/it/tdlight/example/Example.java
@@ -1,14 +1,17 @@
package it.tdlight.example;
import it.tdlight.client.*;
-import it.tdlight.client.AuthenticationData;
+import it.tdlight.client.AuthenticationSupplier;
import it.tdlight.client.CommandHandler;
import it.tdlight.client.SimpleTelegramClient;
import it.tdlight.client.TDLibSettings;
-import it.tdlight.common.Init;
-import it.tdlight.common.Log;
-import it.tdlight.common.utils.CantLoadLibrary;
+import it.tdlight.Init;
+import it.tdlight.jni.TdApi.AuthorizationState;
+import it.tdlight.jni.TdApi.Chat;
+import it.tdlight.jni.TdApi.MessageContent;
+import it.tdlight.utils.CantLoadLibrary;
import it.tdlight.jni.TdApi;
+import java.nio.file.Path;
import java.nio.file.Paths;
/**
@@ -29,37 +32,45 @@ public final class Example {
// Initialize TDLight native libraries
Init.start();
- // Obtain the API token
- var apiToken = APIToken.example();
+ // Create the client factory
+ try (SimpleTelegramClientFactory clientFactory = new SimpleTelegramClientFactory()) {
- // Configure the client
- var settings = TDLibSettings.create(apiToken);
+ // Obtain the API token
+ //
+ // var apiToken = new APIToken(your-api-id-here, "your-api-hash-here");
+ //
+ APIToken apiToken = APIToken.example();
- // Configure the session directory
- var sessionPath = Paths.get("example-tdlight-session");
- settings.setDatabaseDirectoryPath(sessionPath.resolve("data"));
- settings.setDownloadedFilesDirectoryPath(sessionPath.resolve("downloads"));
- // Create a client
- client = new SimpleTelegramClient(settings);
+ // Configure the client
+ TDLibSettings settings = TDLibSettings.create(apiToken);
- // Configure the authentication info
- var authenticationData = AuthenticationData.consoleLogin();
+ // Configure the session directory
+ Path sessionPath = Paths.get("example-tdlight-session");
+ settings.setDatabaseDirectoryPath(sessionPath.resolve("data"));
+ settings.setDownloadedFilesDirectoryPath(sessionPath.resolve("downloads"));
- // Add an example update handler that prints when the bot is started
- client.addUpdateHandler(TdApi.UpdateAuthorizationState.class, Example::onUpdateAuthorizationState);
+ // Prepare a new client builder
+ SimpleTelegramClientBuilder clientBuilder = clientFactory.builder(settings);
- // Add an example update handler that prints every received message
- client.addUpdateHandler(TdApi.UpdateNewMessage.class, Example::onUpdateNewMessage);
+ // Configure the authentication info
+ ConsoleInteractiveAuthenticationData authenticationData = AuthenticationSupplier.consoleLogin();
- // Add an example command handler that stops the bot
- client.addCommandHandler("stop", new StopCommandHandler());
+ // Add an example update handler that prints when the bot is started
+ clientBuilder.addUpdateHandler(TdApi.UpdateAuthorizationState.class, Example::onUpdateAuthorizationState);
- // Start the client
- client.start(authenticationData);
+ // Add an example update handler that prints every received message
+ clientBuilder.addUpdateHandler(TdApi.UpdateNewMessage.class, Example::onUpdateNewMessage);
- // Wait for exit
- client.waitForExit();
+ // Add an example command handler that stops the bot
+ clientBuilder.addCommandHandler("stop", new StopCommandHandler());
+
+ // Create and start the client
+ client = clientBuilder.build(authenticationData);
+
+ // Wait for exit
+ client.waitForExit();
+ }
}
/**
@@ -67,7 +78,7 @@ public final class Example {
*/
private static void onUpdateNewMessage(TdApi.UpdateNewMessage update) {
// Get the message content
- var messageContent = update.message.content;
+ MessageContent messageContent = update.message.content;
// Get the message text
String text;
@@ -82,9 +93,9 @@ public final class Example {
// Get the chat title
client.send(new TdApi.GetChat(update.message.chatId), chatIdResult -> {
// Get the chat response
- var chat = chatIdResult.get();
+ Chat chat = chatIdResult.get();
// Get the chat name
- var chatName = chat.title;
+ String chatName = chat.title;
// Print the message
System.out.printf("Received new message from chat %s: %s%n", chatName, text);
@@ -111,7 +122,7 @@ public final class Example {
* Print the bot status
*/
private static void onUpdateAuthorizationState(TdApi.UpdateAuthorizationState update) {
- var authorizationState = update.authorizationState;
+ AuthorizationState authorizationState = update.authorizationState;
if (authorizationState instanceof TdApi.AuthorizationStateReady) {
System.out.println("Logged in");
} else if (authorizationState instanceof TdApi.AuthorizationStateClosing) {
diff --git a/parent/pom.xml b/pom.xml
similarity index 90%
rename from parent/pom.xml
rename to pom.xml
index 2e81787..f094c71 100644
--- a/parent/pom.xml
+++ b/pom.xml
@@ -8,10 +8,10 @@
it.tdlight
${revision}
tdlight-java-bom
- ../bom/pom.xml
+ bom/pom.xml
- 1.1.0.0-SNAPSHOT
+ 3.0.0.0-SNAPSHOT
3.5.0
1.0.4
2.0.5
@@ -19,8 +19,7 @@
8.5.11
- ../tdlight-java
- ../tdlight-java-8
+ tdlight-java
diff --git a/scripts/core/deploy_release.sh b/scripts/core/deploy_release.sh
index 4323e87..00bbd35 100755
--- a/scripts/core/deploy_release.sh
+++ b/scripts/core/deploy_release.sh
@@ -22,7 +22,7 @@ fi
cd "../../"
cd "bom"
-mvn -B -Drevision="${REVISION}${SSL_SUFFIX}" -DnativesSsl3Suffix="${SSL_SUFFIX}" clean deploy
+mvn -B -Drevision="${REVISION}${SSL_SUFFIX}" -DnativesSsl3Suffix="${SSL_SUFFIX}" -P "java8,java17" clean deploy
cd "../"
echo "Done."
diff --git a/scripts/core/deploy_snapshot.sh b/scripts/core/deploy_snapshot.sh
index 4a3d805..f829c87 100755
--- a/scripts/core/deploy_snapshot.sh
+++ b/scripts/core/deploy_snapshot.sh
@@ -4,7 +4,7 @@
cd "../../"
cd "bom"
-mvn -B clean deploy
+mvn -B -P "java8,java17" clean deploy
cd "../"
echo "Done."
diff --git a/src/main/java/it/tdlight/client/ClientInteraction.java b/src/main/java/it/tdlight/client/ClientInteraction.java
deleted file mode 100644
index 89d61fd..0000000
--- a/src/main/java/it/tdlight/client/ClientInteraction.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package it.tdlight.client;
-
-import java.util.function.Consumer;
-
-public interface ClientInteraction {
-
- void onParameterRequest(InputParameter parameter, ParameterInfo parameterInfo, Consumer result);
-}
diff --git a/src/main/java/it/tdlight/client/ConsoleInteractiveAuthenticationData.java b/src/main/java/it/tdlight/client/ConsoleInteractiveAuthenticationData.java
deleted file mode 100644
index 037a7b4..0000000
--- a/src/main/java/it/tdlight/client/ConsoleInteractiveAuthenticationData.java
+++ /dev/null
@@ -1,127 +0,0 @@
-package it.tdlight.client;
-
-import it.tdlight.common.utils.ScannerUtils;
-import java.util.Locale;
-
-public final class ConsoleInteractiveAuthenticationData implements AuthenticationData {
-
- private static final Object LOCK = new Object();
-
- private boolean initialized = false;
- private boolean isQr;
- private boolean isBot;
- private String botToken;
- private String phoneNumber;
-
- ConsoleInteractiveAuthenticationData() {
-
- }
-
- public void askData() {
- initializeIfNeeded();
- }
-
- public boolean isInitialized() {
- return initialized;
- }
-
- @Override
- public boolean isQrCode() {
- initializeIfNeeded();
- return isQr;
- }
-
- @Override
- public boolean isBot() {
- initializeIfNeeded();
- return isBot;
- }
-
- @Override
- public String getUserPhoneNumber() {
- initializeIfNeeded();
- if (isBot || isQr) {
- throw new UnsupportedOperationException("This is not a user");
- }
- return phoneNumber;
- }
-
- @Override
- public String getBotToken() {
- initializeIfNeeded();
- if (!isBot || isQr) {
- 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
- String mode;
- do {
- String response = ScannerUtils.askParameter("login",
- "Do you want to login using a bot [token], a [phone] number, or a [qr] code? [token/phone/qr]");
- if (response != null) {
- choice = response.trim().toLowerCase(Locale.ROOT);
- switch (choice) {
- case "phone":
- mode = "PHONE";
- break;
- case "token":
- mode = "TOKEN";
- break;
- case "qr":
- mode = "QR";
- break;
- default:
- mode = null;
- break;
- }
- } else {
- mode = null;
- }
- } while (mode == null);
-
- if ("TOKEN".equals(mode)) {
- String token;
- do {
- token = ScannerUtils.askParameter("login", "Please type the bot token");
- } while (token.length() < 5 || !token.contains(":"));
-
- this.isBot = true;
- this.phoneNumber = null;
- this.botToken = token;
- this.isQr = false;
- } else if ("PHONE".equals(mode)) {
- String phoneNumber;
- do {
- phoneNumber = ScannerUtils.askParameter("login", "Please type your phone number");
- } while (phoneNumber.length() < 3);
-
- this.isBot = false;
- this.phoneNumber = phoneNumber;
- this.botToken = null;
- this.isQr = false;
- } else {
-
- this.isBot = false;
- this.phoneNumber = null;
- this.botToken = null;
- this.isQr = true;
- }
-
- initialized = true;
- }
- }
-}
diff --git a/src/main/java/it/tdlight/client/ScannerClientInteraction.java b/src/main/java/it/tdlight/client/ScannerClientInteraction.java
deleted file mode 100644
index cbfdf97..0000000
--- a/src/main/java/it/tdlight/client/ScannerClientInteraction.java
+++ /dev/null
@@ -1,127 +0,0 @@
-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;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-final class ScannerClientInteraction implements ClientInteraction {
-
- private static final Logger LOG = LoggerFactory.getLogger(ScannerClientInteraction.class);
-
- private final ExecutorService blockingExecutor;
- private final Authenticable authenticable;
-
- public ScannerClientInteraction(ExecutorService blockingExecutor, Authenticable authenticable) {
- this.blockingExecutor = blockingExecutor;
- this.authenticable = authenticable;
- }
-
- @Override
- public void onParameterRequest(InputParameter parameter, ParameterInfo parameterInfo, Consumer resultCons) {
- authenticable.getAuthenticationData(authenticationData -> {
- blockingExecutor.execute(() -> {
- String who;
- boolean useRealWho;
- if (authenticationData instanceof ConsoleInteractiveAuthenticationData) {
- useRealWho = ((ConsoleInteractiveAuthenticationData) authenticationData).isInitialized();
- } else {
- useRealWho = true;
- }
- if (!useRealWho) {
- who = "login";
- } else if (authenticationData.isQrCode()) {
- who = "QR login";
- } else if (authenticationData.isBot()) {
- who = authenticationData.getBotToken().split(":", 2)[0];
- } else {
- who = "+" + authenticationData.getUserPhoneNumber();
- }
- String question;
- boolean trim = false;
- switch (parameter) {
- case ASK_FIRST_NAME:
- question = "Enter first name";
- trim = true;
- break;
- case ASK_LAST_NAME:
- question = "Enter last name";
- trim = true;
- break;
- case ASK_CODE:
- question = "Enter authentication code";
- 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", "");
- if (codeInfo.getNextType() != null) {
- question += "\n\tNext code type: " + codeInfo
- .getNextType()
- .getClass()
- .getSimpleName()
- .replace("AuthenticationCodeType", "");
- }
- trim = true;
- break;
- case ASK_PASSWORD:
- question = "Enter your password";
- String passwordMessage = "Password authorization:";
- String hint = ((ParameterInfoPasswordHint) parameterInfo).getHint();
- if (hint != null && !hint.isEmpty()) {
- passwordMessage += "\n\tHint: " + hint;
- }
- boolean hasRecoveryEmailAddress = ((ParameterInfoPasswordHint) parameterInfo)
- .hasRecoveryEmailAddress();
- passwordMessage += "\n\tHas recovery email: " + hasRecoveryEmailAddress;
- String recoveryEmailAddressPattern = ((ParameterInfoPasswordHint) parameterInfo)
- .getRecoveryEmailAddressPattern();
- if (recoveryEmailAddressPattern != null && !recoveryEmailAddressPattern.isEmpty()) {
- passwordMessage += "\n\tRecovery email address pattern: " + recoveryEmailAddressPattern;
- }
- System.out.println(passwordMessage);
- break;
- case NOTIFY_LINK:
- String link = ((ParameterInfoNotifyLink) parameterInfo).getLink();
- System.out.println("Please confirm this login link on another device: " + link);
- System.out.println();
- try {
- System.out.println(QrCodeTerminal.getQr(link));
- System.out.println();
- } catch (NoClassDefFoundError ex) {
- LOG.warn("QR code library is missing!"
- + " Please add the following dependency to your project: com.google.zxing:core");
- }
- resultCons.accept("");
- return;
- case TERMS_OF_SERVICE:
- TermsOfService tos = ((ParameterInfoTermsOfService) parameterInfo).getTermsOfService();
- question = "Terms of service:\n\t" + tos.text.text;
- if (tos.minUserAge > 0) {
- question += "\n\tMinimum user age: " + tos.minUserAge;
- }
- if (tos.showPopup) {
- question += "\nPlease press enter.";
- trim = true;
- } else {
- System.out.println(question);
- resultCons.accept("");
- return;
- }
- break;
- default:
- question = parameter.toString();
- break;
- }
- String result = ScannerUtils.askParameter(who, question);
- if (trim) {
- resultCons.accept(result.trim());
- } else {
- resultCons.accept(result);
- }
- });
- });
- }
-}
diff --git a/src/main/java/it/tdlight/common/NativeClientAccess.java b/src/main/java/it/tdlight/common/NativeClientAccess.java
deleted file mode 100644
index 4b60e0c..0000000
--- a/src/main/java/it/tdlight/common/NativeClientAccess.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package it.tdlight.common;
-
-import it.tdlight.jni.TdApi;
-import it.tdlight.jni.TdApi.Function;
-import it.tdlight.tdnative.NativeClient;
-
-final class NativeClientAccess extends NativeClient {
-
- public static TdApi.Object execute(Function function) {
- return nativeClientExecute(function);
- }
-
- public static void setLogMessageHandler(int maxVerbosityLevel, LogMessageHandler logMessageHandler) {
- nativeClientSetLogMessageHandler(maxVerbosityLevel, logMessageHandler);
- }
-}
diff --git a/src/main/java/it/tdlight/common/internal/CommonClientManager.java b/src/main/java/it/tdlight/common/internal/CommonClientManager.java
deleted file mode 100644
index 0220bbf..0000000
--- a/src/main/java/it/tdlight/common/internal/CommonClientManager.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package it.tdlight.common.internal;
-
-import it.tdlight.common.ReactiveTelegramClient;
-import it.tdlight.common.TelegramClient;
-
-public abstract class CommonClientManager {
-
- private static InternalClientManager getClientManager(String implementationName) {
- // ClientManager is singleton
- return InternalClientManager.get(implementationName);
- }
-
- public synchronized static TelegramClient create(String implementationName) {
- InternalClient client = new InternalClient(getClientManager(implementationName));
- return create(client);
- }
-
- public synchronized static ReactiveTelegramClient createReactive(String implementationName) {
- InternalReactiveClient reactiveClient = new InternalReactiveClient(getClientManager(implementationName));
- return createReactive(reactiveClient);
- }
-
- private static TelegramClient create(InternalClient internalClient) {
- return internalClient;
- }
-
- private static ReactiveTelegramClient createReactive(InternalReactiveClient internalReactiveClient) {
- return internalReactiveClient;
- }
-}
diff --git a/src/main/java/it/tdlight/common/internal/InternalClientManager.java b/src/main/java/it/tdlight/common/internal/InternalClientManager.java
deleted file mode 100644
index 3182722..0000000
--- a/src/main/java/it/tdlight/common/internal/InternalClientManager.java
+++ /dev/null
@@ -1,161 +0,0 @@
-package it.tdlight.common.internal;
-
-import it.tdlight.common.ClientEventsHandler;
-import it.tdlight.common.Init;
-import it.tdlight.jni.TdApi;
-import it.tdlight.jni.TdApi.Object;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicReference;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public final class InternalClientManager implements AutoCloseable {
-
- private static final Logger logger = LoggerFactory.getLogger(InternalClientManager.class);
- private static final AtomicReference INSTANCE = new AtomicReference<>(null);
-
- private final AtomicBoolean startCalled = new AtomicBoolean();
- private final AtomicBoolean closeCalled = new AtomicBoolean();
-
- private final String implementationName;
- private final ResponseReceiver responseReceiver;
- private final ConcurrentHashMap registeredClientEventHandlers = new ConcurrentHashMap<>();
- private final AtomicLong currentQueryId = new AtomicLong();
-
- private InternalClientManager(String implementationName) {
- this.implementationName = implementationName;
- responseReceiver = new NativeResponseReceiver(this::handleClientEvents);
- }
-
- /**
- * @return true if started as a result of this call
- */
- public boolean startIfNeeded() {
- if (closeCalled.get()) {
- return false;
- }
- if (startCalled.compareAndSet(false, true)) {
- try {
- Init.start();
- } catch (Throwable ex) {
- ex.printStackTrace();
- System.exit(1);
- }
- responseReceiver.start();
- return true;
- } else {
- return false;
- }
- }
-
- public static InternalClientManager get(String implementationName) {
- return INSTANCE.updateAndGet(val -> {
- if (val == null) {
- return new InternalClientManager(implementationName);
- }
- return val;
- });
- }
-
- private void handleClientEvents(int clientId,
- boolean isClosed,
- long[] clientEventIds,
- TdApi.Object[] clientEvents,
- int arrayOffset,
- int arrayLength) {
- ClientEventsHandler handler = registeredClientEventHandlers.get(clientId);
-
- if (handler != null) {
- handler.handleEvents(isClosed, clientEventIds, clientEvents, arrayOffset, arrayLength);
- } else {
- java.util.List droppedEvents = getEffectivelyDroppedEvents(clientEventIds,
- clientEvents,
- arrayOffset,
- arrayLength
- );
-
- if (!droppedEvents.isEmpty()) {
- logger.error("Unknown client id \"{}\"! {} events have been dropped!", clientId, droppedEvents.size());
- for (DroppedEvent droppedEvent : droppedEvents) {
- logger.error("The following event, with id \"{}\", has been dropped: {}",
- droppedEvent.id,
- droppedEvent.event
- );
- }
- }
- }
-
- if (isClosed) {
- logger.trace("Removing Client {} from event handlers", clientId);
- registeredClientEventHandlers.remove(clientId);
- logger.trace("Removed Client {} from event handlers", clientId);
- }
- }
-
- /**
- * Get only events that have been dropped, ignoring synthetic errors related to the closure of a client
- */
- private List getEffectivelyDroppedEvents(long[] clientEventIds,
- TdApi.Object[] clientEvents,
- int arrayOffset,
- int arrayLength) {
- java.util.List droppedEvents = new ArrayList<>(arrayLength);
- for (int i = arrayOffset; i < arrayOffset + arrayLength; i++) {
- long id = clientEventIds[i];
- TdApi.Object event = clientEvents[i];
- boolean mustPrintError = true;
- if (event instanceof TdApi.Error) {
- TdApi.Error errorEvent = (TdApi.Error) event;
- if (Objects.equals("Request aborted", errorEvent.message)) {
- mustPrintError = false;
- }
- }
- if (mustPrintError) {
- droppedEvents.add(new DroppedEvent(id, event));
- }
- }
- return droppedEvents;
- }
-
- public void registerClient(int clientId, ClientEventsHandler internalClient) {
- this.startIfNeeded();
- boolean replaced = registeredClientEventHandlers.put(clientId, internalClient) != null;
- if (replaced) {
- throw new IllegalStateException("Client " + clientId + " already registered");
- }
- responseReceiver.registerClient(clientId);
- }
-
- public String getImplementationName() {
- return implementationName;
- }
-
- public long getNextQueryId() {
- return currentQueryId.updateAndGet(value -> (value >= Long.MAX_VALUE ? 0 : value) + 1);
- }
-
- @Override
- public void close() throws InterruptedException {
- if (startCalled.get()) {
- if (closeCalled.compareAndSet(false, true)) {
- responseReceiver.close();
- }
- }
- }
-
- private static final class DroppedEvent {
-
- private final long id;
- private final TdApi.Object event;
-
- private DroppedEvent(long id, Object event) {
- this.id = id;
- this.event = event;
- }
- }
-}
diff --git a/src/main/java/it/tdlight/tdlib/ClientManager.java b/src/main/java/it/tdlight/tdlib/ClientManager.java
deleted file mode 100644
index e882aa0..0000000
--- a/src/main/java/it/tdlight/tdlib/ClientManager.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package it.tdlight.tdlib;
-
-import it.tdlight.common.ReactiveTelegramClient;
-import it.tdlight.common.TelegramClient;
-import it.tdlight.common.internal.CommonClientManager;
-
-/**
- * Interface for interaction with TDLib.
- */
-public class ClientManager extends CommonClientManager {
-
- private static final String implementationName = "tdlib";
-
- public static TelegramClient create() {
- return CommonClientManager.create(implementationName);
- }
-
- public static ReactiveTelegramClient createReactive() {
- return CommonClientManager.createReactive(implementationName);
- }
-}
diff --git a/src/main/java/it/tdlight/tdlib/DummyClass.java b/src/main/java/it/tdlight/tdlib/DummyClass.java
deleted file mode 100644
index 141cdf6..0000000
--- a/src/main/java/it/tdlight/tdlib/DummyClass.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package it.tdlight.tdlib;
-
-/**
- * This class is used to avoid jigsaw errors about empty exports
- */
-@Deprecated
-public class DummyClass {}
diff --git a/src/main/java/it/tdlight/tdlight/ClientManager.java b/src/main/java/it/tdlight/tdlight/ClientManager.java
deleted file mode 100644
index 7485410..0000000
--- a/src/main/java/it/tdlight/tdlight/ClientManager.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package it.tdlight.tdlight;
-
-import it.tdlight.common.ReactiveTelegramClient;
-import it.tdlight.common.TelegramClient;
-import it.tdlight.common.internal.CommonClientManager;
-
-/**
- * Interface for interaction with TDLight.
- */
-public class ClientManager extends CommonClientManager {
-
- private static final String implementationName = "tdlight";
-
- public static TelegramClient create() {
- return CommonClientManager.create(implementationName);
- }
-
- public static ReactiveTelegramClient createReactive() {
- return CommonClientManager.createReactive(implementationName);
- }
-}
diff --git a/src/main/java/it/tdlight/tdlight/DummyClass.java b/src/main/java/it/tdlight/tdlight/DummyClass.java
deleted file mode 100644
index 22eff52..0000000
--- a/src/main/java/it/tdlight/tdlight/DummyClass.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package it.tdlight.tdlight;
-
-/**
- * This class is used to avoid jigsaw errors about empty exports
- */
-@Deprecated
-public class DummyClass {}
diff --git a/tdlight-java-8/.gitignore b/tdlight-java-8/.gitignore
deleted file mode 100644
index d3464a6..0000000
--- a/tdlight-java-8/.gitignore
+++ /dev/null
@@ -1,151 +0,0 @@
-# ---> Eclipse
-*.pydevproject
-.metadata
-.gradle
-bin/
-tmp/
-*.tmp
-*.bak
-*.swp
-*~.nib
-local.properties
-.settings/
-.loadpath
-
-# Eclipse Core
-.project
-
-# External tool builders
-.externalToolBuilders/
-
-# Locally stored "Eclipse launch configurations"
-*.launch
-
-# CDT-specific
-.cproject
-
-# JDT-specific (Eclipse Java Development Tools)
-.classpath
-
-# Java annotation processor (APT)
-.factorypath
-
-# PDT-specific
-.buildpath
-
-# sbteclipse plugin
-.target
-
-# TeXlipse plugin
-.texlipse
-
-# ---> Java
-*.class
-
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
-
-# Package Files #
-*.jar
-*.war
-*.ear
-
-# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
-hs_err_pid*
-
-# ---> Maven
-target/
-pom.xml.tag
-pom.xml.releaseBackup
-pom.xml.versionsBackup
-pom.xml.next
-release.properties
-dependency-reduced-pom.xml
-buildNumber.properties
-.mvn/timing.properties
-
-# Created by https://www.gitignore.io/api/intellij+all
-
-### Intellij+all ###
-# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
-# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
-
-# User-specific stuff
-.idea/**/workspace.xml
-.idea/**/tasks.xml
-.idea/**/usage.statistics.xml
-.idea/**/dictionaries
-.idea/**/shelf
-
-# Generated files
-.idea/**/contentModel.xml
-
-# Sensitive or high-churn files
-.idea/**/dataSources/
-.idea/**/dataSources.ids
-.idea/**/dataSources.local.xml
-.idea/**/sqlDataSources.xml
-.idea/**/dynamic.xml
-.idea/**/uiDesigner.xml
-.idea/**/dbnavigator.xml
-
-# Gradle
-.idea/**/gradle.xml
-.idea/**/libraries
-
-# Gradle and Maven with auto-import
-# When using Gradle or Maven with auto-import, you should exclude module files,
-# since they will be recreated, and may cause churn. Uncomment if using
-# auto-import.
-# .idea/modules.xml
-# .idea/*.iml
-# .idea/modules
-
-# CMake
-cmake-build-*/
-
-# Mongo Explorer plugin
-.idea/**/mongoSettings.xml
-
-# File-based project format
-*.iws
-
-# IntelliJ
-out/
-
-# mpeltonen/sbt-idea plugin
-.idea_modules/
-
-# JIRA plugin
-atlassian-ide-plugin.xml
-
-# Cursive Clojure plugin
-.idea/replstate.xml
-
-# Crashlytics plugin (for Android Studio and IntelliJ)
-com_crashlytics_export_strings.xml
-crashlytics.properties
-crashlytics-build.properties
-fabric.properties
-
-# Editor-based Rest Client
-.idea/httpRequests
-
-# Android studio 3.1+ serialized cache file
-.idea/caches/build_file_checksums.ser
-
-### Intellij+all Patch ###
-# Ignores the whole .idea folder and all .iml files
-# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
-
-.idea/
-
-# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
-
-*.iml
-modules.xml
-.idea/misc.xml
-*.ipr
-
-
-# End of https://www.gitignore.io/api/intellij+all
\ No newline at end of file
diff --git a/tdlight-java-8/pom.xml b/tdlight-java-8/pom.xml
deleted file mode 100644
index 1db4a1a..0000000
--- a/tdlight-java-8/pom.xml
+++ /dev/null
@@ -1,346 +0,0 @@
-
- 4.0.0
- tdlight-java-8
- TDLight Java Legacy Wrapper
- jar
-
- it.tdlight
- ${revision}
- tdlight-java-parent
- ../parent/pom.xml
-
-
- UTF-8
- 1.1.0.0-SNAPSHOT
-
-
-
-
- mchv-release
- MCHV Release Apache Maven Packages
- https://mvn.mchv.eu/repository/mchv
-
-
- mchv-snapshot
- MCHV Snapshot Apache Maven Packages
- https://mvn.mchv.eu/repository/mchv-snapshot
-
-
-
-
- mchv-release-distribution
- MCHV Release Apache Maven Packages Distribution
- https://mvn.mchv.eu/repository/mchv
-
-
- mchv-snapshot-distribution
- MCHV Snapshot Apache Maven Packages Distribution
- https://mvn.mchv.eu/repository/mchv-snapshot
-
-
-
- scm:git:https://git.ignuranza.net/tdlight-team/tdlight-java.git
- scm:git:https://git.ignuranza.net/tdlight-team/tdlight-java.git
- HEAD
-
-
-
- it.tdlight
- tdlight-api-legacy
-
-
- org.slf4j
- slf4j-api
- ${slf4j.api.version}
-
-
- org.reactivestreams
- reactive-streams
- ${reactive.streams.version}
-
-
- com.google.zxing
- core
- ${zxing.version}
- true
-
-
- org.junit.jupiter
- junit-jupiter-engine
- ${junit.jupiter.engine.version}
- test
-
-
- it.unimi.dsi
- fastutil-core
- ${fastutil.core.version}
- test
-
-
-
-
-
- it.tdlight
- tdlight-java-bom
- ${revision}
- pom
- import
-
-
-
-
-
- releaseDir
-
- target-release
-
-
-
- snapshotDir
-
- target-snapshot
-
-
-
-
- ../src/main/java
- ../src/test/java
-
-
- maven-clean-plugin
- 3.1.0
-
-
- maven-resources-plugin
- 3.0.2
-
-
- maven-source-plugin
- 3.2.1
-
-
- attach-sources
-
- jar
-
-
-
-
-
- maven-javadoc-plugin
- 3.4.1
-
-
- -html5
- public
- false
- true
- -Xdoclint:none
- -Xdoclint:none
-
-
-
- attach-javadocs
-
- jar
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-enforcer-plugin
- 3.0.0-M3
-
-
- enforce-jdk9
-
- enforce
-
-
-
-
- [1.9,)
- JDK 9+ is required for compilation
-
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.8.1
-
- UTF-8
-
- it/tdlight/tdlib/ClientManager.java
-
- 8
-
-
-
-
- default-compile
- none
-
-
- 9
-
-
-
-
- java-11-module-compile
-
- compile
-
-
- 11
-
- ../src/main/java11
-
- true
-
-
-
-
- java-9-module-compile
-
- compile
-
-
- 9
-
-
-
-
- java-8-compile
-
- compile
-
-
-
- 8
-
-
- it/tdlight/tdlib/ClientManager.java
- module-info.java
-
-
-
-
-
-
- org.codehaus.mojo
- flatten-maven-plugin
- 1.1.0
-
- true
- oss
-
-
-
- flatten
- process-resources
-
- flatten
-
-
-
- flatten.clean
- clean
-
- clean
-
-
-
-
-
- maven-jar-plugin
- 3.2.0
-
-
-
- true
-
-
-
-
-
- maven-install-plugin
- 3.0.0-M1
-
-
- maven-deploy-plugin
- 2.8.2
-
-
- org.codehaus.mojo
- templating-maven-plugin
- 1.0.0
-
-
- filtering-java-templates
-
- filter-sources
-
-
- ../src/main/java-templates-tdlight
-
-
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
- 3.0.0-M5
-
-
- org.junit.jupiter
- junit-jupiter-engine
- 5.9.0
-
-
-
-
-
-
-
-
- org.eclipse.m2e
- lifecycle-mapping
- 1.0.0
-
-
-
-
-
-
- org.codehaus.mojo
-
-
- flatten-maven-plugin
-
-
- [1.1.0,)
-
-
- flatten
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tdlight-java/pom.xml b/tdlight-java/pom.xml
index 14e46cb..ed255a2 100644
--- a/tdlight-java/pom.xml
+++ b/tdlight-java/pom.xml
@@ -8,11 +8,11 @@
it.tdlight
${revision}
tdlight-java-parent
- ../parent/pom.xml
+ ../pom.xml
UTF-8
- 1.1.0.0-SNAPSHOT
+ 3.0.0.0-SNAPSHOT
@@ -45,10 +45,6 @@
HEAD
-
- it.tdlight
- tdlight-api-sealed
-
org.slf4j
slf4j-api
@@ -77,6 +73,12 @@
${fastutil.core.version}
test
+
+ io.projectreactor.tools
+ blockhound
+ 1.0.7.RELEASE
+ provided
+
@@ -102,20 +104,109 @@
target-snapshot
+
+ java8
+
+ [,17)
+
+
+
+ it.tdlight
+ tdlight-api-legacy
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.2.0
+
+
+ jdk8
+ package
+
+ jar
+
+
+
+
+ true
+
+
+ jdk8
+
+ module-info.class
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+
+ jdk8
+ compile
+
+ compile
+
+
+
+ module-info.java
+
+
+
+
+
+
+
+
+
+ java17
+
+ [17,)
+
+
+
+ it.tdlight
+ tdlight-api-sealed
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.2.0
+
+
+
+ true
+
+
+
+
+
+
+
- ../src/main/java
- ../src/test/java
+ org.apache.maven.plugins
maven-clean-plugin
3.1.0
+ org.apache.maven.plugins
maven-resources-plugin
3.0.2
+ org.apache.maven.plugins
maven-source-plugin
3.2.1
@@ -128,6 +219,7 @@
+ org.apache.maven.plugins
maven-javadoc-plugin
3.4.1
@@ -177,9 +269,6 @@
3.8.1
UTF-8
-
- it/tdlight/tdlib/ClientManager.java
-
8
@@ -201,7 +290,7 @@
11
- ../src/main/java11
+ ${project.basedir}/src/main/java11
true
@@ -227,7 +316,6 @@
8
- it/tdlight/tdlib/ClientManager.java
module-info.java
@@ -260,21 +348,12 @@
- maven-jar-plugin
- 3.2.0
-
-
-
- true
-
-
-
-
-
+ org.apache.maven.plugins
maven-install-plugin
3.0.0-M1
+ org.apache.maven.plugins
maven-deploy-plugin
2.8.2
@@ -289,7 +368,7 @@
filter-sources
- ../src/main/java-templates-tdlight
+ ${project.basedir}/src/main/java-templates
diff --git a/src/main/java-templates/it/tdlight/common/utils/LibraryVersion.java b/tdlight-java/src/main/java-templates/it/tdlight/utils/LibraryVersion.java
similarity index 97%
rename from src/main/java-templates/it/tdlight/common/utils/LibraryVersion.java
rename to tdlight-java/src/main/java-templates/it/tdlight/utils/LibraryVersion.java
index b4e456a..e43a324 100644
--- a/src/main/java-templates/it/tdlight/common/utils/LibraryVersion.java
+++ b/tdlight-java/src/main/java-templates/it/tdlight/utils/LibraryVersion.java
@@ -1,4 +1,4 @@
-package it.tdlight.common.utils;
+package it.tdlight.utils;
public final class LibraryVersion {
diff --git a/src/main/java/it/tdlight/common/internal/ArrayUtil.java b/tdlight-java/src/main/java/it/tdlight/ArrayUtil.java
similarity index 96%
rename from src/main/java/it/tdlight/common/internal/ArrayUtil.java
rename to tdlight-java/src/main/java/it/tdlight/ArrayUtil.java
index fe4579c..8e35aa8 100644
--- a/src/main/java/it/tdlight/common/internal/ArrayUtil.java
+++ b/tdlight-java/src/main/java/it/tdlight/ArrayUtil.java
@@ -1,8 +1,8 @@
-package it.tdlight.common.internal;
+package it.tdlight;
-import it.tdlight.common.utils.IntSwapper;
+import it.tdlight.utils.IntSwapper;
-public class ArrayUtil {
+class ArrayUtil {
public interface IntComparator {
int compare(int k1, int k2);
diff --git a/src/main/java/it/tdlight/common/ClientEventsHandler.java b/tdlight-java/src/main/java/it/tdlight/ClientEventsHandler.java
similarity index 88%
rename from src/main/java/it/tdlight/common/ClientEventsHandler.java
rename to tdlight-java/src/main/java/it/tdlight/ClientEventsHandler.java
index 4c5b500..273a0b0 100644
--- a/src/main/java/it/tdlight/common/ClientEventsHandler.java
+++ b/tdlight-java/src/main/java/it/tdlight/ClientEventsHandler.java
@@ -1,4 +1,4 @@
-package it.tdlight.common;
+package it.tdlight;
import it.tdlight.jni.TdApi;
diff --git a/tdlight-java/src/main/java/it/tdlight/ClientFactory.java b/tdlight-java/src/main/java/it/tdlight/ClientFactory.java
new file mode 100644
index 0000000..bbe90bd
--- /dev/null
+++ b/tdlight-java/src/main/java/it/tdlight/ClientFactory.java
@@ -0,0 +1,175 @@
+package it.tdlight;
+
+import it.tdlight.jni.TdApi;
+import it.tdlight.jni.TdApi.Object;
+import it.tdlight.utils.CantLoadLibrary;
+import it.tdlight.utils.CleanSupport;
+import it.tdlight.utils.CleanSupport.CleanableSupport;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * TDLight client factory
+ */
+public class ClientFactory implements AutoCloseable {
+
+ private static final Logger logger = LoggerFactory.getLogger(ClientFactory.class);
+
+ private static volatile ClientFactory COMMON;
+
+ private final InternalClientsState state = new InternalClientsState() {
+ @Override
+ public void registerClient(int clientId, ClientEventsHandler internalClient) {
+ startIfNeeded();
+ super.registerClient(clientId, internalClient);
+ responseReceiver.registerClient(clientId);
+ }
+ };
+
+ private final ResponseReceiver responseReceiver = new NativeResponseReceiver(this::handleClientEvents);
+ private volatile CleanableSupport cleanable;
+
+ public static ClientFactory getCommonClientFactory() {
+ ClientFactory common = COMMON;
+ if (common == null) {
+ synchronized (ClientFactory.class) {
+ if (COMMON == null) {
+ COMMON = new ClientFactory() {
+ @Override
+ public void close() {
+ throw new UnsupportedOperationException("Common client factory can't be closed");
+ }
+ };
+ }
+ common = COMMON;
+ }
+ }
+ return common;
+ }
+
+ public ClientFactory() {
+ try {
+ Init.start();
+ } catch (CantLoadLibrary e) {
+ throw new RuntimeException("Can't load the client factory because TDLight can't be loaded", e);
+ }
+ }
+
+ public TelegramClient createClient() {
+ return new InternalClient(state);
+ }
+
+ public ReactiveTelegramClient createReactive() {
+ return new InternalReactiveClient(state);
+ }
+
+ public void startIfNeeded() {
+ if (state.shouldStartNow()) {
+ try {
+ Init.start();
+ responseReceiver.start();
+ this.cleanable = CleanSupport.register(responseReceiver, () -> {
+ try {
+ this.responseReceiver.close();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ });
+ state.setStarted();
+ } catch (Throwable ex) {
+ state.setStopped();
+ logger.error("Failed to start TDLight", ex);
+ }
+ }
+ }
+
+ private void handleClientEvents(int clientId,
+ boolean isClosed,
+ long[] clientEventIds,
+ TdApi.Object[] clientEvents,
+ int arrayOffset,
+ int arrayLength) {
+ ClientEventsHandler handler = state.getClientEventsHandler(clientId);
+
+ if (handler != null) {
+ handler.handleEvents(isClosed, clientEventIds, clientEvents, arrayOffset, arrayLength);
+ } else {
+ java.util.List droppedEvents = getEffectivelyDroppedEvents(clientEventIds,
+ clientEvents,
+ arrayOffset,
+ arrayLength
+ );
+
+ if (!droppedEvents.isEmpty()) {
+ logger.error("Unknown client id \"{}\"! {} events have been dropped!", clientId, droppedEvents.size());
+ for (DroppedEvent droppedEvent : droppedEvents) {
+ logger.error("The following event, with id \"{}\", has been dropped: {}",
+ droppedEvent.id,
+ droppedEvent.event
+ );
+ }
+ }
+ }
+
+ if (isClosed) {
+ logger.trace("Removing Client {} from event handlers", clientId);
+ state.removeClientEventHandlers(clientId);
+ logger.trace("Removed Client {} from event handlers", clientId);
+ }
+ }
+
+ /**
+ * Get only events that have been dropped, ignoring synthetic errors related to the closure of a client
+ */
+ private List getEffectivelyDroppedEvents(long[] clientEventIds,
+ TdApi.Object[] clientEvents,
+ int arrayOffset,
+ int arrayLength) {
+ java.util.List droppedEvents = new ArrayList<>(arrayLength);
+ for (int i = arrayOffset; i < arrayOffset + arrayLength; i++) {
+ long id = clientEventIds[i];
+ TdApi.Object event = clientEvents[i];
+ boolean mustPrintError = true;
+ if (event instanceof TdApi.Error) {
+ TdApi.Error errorEvent = (TdApi.Error) event;
+ if (Objects.equals("Request aborted", errorEvent.message)) {
+ mustPrintError = false;
+ }
+ }
+ if (mustPrintError) {
+ droppedEvents.add(new DroppedEvent(id, event));
+ }
+ }
+ return droppedEvents;
+ }
+
+ protected void closeInternal() {
+ if (state.shouldCloseNow()) {
+ try {
+ cleanable.clean();
+ } catch (Throwable e) {
+ logger.error("Failed to close", e);
+ }
+ this.state.setStopped();
+ }
+ }
+
+ @Override
+ public void close() {
+ this.closeInternal();
+ }
+
+ private static final class DroppedEvent {
+
+ private final long id;
+ private final TdApi.Object event;
+
+ private DroppedEvent(long id, Object event) {
+ this.id = id;
+ this.event = event;
+ }
+ }
+}
diff --git a/src/main/java/it/tdlight/common/ConstructorDetector.java b/tdlight-java/src/main/java/it/tdlight/ConstructorDetector.java
similarity index 99%
rename from src/main/java/it/tdlight/common/ConstructorDetector.java
rename to tdlight-java/src/main/java/it/tdlight/ConstructorDetector.java
index 03d4c73..719268e 100644
--- a/src/main/java/it/tdlight/common/ConstructorDetector.java
+++ b/tdlight-java/src/main/java/it/tdlight/ConstructorDetector.java
@@ -15,7 +15,7 @@
* along with JTdlib. If not, see .
*/
-package it.tdlight.common;
+package it.tdlight;
import it.tdlight.jni.TdApi;
import java.lang.reflect.Field;
diff --git a/src/main/java/it/tdlight/common/EventsHandler.java b/tdlight-java/src/main/java/it/tdlight/EventsHandler.java
similarity index 89%
rename from src/main/java/it/tdlight/common/EventsHandler.java
rename to tdlight-java/src/main/java/it/tdlight/EventsHandler.java
index 89b8645..f40ede3 100644
--- a/src/main/java/it/tdlight/common/EventsHandler.java
+++ b/tdlight-java/src/main/java/it/tdlight/EventsHandler.java
@@ -1,4 +1,4 @@
-package it.tdlight.common;
+package it.tdlight;
import it.tdlight.jni.TdApi;
diff --git a/src/main/java/it/tdlight/common/ExceptionHandler.java b/tdlight-java/src/main/java/it/tdlight/ExceptionHandler.java
similarity index 93%
rename from src/main/java/it/tdlight/common/ExceptionHandler.java
rename to tdlight-java/src/main/java/it/tdlight/ExceptionHandler.java
index bab189a..864f2f8 100644
--- a/src/main/java/it/tdlight/common/ExceptionHandler.java
+++ b/tdlight-java/src/main/java/it/tdlight/ExceptionHandler.java
@@ -1,4 +1,4 @@
-package it.tdlight.common;
+package it.tdlight;
/**
* Interface for handler of exceptions thrown while invoking ResultHandler. By default, all such exceptions are ignored.
diff --git a/src/main/java/it/tdlight/common/internal/Handler.java b/tdlight-java/src/main/java/it/tdlight/Handler.java
similarity index 72%
rename from src/main/java/it/tdlight/common/internal/Handler.java
rename to tdlight-java/src/main/java/it/tdlight/Handler.java
index 476a620..58e7aeb 100644
--- a/src/main/java/it/tdlight/common/internal/Handler.java
+++ b/tdlight-java/src/main/java/it/tdlight/Handler.java
@@ -1,10 +1,10 @@
-package it.tdlight.common.internal;
+package it.tdlight;
-import it.tdlight.common.ExceptionHandler;
-import it.tdlight.common.ResultHandler;
+import it.tdlight.ExceptionHandler;
+import it.tdlight.ResultHandler;
import it.tdlight.jni.TdApi;
-public final class Handler {
+final class Handler {
private final ResultHandler resultHandler;
private final ExceptionHandler exceptionHandler;
diff --git a/src/main/java/it/tdlight/common/Init.java b/tdlight-java/src/main/java/it/tdlight/Init.java
similarity index 88%
rename from src/main/java/it/tdlight/common/Init.java
rename to tdlight-java/src/main/java/it/tdlight/Init.java
index 8c2bfa9..b45e838 100644
--- a/src/main/java/it/tdlight/common/Init.java
+++ b/tdlight-java/src/main/java/it/tdlight/Init.java
@@ -15,17 +15,13 @@
* along with JTdlib. If not, see .
*/
-package it.tdlight.common;
+package it.tdlight;
-import it.tdlight.client.SimpleTelegramClient;
-import it.tdlight.common.utils.CantLoadLibrary;
-import it.tdlight.common.utils.LoadLibrary;
-import it.tdlight.jni.TdApi;
+import it.tdlight.utils.CantLoadLibrary;
+import it.tdlight.utils.LoadLibrary;
import it.tdlight.jni.TdApi.LogStreamEmpty;
import it.tdlight.jni.TdApi.SetLogStream;
import it.tdlight.jni.TdApi.SetLogVerbosityLevel;
-import it.tdlight.tdnative.NativeClient.LogMessageHandler;
-import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/it/tdlight/common/internal/InternalClient.java b/tdlight-java/src/main/java/it/tdlight/InternalClient.java
similarity index 89%
rename from src/main/java/it/tdlight/common/internal/InternalClient.java
rename to tdlight-java/src/main/java/it/tdlight/InternalClient.java
index f4f865c..8fc2011 100644
--- a/src/main/java/it/tdlight/common/internal/InternalClient.java
+++ b/tdlight-java/src/main/java/it/tdlight/InternalClient.java
@@ -1,10 +1,5 @@
-package it.tdlight.common.internal;
+package it.tdlight;
-import it.tdlight.common.ClientEventsHandler;
-import it.tdlight.common.ExceptionHandler;
-import it.tdlight.common.ResultHandler;
-import it.tdlight.common.TelegramClient;
-import it.tdlight.common.UpdatesHandler;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.Function;
import it.tdlight.jni.TdApi.Object;
@@ -18,7 +13,7 @@ import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
-public final class InternalClient implements ClientEventsHandler, TelegramClient {
+final class InternalClient implements ClientEventsHandler, TelegramClient {
private static final Marker TG_MARKER = MarkerFactory.getMarker("TG");
private static final Logger logger = LoggerFactory.getLogger(TelegramClient.class);
@@ -28,15 +23,15 @@ public final class InternalClient implements ClientEventsHandler, TelegramClient
private final Thread shutdownHook = new Thread(this::onJVMShutdown);
private volatile Integer clientId = null;
- private final InternalClientManager clientManager;
+ private final InternalClientsState clientManagerState;
private Handler updateHandler;
private MultiHandler updatesHandler;
private ExceptionHandler defaultExceptionHandler;
private final AtomicBoolean isClosed = new AtomicBoolean();
- public InternalClient(InternalClientManager clientManager) {
- this.clientManager = clientManager;
+ public InternalClient(InternalClientsState clientManagerState) {
+ this.clientManagerState = clientManagerState;
Runtime.getRuntime().addShutdownHook(shutdownHook);
}
@@ -153,11 +148,13 @@ public final class InternalClient implements ClientEventsHandler, TelegramClient
}
private void createAndRegisterClient() {
- if (clientId != null) {
- throw new UnsupportedOperationException("Can't initialize the same client twice!");
+ synchronized (this) {
+ if (clientId != null) {
+ throw new UnsupportedOperationException("Can't initialize the same client twice!");
+ }
+ clientId = NativeClientAccess.create();
}
- clientId = NativeClientAccess.create();
- clientManager.registerClient(clientId, this);
+ clientManagerState.registerClient(clientId, this);
logger.info(TG_MARKER, "Registered new client {}", clientId);
// Send a dummy request to start TDLib
@@ -178,7 +175,7 @@ public final class InternalClient implements ClientEventsHandler, TelegramClient
"Can't send a request to TDLib before calling \"initialize\" function!"));
return;
}
- long queryId = clientManager.getNextQueryId();
+ long queryId = clientManagerState.getNextQueryId();
if (resultHandler != null) {
handlers.put(queryId, new Handler<>(resultHandler, exceptionHandler));
}
diff --git a/tdlight-java/src/main/java/it/tdlight/InternalClientsState.java b/tdlight-java/src/main/java/it/tdlight/InternalClientsState.java
new file mode 100644
index 0000000..e413c06
--- /dev/null
+++ b/tdlight-java/src/main/java/it/tdlight/InternalClientsState.java
@@ -0,0 +1,63 @@
+package it.tdlight;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class InternalClientsState {
+ static final int STATE_INITIAL = 0;
+ static final int STATE_STARTING = 1;
+ static final int STATE_STARTED = 2;
+ static final int STATE_STOPPING = 3;
+ static final int STATE_STOPPED = 4;
+ private final AtomicInteger runState = new AtomicInteger();
+ private final AtomicLong currentQueryId = new AtomicLong();
+ private final ConcurrentHashMap registeredClientEventHandlers = new ConcurrentHashMap<>();
+
+
+ public long getNextQueryId() {
+ return currentQueryId.updateAndGet(value -> (value >= Long.MAX_VALUE ? 0 : value) + 1);
+ }
+
+ public void registerClient(int clientId, ClientEventsHandler internalClient) {
+ boolean replaced = registeredClientEventHandlers.put(clientId, internalClient) != null;
+ if (replaced) {
+ throw new IllegalStateException("Client " + clientId + " already registered");
+ }
+ }
+
+ public ClientEventsHandler getClientEventsHandler(int clientId) {
+ return registeredClientEventHandlers.get(clientId);
+ }
+
+ public boolean shouldStartNow() {
+ return runState.compareAndSet(STATE_INITIAL, STATE_STARTING);
+ }
+
+ public void setStopped() {
+ runState.set(STATE_STOPPED);
+ }
+
+ public void setStarted() {
+ if (!runState.compareAndSet(STATE_STARTING, STATE_STARTED)) {
+ throw new IllegalStateException();
+ }
+ }
+
+ public void removeClientEventHandlers(int clientId) {
+ registeredClientEventHandlers.remove(clientId);
+ }
+
+ public boolean shouldCloseNow() {
+ int prevS = runState.getAndUpdate(prev -> {
+ if (prev == STATE_INITIAL) {
+ return STATE_STOPPED;
+ } else if (prev == STATE_STARTED) {
+ return STATE_STOPPING;
+ } else {
+ return prev;
+ }
+ });
+ return prevS == STATE_STARTED;
+ }
+}
diff --git a/src/main/java/it/tdlight/common/internal/InternalReactiveClient.java b/tdlight-java/src/main/java/it/tdlight/InternalReactiveClient.java
similarity index 95%
rename from src/main/java/it/tdlight/common/internal/InternalReactiveClient.java
rename to tdlight-java/src/main/java/it/tdlight/InternalReactiveClient.java
index b353f7d..9430380 100644
--- a/src/main/java/it/tdlight/common/internal/InternalReactiveClient.java
+++ b/tdlight-java/src/main/java/it/tdlight/InternalReactiveClient.java
@@ -1,10 +1,5 @@
-package it.tdlight.common.internal;
+package it.tdlight;
-import it.tdlight.common.ClientEventsHandler;
-import it.tdlight.common.ExceptionHandler;
-import it.tdlight.common.ReactiveTelegramClient;
-import it.tdlight.common.Signal;
-import it.tdlight.common.SignalListener;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.Error;
import it.tdlight.jni.TdApi.Function;
@@ -26,7 +21,7 @@ import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
-public final class InternalReactiveClient implements ClientEventsHandler, ReactiveTelegramClient {
+final class InternalReactiveClient implements ClientEventsHandler, ReactiveTelegramClient {
private static final Marker TG_MARKER = MarkerFactory.getMarker("TG");
private static final Logger logger = LoggerFactory.getLogger(InternalReactiveClient.class);
@@ -41,15 +36,15 @@ public final class InternalReactiveClient implements ClientEventsHandler, Reacti
private final Thread shutdownHook = new Thread(this::onJVMShutdown);
private volatile Integer clientId = null;
- private final InternalClientManager clientManager;
+ private final InternalClientsState clientManagerState;
private final AtomicBoolean alreadyReceivedClosed = new AtomicBoolean();
// This field is not volatile, but it's not problematic, because ReplayStartupUpdatesListener is able to forward
// updates to the right listener
private SignalListener signalListener = new ReplayStartupUpdatesListener();
- public InternalReactiveClient(InternalClientManager clientManager) {
- this.clientManager = clientManager;
+ public InternalReactiveClient(InternalClientsState clientManagerState) {
+ this.clientManagerState = clientManagerState;
this.updateHandler = new Handler<>(this::onUpdateFromHandler, this::onUpdateException);
this.defaultExceptionHandler = this::onDefaultException;
try {
@@ -167,7 +162,7 @@ public final class InternalReactiveClient implements ClientEventsHandler, Reacti
logger.debug(TG_MARKER, "Creating new client");
clientId = NativeClientAccess.create();
logger.debug(TG_MARKER, "Registering new client {}", clientId);
- clientManager.registerClient(clientId, this);
+ clientManagerState.registerClient(clientId, this);
logger.debug(TG_MARKER, "Registered new client {}", clientId);
}
@@ -193,7 +188,7 @@ public final class InternalReactiveClient implements ClientEventsHandler, Reacti
subscriber.onError(new IllegalStateException(
"Can't send a request to TDLib before calling \"createAndRegisterClient\" function!"));
} else {
- long queryId = clientManager.getNextQueryId();
+ long queryId = clientManagerState.getNextQueryId();
// Handle timeout
ScheduledFuture> timeoutFuture = timers.schedule(() -> {
@@ -275,7 +270,7 @@ public final class InternalReactiveClient implements ClientEventsHandler, Reacti
this.signalListener = listener;
TdApi.GetAuthorizationState query = new TdApi.GetAuthorizationState();
- long queryId = clientManager.getNextQueryId();
+ long queryId = clientManagerState.getNextQueryId();
// Send a dummy request to effectively start the TDLib session
{
@@ -303,7 +298,7 @@ public final class InternalReactiveClient implements ClientEventsHandler, Reacti
private void sendCloseAndIgnoreResponse() {
if (!alreadyReceivedClosed.get()) {
TdApi.Close query = new TdApi.Close();
- long queryId = clientManager.getNextQueryId();
+ long queryId = clientManagerState.getNextQueryId();
handlers.put(queryId, EMPTY_HANDLER);
logger.trace(TG_MARKER, "Client {} is requesting with query id {}: {}", clientId, queryId, query);
diff --git a/src/main/java/it/tdlight/common/Log.java b/tdlight-java/src/main/java/it/tdlight/Log.java
similarity index 96%
rename from src/main/java/it/tdlight/common/Log.java
rename to tdlight-java/src/main/java/it/tdlight/Log.java
index 13c7f4a..9baee5f 100644
--- a/src/main/java/it/tdlight/common/Log.java
+++ b/tdlight-java/src/main/java/it/tdlight/Log.java
@@ -1,15 +1,12 @@
-package it.tdlight.common;
+package it.tdlight;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.LogStreamDefault;
import it.tdlight.jni.TdApi.LogStreamFile;
import it.tdlight.jni.TdApi.SetLogVerbosityLevel;
-import it.tdlight.tdnative.NativeClient;
import it.tdlight.tdnative.NativeClient.LogMessageHandler;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.Consumer;
/**
* Class used for managing internal TDLib logging. Use TdApi.*Log* methods instead.
diff --git a/src/main/java/it/tdlight/common/internal/MultiHandler.java b/tdlight-java/src/main/java/it/tdlight/MultiHandler.java
similarity index 73%
rename from src/main/java/it/tdlight/common/internal/MultiHandler.java
rename to tdlight-java/src/main/java/it/tdlight/MultiHandler.java
index 550925c..7c81c3d 100644
--- a/src/main/java/it/tdlight/common/internal/MultiHandler.java
+++ b/tdlight-java/src/main/java/it/tdlight/MultiHandler.java
@@ -1,9 +1,9 @@
-package it.tdlight.common.internal;
+package it.tdlight;
-import it.tdlight.common.ExceptionHandler;
-import it.tdlight.common.UpdatesHandler;
+import it.tdlight.ExceptionHandler;
+import it.tdlight.UpdatesHandler;
-public final class MultiHandler {
+final class MultiHandler {
private final UpdatesHandler updatesHandler;
private final ExceptionHandler exceptionHandler;
diff --git a/src/main/java/it/tdlight/common/internal/NativeClientAccess.java b/tdlight-java/src/main/java/it/tdlight/NativeClientAccess.java
similarity index 72%
rename from src/main/java/it/tdlight/common/internal/NativeClientAccess.java
rename to tdlight-java/src/main/java/it/tdlight/NativeClientAccess.java
index 3b2a5c9..a9dd297 100644
--- a/src/main/java/it/tdlight/common/internal/NativeClientAccess.java
+++ b/tdlight-java/src/main/java/it/tdlight/NativeClientAccess.java
@@ -1,4 +1,4 @@
-package it.tdlight.common.internal;
+package it.tdlight;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.Function;
@@ -6,7 +6,7 @@ import it.tdlight.tdnative.NativeClient;
final class NativeClientAccess extends NativeClient {
- public static int create() {
+ static int create() {
return NativeClientAccess.createNativeClient();
}
@@ -14,11 +14,11 @@ final class NativeClientAccess extends NativeClient {
return NativeClientAccess.nativeClientExecute(function);
}
- public static void send(int nativeClientId, long eventId, TdApi.Function function) {
+ static void send(int nativeClientId, long eventId, TdApi.Function function) {
NativeClientAccess.nativeClientSend(nativeClientId, eventId, function);
}
- public static int receive(int[] clientIds, long[] eventIds, TdApi.Object[] events, double timeout) {
+ static int receive(int[] clientIds, long[] eventIds, TdApi.Object[] events, double timeout) {
return NativeClientAccess.nativeClientReceive(clientIds, eventIds, events, timeout);
}
diff --git a/src/main/java/it/tdlight/common/internal/NativeResponseReceiver.java b/tdlight-java/src/main/java/it/tdlight/NativeResponseReceiver.java
similarity index 68%
rename from src/main/java/it/tdlight/common/internal/NativeResponseReceiver.java
rename to tdlight-java/src/main/java/it/tdlight/NativeResponseReceiver.java
index caa9d29..6a3c65b 100644
--- a/src/main/java/it/tdlight/common/internal/NativeResponseReceiver.java
+++ b/tdlight-java/src/main/java/it/tdlight/NativeResponseReceiver.java
@@ -1,9 +1,8 @@
-package it.tdlight.common.internal;
+package it.tdlight;
-import it.tdlight.common.EventsHandler;
import it.tdlight.jni.TdApi.Object;
-public class NativeResponseReceiver extends ResponseReceiver {
+class NativeResponseReceiver extends ResponseReceiver {
public NativeResponseReceiver(EventsHandler eventsHandler) {
super(eventsHandler);
diff --git a/src/main/java/it/tdlight/common/ReactiveTelegramClient.java b/tdlight-java/src/main/java/it/tdlight/ReactiveTelegramClient.java
similarity index 97%
rename from src/main/java/it/tdlight/common/ReactiveTelegramClient.java
rename to tdlight-java/src/main/java/it/tdlight/ReactiveTelegramClient.java
index 260f125..d4df222 100644
--- a/src/main/java/it/tdlight/common/ReactiveTelegramClient.java
+++ b/tdlight-java/src/main/java/it/tdlight/ReactiveTelegramClient.java
@@ -1,4 +1,4 @@
-package it.tdlight.common;
+package it.tdlight;
import it.tdlight.jni.TdApi;
import java.time.Duration;
diff --git a/src/main/java/it/tdlight/common/Response.java b/tdlight-java/src/main/java/it/tdlight/Response.java
similarity index 98%
rename from src/main/java/it/tdlight/common/Response.java
rename to tdlight-java/src/main/java/it/tdlight/Response.java
index 797be73..702799e 100644
--- a/src/main/java/it/tdlight/common/Response.java
+++ b/tdlight-java/src/main/java/it/tdlight/Response.java
@@ -15,7 +15,7 @@
* along with JTdlib. If not, see .
*/
-package it.tdlight.common;
+package it.tdlight;
import it.tdlight.jni.TdApi;
import java.util.Objects;
diff --git a/src/main/java/it/tdlight/common/internal/ResponseReceiver.java b/tdlight-java/src/main/java/it/tdlight/ResponseReceiver.java
similarity index 89%
rename from src/main/java/it/tdlight/common/internal/ResponseReceiver.java
rename to tdlight-java/src/main/java/it/tdlight/ResponseReceiver.java
index 780c0b3..49b6e31 100644
--- a/src/main/java/it/tdlight/common/internal/ResponseReceiver.java
+++ b/tdlight-java/src/main/java/it/tdlight/ResponseReceiver.java
@@ -1,11 +1,10 @@
-package it.tdlight.common.internal;
+package it.tdlight;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
-import it.tdlight.common.EventsHandler;
-import it.tdlight.common.utils.IntSwapper;
-import it.tdlight.common.utils.SpinWaitSupport;
+import it.tdlight.utils.IntSwapper;
+import it.tdlight.utils.SpinWaitSupport;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.UpdateAuthorizationState;
import java.util.ArrayList;
@@ -33,9 +32,6 @@ abstract class ResponseReceiver extends Thread implements AutoCloseable {
}
}
- private final AtomicBoolean startCalled = new AtomicBoolean();
- private final AtomicBoolean closeCalled = new AtomicBoolean();
-
private final EventsHandler eventsHandler;
private final int[] clientIds = new int[MAX_EVENTS];
private final long[] eventIds = new long[MAX_EVENTS];
@@ -64,24 +60,10 @@ abstract class ResponseReceiver extends Thread implements AutoCloseable {
@Override
public void run() {
- if (closeCalled.get()) {
- throw new IllegalStateException("Closed");
- }
- if (startCalled.compareAndSet(false, true)) {
- this.runInternal();
- } else {
- throw new IllegalStateException("Start already called");
- }
- }
-
- private void runInternal() {
int[] sortIndex;
try {
boolean interrupted;
- while (
- !(interrupted = Thread.interrupted())
- && (!closeCalled.get() || !registeredClients.isEmpty())
- ) {
+ while (!(interrupted = Thread.interrupted()) && !registeredClients.isEmpty()) {
// Timeout is expressed in seconds
int resultsCount = receive(clientIds, eventIds, events, 2.0);
@@ -221,7 +203,7 @@ abstract class ResponseReceiver extends Thread implements AutoCloseable {
}
}
- if (interrupted || closeCalled.get()) {
+ if (interrupted) {
for (Integer clientId : this.registeredClients) {
eventsHandler.handleClientEvents(clientId, true, clientEventIds, clientEvents, 0, 0);
}
@@ -274,13 +256,9 @@ abstract class ResponseReceiver extends Thread implements AutoCloseable {
@Override
public void close() throws InterruptedException {
- if (startCalled.get()) {
- if (closeCalled.compareAndSet(false, true)) {
- this.closeWait.await();
- if (registeredClients.isEmpty()) {
- this.interrupt();
- }
- }
+ this.closeWait.await();
+ if (registeredClients.isEmpty()) {
+ ResponseReceiver.this.interrupt();
}
}
}
diff --git a/src/main/java/it/tdlight/common/ResultHandler.java b/tdlight-java/src/main/java/it/tdlight/ResultHandler.java
similarity index 94%
rename from src/main/java/it/tdlight/common/ResultHandler.java
rename to tdlight-java/src/main/java/it/tdlight/ResultHandler.java
index 17b258a..6c8f0a8 100644
--- a/src/main/java/it/tdlight/common/ResultHandler.java
+++ b/tdlight-java/src/main/java/it/tdlight/ResultHandler.java
@@ -1,4 +1,4 @@
-package it.tdlight.common;
+package it.tdlight;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.Object;
diff --git a/src/main/java/it/tdlight/common/Signal.java b/tdlight-java/src/main/java/it/tdlight/Signal.java
similarity index 98%
rename from src/main/java/it/tdlight/common/Signal.java
rename to tdlight-java/src/main/java/it/tdlight/Signal.java
index 48780c8..cc697ea 100644
--- a/src/main/java/it/tdlight/common/Signal.java
+++ b/tdlight-java/src/main/java/it/tdlight/Signal.java
@@ -1,4 +1,4 @@
-package it.tdlight.common;
+package it.tdlight;
import it.tdlight.jni.TdApi;
import java.util.Objects;
diff --git a/src/main/java/it/tdlight/common/SignalListener.java b/tdlight-java/src/main/java/it/tdlight/SignalListener.java
similarity index 71%
rename from src/main/java/it/tdlight/common/SignalListener.java
rename to tdlight-java/src/main/java/it/tdlight/SignalListener.java
index 8f023de..7eaa816 100644
--- a/src/main/java/it/tdlight/common/SignalListener.java
+++ b/tdlight-java/src/main/java/it/tdlight/SignalListener.java
@@ -1,4 +1,4 @@
-package it.tdlight.common;
+package it.tdlight;
public interface SignalListener {
diff --git a/src/main/java/it/tdlight/common/SignalType.java b/tdlight-java/src/main/java/it/tdlight/SignalType.java
similarity index 66%
rename from src/main/java/it/tdlight/common/SignalType.java
rename to tdlight-java/src/main/java/it/tdlight/SignalType.java
index bead002..49776c2 100644
--- a/src/main/java/it/tdlight/common/SignalType.java
+++ b/tdlight-java/src/main/java/it/tdlight/SignalType.java
@@ -1,4 +1,4 @@
-package it.tdlight.common;
+package it.tdlight;
public enum SignalType {
UPDATE, EXCEPTION, CLOSE
diff --git a/src/main/java/it/tdlight/common/TelegramClient.java b/tdlight-java/src/main/java/it/tdlight/TelegramClient.java
similarity index 97%
rename from src/main/java/it/tdlight/common/TelegramClient.java
rename to tdlight-java/src/main/java/it/tdlight/TelegramClient.java
index 5de29db..9675999 100644
--- a/src/main/java/it/tdlight/common/TelegramClient.java
+++ b/tdlight-java/src/main/java/it/tdlight/TelegramClient.java
@@ -1,7 +1,6 @@
-package it.tdlight.common;
+package it.tdlight;
import it.tdlight.jni.TdApi;
-import it.tdlight.jni.TdApi.Object;
public interface TelegramClient {
diff --git a/src/main/java/it/tdlight/common/UpdatesHandler.java b/tdlight-java/src/main/java/it/tdlight/UpdatesHandler.java
similarity index 93%
rename from src/main/java/it/tdlight/common/UpdatesHandler.java
rename to tdlight-java/src/main/java/it/tdlight/UpdatesHandler.java
index 4229af4..97a34bf 100644
--- a/src/main/java/it/tdlight/common/UpdatesHandler.java
+++ b/tdlight-java/src/main/java/it/tdlight/UpdatesHandler.java
@@ -1,4 +1,4 @@
-package it.tdlight.common;
+package it.tdlight;
import it.tdlight.jni.TdApi;
import java.util.List;
diff --git a/src/main/java/it/tdlight/client/APIToken.java b/tdlight-java/src/main/java/it/tdlight/client/APIToken.java
similarity index 100%
rename from src/main/java/it/tdlight/client/APIToken.java
rename to tdlight-java/src/main/java/it/tdlight/client/APIToken.java
diff --git a/src/main/java/it/tdlight/client/Authenticable.java b/tdlight-java/src/main/java/it/tdlight/client/Authenticable.java
similarity index 60%
rename from src/main/java/it/tdlight/client/Authenticable.java
rename to tdlight-java/src/main/java/it/tdlight/client/Authenticable.java
index 5d76fcf..5ef4a67 100644
--- a/src/main/java/it/tdlight/client/Authenticable.java
+++ b/tdlight-java/src/main/java/it/tdlight/client/Authenticable.java
@@ -4,5 +4,5 @@ import java.util.function.Consumer;
public interface Authenticable {
- void getAuthenticationData(Consumer result);
+ AuthenticationSupplier> getAuthenticationSupplier();
}
diff --git a/tdlight-java/src/main/java/it/tdlight/client/AuthenticationData.java b/tdlight-java/src/main/java/it/tdlight/client/AuthenticationData.java
new file mode 100644
index 0000000..272404c
--- /dev/null
+++ b/tdlight-java/src/main/java/it/tdlight/client/AuthenticationData.java
@@ -0,0 +1,12 @@
+package it.tdlight.client;
+
+public interface AuthenticationData {
+
+ boolean isQrCode();
+
+ boolean isBot();
+
+ String getUserPhoneNumber();
+
+ String getBotToken();
+}
diff --git a/src/main/java/it/tdlight/client/AuthenticationDataImpl.java b/tdlight-java/src/main/java/it/tdlight/client/AuthenticationDataImpl.java
similarity index 83%
rename from src/main/java/it/tdlight/client/AuthenticationDataImpl.java
rename to tdlight-java/src/main/java/it/tdlight/client/AuthenticationDataImpl.java
index 8e7209c..c22b6ba 100644
--- a/src/main/java/it/tdlight/client/AuthenticationDataImpl.java
+++ b/tdlight-java/src/main/java/it/tdlight/client/AuthenticationDataImpl.java
@@ -1,9 +1,12 @@
package it.tdlight.client;
+import static java.util.concurrent.CompletableFuture.completedFuture;
+
import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
@SuppressWarnings("unused")
-final class AuthenticationDataImpl implements AuthenticationData {
+final class AuthenticationDataImpl implements AuthenticationSupplier, AuthenticationData {
private final String userPhoneNumber;
private final String botToken;
@@ -72,4 +75,9 @@ final class AuthenticationDataImpl implements AuthenticationData {
public int hashCode() {
return Objects.hash(userPhoneNumber, botToken);
}
+
+ @Override
+ public CompletableFuture get() {
+ return completedFuture(this);
+ }
}
diff --git a/src/main/java/it/tdlight/client/AuthenticationDataQrCode.java b/tdlight-java/src/main/java/it/tdlight/client/AuthenticationDataQrCode.java
similarity index 56%
rename from src/main/java/it/tdlight/client/AuthenticationDataQrCode.java
rename to tdlight-java/src/main/java/it/tdlight/client/AuthenticationDataQrCode.java
index 6954af1..ce911ee 100644
--- a/src/main/java/it/tdlight/client/AuthenticationDataQrCode.java
+++ b/tdlight-java/src/main/java/it/tdlight/client/AuthenticationDataQrCode.java
@@ -1,6 +1,8 @@
package it.tdlight.client;
-class AuthenticationDataQrCode implements AuthenticationData {
+import java.util.concurrent.CompletableFuture;
+
+class AuthenticationDataQrCode implements AuthenticationSupplier, AuthenticationData {
@Override
public boolean isQrCode() {
@@ -21,4 +23,9 @@ class AuthenticationDataQrCode implements AuthenticationData {
public String getBotToken() {
throw new UnsupportedOperationException("This is not a bot");
}
+
+ @Override
+ public CompletableFuture get() {
+ return CompletableFuture.completedFuture(this);
+ }
}
diff --git a/src/main/java/it/tdlight/client/AuthenticationData.java b/tdlight-java/src/main/java/it/tdlight/client/AuthenticationSupplier.java
similarity index 54%
rename from src/main/java/it/tdlight/client/AuthenticationData.java
rename to tdlight-java/src/main/java/it/tdlight/client/AuthenticationSupplier.java
index f735023..1b979ac 100644
--- a/src/main/java/it/tdlight/client/AuthenticationData.java
+++ b/tdlight-java/src/main/java/it/tdlight/client/AuthenticationSupplier.java
@@ -1,16 +1,12 @@
package it.tdlight.client;
-public interface AuthenticationData {
+import java.util.concurrent.CompletableFuture;
- boolean isQrCode();
+public interface AuthenticationSupplier {
- boolean isBot();
+ CompletableFuture get();
- String getUserPhoneNumber();
-
- String getBotToken();
-
- static AuthenticationData qrCode() {
+ static AuthenticationSupplier> qrCode() {
return new AuthenticationDataQrCode();
}
@@ -18,15 +14,15 @@ public interface AuthenticationData {
* Deprecated, use {@link #user(String)} instead
*/
@Deprecated
- static AuthenticationData user(long userPhoneNumber) {
+ static AuthenticationSupplier> user(long userPhoneNumber) {
return user(String.valueOf(userPhoneNumber));
}
- static AuthenticationData user(String userPhoneNumber) {
+ static AuthenticationSupplier> user(String userPhoneNumber) {
return new AuthenticationDataImpl(userPhoneNumber, null);
}
- static AuthenticationData bot(String botToken) {
+ static AuthenticationSupplier> bot(String botToken) {
return new AuthenticationDataImpl(null, botToken);
}
diff --git a/src/main/java/it/tdlight/client/AuthorizationStateReadyGetMe.java b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateReadyGetMe.java
similarity index 96%
rename from src/main/java/it/tdlight/client/AuthorizationStateReadyGetMe.java
rename to tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateReadyGetMe.java
index 09bf93a..ae643e7 100644
--- a/src/main/java/it/tdlight/client/AuthorizationStateReadyGetMe.java
+++ b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateReadyGetMe.java
@@ -1,7 +1,6 @@
package it.tdlight.client;
-import it.tdlight.common.TelegramClient;
-import it.tdlight.jni.TdApi;
+import it.tdlight.TelegramClient;
import it.tdlight.jni.TdApi.AuthorizationStateReady;
import it.tdlight.jni.TdApi.GetMe;
import it.tdlight.jni.TdApi.UpdateAuthorizationState;
diff --git a/src/main/java/it/tdlight/client/AuthorizationStateReadyLoadChats.java b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateReadyLoadChats.java
similarity index 83%
rename from src/main/java/it/tdlight/client/AuthorizationStateReadyLoadChats.java
rename to tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateReadyLoadChats.java
index e41012a..c140160 100644
--- a/src/main/java/it/tdlight/client/AuthorizationStateReadyLoadChats.java
+++ b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateReadyLoadChats.java
@@ -1,17 +1,11 @@
package it.tdlight.client;
-import it.tdlight.common.TelegramClient;
-import it.tdlight.jni.TdApi;
+import it.tdlight.TelegramClient;
import it.tdlight.jni.TdApi.AuthorizationStateReady;
import it.tdlight.jni.TdApi.ChatList;
-import it.tdlight.jni.TdApi.ChatListMain;
import it.tdlight.jni.TdApi.Error;
-import it.tdlight.jni.TdApi.GetMe;
import it.tdlight.jni.TdApi.LoadChats;
import it.tdlight.jni.TdApi.UpdateAuthorizationState;
-import it.tdlight.jni.TdApi.User;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/src/main/java/it/tdlight/client/AuthorizationStateWaitAuthenticationDataHandler.java b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitAuthenticationDataHandler.java
similarity index 84%
rename from src/main/java/it/tdlight/client/AuthorizationStateWaitAuthenticationDataHandler.java
rename to tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitAuthenticationDataHandler.java
index fd7b7d7..c5a10f6 100644
--- a/src/main/java/it/tdlight/client/AuthorizationStateWaitAuthenticationDataHandler.java
+++ b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitAuthenticationDataHandler.java
@@ -1,7 +1,7 @@
package it.tdlight.client;
-import it.tdlight.common.ExceptionHandler;
-import it.tdlight.common.TelegramClient;
+import it.tdlight.ExceptionHandler;
+import it.tdlight.TelegramClient;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.PhoneNumberAuthenticationSettings;
import it.tdlight.jni.TdApi.SetAuthenticationPhoneNumber;
@@ -24,7 +24,13 @@ final class AuthorizationStateWaitAuthenticationDataHandler implements GenericUp
@Override
public void onUpdate(UpdateAuthorizationState update) {
if (update.authorizationState.getConstructor() == TdApi.AuthorizationStateWaitPhoneNumber.CONSTRUCTOR) {
- authenticable.getAuthenticationData(this::onAuthData);
+ authenticable.getAuthenticationSupplier().get().whenComplete((authData, ex) -> {
+ if (ex != null) {
+ exceptionHandler.onException(ex);
+ return;
+ }
+ this.onAuthData(authData);
+ });
}
}
@@ -45,7 +51,13 @@ final class AuthorizationStateWaitAuthenticationDataHandler implements GenericUp
}
}, exceptionHandler);
} else {
- PhoneNumberAuthenticationSettings phoneSettings = new PhoneNumberAuthenticationSettings(false, false, false, false, null);
+ PhoneNumberAuthenticationSettings phoneSettings = new PhoneNumberAuthenticationSettings(false,
+ false,
+ false,
+ false,
+ null,
+ null
+ );
String phoneNumber = authenticationData.getUserPhoneNumber();
SetAuthenticationPhoneNumber response = new SetAuthenticationPhoneNumber(phoneNumber, phoneSettings);
diff --git a/src/main/java/it/tdlight/client/AuthorizationStateWaitCodeHandler.java b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitCodeHandler.java
similarity index 88%
rename from src/main/java/it/tdlight/client/AuthorizationStateWaitCodeHandler.java
rename to tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitCodeHandler.java
index b6ddfdd..1cb860d 100644
--- a/src/main/java/it/tdlight/client/AuthorizationStateWaitCodeHandler.java
+++ b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitCodeHandler.java
@@ -1,7 +1,7 @@
package it.tdlight.client;
-import it.tdlight.common.ExceptionHandler;
-import it.tdlight.common.TelegramClient;
+import it.tdlight.ExceptionHandler;
+import it.tdlight.TelegramClient;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.AuthorizationStateWaitCode;
import it.tdlight.jni.TdApi.CheckAuthenticationCode;
@@ -30,7 +30,11 @@ final class AuthorizationStateWaitCodeHandler implements GenericUpdateHandler {
+ clientInteraction.onParameterRequest(InputParameter.ASK_CODE, parameterInfo).whenComplete((code, ex) -> {
+ if (ex != null) {
+ exceptionHandler.onException(ex);
+ return;
+ }
CheckAuthenticationCode response = new CheckAuthenticationCode(code);
client.send(response, ok -> {
if (ok.getConstructor() == TdApi.Error.CONSTRUCTOR) {
diff --git a/src/main/java/it/tdlight/client/AuthorizationStateWaitForExit.java b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitForExit.java
similarity index 100%
rename from src/main/java/it/tdlight/client/AuthorizationStateWaitForExit.java
rename to tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitForExit.java
diff --git a/src/main/java/it/tdlight/client/AuthorizationStateWaitOtherDeviceConfirmationHandler.java b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitOtherDeviceConfirmationHandler.java
similarity index 67%
rename from src/main/java/it/tdlight/client/AuthorizationStateWaitOtherDeviceConfirmationHandler.java
rename to tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitOtherDeviceConfirmationHandler.java
index cf13fca..ec3e053 100644
--- a/src/main/java/it/tdlight/client/AuthorizationStateWaitOtherDeviceConfirmationHandler.java
+++ b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitOtherDeviceConfirmationHandler.java
@@ -1,5 +1,6 @@
package it.tdlight.client;
+import it.tdlight.ExceptionHandler;
import it.tdlight.jni.TdApi.AuthorizationStateWaitOtherDeviceConfirmation;
import it.tdlight.jni.TdApi.UpdateAuthorizationState;
@@ -7,18 +8,24 @@ final class AuthorizationStateWaitOtherDeviceConfirmationHandler implements
GenericUpdateHandler {
private final ClientInteraction clientInteraction;
+ private final ExceptionHandler exceptionHandler;
- public AuthorizationStateWaitOtherDeviceConfirmationHandler(ClientInteraction clientInteraction) {
+ public AuthorizationStateWaitOtherDeviceConfirmationHandler(ClientInteraction clientInteraction,
+ ExceptionHandler exceptionHandler) {
this.clientInteraction = clientInteraction;
+ this.exceptionHandler = exceptionHandler;
}
@Override
public void onUpdate(UpdateAuthorizationState update) {
if (update.authorizationState.getConstructor() == AuthorizationStateWaitOtherDeviceConfirmation.CONSTRUCTOR) {
- AuthorizationStateWaitOtherDeviceConfirmation authorizationState = (AuthorizationStateWaitOtherDeviceConfirmation) update.authorizationState;
+ AuthorizationStateWaitOtherDeviceConfirmation authorizationState
+ = (AuthorizationStateWaitOtherDeviceConfirmation) update.authorizationState;
ParameterInfo parameterInfo = new ParameterInfoNotifyLink(authorizationState.link);
- clientInteraction.onParameterRequest(InputParameter.NOTIFY_LINK, parameterInfo, ignored -> {
-
+ clientInteraction.onParameterRequest(InputParameter.NOTIFY_LINK, parameterInfo).whenComplete((ignored, ex) -> {
+ if (ex != null) {
+ exceptionHandler.onException(ex);
+ }
});
}
}
diff --git a/src/main/java/it/tdlight/client/AuthorizationStateWaitPasswordHandler.java b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitPasswordHandler.java
similarity index 88%
rename from src/main/java/it/tdlight/client/AuthorizationStateWaitPasswordHandler.java
rename to tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitPasswordHandler.java
index b07a020..562847f 100644
--- a/src/main/java/it/tdlight/client/AuthorizationStateWaitPasswordHandler.java
+++ b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitPasswordHandler.java
@@ -1,7 +1,7 @@
package it.tdlight.client;
-import it.tdlight.common.ExceptionHandler;
-import it.tdlight.common.TelegramClient;
+import it.tdlight.ExceptionHandler;
+import it.tdlight.TelegramClient;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.AuthorizationStateWaitPassword;
import it.tdlight.jni.TdApi.CheckAuthenticationPassword;
@@ -29,7 +29,11 @@ final class AuthorizationStateWaitPasswordHandler implements GenericUpdateHandle
authorizationState.hasRecoveryEmailAddress,
authorizationState.recoveryEmailAddressPattern
);
- clientInteraction.onParameterRequest(InputParameter.ASK_PASSWORD, parameterInfo, password -> {
+ clientInteraction.onParameterRequest(InputParameter.ASK_PASSWORD, parameterInfo).whenComplete((password, ex) -> {
+ if (ex != null) {
+ exceptionHandler.onException(ex);
+ return;
+ }
CheckAuthenticationPassword response = new CheckAuthenticationPassword(password);
client.send(response, ok -> {
if (ok.getConstructor() == TdApi.Error.CONSTRUCTOR) {
diff --git a/src/main/java/it/tdlight/client/AuthorizationStateWaitRegistrationHandler.java b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitRegistrationHandler.java
similarity index 78%
rename from src/main/java/it/tdlight/client/AuthorizationStateWaitRegistrationHandler.java
rename to tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitRegistrationHandler.java
index d1f179c..88e354c 100644
--- a/src/main/java/it/tdlight/client/AuthorizationStateWaitRegistrationHandler.java
+++ b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitRegistrationHandler.java
@@ -1,7 +1,7 @@
package it.tdlight.client;
-import it.tdlight.common.ExceptionHandler;
-import it.tdlight.common.TelegramClient;
+import it.tdlight.ExceptionHandler;
+import it.tdlight.TelegramClient;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.AuthorizationStateWaitRegistration;
import it.tdlight.jni.TdApi.RegisterUser;
@@ -26,9 +26,12 @@ final class AuthorizationStateWaitRegistrationHandler implements GenericUpdateHa
if (update.authorizationState.getConstructor() == AuthorizationStateWaitRegistration.CONSTRUCTOR) {
TdApi.AuthorizationStateWaitRegistration authorizationState = (TdApi.AuthorizationStateWaitRegistration) update.authorizationState;
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 -> {
+ clientInteraction
+ .onParameterRequest(InputParameter.TERMS_OF_SERVICE, tos)
+ .thenCompose(ignored -> clientInteraction
+ .onParameterRequest(InputParameter.ASK_FIRST_NAME, new EmptyParameterInfo()))
+ .thenCompose(firstName -> clientInteraction
+ .onParameterRequest(InputParameter.ASK_LAST_NAME, new EmptyParameterInfo()).thenAccept(lastName -> {
if (firstName == null || firstName.isEmpty()) {
exceptionHandler.onException(new IllegalArgumentException("First name must not be null or empty"));
return;
@@ -51,9 +54,12 @@ final class AuthorizationStateWaitRegistrationHandler implements GenericUpdateHa
throw new TelegramError((TdApi.Error) ok);
}
}, exceptionHandler);
+ }))
+ .whenComplete((ignored, ex) -> {
+ if (ex != null) {
+ exceptionHandler.onException(ex);
+ }
});
- });
- });
}
}
}
diff --git a/src/main/java/it/tdlight/client/AuthorizationStateWaitTdlibParametersHandler.java b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitTdlibParametersHandler.java
similarity index 93%
rename from src/main/java/it/tdlight/client/AuthorizationStateWaitTdlibParametersHandler.java
rename to tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitTdlibParametersHandler.java
index 41f89c6..6801c4e 100644
--- a/src/main/java/it/tdlight/client/AuthorizationStateWaitTdlibParametersHandler.java
+++ b/tdlight-java/src/main/java/it/tdlight/client/AuthorizationStateWaitTdlibParametersHandler.java
@@ -1,10 +1,9 @@
package it.tdlight.client;
-import it.tdlight.common.ExceptionHandler;
-import it.tdlight.common.TelegramClient;
+import it.tdlight.ExceptionHandler;
+import it.tdlight.TelegramClient;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.AuthorizationStateWaitTdlibParameters;
-import it.tdlight.jni.TdApi.SetTdlibParameters;
import it.tdlight.jni.TdApi.UpdateAuthorizationState;
final class AuthorizationStateWaitTdlibParametersHandler implements GenericUpdateHandler {
diff --git a/tdlight-java/src/main/java/it/tdlight/client/ClientInteraction.java b/tdlight-java/src/main/java/it/tdlight/client/ClientInteraction.java
new file mode 100644
index 0000000..a86090d
--- /dev/null
+++ b/tdlight-java/src/main/java/it/tdlight/client/ClientInteraction.java
@@ -0,0 +1,9 @@
+package it.tdlight.client;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+
+public interface ClientInteraction {
+
+ CompletableFuture onParameterRequest(InputParameter parameter, ParameterInfo parameterInfo);
+}
diff --git a/src/main/java/it/tdlight/client/CommandHandler.java b/tdlight-java/src/main/java/it/tdlight/client/CommandHandler.java
similarity index 100%
rename from src/main/java/it/tdlight/client/CommandHandler.java
rename to tdlight-java/src/main/java/it/tdlight/client/CommandHandler.java
diff --git a/src/main/java/it/tdlight/client/CommandsHandler.java b/tdlight-java/src/main/java/it/tdlight/client/CommandsHandler.java
similarity index 97%
rename from src/main/java/it/tdlight/client/CommandsHandler.java
rename to tdlight-java/src/main/java/it/tdlight/client/CommandsHandler.java
index 2e4e35b..e8a14d8 100644
--- a/src/main/java/it/tdlight/client/CommandsHandler.java
+++ b/tdlight-java/src/main/java/it/tdlight/client/CommandsHandler.java
@@ -1,6 +1,6 @@
package it.tdlight.client;
-import it.tdlight.common.TelegramClient;
+import it.tdlight.TelegramClient;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.Chat;
import it.tdlight.jni.TdApi.Message;
@@ -11,7 +11,6 @@ import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
-import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --git a/tdlight-java/src/main/java/it/tdlight/client/ConsoleInteractiveAuthenticationData.java b/tdlight-java/src/main/java/it/tdlight/client/ConsoleInteractiveAuthenticationData.java
new file mode 100644
index 0000000..9db9a3e
--- /dev/null
+++ b/tdlight-java/src/main/java/it/tdlight/client/ConsoleInteractiveAuthenticationData.java
@@ -0,0 +1,127 @@
+package it.tdlight.client;
+
+import it.tdlight.utils.ScannerUtils;
+import java.util.Locale;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
+
+public final class ConsoleInteractiveAuthenticationData implements AuthenticationSupplier {
+
+ private static final class State implements AuthenticationData {
+ final boolean isQr;
+ final boolean isBot;
+ final String botToken;
+ final String phoneNumber;
+
+ State(boolean isQr, boolean isBot, String botToken, String phoneNumber) {
+ this.isQr = isQr;
+ this.isBot = isBot;
+ this.botToken = botToken;
+ this.phoneNumber = phoneNumber;
+ }
+
+ @Override
+ public boolean isQrCode() {
+ return isQr;
+ }
+
+ @Override
+ public boolean isBot() {
+ return isBot;
+ }
+
+ @Override
+ public String getUserPhoneNumber() {
+ if (isBot || isQr) {
+ throw new UnsupportedOperationException("This is not a user");
+ }
+ return phoneNumber;
+ }
+
+ @Override
+ public String getBotToken() {
+ if (!isBot || isQr) {
+ throw new UnsupportedOperationException("This is not a bot");
+ }
+ return botToken;
+ }
+ }
+
+ private final AtomicReference> state = new AtomicReference<>();
+
+ ConsoleInteractiveAuthenticationData() {
+
+ }
+
+ public CompletableFuture askData() {
+ return get();
+ }
+
+ public boolean isInitialized() {
+ CompletableFuture cf = state.get();
+ return cf != null && cf.isDone();
+ }
+
+ @Override
+ public CompletableFuture get() {
+ CompletableFuture cf = new CompletableFuture();
+ if (state.compareAndSet(null, cf)) {
+ SequentialRequestsExecutor.getInstance().execute(() -> {
+ try {
+ String choice;
+
+ // Choose login type
+ String mode;
+ do {
+ String response = ScannerUtils.askParameter("login",
+ "Do you want to login using a bot [token], a [phone] number, or a [qr] code? [token/phone/qr]");
+ if (response != null) {
+ choice = response.trim().toLowerCase(Locale.ROOT);
+ switch (choice) {
+ case "phone":
+ mode = "PHONE";
+ break;
+ case "token":
+ mode = "TOKEN";
+ break;
+ case "qr":
+ mode = "QR";
+ break;
+ default:
+ mode = null;
+ break;
+ }
+ } else {
+ mode = null;
+ }
+ } while (mode == null);
+
+ if ("TOKEN".equals(mode)) {
+ String token;
+ do {
+ token = ScannerUtils.askParameter("login", "Please type the bot token");
+ } while (token.length() < 5 || !token.contains(":"));
+
+ cf.complete(new State(false, true, token, null));
+ } else if ("PHONE".equals(mode)) {
+ String phoneNumber;
+ do {
+ phoneNumber = ScannerUtils.askParameter("login", "Please type your phone number");
+ } while (phoneNumber.length() < 3);
+
+ cf.complete(new State(false, false, null, phoneNumber));
+ } else {
+ cf.complete(new State(true, false, null, null));
+ }
+ } catch (Throwable ex) {
+ cf.completeExceptionally(ex);
+ throw ex;
+ }
+ });
+ return cf;
+ } else {
+ return state.get();
+ }
+ }
+}
diff --git a/src/main/java/it/tdlight/client/EmptyParameterInfo.java b/tdlight-java/src/main/java/it/tdlight/client/EmptyParameterInfo.java
similarity index 100%
rename from src/main/java/it/tdlight/client/EmptyParameterInfo.java
rename to tdlight-java/src/main/java/it/tdlight/client/EmptyParameterInfo.java
diff --git a/src/main/java/it/tdlight/client/GenericResultHandler.java b/tdlight-java/src/main/java/it/tdlight/client/GenericResultHandler.java
similarity index 100%
rename from src/main/java/it/tdlight/client/GenericResultHandler.java
rename to tdlight-java/src/main/java/it/tdlight/client/GenericResultHandler.java
diff --git a/src/main/java/it/tdlight/client/GenericUpdateHandler.java b/tdlight-java/src/main/java/it/tdlight/client/GenericUpdateHandler.java
similarity index 100%
rename from src/main/java/it/tdlight/client/GenericUpdateHandler.java
rename to tdlight-java/src/main/java/it/tdlight/client/GenericUpdateHandler.java
diff --git a/src/main/java/it/tdlight/client/InputParameter.java b/tdlight-java/src/main/java/it/tdlight/client/InputParameter.java
similarity index 100%
rename from src/main/java/it/tdlight/client/InputParameter.java
rename to tdlight-java/src/main/java/it/tdlight/client/InputParameter.java
diff --git a/tdlight-java/src/main/java/it/tdlight/client/MutableTelegramClient.java b/tdlight-java/src/main/java/it/tdlight/client/MutableTelegramClient.java
new file mode 100644
index 0000000..7fb8a1f
--- /dev/null
+++ b/tdlight-java/src/main/java/it/tdlight/client/MutableTelegramClient.java
@@ -0,0 +1,19 @@
+package it.tdlight.client;
+
+import it.tdlight.ExceptionHandler;
+import it.tdlight.jni.TdApi;
+
+public interface MutableTelegramClient {
+
+ void setClientInteraction(ClientInteraction clientInteraction);
+
+ void addCommandHandler(String commandName, CommandHandler handler);
+
+ void addUpdateHandler(Class updateType, GenericUpdateHandler handler);
+
+ void addUpdatesHandler(GenericUpdateHandler handler);
+
+ void addUpdateExceptionHandler(ExceptionHandler updateExceptionHandler);
+
+ void addDefaultExceptionHandler(ExceptionHandler defaultExceptionHandlers);
+}
diff --git a/src/main/java/it/tdlight/client/ParameterInfo.java b/tdlight-java/src/main/java/it/tdlight/client/ParameterInfo.java
similarity index 100%
rename from src/main/java/it/tdlight/client/ParameterInfo.java
rename to tdlight-java/src/main/java/it/tdlight/client/ParameterInfo.java
diff --git a/src/main/java/it/tdlight/client/ParameterInfoCode.java b/tdlight-java/src/main/java/it/tdlight/client/ParameterInfoCode.java
similarity index 100%
rename from src/main/java/it/tdlight/client/ParameterInfoCode.java
rename to tdlight-java/src/main/java/it/tdlight/client/ParameterInfoCode.java
diff --git a/src/main/java/it/tdlight/client/ParameterInfoNotifyLink.java b/tdlight-java/src/main/java/it/tdlight/client/ParameterInfoNotifyLink.java
similarity index 100%
rename from src/main/java/it/tdlight/client/ParameterInfoNotifyLink.java
rename to tdlight-java/src/main/java/it/tdlight/client/ParameterInfoNotifyLink.java
diff --git a/src/main/java/it/tdlight/client/ParameterInfoPasswordHint.java b/tdlight-java/src/main/java/it/tdlight/client/ParameterInfoPasswordHint.java
similarity index 100%
rename from src/main/java/it/tdlight/client/ParameterInfoPasswordHint.java
rename to tdlight-java/src/main/java/it/tdlight/client/ParameterInfoPasswordHint.java
diff --git a/src/main/java/it/tdlight/client/ParameterInfoTermsOfService.java b/tdlight-java/src/main/java/it/tdlight/client/ParameterInfoTermsOfService.java
similarity index 100%
rename from src/main/java/it/tdlight/client/ParameterInfoTermsOfService.java
rename to tdlight-java/src/main/java/it/tdlight/client/ParameterInfoTermsOfService.java
diff --git a/src/main/java/it/tdlight/client/QrCodeTerminal.java b/tdlight-java/src/main/java/it/tdlight/client/QrCodeTerminal.java
similarity index 100%
rename from src/main/java/it/tdlight/client/QrCodeTerminal.java
rename to tdlight-java/src/main/java/it/tdlight/client/QrCodeTerminal.java
diff --git a/src/main/java/it/tdlight/client/Result.java b/tdlight-java/src/main/java/it/tdlight/client/Result.java
similarity index 100%
rename from src/main/java/it/tdlight/client/Result.java
rename to tdlight-java/src/main/java/it/tdlight/client/Result.java
diff --git a/tdlight-java/src/main/java/it/tdlight/client/ScannerClientInteraction.java b/tdlight-java/src/main/java/it/tdlight/client/ScannerClientInteraction.java
new file mode 100644
index 0000000..0557088
--- /dev/null
+++ b/tdlight-java/src/main/java/it/tdlight/client/ScannerClientInteraction.java
@@ -0,0 +1,129 @@
+package it.tdlight.client;
+
+import it.tdlight.utils.ScannerUtils;
+import it.tdlight.jni.TdApi.TermsOfService;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class ScannerClientInteraction implements ClientInteraction {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ScannerClientInteraction.class);
+
+ private final Executor blockingExecutor;
+ private final Authenticable authenticable;
+
+ public ScannerClientInteraction(Executor blockingExecutor, Authenticable authenticable) {
+ this.blockingExecutor = blockingExecutor;
+ this.authenticable = authenticable;
+ }
+
+ @Override
+ public CompletableFuture onParameterRequest(InputParameter parameter, ParameterInfo parameterInfo) {
+ AuthenticationSupplier> authSupplier = authenticable.getAuthenticationSupplier();
+ AuthenticationData authData = getAuthDataNowOrNull(authSupplier);
+ return CompletableFuture.supplyAsync(() -> {
+ String who;
+ boolean useRealWho = authData != null;
+ if (!useRealWho) {
+ who = "login";
+ } else if (authData.isQrCode()) {
+ who = "QR login";
+ } else if (authData.isBot()) {
+ who = authData.getBotToken().split(":", 2)[0];
+ } else {
+ who = "+" + authData.getUserPhoneNumber();
+ }
+ String question;
+ boolean trim = false;
+ switch (parameter) {
+ case ASK_FIRST_NAME:
+ question = "Enter first name";
+ trim = true;
+ break;
+ case ASK_LAST_NAME:
+ question = "Enter last name";
+ trim = true;
+ break;
+ case ASK_CODE:
+ question = "Enter authentication code";
+ 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", "");
+ if (codeInfo.getNextType() != null) {
+ question += "\n\tNext code type: " + codeInfo
+ .getNextType()
+ .getClass()
+ .getSimpleName()
+ .replace("AuthenticationCodeType", "");
+ }
+ trim = true;
+ break;
+ case ASK_PASSWORD:
+ question = "Enter your password";
+ String passwordMessage = "Password authorization:";
+ String hint = ((ParameterInfoPasswordHint) parameterInfo).getHint();
+ if (hint != null && !hint.isEmpty()) {
+ passwordMessage += "\n\tHint: " + hint;
+ }
+ boolean hasRecoveryEmailAddress = ((ParameterInfoPasswordHint) parameterInfo)
+ .hasRecoveryEmailAddress();
+ passwordMessage += "\n\tHas recovery email: " + hasRecoveryEmailAddress;
+ String recoveryEmailAddressPattern = ((ParameterInfoPasswordHint) parameterInfo)
+ .getRecoveryEmailAddressPattern();
+ if (recoveryEmailAddressPattern != null && !recoveryEmailAddressPattern.isEmpty()) {
+ passwordMessage += "\n\tRecovery email address pattern: " + recoveryEmailAddressPattern;
+ }
+ System.out.println(passwordMessage);
+ break;
+ case NOTIFY_LINK:
+ String link = ((ParameterInfoNotifyLink) parameterInfo).getLink();
+ System.out.println("Please confirm this login link on another device: " + link);
+ System.out.println();
+ try {
+ System.out.println(QrCodeTerminal.getQr(link));
+ System.out.println();
+ } catch (NoClassDefFoundError ex) {
+ LOG.warn("QR code library is missing!"
+ + " Please add the following dependency to your project: com.google.zxing:core");
+ }
+ return "";
+ case TERMS_OF_SERVICE:
+ TermsOfService tos = ((ParameterInfoTermsOfService) parameterInfo).getTermsOfService();
+ question = "Terms of service:\n\t" + tos.text.text;
+ if (tos.minUserAge > 0) {
+ question += "\n\tMinimum user age: " + tos.minUserAge;
+ }
+ if (tos.showPopup) {
+ question += "\nPlease press enter.";
+ trim = true;
+ } else {
+ System.out.println(question);
+ return "";
+ }
+ break;
+ default:
+ question = parameter.toString();
+ break;
+ }
+ String result = ScannerUtils.askParameter(who, question);
+ if (trim) {
+ return result.trim();
+ } else {
+ return Objects.requireNonNull(result);
+ }
+ }, blockingExecutor);
+ }
+
+ private AuthenticationData getAuthDataNowOrNull(AuthenticationSupplier> authSupplier) {
+ try {
+ return authSupplier.get().getNow(null);
+ } catch (Throwable ignored) {
+ return null;
+ }
+ }
+}
diff --git a/tdlight-java/src/main/java/it/tdlight/client/SequentialRequestsExecutor.java b/tdlight-java/src/main/java/it/tdlight/client/SequentialRequestsExecutor.java
new file mode 100644
index 0000000..0a2161f
--- /dev/null
+++ b/tdlight-java/src/main/java/it/tdlight/client/SequentialRequestsExecutor.java
@@ -0,0 +1,37 @@
+package it.tdlight.client;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+class SequentialRequestsExecutor implements Executor {
+
+ private static volatile SequentialRequestsExecutor INSTANCE;
+
+ private final Executor executor = Executors.newSingleThreadExecutor(r -> {
+ final Thread thread = new Thread(r);
+ thread.setDaemon(true);
+ return thread;
+ });
+
+ private SequentialRequestsExecutor() {
+
+ }
+
+ public static SequentialRequestsExecutor getInstance() {
+ SequentialRequestsExecutor instance = INSTANCE;
+ if (instance == null) {
+ synchronized (SequentialRequestsExecutor.class) {
+ if (INSTANCE == null) {
+ INSTANCE = new SequentialRequestsExecutor();
+ }
+ instance = INSTANCE;
+ }
+ }
+ return instance;
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ executor.execute(command);
+ }
+}
diff --git a/tdlight-java/src/main/java/it/tdlight/client/SimpleResultHandler.java b/tdlight-java/src/main/java/it/tdlight/client/SimpleResultHandler.java
new file mode 100644
index 0000000..479d513
--- /dev/null
+++ b/tdlight-java/src/main/java/it/tdlight/client/SimpleResultHandler.java
@@ -0,0 +1,25 @@
+package it.tdlight.client;
+
+import it.tdlight.ConstructorDetector;
+import it.tdlight.ResultHandler;
+import it.tdlight.jni.TdApi.Object;
+import it.tdlight.jni.TdApi.Update;
+
+class SimpleResultHandler implements ResultHandler {
+
+ private final int updateConstructor;
+ private final GenericUpdateHandler handler;
+
+ public SimpleResultHandler(Class type, GenericUpdateHandler handler) {
+ this.updateConstructor = ConstructorDetector.getConstructor(type);
+ this.handler = handler;
+ }
+
+ @Override
+ public void onResult(Object update) {
+ if (update.getConstructor() == updateConstructor) {
+ //noinspection unchecked
+ handler.onUpdate((T) update);
+ }
+ }
+}
diff --git a/src/main/java/it/tdlight/client/SimpleTelegramClient.java b/tdlight-java/src/main/java/it/tdlight/client/SimpleTelegramClient.java
similarity index 75%
rename from src/main/java/it/tdlight/client/SimpleTelegramClient.java
rename to tdlight-java/src/main/java/it/tdlight/client/SimpleTelegramClient.java
index 9afa0e4..47bf2ed 100644
--- a/src/main/java/it/tdlight/client/SimpleTelegramClient.java
+++ b/tdlight-java/src/main/java/it/tdlight/client/SimpleTelegramClient.java
@@ -1,44 +1,36 @@
package it.tdlight.client;
-import it.tdlight.common.ConstructorDetector;
-import it.tdlight.common.ExceptionHandler;
-import it.tdlight.common.Init;
-import it.tdlight.common.Log;
-import it.tdlight.common.ResultHandler;
-import it.tdlight.common.TelegramClient;
-import it.tdlight.common.internal.CommonClientManager;
-import it.tdlight.common.utils.CantLoadLibrary;
-import it.tdlight.common.utils.LibraryVersion;
+import it.tdlight.ClientFactory;
+import it.tdlight.ExceptionHandler;
+import it.tdlight.Init;
+import it.tdlight.ResultHandler;
+import it.tdlight.TelegramClient;
+import it.tdlight.jni.TdApi.Update;
+import it.tdlight.utils.CantLoadLibrary;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.ChatListArchive;
import it.tdlight.jni.TdApi.ChatListMain;
import it.tdlight.jni.TdApi.Function;
import it.tdlight.jni.TdApi.User;
-import it.tdlight.tdnative.NativeClient;
-import it.tdlight.tdnative.NativeClient.LogMessageHandler;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
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;
@SuppressWarnings("unused")
-public final class SimpleTelegramClient implements Authenticable {
+public final class SimpleTelegramClient implements Authenticable, MutableTelegramClient {
public static final Logger LOG = LoggerFactory.getLogger(SimpleTelegramClient.class);
- public static ExecutorService blockingExecutor = Executors.newSingleThreadExecutor();
static {
try {
@@ -49,9 +41,9 @@ public final class SimpleTelegramClient implements Authenticable {
}
private final TelegramClient client;
- private ClientInteraction clientInteraction = new ScannerClientInteraction(blockingExecutor, this);
+ private ClientInteraction clientInteraction;
private final TDLibSettings settings;
- private AuthenticationData authenticationData;
+ private AuthenticationSupplier> authenticationData;
private final Map> commandHandlers = new ConcurrentHashMap<>();
private final Set> updateHandlers = new ConcurrentHashMap, Object>().keySet(
@@ -67,9 +59,27 @@ public final class SimpleTelegramClient implements Authenticable {
private final CountDownLatch closed = new CountDownLatch(1);
- public SimpleTelegramClient(TDLibSettings settings) {
- this.client = CommonClientManager.create(LibraryVersion.IMPLEMENTATION_NAME);
- this.settings = settings;
+ SimpleTelegramClient(ClientFactory clientFactory,
+ TDLibSettings settings,
+ Map> commandHandlers,
+ Set> updateHandlers,
+ Set updateExceptionHandlers,
+ Set defaultExceptionHandlers,
+ ClientInteraction clientInteraction) {
+ this.client = clientFactory.createClient();
+ this.settings = Objects.requireNonNull(settings, "TDLight client settings are null");
+
+ this.commandHandlers.putAll(commandHandlers);
+ this.updateHandlers.addAll(updateHandlers);
+ this.updateExceptionHandlers.addAll(updateExceptionHandlers);
+ this.defaultExceptionHandlers.addAll(defaultExceptionHandlers);
+ if (clientInteraction != null) {
+ this.clientInteraction = clientInteraction;
+ } else {
+ this.clientInteraction = new ScannerClientInteraction(SequentialRequestsExecutor.getInstance(), this);
+ }
+
+
this.addUpdateHandler(TdApi.UpdateAuthorizationState.class,
new AuthorizationStateWaitTdlibParametersHandler(client, settings, this::handleDefaultException)
);
@@ -78,22 +88,24 @@ public final class SimpleTelegramClient implements Authenticable {
);
this.addUpdateHandler(TdApi.UpdateAuthorizationState.class,
new AuthorizationStateWaitRegistrationHandler(client,
- new SimpleTelegramClientInteraction(blockingExecutor),
+ new SimpleTelegramClientInteraction(),
this::handleDefaultException
)
);
this.addUpdateHandler(TdApi.UpdateAuthorizationState.class,
new AuthorizationStateWaitPasswordHandler(client,
- new SimpleTelegramClientInteraction(blockingExecutor),
+ new SimpleTelegramClientInteraction(),
this::handleDefaultException
)
);
this.addUpdateHandler(TdApi.UpdateAuthorizationState.class,
- new AuthorizationStateWaitOtherDeviceConfirmationHandler(new SimpleTelegramClientInteraction(blockingExecutor))
+ new AuthorizationStateWaitOtherDeviceConfirmationHandler(new SimpleTelegramClientInteraction(),
+ this::handleDefaultException
+ )
);
this.addUpdateHandler(TdApi.UpdateAuthorizationState.class,
new AuthorizationStateWaitCodeHandler(client,
- new SimpleTelegramClientInteraction(blockingExecutor),
+ new SimpleTelegramClientInteraction(),
this::handleDefaultException
)
);
@@ -143,28 +155,16 @@ public final class SimpleTelegramClient implements Authenticable {
}
@Override
- public void getAuthenticationData(Consumer 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 AuthenticationSupplier> getAuthenticationSupplier() {
+ return authenticationData;
}
+ @Override
public void setClientInteraction(ClientInteraction clientInteraction) {
this.clientInteraction = clientInteraction;
}
+ @Override
public void addCommandHandler(String commandName, CommandHandler handler) {
Set handlers = this.commandHandlers.computeIfAbsent(commandName,
k -> new ConcurrentHashMap().keySet(new Object())
@@ -172,29 +172,20 @@ public final class SimpleTelegramClient implements Authenticable {
handlers.add(handler);
}
- @SuppressWarnings("unchecked")
+ @Override
public void addUpdateHandler(Class updateType, GenericUpdateHandler handler) {
- int updateConstructor = ConstructorDetector.getConstructor(updateType);
- this.updateHandlers.add(update -> {
- if (update.getConstructor() == updateConstructor) {
- handler.onUpdate((T) update);
- }
- });
+ this.updateHandlers.add(new SimpleResultHandler<>(updateType, handler));
}
+ @Override
public void addUpdatesHandler(GenericUpdateHandler handler) {
- this.updateHandlers.add(update -> {
- if (update instanceof TdApi.Update) {
- handler.onUpdate((TdApi.Update) update);
- } else {
- LOG.warn("Unknown update type: {}", update);
- }
- });
+ this.updateHandlers.add(new SimpleUpdateHandler(handler, LOG));
}
/**
* Optional handler to handle errors received from TDLib
*/
+ @Override
public void addUpdateExceptionHandler(ExceptionHandler updateExceptionHandler) {
this.updateExceptionHandlers.add(updateExceptionHandler);
}
@@ -202,6 +193,7 @@ public final class SimpleTelegramClient implements Authenticable {
/**
* Optional handler to handle uncaught errors (when using send without an appropriate error handler)
*/
+ @Override
public void addDefaultExceptionHandler(ExceptionHandler defaultExceptionHandlers) {
this.defaultExceptionHandlers.add(defaultExceptionHandlers);
}
@@ -209,7 +201,7 @@ public final class SimpleTelegramClient implements Authenticable {
/**
* Start the client
*/
- public void start(AuthenticationData authenticationData) {
+ public void start(AuthenticationSupplier> authenticationData) {
this.authenticationData = authenticationData;
createDirectories();
client.initialize(this::handleUpdate, this::handleUpdateException, this::handleDefaultException);
@@ -297,19 +289,16 @@ public final class SimpleTelegramClient implements Authenticable {
private final class SimpleTelegramClientInteraction implements ClientInteraction {
- private final ExecutorService blockingExecutor;
-
- public SimpleTelegramClientInteraction(ExecutorService blockingExecutor) {
- this.blockingExecutor = blockingExecutor;
+ public SimpleTelegramClientInteraction() {
}
@Override
- public void onParameterRequest(InputParameter parameter, ParameterInfo parameterInfo, Consumer result) {
+ public CompletableFuture onParameterRequest(InputParameter parameter, ParameterInfo parameterInfo) {
try {
- blockingExecutor.execute(() -> clientInteraction.onParameterRequest(parameter, parameterInfo, result));
+ return clientInteraction.onParameterRequest(parameter, parameterInfo);
} catch (RejectedExecutionException | NullPointerException ex) {
LOG.error("Failed to execute onParameterRequest. Returning an empty string", ex);
- result.accept("");
+ return CompletableFuture.completedFuture("");
}
}
}
diff --git a/tdlight-java/src/main/java/it/tdlight/client/SimpleTelegramClientBuilder.java b/tdlight-java/src/main/java/it/tdlight/client/SimpleTelegramClientBuilder.java
new file mode 100644
index 0000000..8b5824f
--- /dev/null
+++ b/tdlight-java/src/main/java/it/tdlight/client/SimpleTelegramClientBuilder.java
@@ -0,0 +1,78 @@
+package it.tdlight.client;
+
+import it.tdlight.ClientFactory;
+import it.tdlight.ExceptionHandler;
+import it.tdlight.ResultHandler;
+import it.tdlight.jni.TdApi.Update;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class SimpleTelegramClientBuilder implements MutableTelegramClient {
+
+ private static final Logger LOG = LoggerFactory.getLogger(SimpleTelegramClientBuilder.class);
+ private final ClientFactory clientManager;
+ private final TDLibSettings clientSettings;
+ private ClientInteraction clientInteraction;
+
+ private final Map> commandHandlers = new HashMap<>();
+ private final Set> updateHandlers = new HashSet<>();
+ private final Set updateExceptionHandlers = new HashSet<>();
+ private final Set defaultExceptionHandlers = new HashSet<>();
+
+ SimpleTelegramClientBuilder(ClientFactory clientManager, TDLibSettings clientSettings) {
+ this.clientManager = clientManager;
+ this.clientSettings = clientSettings;
+ }
+
+ @Override
+ public void setClientInteraction(ClientInteraction clientInteraction) {
+ this.clientInteraction = clientInteraction;
+ }
+
+ @Override
+ public void addCommandHandler(String commandName, CommandHandler handler) {
+ commandHandlers.computeIfAbsent(commandName, k -> new HashSet<>()).add(handler);
+ }
+
+ @Override
+ public void addUpdateHandler(Class updateType, GenericUpdateHandler handler) {
+ this.updateHandlers.add(new SimpleResultHandler<>(updateType, handler));
+ }
+
+ @Override
+ public void addUpdatesHandler(GenericUpdateHandler handler) {
+ this.updateHandlers.add(new SimpleUpdateHandler(handler, LOG));
+ }
+
+ @Override
+ public void addUpdateExceptionHandler(ExceptionHandler updateExceptionHandler) {
+ this.updateExceptionHandlers.add(updateExceptionHandler);
+ }
+
+ @Override
+ public void addDefaultExceptionHandler(ExceptionHandler defaultExceptionHandlers) {
+ this.defaultExceptionHandlers.add(defaultExceptionHandlers);
+ }
+
+ /**
+ * Build and start the client
+ * @return Telegram client
+ */
+ public SimpleTelegramClient build(AuthenticationSupplier authenticationData) {
+ SimpleTelegramClient client = new SimpleTelegramClient(clientManager,
+ clientSettings,
+ commandHandlers,
+ updateHandlers,
+ updateExceptionHandlers,
+ defaultExceptionHandlers,
+ clientInteraction
+ );
+ client.start(authenticationData);
+ return client;
+ }
+
+}
diff --git a/tdlight-java/src/main/java/it/tdlight/client/SimpleTelegramClientFactory.java b/tdlight-java/src/main/java/it/tdlight/client/SimpleTelegramClientFactory.java
new file mode 100644
index 0000000..1b1c2aa
--- /dev/null
+++ b/tdlight-java/src/main/java/it/tdlight/client/SimpleTelegramClientFactory.java
@@ -0,0 +1,33 @@
+package it.tdlight.client;
+
+import it.tdlight.ClientFactory;
+
+public class SimpleTelegramClientFactory implements AutoCloseable {
+ private final ClientFactory clientFactory;
+ private final boolean commonClientFactory;
+
+ public SimpleTelegramClientFactory() {
+ this(null);
+ }
+
+ public SimpleTelegramClientFactory(ClientFactory clientFactory) {
+ if (clientFactory == null) {
+ this.clientFactory = ClientFactory.getCommonClientFactory();
+ this.commonClientFactory = true;
+ } else {
+ this.clientFactory = clientFactory;
+ this.commonClientFactory = false;
+ }
+ }
+
+ public SimpleTelegramClientBuilder builder(TDLibSettings clientSettings) {
+ return new SimpleTelegramClientBuilder(clientFactory, clientSettings);
+ }
+
+ @Override
+ public void close() {
+ if (!commonClientFactory) {
+ clientFactory.close();
+ }
+ }
+}
diff --git a/tdlight-java/src/main/java/it/tdlight/client/SimpleUpdateHandler.java b/tdlight-java/src/main/java/it/tdlight/client/SimpleUpdateHandler.java
new file mode 100644
index 0000000..fb52ad9
--- /dev/null
+++ b/tdlight-java/src/main/java/it/tdlight/client/SimpleUpdateHandler.java
@@ -0,0 +1,27 @@
+package it.tdlight.client;
+
+import it.tdlight.ResultHandler;
+import it.tdlight.jni.TdApi;
+import it.tdlight.jni.TdApi.Object;
+import it.tdlight.jni.TdApi.Update;
+import org.slf4j.Logger;
+
+public class SimpleUpdateHandler implements ResultHandler {
+
+ private final GenericUpdateHandler handler;
+ private final Logger logger;
+
+ public SimpleUpdateHandler(GenericUpdateHandler handler, Logger logger) {
+ this.handler = handler;
+ this.logger = logger;
+ }
+
+ @Override
+ public void onResult(Object update) {
+ if (update instanceof TdApi.Update) {
+ handler.onUpdate((TdApi.Update) update);
+ } else {
+ logger.warn("Unknown update type: {}", update);
+ }
+ }
+}
diff --git a/src/main/java/it/tdlight/client/TDLibSettings.java b/tdlight-java/src/main/java/it/tdlight/client/TDLibSettings.java
similarity index 99%
rename from src/main/java/it/tdlight/client/TDLibSettings.java
rename to tdlight-java/src/main/java/it/tdlight/client/TDLibSettings.java
index fe10ad8..7eceed1 100644
--- a/src/main/java/it/tdlight/client/TDLibSettings.java
+++ b/tdlight-java/src/main/java/it/tdlight/client/TDLibSettings.java
@@ -1,6 +1,6 @@
package it.tdlight.client;
-import it.tdlight.common.utils.LibraryVersion;
+import it.tdlight.utils.LibraryVersion;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Locale;
diff --git a/src/main/java/it/tdlight/client/TelegramError.java b/tdlight-java/src/main/java/it/tdlight/client/TelegramError.java
similarity index 100%
rename from src/main/java/it/tdlight/client/TelegramError.java
rename to tdlight-java/src/main/java/it/tdlight/client/TelegramError.java
diff --git a/src/main/java/it/tdlight/tdnative/NativeClient.java b/tdlight-java/src/main/java/it/tdlight/tdnative/NativeClient.java
similarity index 100%
rename from src/main/java/it/tdlight/tdnative/NativeClient.java
rename to tdlight-java/src/main/java/it/tdlight/tdnative/NativeClient.java
diff --git a/src/main/java/it/tdlight/common/utils/Arch.java b/tdlight-java/src/main/java/it/tdlight/utils/Arch.java
similarity index 96%
rename from src/main/java/it/tdlight/common/utils/Arch.java
rename to tdlight-java/src/main/java/it/tdlight/utils/Arch.java
index 28587e3..5487af9 100644
--- a/src/main/java/it/tdlight/common/utils/Arch.java
+++ b/tdlight-java/src/main/java/it/tdlight/utils/Arch.java
@@ -15,7 +15,7 @@
* along with JTdlib. If not, see .
*/
-package it.tdlight.common.utils;
+package it.tdlight.utils;
/**
* Architectures recognized by this library.
diff --git a/src/main/java/it/tdlight/common/utils/CantLoadLibrary.java b/tdlight-java/src/main/java/it/tdlight/utils/CantLoadLibrary.java
similarity index 97%
rename from src/main/java/it/tdlight/common/utils/CantLoadLibrary.java
rename to tdlight-java/src/main/java/it/tdlight/utils/CantLoadLibrary.java
index 85d4a4e..2fa4b99 100644
--- a/src/main/java/it/tdlight/common/utils/CantLoadLibrary.java
+++ b/tdlight-java/src/main/java/it/tdlight/utils/CantLoadLibrary.java
@@ -15,7 +15,7 @@
* along with JTdlib. If not, see .
*/
-package it.tdlight.common.utils;
+package it.tdlight.utils;
/**
* An exception that is thrown when the LoadLibrary class fails to load the library.
diff --git a/tdlight-java/src/main/java/it/tdlight/utils/CleanSupport.java b/tdlight-java/src/main/java/it/tdlight/utils/CleanSupport.java
new file mode 100644
index 0000000..be702bb
--- /dev/null
+++ b/tdlight-java/src/main/java/it/tdlight/utils/CleanSupport.java
@@ -0,0 +1,13 @@
+package it.tdlight.utils;
+
+public class CleanSupport {
+
+ public static CleanableSupport register(Object object, Runnable cleanAction) {
+ return cleanAction::run;
+ }
+
+
+ public interface CleanableSupport {
+ public void clean();
+ }
+}
diff --git a/src/main/java/it/tdlight/common/utils/IntSwapper.java b/tdlight-java/src/main/java/it/tdlight/utils/IntSwapper.java
similarity index 88%
rename from src/main/java/it/tdlight/common/utils/IntSwapper.java
rename to tdlight-java/src/main/java/it/tdlight/utils/IntSwapper.java
index 078773c..2962413 100644
--- a/src/main/java/it/tdlight/common/utils/IntSwapper.java
+++ b/tdlight-java/src/main/java/it/tdlight/utils/IntSwapper.java
@@ -1,4 +1,4 @@
-package it.tdlight.common.utils;
+package it.tdlight.utils;
public final class IntSwapper {
diff --git a/src/main/java/it/tdlight/common/utils/LoadLibrary.java b/tdlight-java/src/main/java/it/tdlight/utils/LoadLibrary.java
similarity index 99%
rename from src/main/java/it/tdlight/common/utils/LoadLibrary.java
rename to tdlight-java/src/main/java/it/tdlight/utils/LoadLibrary.java
index b0ec88f..b6d17c9 100644
--- a/src/main/java/it/tdlight/common/utils/LoadLibrary.java
+++ b/tdlight-java/src/main/java/it/tdlight/utils/LoadLibrary.java
@@ -15,7 +15,7 @@
* along with JTdlib. If not, see .
*/
-package it.tdlight.common.utils;
+package it.tdlight.utils;
import java.io.IOException;
import java.io.InputStream;
diff --git a/src/main/java/it/tdlight/common/utils/Os.java b/tdlight-java/src/main/java/it/tdlight/utils/Os.java
similarity index 96%
rename from src/main/java/it/tdlight/common/utils/Os.java
rename to tdlight-java/src/main/java/it/tdlight/utils/Os.java
index 618f7eb..406d777 100644
--- a/src/main/java/it/tdlight/common/utils/Os.java
+++ b/tdlight-java/src/main/java/it/tdlight/utils/Os.java
@@ -15,7 +15,7 @@
* along with JTdlib. If not, see .
*/
-package it.tdlight.common.utils;
+package it.tdlight.utils;
/**
* Enumeration with all operating systems recognized by this library.
diff --git a/src/main/java/it/tdlight/common/utils/ScannerUtils.java b/tdlight-java/src/main/java/it/tdlight/utils/ScannerUtils.java
similarity index 97%
rename from src/main/java/it/tdlight/common/utils/ScannerUtils.java
rename to tdlight-java/src/main/java/it/tdlight/utils/ScannerUtils.java
index 5719851..15e9d35 100644
--- a/src/main/java/it/tdlight/common/utils/ScannerUtils.java
+++ b/tdlight-java/src/main/java/it/tdlight/utils/ScannerUtils.java
@@ -1,4 +1,4 @@
-package it.tdlight.common.utils;
+package it.tdlight.utils;
import java.io.Console;
import java.io.IOException;
diff --git a/src/main/java/it/tdlight/common/utils/SpinWaitSupport.java b/tdlight-java/src/main/java/it/tdlight/utils/SpinWaitSupport.java
similarity index 86%
rename from src/main/java/it/tdlight/common/utils/SpinWaitSupport.java
rename to tdlight-java/src/main/java/it/tdlight/utils/SpinWaitSupport.java
index be6a548..8ee7bd8 100644
--- a/src/main/java/it/tdlight/common/utils/SpinWaitSupport.java
+++ b/tdlight-java/src/main/java/it/tdlight/utils/SpinWaitSupport.java
@@ -1,4 +1,4 @@
-package it.tdlight.common.utils;
+package it.tdlight.utils;
import java.util.concurrent.locks.LockSupport;
diff --git a/src/main/java/module-info.java b/tdlight-java/src/main/java/module-info.java
similarity index 55%
rename from src/main/java/module-info.java
rename to tdlight-java/src/main/java/module-info.java
index 7463340..cbd41e8 100644
--- a/src/main/java/module-info.java
+++ b/tdlight-java/src/main/java/module-info.java
@@ -3,11 +3,8 @@ module tdlight.java {
requires org.reactivestreams;
requires org.slf4j;
requires static com.google.zxing;
- exports it.tdlight.tdlight;
exports it.tdlight.tdnative;
- exports it.tdlight.tdlib;
- exports it.tdlight.common;
- exports it.tdlight.common.utils;
- exports it.tdlight.common.internal;
+ exports it.tdlight;
+ exports it.tdlight.utils;
exports it.tdlight.client;
}
diff --git a/tdlight-java/src/main/java11/it/tdlight/utils/CleanSupport.java b/tdlight-java/src/main/java11/it/tdlight/utils/CleanSupport.java
new file mode 100644
index 0000000..d446f57
--- /dev/null
+++ b/tdlight-java/src/main/java11/it/tdlight/utils/CleanSupport.java
@@ -0,0 +1,17 @@
+package it.tdlight.utils;
+
+import java.lang.ref.Cleaner;
+
+public class CleanSupport {
+
+ private static final Cleaner cleaner = Cleaner.create();
+
+ public static CleanableSupport register(Object object, Runnable cleanAction) {
+ var c = cleaner.register(object, cleanAction);
+ return c::clean;
+ }
+
+ public interface CleanableSupport {
+ public void clean();
+ }
+}
diff --git a/src/main/java11/it/tdlight/common/utils/SpinWaitSupport.java b/tdlight-java/src/main/java11/it/tdlight/utils/SpinWaitSupport.java
similarity index 80%
rename from src/main/java11/it/tdlight/common/utils/SpinWaitSupport.java
rename to tdlight-java/src/main/java11/it/tdlight/utils/SpinWaitSupport.java
index d161234..21e1b3b 100644
--- a/src/main/java11/it/tdlight/common/utils/SpinWaitSupport.java
+++ b/tdlight-java/src/main/java11/it/tdlight/utils/SpinWaitSupport.java
@@ -1,4 +1,4 @@
-package it.tdlight.common.utils;
+package it.tdlight.utils;
public class SpinWaitSupport {
diff --git a/src/test/java/it/tdlight/common/internal/Event.java b/tdlight-java/src/test/java/it/tdlight/Event.java
similarity index 96%
rename from src/test/java/it/tdlight/common/internal/Event.java
rename to tdlight-java/src/test/java/it/tdlight/Event.java
index 90a5018..d795b79 100644
--- a/src/test/java/it/tdlight/common/internal/Event.java
+++ b/tdlight-java/src/test/java/it/tdlight/Event.java
@@ -1,4 +1,4 @@
-package it.tdlight.common.internal;
+package it.tdlight;
import it.tdlight.jni.TdApi;
import java.util.Objects;
diff --git a/src/test/java/it/tdlight/common/internal/HandleEventsTest.java b/tdlight-java/src/test/java/it/tdlight/HandleEventsTest.java
similarity index 96%
rename from src/test/java/it/tdlight/common/internal/HandleEventsTest.java
rename to tdlight-java/src/test/java/it/tdlight/HandleEventsTest.java
index 75d81c7..b7c5e25 100644
--- a/src/test/java/it/tdlight/common/internal/HandleEventsTest.java
+++ b/tdlight-java/src/test/java/it/tdlight/HandleEventsTest.java
@@ -1,22 +1,19 @@
-package it.tdlight.common.internal;
+package it.tdlight;
import static org.junit.jupiter.api.Assertions.*;
-import it.tdlight.common.EventsHandler;
+import it.tdlight.ResponseReceiver;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.Object;
import it.unimi.dsi.fastutil.longs.LongArraySet;
-import it.unimi.dsi.fastutil.longs.LongSets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
-import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class HandleEventsTest {
diff --git a/src/test/java/it/tdlight/common/internal/Result.java b/tdlight-java/src/test/java/it/tdlight/Result.java
similarity index 96%
rename from src/test/java/it/tdlight/common/internal/Result.java
rename to tdlight-java/src/test/java/it/tdlight/Result.java
index 99fada0..2a00d50 100644
--- a/src/test/java/it/tdlight/common/internal/Result.java
+++ b/tdlight-java/src/test/java/it/tdlight/Result.java
@@ -1,7 +1,6 @@
-package it.tdlight.common.internal;
+package it.tdlight;
import it.tdlight.jni.TdApi;
-import java.util.List;
import java.util.Objects;
public final class Result {