New api
This commit is contained in:
parent
4d51b63737
commit
0fd22c61f4
2
dependencies/tdlight
vendored
2
dependencies/tdlight
vendored
@ -1 +1 @@
|
||||
Subproject commit f5ecc4b89655ddfaa1e05b77d6740e8d9cdfcaea
|
||||
Subproject commit 85bf271fb827a31b68d761a06a92972aa6548338
|
10
src/main/java/it/tdlight/common/ClientEventsHandler.java
Normal file
10
src/main/java/it/tdlight/common/ClientEventsHandler.java
Normal file
@ -0,0 +1,10 @@
|
||||
package it.tdlight.common;
|
||||
|
||||
import it.tdlight.jni.TdApi.Object;
|
||||
|
||||
public interface ClientEventsHandler {
|
||||
|
||||
int getClientId();
|
||||
|
||||
void handleEvents(boolean isClosed, long[] eventIds, Object[] events);
|
||||
}
|
38
src/main/java/it/tdlight/common/CommonClient.java
Normal file
38
src/main/java/it/tdlight/common/CommonClient.java
Normal file
@ -0,0 +1,38 @@
|
||||
package it.tdlight.common;
|
||||
|
||||
public abstract class CommonClient {
|
||||
|
||||
protected abstract String getImplementationName();
|
||||
|
||||
|
||||
private InternalClientManager getClientManager() {
|
||||
// ClientManager is singleton:
|
||||
return InternalClientManager.get(getImplementationName());
|
||||
}
|
||||
|
||||
public TelegramClient create(ResultHandler updateHandler,
|
||||
ExceptionHandler updateExceptionHandler,
|
||||
ExceptionHandler defaultExceptionHandler) {
|
||||
InternalClient client = new InternalClient(getClientManager(),
|
||||
updateHandler,
|
||||
updateExceptionHandler,
|
||||
defaultExceptionHandler
|
||||
);
|
||||
return create(client);
|
||||
}
|
||||
|
||||
public TelegramClient create(UpdatesHandler updatesHandler,
|
||||
ExceptionHandler updateExceptionHandler,
|
||||
ExceptionHandler defaultExceptionHandler) {
|
||||
InternalClient client = new InternalClient(getClientManager(),
|
||||
updatesHandler,
|
||||
updateExceptionHandler,
|
||||
defaultExceptionHandler
|
||||
);
|
||||
return create(client);
|
||||
}
|
||||
|
||||
private TelegramClient create(InternalClient internalClient) {
|
||||
return internalClient;
|
||||
}
|
||||
}
|
7
src/main/java/it/tdlight/common/EventsHandler.java
Normal file
7
src/main/java/it/tdlight/common/EventsHandler.java
Normal file
@ -0,0 +1,7 @@
|
||||
package it.tdlight.common;
|
||||
|
||||
import it.tdlight.jni.TdApi.Object;
|
||||
|
||||
public interface EventsHandler {
|
||||
void handleClientEvents(int clientId, boolean isClosed, long[] clientEventIds, Object[] clientEvents);
|
||||
}
|
19
src/main/java/it/tdlight/common/Handler.java
Normal file
19
src/main/java/it/tdlight/common/Handler.java
Normal file
@ -0,0 +1,19 @@
|
||||
package it.tdlight.common;
|
||||
|
||||
public class Handler {
|
||||
private final ResultHandler resultHandler;
|
||||
private final ExceptionHandler exceptionHandler;
|
||||
|
||||
public Handler(ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
|
||||
this.resultHandler = resultHandler;
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
public ResultHandler getResultHandler() {
|
||||
return resultHandler;
|
||||
}
|
||||
|
||||
public ExceptionHandler getExceptionHandler() {
|
||||
return exceptionHandler;
|
||||
}
|
||||
}
|
21
src/main/java/it/tdlight/common/IntSwapper.java
Normal file
21
src/main/java/it/tdlight/common/IntSwapper.java
Normal file
@ -0,0 +1,21 @@
|
||||
package it.tdlight.common;
|
||||
|
||||
import it.unimi.dsi.fastutil.Swapper;
|
||||
|
||||
class IntSwapper implements Swapper {
|
||||
|
||||
private final int[] array;
|
||||
int tmp;
|
||||
|
||||
public IntSwapper(int[] array) {
|
||||
this.array = array;
|
||||
tmp = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void swap(int a, int b) {
|
||||
tmp = array[a];
|
||||
array[a] = array[b];
|
||||
array[b] = tmp;
|
||||
}
|
||||
}
|
162
src/main/java/it/tdlight/common/InternalClient.java
Normal file
162
src/main/java/it/tdlight/common/InternalClient.java
Normal file
@ -0,0 +1,162 @@
|
||||
package it.tdlight.common;
|
||||
|
||||
import it.tdlight.jni.TdApi.Error;
|
||||
import it.tdlight.jni.TdApi.Function;
|
||||
import it.tdlight.jni.TdApi.Object;
|
||||
import it.tdlight.jni.TdApi.Update;
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class InternalClient implements ClientEventsHandler, TelegramClient {
|
||||
|
||||
private final ConcurrentHashMap<Long, Handler> handlers = new ConcurrentHashMap<Long, Handler>();
|
||||
|
||||
private final int clientId;
|
||||
private final InternalClientManager clientManager;
|
||||
private final Handler updateHandler;
|
||||
private final MultiHandler updatesHandler;
|
||||
private final ExceptionHandler defaultExceptionHandler;
|
||||
|
||||
private volatile boolean isClosed;
|
||||
|
||||
public InternalClient(InternalClientManager clientManager,
|
||||
ResultHandler updateHandler,
|
||||
ExceptionHandler updateExceptionHandler,
|
||||
ExceptionHandler defaultExceptionHandler) {
|
||||
this.updateHandler = new Handler(updateHandler, updateExceptionHandler);
|
||||
this.updatesHandler = null;
|
||||
this.clientManager = clientManager;
|
||||
this.clientId = NativeClientAccess.create();
|
||||
this.defaultExceptionHandler = defaultExceptionHandler;
|
||||
|
||||
clientManager.registerClient(this);
|
||||
}
|
||||
|
||||
public InternalClient(InternalClientManager clientManager,
|
||||
UpdatesHandler updatesHandler,
|
||||
ExceptionHandler updateExceptionHandler,
|
||||
ExceptionHandler defaultExceptionHandler) {
|
||||
this.updateHandler = null;
|
||||
this.updatesHandler = new MultiHandler(updatesHandler, updateExceptionHandler);
|
||||
this.clientManager = clientManager;
|
||||
this.clientId = NativeClientAccess.create();
|
||||
this.defaultExceptionHandler = defaultExceptionHandler;
|
||||
|
||||
clientManager.registerClient(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvents(boolean isClosed, long[] eventIds, Object[] events) {
|
||||
if (updatesHandler != null) {
|
||||
LongArrayList idsToFilter = new LongArrayList(eventIds);
|
||||
ObjectArrayList<Object> eventsToFilter = new ObjectArrayList<>(events);
|
||||
|
||||
for (int i = eventIds.length - 1; i >= 0; i--) {
|
||||
if (eventIds[i] != 0) {
|
||||
idsToFilter.removeLong(i);
|
||||
eventsToFilter.remove(i);
|
||||
|
||||
long eventId = eventIds[i];
|
||||
Object event = events[i];
|
||||
|
||||
Handler handler = handlers.remove(eventId);
|
||||
handleResponse(eventId, event, handler);
|
||||
}
|
||||
}
|
||||
|
||||
eventsToFilter.removeIf(event -> {
|
||||
if (event instanceof Error) {
|
||||
handleException(updatesHandler.getExceptionHandler(), new TDLibException((Error) event));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
ObjectArrayList<Update> updates = new ObjectArrayList<>(eventsToFilter.size());
|
||||
for (Object object : eventsToFilter) {
|
||||
updates.add((Update) object);
|
||||
}
|
||||
|
||||
try {
|
||||
updatesHandler.getUpdatesHandler().onUpdates(updates);
|
||||
} catch (Throwable cause) {
|
||||
handleException(updatesHandler.getExceptionHandler(), cause);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < eventIds.length; i++) {
|
||||
handleEvent(eventIds[i], events[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isClosed) {
|
||||
this.isClosed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles only a response (not an update!)
|
||||
*/
|
||||
private void handleResponse(long eventId, Object event, Handler handler) {
|
||||
if (handler != null) {
|
||||
try {
|
||||
if (event instanceof Error) {
|
||||
handleException(handler.getExceptionHandler(), new TDLibException((Error) event));
|
||||
} else {
|
||||
handler.getResultHandler().onResult(event);
|
||||
}
|
||||
} catch (Throwable cause) {
|
||||
handleException(handler.getExceptionHandler(), cause);
|
||||
}
|
||||
} else {
|
||||
System.err.println("Unknown event id " + eventId + ", the event has been dropped!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a response or an update
|
||||
*/
|
||||
private void handleEvent(long eventId, Object event) {
|
||||
if (updatesHandler != null || updateHandler == null) throw new IllegalStateException();
|
||||
Handler handler = eventId == 0 ? updateHandler : handlers.remove(eventId);
|
||||
handleResponse(eventId, event, handler);
|
||||
}
|
||||
|
||||
private void handleException(ExceptionHandler exceptionHandler, Throwable cause) {
|
||||
if (exceptionHandler == null) {
|
||||
exceptionHandler = defaultExceptionHandler;
|
||||
}
|
||||
if (exceptionHandler != null) {
|
||||
try {
|
||||
exceptionHandler.onException(cause);
|
||||
} catch (Throwable ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Function query, ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
|
||||
ensureOpen();
|
||||
long queryId = clientManager.getNextQueryId();
|
||||
if (resultHandler != null) {
|
||||
handlers.put(queryId, new Handler(resultHandler, exceptionHandler));
|
||||
}
|
||||
NativeClientAccess.send(clientId, queryId, query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object execute(Function query) {
|
||||
ensureOpen();
|
||||
return NativeClientAccess.execute(query);
|
||||
}
|
||||
|
||||
private void ensureOpen() {
|
||||
if (isClosed) {
|
||||
throw new IllegalStateException("The client is closed!");
|
||||
}
|
||||
}
|
||||
}
|
56
src/main/java/it/tdlight/common/InternalClientManager.java
Normal file
56
src/main/java/it/tdlight/common/InternalClientManager.java
Normal file
@ -0,0 +1,56 @@
|
||||
package it.tdlight.common;
|
||||
|
||||
import it.tdlight.jni.TdApi.Object;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class InternalClientManager implements AutoCloseable {
|
||||
|
||||
private static final AtomicReference<InternalClientManager> INSTANCE = new AtomicReference<>(null);
|
||||
|
||||
private final String implementationName;
|
||||
private final ResponseReceiver responseReceiver = new ResponseReceiver(this::handleClientEvents);
|
||||
private final Int2ObjectMap<ClientEventsHandler> clientEventsHandlerMap = new Int2ObjectOpenHashMap<>();
|
||||
private final AtomicLong currentQueryId = new AtomicLong();
|
||||
|
||||
private InternalClientManager(String implementationName) {
|
||||
this.implementationName = implementationName;
|
||||
}
|
||||
|
||||
public static InternalClientManager get(String implementationName) {
|
||||
return INSTANCE.updateAndGet(val -> val == null ? new InternalClientManager(implementationName) : val);
|
||||
}
|
||||
|
||||
private void handleClientEvents(int clientId, boolean isClosed, long[] clientEventIds, Object[] clientEvents) {
|
||||
ClientEventsHandler handler = clientEventsHandlerMap.get(clientId);
|
||||
|
||||
if (handler != null) {
|
||||
handler.handleEvents(isClosed, clientEventIds, clientEvents);
|
||||
} else {
|
||||
System.err.println("Unknown client id " + clientId + ", " + clientEvents.length + " events have been dropped!");
|
||||
}
|
||||
|
||||
if (isClosed) {
|
||||
clientEventsHandlerMap.remove(clientId);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerClient(ClientEventsHandler client) {
|
||||
this.clientEventsHandlerMap.put(client.getClientId(), client);
|
||||
}
|
||||
|
||||
public String getImplementationName() {
|
||||
return implementationName;
|
||||
}
|
||||
|
||||
public long getNextQueryId() {
|
||||
return currentQueryId.getAndUpdate(value -> (value >= Long.MAX_VALUE ? 0 : value) + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws InterruptedException {
|
||||
responseReceiver.close();
|
||||
}
|
||||
}
|
19
src/main/java/it/tdlight/common/MultiHandler.java
Normal file
19
src/main/java/it/tdlight/common/MultiHandler.java
Normal file
@ -0,0 +1,19 @@
|
||||
package it.tdlight.common;
|
||||
|
||||
public class MultiHandler {
|
||||
private final UpdatesHandler updatesHandler;
|
||||
private final ExceptionHandler exceptionHandler;
|
||||
|
||||
public MultiHandler(UpdatesHandler updatesHandler, ExceptionHandler exceptionHandler) {
|
||||
this.updatesHandler = updatesHandler;
|
||||
this.exceptionHandler = exceptionHandler;
|
||||
}
|
||||
|
||||
public UpdatesHandler getUpdatesHandler() {
|
||||
return updatesHandler;
|
||||
}
|
||||
|
||||
public ExceptionHandler getExceptionHandler() {
|
||||
return exceptionHandler;
|
||||
}
|
||||
}
|
24
src/main/java/it/tdlight/common/NativeClientAccess.java
Normal file
24
src/main/java/it/tdlight/common/NativeClientAccess.java
Normal file
@ -0,0 +1,24 @@
|
||||
package it.tdlight.common;
|
||||
|
||||
import it.tdlight.jni.NativeClient;
|
||||
import it.tdlight.jni.TdApi;
|
||||
import it.tdlight.jni.TdApi.Function;
|
||||
|
||||
class NativeClientAccess extends NativeClient {
|
||||
|
||||
public static int create() {
|
||||
return NativeClientAccess.createNativeClient();
|
||||
}
|
||||
|
||||
public static TdApi.Object execute(Function function) {
|
||||
return NativeClientAccess.nativeClientExecute(function);
|
||||
}
|
||||
|
||||
public 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) {
|
||||
return NativeClientAccess.nativeClientReceive(clientIds, eventIds, events, timeout);
|
||||
}
|
||||
}
|
100
src/main/java/it/tdlight/common/ResponseReceiver.java
Normal file
100
src/main/java/it/tdlight/common/ResponseReceiver.java
Normal file
@ -0,0 +1,100 @@
|
||||
package it.tdlight.common;
|
||||
|
||||
import it.tdlight.jni.TdApi;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public class ResponseReceiver extends Thread implements AutoCloseable {
|
||||
|
||||
private static final int MAX_EVENTS = 1000;
|
||||
private static final int[] originalSortingSource = new int[MAX_EVENTS];
|
||||
static {
|
||||
for (int i = 0; i < originalSortingSource.length; i++) {
|
||||
originalSortingSource[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
private final EventsHandler eventsHandler;
|
||||
private final int[] clientIds = new int[MAX_EVENTS];
|
||||
private final long[] eventIds = new long[MAX_EVENTS];
|
||||
private final TdApi.Object[] events = new TdApi.Object[MAX_EVENTS];
|
||||
|
||||
private final CountDownLatch closeWait = new CountDownLatch(1);
|
||||
|
||||
|
||||
public ResponseReceiver(EventsHandler eventsHandler) {
|
||||
super("TDLib thread");
|
||||
this.eventsHandler = eventsHandler;
|
||||
|
||||
this.setDaemon(true);
|
||||
|
||||
this.start();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"UnnecessaryLocalVariable", "InfiniteLoopStatement"})
|
||||
@Override
|
||||
public void run() {
|
||||
int[] sortIndex;
|
||||
try {
|
||||
while(true) {
|
||||
int resultsCount = NativeClientAccess.receive(clientIds, eventIds, events, 2.0 /*seconds*/);
|
||||
|
||||
if (resultsCount <= 0)
|
||||
continue;
|
||||
|
||||
// Generate a list of indices sorted by client id, from 0 to resultsCount
|
||||
sortIndex = generateSortIndex(0, resultsCount, clientIds);
|
||||
|
||||
int lastClientId = clientIds[sortIndex[0]];
|
||||
int lastClientIdEventsCount = 0;
|
||||
boolean lastClientClosed = false;
|
||||
|
||||
for (int i = 0; i <= resultsCount; i++) {
|
||||
if (i == resultsCount || (i != 0 && clientIds[sortIndex[i]] != lastClientId)) {
|
||||
if (lastClientIdEventsCount > 0) {
|
||||
int clientId = lastClientId;
|
||||
long[] clientEventIds = new long[lastClientIdEventsCount];
|
||||
TdApi.Object[] clientEvents = new TdApi.Object[lastClientIdEventsCount];
|
||||
for (int j = 0; j < lastClientIdEventsCount; j++) {
|
||||
clientEventIds[j] = eventIds[sortIndex[i - lastClientIdEventsCount + j]];
|
||||
clientEvents[j] = events[sortIndex[i - lastClientIdEventsCount + j]];
|
||||
|
||||
if (clientEventIds[j] == 0 && clientEvents[j] instanceof TdApi.UpdateAuthorizationState) {
|
||||
TdApi.AuthorizationState authorizationState = ((TdApi.UpdateAuthorizationState) clientEvents[j]).authorizationState;
|
||||
if (authorizationState instanceof TdApi.AuthorizationStateClosed) {
|
||||
lastClientClosed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eventsHandler.handleClientEvents(clientId, lastClientClosed, clientEventIds, clientEvents);
|
||||
}
|
||||
|
||||
lastClientId = clientIds[sortIndex[i]];
|
||||
lastClientIdEventsCount = 0;
|
||||
lastClientClosed = false;
|
||||
}
|
||||
|
||||
lastClientIdEventsCount++;
|
||||
}
|
||||
Arrays.fill(events, null);
|
||||
}
|
||||
} finally {
|
||||
this.closeWait.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private int[] generateSortIndex(int from, int to, int[] data) {
|
||||
int[] sortedIndices = Arrays.copyOfRange(originalSortingSource, from, to);
|
||||
it.unimi.dsi.fastutil.Arrays.mergeSort(from, to, (o1, o2) -> {
|
||||
return Integer.compare(data[sortedIndices[o1]], data[sortedIndices[o2]]);
|
||||
}, new IntSwapper(sortedIndices));
|
||||
return sortedIndices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws InterruptedException {
|
||||
this.closeWait.await();
|
||||
}
|
||||
}
|
21
src/main/java/it/tdlight/common/TDLibException.java
Normal file
21
src/main/java/it/tdlight/common/TDLibException.java
Normal file
@ -0,0 +1,21 @@
|
||||
package it.tdlight.common;
|
||||
|
||||
import it.tdlight.jni.TdApi.Error;
|
||||
|
||||
public class TDLibException extends RuntimeException {
|
||||
|
||||
private final Error event;
|
||||
|
||||
public TDLibException(Error event) {
|
||||
super(event.code + ": " + event.message);
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
public int getErrorCode() {
|
||||
return event.code;
|
||||
}
|
||||
|
||||
public String getErrorMessage() {
|
||||
return event.message;
|
||||
}
|
||||
}
|
@ -1,74 +1,42 @@
|
||||
package it.tdlight.common;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import it.tdlight.jni.TdApi;
|
||||
|
||||
public interface TelegramClient {
|
||||
|
||||
/**
|
||||
* Sends request to TDLib. May be called from any thread.
|
||||
* @param request Request to TDLib.
|
||||
*/
|
||||
void send(Request request);
|
||||
|
||||
/**
|
||||
* Receives incoming updates and request responses from TDLib. May be called from any thread, but shouldn't be called simultaneously from two different threads.
|
||||
* @param timeout Maximum number of seconds allowed for this function to wait for new records.
|
||||
* @param eventSize Maximum number of events allowed in list.
|
||||
* @return An incoming update or request response list. The object returned in the response may be an empty list if the timeout expires.
|
||||
*/
|
||||
default List<Response> receive(double timeout, int eventSize) {
|
||||
return receive(timeout, eventSize, true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives incoming updates and/or request responses from TDLib. May be called from any thread, but shouldn't be called simultaneously from two different threads.
|
||||
* @param timeout Maximum number of seconds allowed for this function to wait for new records.
|
||||
* @param eventSize Maximum number of events allowed in list.
|
||||
* @param receiveResponses True to receive responses.
|
||||
* @param receiveUpdates True to receive updates from TDLib.
|
||||
* @return An incoming update or request response list. The object returned in the response may be an empty list if the timeout expires.
|
||||
*/
|
||||
List<Response> receive(double timeout, int eventSize, boolean receiveResponses, boolean receiveUpdates);
|
||||
|
||||
/**
|
||||
* Receives incoming updates and request responses from TDLib. May be called from any thread, but
|
||||
* shouldn't be called simultaneously from two different threads.
|
||||
* Sends a request to the TDLib.
|
||||
*
|
||||
* @param timeout Maximum number of seconds allowed for this function to wait for new records.
|
||||
* @return An incoming update or request response. The object returned in the response may be a
|
||||
* nullptr if the timeout expires.
|
||||
* @param query Object representing a query to the TDLib.
|
||||
* @param resultHandler Result handler with onResult method which will be called with result
|
||||
* of the query or with TdApi.Error as parameter. If it is null, nothing
|
||||
* will be called.
|
||||
* @param exceptionHandler Exception handler with onException method which will be called on
|
||||
* exception thrown from resultHandler. If it is null, then
|
||||
* defaultExceptionHandler will be called.
|
||||
* @throws NullPointerException if query is null.
|
||||
*/
|
||||
default Response receive(double timeout) {
|
||||
return receive(timeout, true, true);
|
||||
}
|
||||
void send(TdApi.Function query, ResultHandler resultHandler, ExceptionHandler exceptionHandler);
|
||||
|
||||
/**
|
||||
* Receives incoming updates and request responses from TDLib. May be called from any thread, but
|
||||
* shouldn't be called simultaneously from two different threads.
|
||||
* Sends a request to the TDLib with an empty ExceptionHandler.
|
||||
*
|
||||
* @param timeout Maximum number of seconds allowed for this function to wait for new records.
|
||||
* @param receiveResponses True to receive responses.
|
||||
* @param receiveUpdates True to receive updates from TDLib.
|
||||
* @return An incoming update or request response. The object returned in the response may be a
|
||||
* nullptr if the timeout expires.
|
||||
* @param query Object representing a query to the TDLib.
|
||||
* @param resultHandler Result handler with onResult method which will be called with result
|
||||
* of the query or with TdApi.Error as parameter. If it is null, then
|
||||
* defaultExceptionHandler will be called.
|
||||
* @throws NullPointerException if query is null.
|
||||
*/
|
||||
Response receive(double timeout, boolean receiveResponses, boolean receiveUpdates);
|
||||
|
||||
/**
|
||||
* Synchronously executes TDLib requests. Only a few requests can be executed synchronously. May be called from any thread.
|
||||
* @param request Request to the TDLib.
|
||||
* @return The request response.
|
||||
*/
|
||||
Response execute(Request request);
|
||||
|
||||
/**
|
||||
* Destroys the client and TDLib instance.
|
||||
*/
|
||||
void destroyClient();
|
||||
|
||||
/**
|
||||
* Initializes the client and TDLib instance.
|
||||
*/
|
||||
void initializeClient() throws IOException;
|
||||
default void send(TdApi.Function query, ResultHandler resultHandler) {
|
||||
send(query, resultHandler, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously executes a TDLib request. Only a few marked accordingly requests can be executed synchronously.
|
||||
*
|
||||
* @param query Object representing a query to the TDLib.
|
||||
* @return request result.
|
||||
* @throws NullPointerException if query is null.
|
||||
*/
|
||||
TdApi.Object execute(TdApi.Function query);
|
||||
}
|
||||
|
17
src/main/java/it/tdlight/common/UpdatesHandler.java
Normal file
17
src/main/java/it/tdlight/common/UpdatesHandler.java
Normal file
@ -0,0 +1,17 @@
|
||||
package it.tdlight.common;
|
||||
|
||||
import it.tdlight.jni.TdApi.Update;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Interface for handler for incoming updates from TDLib.
|
||||
*/
|
||||
public interface UpdatesHandler {
|
||||
|
||||
/**
|
||||
* Callback called on incoming update from TDLib.
|
||||
*
|
||||
* @param object Updates of type TdApi.Update about new events.
|
||||
*/
|
||||
void onUpdates(List<Update> object);
|
||||
}
|
@ -8,7 +8,5 @@ public class NativeClient {
|
||||
|
||||
protected static native int nativeClientReceive(int[] clientIds, long[] eventIds, TdApi.Object[] events, double timeout);
|
||||
|
||||
protected static native int nativeClientReceive(int[] clientIds, long[] eventIds, TdApi.Object[] events, double timeout, boolean include_responses, boolean include_updates);
|
||||
|
||||
protected static native TdApi.Object nativeClientExecute(TdApi.Function function);
|
||||
}
|
||||
|
@ -1,248 +1,14 @@
|
||||
package it.tdlight.tdlib;
|
||||
|
||||
import it.cavallium.concurrentlocks.ReentrantReadWriteUpdateLock;
|
||||
import it.tdlight.common.Init;
|
||||
import it.tdlight.common.Request;
|
||||
import it.tdlight.common.Response;
|
||||
import it.tdlight.jni.NativeClient;
|
||||
import it.tdlight.jni.TdApi;
|
||||
import it.tdlight.jni.TdApi.AuthorizationStateClosed;
|
||||
import it.tdlight.jni.TdApi.AuthorizationStateClosing;
|
||||
import it.tdlight.jni.TdApi.AuthorizationStateWaitTdlibParameters;
|
||||
import it.tdlight.jni.TdApi.GetOption;
|
||||
import it.tdlight.jni.TdApi.Object;
|
||||
import it.tdlight.jni.TdApi.SetOption;
|
||||
import it.tdlight.jni.TdApi.UpdateAuthorizationState;
|
||||
import it.tdlight.common.TelegramClient;
|
||||
import it.tdlight.common.ClientState;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import it.tdlight.common.CommonClient;
|
||||
|
||||
/**
|
||||
* Interface for interaction with TDLib.
|
||||
*/
|
||||
public class Client extends NativeClient implements TelegramClient {
|
||||
|
||||
private ClientState state = ClientState.of(false, 0, false, false, false);
|
||||
private final ReentrantReadWriteUpdateLock stateLock = new ReentrantReadWriteUpdateLock();
|
||||
|
||||
/**
|
||||
* Creates a new TDLib client.
|
||||
*/
|
||||
public Client() {
|
||||
try {
|
||||
Init.start();
|
||||
} catch (Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
this.initializeClient();
|
||||
}
|
||||
public class Client extends CommonClient {
|
||||
|
||||
@Override
|
||||
public void send(Request request) {
|
||||
long clientId;
|
||||
stateLock.readLock().lock();
|
||||
try {
|
||||
requireInitialized();
|
||||
requireReadyToSend(request.getFunction().getConstructor());
|
||||
clientId = state.getClientId();
|
||||
} finally {
|
||||
stateLock.readLock().unlock();
|
||||
}
|
||||
|
||||
nativeClientSend(clientId, request.getId(), request.getFunction());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Response> receive(double timeout, int eventsSize, boolean receiveResponses, boolean receiveUpdates) {
|
||||
long clientId;
|
||||
stateLock.updateLock().lock();
|
||||
try {
|
||||
if (!state.isInitialized()) {
|
||||
sleep(timeout);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
requireInitialized();
|
||||
if (!state.isReadyToReceive()) {
|
||||
sleep(timeout);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
requireReadyToReceive();
|
||||
clientId = state.getClientId();
|
||||
return Arrays.asList(this.internalReceive(clientId, timeout, eventsSize, receiveResponses, receiveUpdates));
|
||||
} finally {
|
||||
stateLock.updateLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void sleep(double timeout) {
|
||||
long nanos = (long) (timeout * 1000000000d);
|
||||
int nanosPart = (int) (nanos % 1000000L);
|
||||
long millis = Duration.ofNanos(nanos - nanosPart).toMillis();
|
||||
try {
|
||||
Thread.sleep(millis, nanosPart);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response receive(double timeout, boolean receiveResponses, boolean receiveUpdates) {
|
||||
long clientId;
|
||||
stateLock.updateLock().lock();
|
||||
try {
|
||||
if (!state.isInitialized()) {
|
||||
sleep(timeout);
|
||||
return null;
|
||||
}
|
||||
requireInitialized();
|
||||
if (!state.isReadyToReceive()) {
|
||||
sleep(timeout);
|
||||
return null;
|
||||
}
|
||||
requireReadyToReceive();
|
||||
clientId = state.getClientId();
|
||||
|
||||
Response[] responses = this.internalReceive(clientId, timeout, 1, receiveResponses, receiveUpdates);
|
||||
|
||||
if (responses.length > 0) {
|
||||
return responses[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
} finally {
|
||||
stateLock.updateLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private Response[] internalReceive(long clientId, double timeout, int eventsSize, boolean receiveResponses, boolean receiveUpdates) {
|
||||
long[] eventIds = new long[eventsSize];
|
||||
TdApi.Object[] events = new TdApi.Object[eventsSize];
|
||||
|
||||
if (!(receiveResponses && receiveUpdates)) {
|
||||
throw new IllegalArgumentException("The variables receiveResponses and receiveUpdates must be both true, because you are using the original TDLib!");
|
||||
}
|
||||
|
||||
int resultSize = nativeClientReceive(clientId, eventIds, events, timeout);
|
||||
|
||||
Response[] responses = new Response[resultSize];
|
||||
|
||||
for (int i = 0; i < resultSize; i++) {
|
||||
responses[i] = new Response(eventIds[i], events[i]);
|
||||
if (eventIds[i] == 0) {
|
||||
handleStateEvent(events[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return responses;
|
||||
}
|
||||
|
||||
private void handleStateEvent(Object event) {
|
||||
if (event == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getConstructor() != UpdateAuthorizationState.CONSTRUCTOR) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateAuthorizationState updateAuthorizationState = (UpdateAuthorizationState) event;
|
||||
|
||||
switch (updateAuthorizationState.authorizationState.getConstructor()) {
|
||||
case AuthorizationStateWaitTdlibParameters.CONSTRUCTOR:
|
||||
stateLock.writeLock().lock();
|
||||
try {
|
||||
state.setReadyToSend(true);
|
||||
} finally {
|
||||
stateLock.writeLock().unlock();
|
||||
}
|
||||
break;
|
||||
case AuthorizationStateClosing.CONSTRUCTOR:
|
||||
stateLock.writeLock().lock();
|
||||
try {
|
||||
state.setReadyToSend(false);
|
||||
} finally {
|
||||
stateLock.writeLock().unlock();
|
||||
}
|
||||
break;
|
||||
case AuthorizationStateClosed.CONSTRUCTOR:
|
||||
stateLock.writeLock().lock();
|
||||
try {
|
||||
state.setReadyToSend(false).setReadyToReceive(false);
|
||||
} finally {
|
||||
stateLock.writeLock().unlock();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response execute(Request request) {
|
||||
stateLock.readLock().lock();
|
||||
try {
|
||||
requireInitialized();
|
||||
requireReadyToSend(request.getFunction().getConstructor());
|
||||
} finally {
|
||||
stateLock.readLock().unlock();
|
||||
}
|
||||
|
||||
Object object = nativeClientExecute(request.getFunction());
|
||||
return new Response(0, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyClient() {
|
||||
stateLock.writeLock().lock();
|
||||
try {
|
||||
if (state.isInitialized() && state.hasClientId()) {
|
||||
if (state.isReadyToSend() || state.isReadyToReceive()) {
|
||||
throw new IllegalStateException("You need to close the Client before destroying it!");
|
||||
}
|
||||
destroyNativeClient(this.state.getClientId());
|
||||
state = ClientState.of(false, 0, false, false, false);
|
||||
}
|
||||
} finally {
|
||||
stateLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeClient() {
|
||||
stateLock.writeLock().lock();
|
||||
try {
|
||||
if (!state.isInitialized() && !state.hasClientId()) {
|
||||
long clientId = createNativeClient();
|
||||
state = ClientState.of(true, clientId, true, true, false);
|
||||
}
|
||||
} finally {
|
||||
stateLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void requireInitialized() {
|
||||
if (!state.isInitialized() || !state.hasClientId()) {
|
||||
throw new IllegalStateException("Client not initialized");
|
||||
}
|
||||
}
|
||||
|
||||
private void requireReadyToSend(int constructor) {
|
||||
if (!state.isReadyToSend()) {
|
||||
switch (constructor) {
|
||||
case SetOption.CONSTRUCTOR:
|
||||
case GetOption.CONSTRUCTOR:
|
||||
case TdApi.SetTdlibParameters.CONSTRUCTOR:
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("Client not ready to send");
|
||||
}
|
||||
}
|
||||
|
||||
private void requireReadyToReceive() {
|
||||
if (!state.isReadyToReceive()) {
|
||||
throw new IllegalStateException("Client not ready to receive");
|
||||
}
|
||||
protected String getImplementationName() {
|
||||
return "tdlib";
|
||||
}
|
||||
}
|
||||
|
@ -1,287 +1,14 @@
|
||||
package it.tdlight.tdlight;
|
||||
|
||||
import it.tdlight.common.ClientState;
|
||||
import it.tdlight.common.Init;
|
||||
import it.tdlight.common.Request;
|
||||
import it.tdlight.common.Response;
|
||||
import it.tdlight.common.TelegramClient;
|
||||
import it.tdlight.jni.NativeClient;
|
||||
import it.tdlight.jni.TdApi;
|
||||
import it.tdlight.jni.TdApi.AuthorizationStateClosed;
|
||||
import it.tdlight.jni.TdApi.AuthorizationStateClosing;
|
||||
import it.tdlight.jni.TdApi.AuthorizationStateWaitTdlibParameters;
|
||||
import it.tdlight.jni.TdApi.GetOption;
|
||||
import it.tdlight.jni.TdApi.Object;
|
||||
import it.tdlight.jni.TdApi.SetOption;
|
||||
import it.tdlight.jni.TdApi.UpdateAuthorizationState;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import it.tdlight.common.CommonClient;
|
||||
|
||||
/**
|
||||
* Interface for interaction with TDLib.
|
||||
* Interface for interaction with TDLight.
|
||||
*/
|
||||
public class Client extends NativeClient implements TelegramClient {
|
||||
|
||||
private ClientState state = ClientState.of(false, 0, false, false, false);
|
||||
private final ReentrantReadWriteLock stateLock = new ReentrantReadWriteLock();
|
||||
private final ReentrantReadWriteLock updatesLock = new ReentrantReadWriteLock();
|
||||
private final ReentrantReadWriteLock responsesLock = new ReentrantReadWriteLock();
|
||||
|
||||
/**
|
||||
* Creates a new TDLib client.
|
||||
*/
|
||||
public Client() {
|
||||
try {
|
||||
Init.start();
|
||||
} catch (Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
this.initializeClient();
|
||||
}
|
||||
public class Client extends CommonClient {
|
||||
|
||||
@Override
|
||||
public void send(Request request) {
|
||||
long clientId;
|
||||
stateLock.readLock().lock();
|
||||
try {
|
||||
requireInitialized();
|
||||
requireReadyToSend(request.getFunction().getConstructor());
|
||||
clientId = state.getClientId();
|
||||
} finally {
|
||||
stateLock.readLock().unlock();
|
||||
}
|
||||
|
||||
nativeClientSend(clientId, request.getId(), request.getFunction());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Response> receive(double timeout, int eventsSize, boolean receiveResponses, boolean receiveUpdates) {
|
||||
if (receiveResponses) responsesLock.readLock().lock();
|
||||
try {
|
||||
if (receiveUpdates) updatesLock.readLock().lock();
|
||||
try {
|
||||
long clientId;
|
||||
stateLock.readLock().lock();
|
||||
try {
|
||||
if (!state.isInitialized()) {
|
||||
sleep(timeout);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
requireInitialized();
|
||||
if (!state.isReadyToReceive()) {
|
||||
sleep(timeout);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
requireReadyToReceive();
|
||||
clientId = state.getClientId();
|
||||
} finally {
|
||||
stateLock.readLock().unlock();
|
||||
}
|
||||
|
||||
return Arrays.asList(this.internalReceive(clientId, timeout, eventsSize, receiveResponses, receiveUpdates));
|
||||
} finally {
|
||||
if (receiveUpdates) updatesLock.readLock().unlock();
|
||||
}
|
||||
} finally {
|
||||
if (receiveResponses) responsesLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void sleep(double timeout) {
|
||||
long nanos = (long) (timeout * 1000000000d);
|
||||
int nanosPart = (int) (nanos % 1000000L);
|
||||
long millis = Duration.ofNanos(nanos - nanosPart).toMillis();
|
||||
try {
|
||||
Thread.sleep(millis, nanosPart);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response receive(double timeout, boolean receiveResponses, boolean receiveUpdates) {
|
||||
responsesLock.readLock().lock();
|
||||
try {
|
||||
updatesLock.readLock().lock();
|
||||
try {
|
||||
long clientId;
|
||||
stateLock.readLock().lock();
|
||||
try {
|
||||
if (!state.isInitialized()) {
|
||||
sleep(timeout);
|
||||
return null;
|
||||
}
|
||||
requireInitialized();
|
||||
if (!state.isReadyToReceive()) {
|
||||
sleep(timeout);
|
||||
return null;
|
||||
}
|
||||
requireReadyToReceive();
|
||||
clientId = state.getClientId();
|
||||
} finally {
|
||||
stateLock.readLock().unlock();
|
||||
}
|
||||
|
||||
Response[] responses = this.internalReceive(clientId, timeout, 1, receiveResponses, receiveUpdates);
|
||||
|
||||
if (responses.length > 0) {
|
||||
return responses[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
} finally {
|
||||
updatesLock.readLock().unlock();
|
||||
}
|
||||
} finally {
|
||||
responsesLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private Response[] internalReceive(long clientId, double timeout, int eventsSize, boolean receiveResponses, boolean receiveUpdates) {
|
||||
long[] eventIds = new long[eventsSize];
|
||||
TdApi.Object[] events = new TdApi.Object[eventsSize];
|
||||
|
||||
int resultSize = nativeClientReceive(clientId, eventIds, events, timeout, receiveResponses, receiveUpdates);
|
||||
|
||||
Response[] responses = new Response[resultSize];
|
||||
|
||||
for (int i = 0; i < resultSize; i++) {
|
||||
responses[i] = new Response(eventIds[i], events[i]);
|
||||
if (eventIds[i] == 0) {
|
||||
handleStateEvent(events[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return responses;
|
||||
}
|
||||
|
||||
private void handleStateEvent(Object event) {
|
||||
if (event == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getConstructor() != UpdateAuthorizationState.CONSTRUCTOR) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateAuthorizationState updateAuthorizationState = (UpdateAuthorizationState) event;
|
||||
|
||||
switch (updateAuthorizationState.authorizationState.getConstructor()) {
|
||||
case AuthorizationStateWaitTdlibParameters.CONSTRUCTOR:
|
||||
stateLock.writeLock().lock();
|
||||
try {
|
||||
state.setReadyToSend(true);
|
||||
} finally {
|
||||
stateLock.writeLock().unlock();
|
||||
}
|
||||
break;
|
||||
case AuthorizationStateClosing.CONSTRUCTOR:
|
||||
stateLock.writeLock().lock();
|
||||
try {
|
||||
state.setReadyToSend(false);
|
||||
} finally {
|
||||
stateLock.writeLock().unlock();
|
||||
}
|
||||
break;
|
||||
case AuthorizationStateClosed.CONSTRUCTOR:
|
||||
stateLock.writeLock().lock();
|
||||
try {
|
||||
state.setReadyToSend(false).setReadyToReceive(false);
|
||||
} finally {
|
||||
stateLock.writeLock().unlock();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response execute(Request request) {
|
||||
stateLock.readLock().lock();
|
||||
try {
|
||||
requireInitialized();
|
||||
requireReadyToSend(request.getFunction().getConstructor());
|
||||
} finally {
|
||||
stateLock.readLock().unlock();
|
||||
}
|
||||
|
||||
Object object = nativeClientExecute(request.getFunction());
|
||||
return new Response(0, object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyClient() {
|
||||
responsesLock.writeLock().lock();
|
||||
try {
|
||||
updatesLock.writeLock().lock();
|
||||
try {
|
||||
stateLock.writeLock().lock();
|
||||
try {
|
||||
if (state.isInitialized() && state.hasClientId()) {
|
||||
if (state.isReadyToSend() || state.isReadyToReceive()) {
|
||||
throw new IllegalStateException("You need to close the Client before destroying it!");
|
||||
}
|
||||
destroyNativeClient(this.state.getClientId());
|
||||
state = ClientState.of(false, 0, false, false, false);
|
||||
}
|
||||
} finally {
|
||||
stateLock.writeLock().unlock();
|
||||
}
|
||||
} finally {
|
||||
updatesLock.writeLock().unlock();
|
||||
}
|
||||
} finally {
|
||||
responsesLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeClient() {
|
||||
responsesLock.writeLock().lock();
|
||||
try {
|
||||
updatesLock.writeLock().lock();
|
||||
try {
|
||||
stateLock.writeLock().lock();
|
||||
try {
|
||||
if (!state.isInitialized() && !state.hasClientId()) {
|
||||
long clientId = createNativeClient();
|
||||
state = ClientState.of(true, clientId, true, true, false);
|
||||
}
|
||||
} finally {
|
||||
stateLock.writeLock().unlock();
|
||||
}
|
||||
} finally {
|
||||
updatesLock.writeLock().unlock();
|
||||
}
|
||||
} finally {
|
||||
responsesLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void requireInitialized() {
|
||||
if (!state.isInitialized() || !state.hasClientId()) {
|
||||
throw new IllegalStateException("Client not initialized");
|
||||
}
|
||||
}
|
||||
|
||||
private void requireReadyToSend(int constructor) {
|
||||
if (!state.isReadyToSend()) {
|
||||
switch (constructor) {
|
||||
case SetOption.CONSTRUCTOR:
|
||||
case GetOption.CONSTRUCTOR:
|
||||
case TdApi.SetTdlibParameters.CONSTRUCTOR:
|
||||
return;
|
||||
}
|
||||
throw new IllegalStateException("Client not ready to send");
|
||||
}
|
||||
}
|
||||
|
||||
private void requireReadyToReceive() {
|
||||
if (!state.isReadyToReceive()) {
|
||||
throw new IllegalStateException("Client not ready to receive");
|
||||
}
|
||||
protected String getImplementationName() {
|
||||
return "tdlight";
|
||||
}
|
||||
}
|
||||
|
@ -42,28 +42,33 @@
|
||||
<dependency>
|
||||
<groupId>it.tdlight</groupId>
|
||||
<artifactId>tdlib-natives-linux-amd64</artifactId>
|
||||
<version>3.0.84</version>
|
||||
<version>3.0.92</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>it.tdlight</groupId>
|
||||
<artifactId>tdlib-natives-linux-aarch64</artifactId>
|
||||
<version>3.0.84</version>
|
||||
<version>3.0.92</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>it.tdlight</groupId>
|
||||
<artifactId>tdlib-natives-windows-amd64</artifactId>
|
||||
<version>3.0.84</version>
|
||||
<version>3.0.92</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>it.tdlight</groupId>
|
||||
<artifactId>tdlib-natives-osx-amd64</artifactId>
|
||||
<version>3.0.84</version>
|
||||
<version>3.0.92</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>it.cavallium</groupId>
|
||||
<artifactId>concurrent-locks</artifactId>
|
||||
<version>1.0.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>it.unimi.dsi</groupId>
|
||||
<artifactId>fastutil</artifactId>
|
||||
<version>8.3.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<sourceDirectory>../src/main/java</sourceDirectory>
|
||||
|
@ -42,28 +42,33 @@
|
||||
<dependency>
|
||||
<groupId>it.tdlight</groupId>
|
||||
<artifactId>tdlight-natives-linux-amd64</artifactId>
|
||||
<version>3.0.84</version>
|
||||
<version>3.0.92</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>it.tdlight</groupId>
|
||||
<artifactId>tdlight-natives-linux-aarch64</artifactId>
|
||||
<version>3.0.84</version>
|
||||
<version>3.0.92</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>it.tdlight</groupId>
|
||||
<artifactId>tdlight-natives-windows-amd64</artifactId>
|
||||
<version>3.0.84</version>
|
||||
<version>3.0.92</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>it.tdlight</groupId>
|
||||
<artifactId>tdlight-natives-osx-amd64</artifactId>
|
||||
<version>3.0.84</version>
|
||||
<version>3.0.92</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>it.cavallium</groupId>
|
||||
<artifactId>concurrent-locks</artifactId>
|
||||
<version>1.0.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>it.unimi.dsi</groupId>
|
||||
<artifactId>fastutil</artifactId>
|
||||
<version>8.3.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<sourceDirectory>../src/main/java</sourceDirectory>
|
||||
|
Loading…
Reference in New Issue
Block a user