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 - - 17 - -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 {