Use generics to check tdlib functions return types

This commit is contained in:
Andrea Cavalli 2021-10-20 23:51:06 +02:00
parent 6deb99f517
commit 646330ae19
19 changed files with 118 additions and 101 deletions

View File

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

View File

@ -36,7 +36,7 @@ final class AuthorizationStateWaitPasswordHandler implements GenericUpdateHandle
authorizationState.recoveryEmailAddressPattern
);
String password = clientInteraction.onParameterRequest(InputParameter.ASK_PASSWORD, parameterInfo);
Function response = new CheckAuthenticationPassword(password);
CheckAuthenticationPassword response = new CheckAuthenticationPassword(password);
client.send(response, ok -> {
if (ok.getConstructor() == Error.CONSTRUCTOR) {
throw new TelegramError((Error) ok);

View File

@ -71,14 +71,19 @@ final class ConsoleInteractiveAuthenticationData implements AuthenticationData {
.askParameter("login", "Do you want to login using a bot [token], a [phone] number, or a [qr] code? [token/phone/qr]")
.trim()
.toLowerCase(Locale.ROOT);
if ("phone".equals(choice)) {
mode = "PHONE";
} else if ("token".equals(choice)) {
mode = "TOKEN";
} else if ("qr".equals(choice)) {
mode = "QR";
} else {
mode = null;
switch (choice) {
case "phone":
mode = "PHONE";
break;
case "token":
mode = "TOKEN";
break;
case "qr":
mode = "QR";
break;
default:
mode = null;
break;
}
} while (mode == null);

View File

@ -49,7 +49,8 @@ public final class SimpleTelegramClient implements Authenticable {
private AuthenticationData authenticationData;
private final Map<String, Set<CommandHandler>> commandHandlers = new ConcurrentHashMap<>();
private final Set<ResultHandler> updateHandlers = new ConcurrentHashMap<ResultHandler, Object>()
private final Set<ResultHandler<TdApi.Update>> updateHandlers
= new ConcurrentHashMap<ResultHandler<TdApi.Update>, Object>()
.keySet(new Object());
private final Set<ExceptionHandler> updateExceptionHandlers = new ConcurrentHashMap<ExceptionHandler, Object>()
.keySet(new Object());
@ -87,7 +88,7 @@ public final class SimpleTelegramClient implements Authenticable {
private void handleUpdate(TdApi.Object update) {
boolean handled = false;
for (ResultHandler updateHandler : updateHandlers) {
for (ResultHandler<TdApi.Update> updateHandler : updateHandlers) {
updateHandler.onResult(update);
handled = true;
}
@ -208,7 +209,7 @@ public final class SimpleTelegramClient implements Authenticable {
/**
* Send a function and get the result
*/
public <T extends TdApi.Object> void send(TdApi.Function function, GenericResultHandler<T> resultHandler) {
public <R extends TdApi.Object> void send(TdApi.Function<R> function, GenericResultHandler<R> resultHandler) {
client.send(function, result -> resultHandler.onResult(Result.of(result)), this::handleResultHandlingException);
}
@ -217,7 +218,7 @@ public final class SimpleTelegramClient implements Authenticable {
* <strong>Please note that only some functions can be executed using this method.</strong>
* If you want to execute a function please use {@link #send(Function, GenericResultHandler)}!
*/
public <T extends TdApi.Object> Result<T> execute(TdApi.Function function) {
public <R extends TdApi.Object> Result<R> execute(TdApi.Function<R> function) {
return Result.of(client.execute(function));
}

View File

@ -35,12 +35,6 @@ public final class Init {
*/
public synchronized static void start() throws CantLoadLibrary {
if (!started) {
Os os = LoadLibrary.getOs();
if (os == Os.WINDOWS) {
// Since 3.0.0, libraries for windows are statically compiled into tdjni.dll
}
LoadLibrary.load("tdjni");
ConstructorDetector.init();
started = true;

View File

@ -4,7 +4,6 @@ import it.tdlight.jni.TdApi;
import java.time.Duration;
import org.reactivestreams.Publisher;
@SuppressWarnings("ReactiveStreamsPublisherImplementation")
public interface ReactiveTelegramClient {
/**
@ -20,7 +19,7 @@ public interface ReactiveTelegramClient {
* @return a publisher that will emit exactly one item, or an error
* @throws NullPointerException if query is null.
*/
Publisher<TdApi.Object> send(TdApi.Function query, Duration timeout);
<R extends TdApi.Object> Publisher<TdApi.Object> send(TdApi.Function<R> query, Duration timeout);
/**
* Synchronously executes a TDLib request. Only a few marked accordingly requests can be executed synchronously.
@ -29,7 +28,7 @@ public interface ReactiveTelegramClient {
* @return request result or {@link TdApi.Error}.
* @throws NullPointerException if query is null.
*/
TdApi.Object execute(TdApi.Function query);
<R extends TdApi.Object> TdApi.Object execute(TdApi.Function<R> query);
void setListener(SignalListener listener);

View File

@ -1,16 +1,18 @@
package it.tdlight.common;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.Object;
/**
* Interface for handler for results of queries to TDLib and incoming updates from TDLib.
*/
public interface ResultHandler {
@SuppressWarnings("unused")
public interface ResultHandler<R extends TdApi.Object> {
/**
* Callback called on result of query to TDLib or incoming update from TDLib.
*
* @param object Result of query or update of type TdApi.Update about new events.
* @param object Result of type r, error of type TdApi.Error, or update of type TdApi.Update.
*/
void onResult(Object object);
void onResult(TdApi.Object object);
}

View File

@ -22,7 +22,7 @@ public interface TelegramClient {
* @param updateExceptionHandler Handler in which the errors from updates are received
* @param defaultExceptionHandler Handler that receives exceptions triggered in a handler
*/
default void initialize(ResultHandler updateHandler,
default void initialize(ResultHandler<TdApi.Update> updateHandler,
ExceptionHandler updateExceptionHandler,
ExceptionHandler defaultExceptionHandler) {
this.initialize((UpdatesHandler) updates -> updates.forEach(updateHandler::onResult),
@ -41,7 +41,8 @@ public interface TelegramClient {
* resultHandler. If it is null, then defaultExceptionHandler will be called.
* @throws NullPointerException if query is null.
*/
void send(TdApi.Function query, ResultHandler resultHandler, ExceptionHandler exceptionHandler);
<R extends TdApi.Object> void send(TdApi.Function<R> query, ResultHandler<R> resultHandler,
ExceptionHandler exceptionHandler);
/**
* Sends a request to the TDLib with an empty ExceptionHandler.
@ -51,7 +52,7 @@ public interface TelegramClient {
* TdApi.Error as parameter. If it is null, then defaultExceptionHandler will be called.
* @throws NullPointerException if query is null.
*/
default void send(TdApi.Function query, ResultHandler resultHandler) {
default <R extends TdApi.Object> void send(TdApi.Function<R> query, ResultHandler<R> resultHandler) {
send(query, resultHandler, null);
}
@ -62,5 +63,5 @@ public interface TelegramClient {
* @return request result or {@link TdApi.Error}.
* @throws NullPointerException if query is null.
*/
TdApi.Object execute(TdApi.Function query);
<R extends TdApi.Object> TdApi.Object execute(TdApi.Function<R> query);
}

View File

@ -2,17 +2,18 @@ package it.tdlight.common.internal;
import it.tdlight.common.ExceptionHandler;
import it.tdlight.common.ResultHandler;
import it.tdlight.jni.TdApi;
public final class Handler {
private final ResultHandler resultHandler;
public final class Handler<R extends TdApi.Object> {
private final ResultHandler<R> resultHandler;
private final ExceptionHandler exceptionHandler;
public Handler(ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
public Handler(ResultHandler<R> resultHandler, ExceptionHandler exceptionHandler) {
this.resultHandler = resultHandler;
this.exceptionHandler = exceptionHandler;
}
public ResultHandler getResultHandler() {
public ResultHandler<R> getResultHandler() {
return resultHandler;
}

View File

@ -8,7 +8,6 @@ import it.tdlight.common.UpdatesHandler;
import it.tdlight.jni.TdApi;
import it.tdlight.jni.TdApi.Error;
import it.tdlight.jni.TdApi.Function;
import it.tdlight.jni.TdApi.Object;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.Objects;
@ -24,13 +23,13 @@ public final class InternalClient implements ClientEventsHandler, TelegramClient
private static final Marker TG_MARKER = MarkerFactory.getMarker("TG");
private static final Logger logger = LoggerFactory.getLogger(TelegramClient.class);
private final ConcurrentHashMap<Long, Handler> handlers = new ConcurrentHashMap<Long, Handler>();
private final ConcurrentHashMap<Long, Handler<?>> handlers = new ConcurrentHashMap<>();
private final Thread shutdownHook = new Thread(this::onJVMShutdown);
private volatile Integer clientId = null;
private final InternalClientManager clientManager;
private Handler updateHandler;
private Handler<TdApi.Update> updateHandler;
private MultiHandler updatesHandler;
private ExceptionHandler defaultExceptionHandler;
@ -47,10 +46,10 @@ public final class InternalClient implements ClientEventsHandler, TelegramClient
}
@Override
public void handleEvents(boolean isClosed, long[] eventIds, Object[] events) {
public void handleEvents(boolean isClosed, long[] eventIds, TdApi.Object[] events) {
if (updatesHandler != null) {
LongArrayList idsToFilter = new LongArrayList(eventIds);
ObjectArrayList<Object> eventsToFilter = new ObjectArrayList<>(events);
ObjectArrayList<TdApi.Object> eventsToFilter = new ObjectArrayList<>(events);
for (int i = eventIds.length - 1; i >= 0; i--) {
if (eventIds[i] != 0) {
@ -58,9 +57,9 @@ public final class InternalClient implements ClientEventsHandler, TelegramClient
eventsToFilter.remove(i);
long eventId = eventIds[i];
Object event = events[i];
TdApi.Object event = events[i];
Handler handler = handlers.remove(eventId);
Handler<?> handler = handlers.remove(eventId);
handleResponse(eventId, event, handler);
}
}
@ -90,9 +89,7 @@ public final class InternalClient implements ClientEventsHandler, TelegramClient
} catch (IllegalStateException ignored) {
logger.trace(TG_MARKER, "Can't remove shutdown hook because the JVM is already shutting down");
}
handlers.forEach((eventId, handler) -> {
handleResponse(eventId, new Error(500, "Instance closed"), handler);
});
handlers.forEach((eventId, handler) -> handleResponse(eventId, new Error(500, "Instance closed"), handler));
handlers.clear();
logger.info(TG_MARKER, "Client closed {}", clientId);
}
@ -100,7 +97,7 @@ public final class InternalClient implements ClientEventsHandler, TelegramClient
/**
* Handles only a response (not an update!)
*/
private void handleResponse(long eventId, Object event, Handler handler) {
private void handleResponse(long eventId, TdApi.Object event, Handler<?> handler) {
if (handler != null) {
try {
handler.getResultHandler().onResult(event);
@ -115,10 +112,10 @@ public final class InternalClient implements ClientEventsHandler, TelegramClient
/**
* Handles a response or an update
*/
private void handleEvent(long eventId, Object event) {
private void handleEvent(long eventId, TdApi.Object event) {
logger.trace(TG_MARKER, "Received response {}: {}", eventId, event);
if (updatesHandler != null || updateHandler == null) throw new IllegalStateException();
Handler handler = eventId == 0 ? updateHandler : handlers.remove(eventId);
Handler<?> handler = eventId == 0 ? updateHandler : handlers.remove(eventId);
handleResponse(eventId, event, handler);
}
@ -144,10 +141,10 @@ public final class InternalClient implements ClientEventsHandler, TelegramClient
}
@Override
public void initialize(ResultHandler updateHandler,
public void initialize(ResultHandler<TdApi.Update> updateHandler,
ExceptionHandler updateExceptionHandler,
ExceptionHandler defaultExceptionHandler) {
this.updateHandler = new Handler(updateHandler, updateExceptionHandler);
this.updateHandler = new Handler<>(updateHandler, updateExceptionHandler);
this.updatesHandler = null;
this.defaultExceptionHandler = defaultExceptionHandler;
createAndRegisterClient();
@ -164,25 +161,27 @@ public final class InternalClient implements ClientEventsHandler, TelegramClient
}
@Override
public void send(Function query, ResultHandler resultHandler, ExceptionHandler exceptionHandler) {
public <R extends TdApi.Object> void send(Function<R> query, ResultHandler<R> resultHandler,
ExceptionHandler exceptionHandler) {
logger.trace(TG_MARKER, "Trying to send {}", query);
if (isClosedAndMaybeThrow(query)) {
resultHandler.onResult(new TdApi.Ok());
}
if (clientId == null) {
ExceptionHandler handler = exceptionHandler == null ? defaultExceptionHandler : exceptionHandler;
handler.onException(new IllegalStateException("Can't send a request to TDLib before calling \"initialize\" function!"));
handler.onException(new IllegalStateException(
"Can't send a request to TDLib before calling \"initialize\" function!"));
return;
}
long queryId = clientManager.getNextQueryId();
if (resultHandler != null) {
handlers.put(queryId, new Handler(resultHandler, exceptionHandler));
handlers.put(queryId, new Handler<>(resultHandler, exceptionHandler));
}
NativeClientAccess.send(clientId, queryId, query);
}
@Override
public Object execute(Function query) {
public <R extends TdApi.Object> TdApi.Object execute(Function<R> query) {
logger.trace(TG_MARKER, "Trying to execute {}", query);
if (isClosedAndMaybeThrow(query)) {
return new TdApi.Ok();
@ -206,7 +205,7 @@ public final class InternalClient implements ClientEventsHandler, TelegramClient
* @param function function used to check if the check will be enforced or not. Can be null
* @return true if closed
*/
private boolean isClosedAndMaybeThrow(Function function) {
private boolean isClosedAndMaybeThrow(Function<?> function) {
boolean closed = isClosed.get();
if (closed) {
if (function != null && function.getConstructor() == TdApi.Close.CONSTRUCTOR) {

View File

@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -30,13 +31,13 @@ public final class InternalReactiveClient implements ClientEventsHandler, Reacti
private static final Marker TG_MARKER = MarkerFactory.getMarker("TG");
private static final Logger logger = LoggerFactory.getLogger(InternalReactiveClient.class);
private static final Handler EMPTY_HANDLER = new Handler(r -> {}, ex -> {});
private static final Handler<?> EMPTY_HANDLER = new Handler<>(r -> {}, ex -> {});
private final ConcurrentHashMap<Long, Handler> handlers = new ConcurrentHashMap<>();
private final ConcurrentHashMap<Long, Handler<?>> handlers = new ConcurrentHashMap<>();
private final Set<Long> timedOutHandlers = new ConcurrentHashMap<Long, Object>().keySet(new Object());
private final ScheduledExecutorService timers = Executors.newSingleThreadScheduledExecutor();
private final ExceptionHandler defaultExceptionHandler;
private final Handler updateHandler;
private final Handler<TdApi.Update> updateHandler;
private final Thread shutdownHook = new Thread(this::onJVMShutdown);
@ -48,7 +49,7 @@ public final class InternalReactiveClient implements ClientEventsHandler, Reacti
public InternalReactiveClient(InternalClientManager clientManager) {
this.clientManager = clientManager;
this.updateHandler = new Handler(this::onUpdateFromHandler, this::onUpdateException);
this.updateHandler = new Handler<>(this::onUpdateFromHandler, this::onUpdateException);
this.defaultExceptionHandler = this::onDefaultException;
Runtime.getRuntime().addShutdownHook(shutdownHook);
}
@ -105,7 +106,7 @@ public final class InternalReactiveClient implements ClientEventsHandler, Reacti
/**
* Handles only a response (not an update!)
*/
private void handleResponse(long eventId, TdApi.Object event, Handler handler) {
private void handleResponse(long eventId, TdApi.Object event, Handler<?> handler) {
if (handler != null) {
try {
if (eventId == 0) {
@ -137,7 +138,7 @@ public final class InternalReactiveClient implements ClientEventsHandler, Reacti
* Handles a response or an update
*/
private void handleEvent(long eventId, TdApi.Object event) {
Handler handler = eventId == 0 ? updateHandler : handlers.remove(eventId);
Handler<?> handler = eventId == 0 ? updateHandler : handlers.remove(eventId);
handleResponse(eventId, event, handler);
}
@ -151,7 +152,6 @@ public final class InternalReactiveClient implements ClientEventsHandler, Reacti
}
}
@SuppressWarnings({"ReactiveStreamsSubscriberImplementation", "Convert2Diamond"})
public void createAndRegisterClient() {
if (clientId != null) {
throw new UnsupportedOperationException("Can't initialize the same client twice!");
@ -164,7 +164,7 @@ public final class InternalReactiveClient implements ClientEventsHandler, Reacti
}
@Override
public Publisher<TdApi.Object> send(Function query, Duration responseTimeout) {
public <R extends TdApi.Object> Publisher<TdApi.Object> send(Function<R> query, Duration responseTimeout) {
return subscriber -> {
Subscription subscription = new Subscription() {
@ -202,7 +202,7 @@ public final class InternalReactiveClient implements ClientEventsHandler, Reacti
}
}, responseTimeout.toMillis(), TimeUnit.MILLISECONDS);
handlers.put(queryId, new Handler(result -> {
handlers.put(queryId, new Handler<>(result -> {
logger.trace(TG_MARKER,
"Client {} is replying the query id {}: request: {} result: {}",
clientId,
@ -243,7 +243,7 @@ public final class InternalReactiveClient implements ClientEventsHandler, Reacti
}
@Override
public TdApi.Object execute(Function query) {
public <R extends TdApi.Object> TdApi.Object execute(Function<R> query) {
if (isClosedAndMaybeThrow(query)) {
return new TdApi.Ok();
}
@ -324,7 +324,7 @@ public final class InternalReactiveClient implements ClientEventsHandler, Reacti
* @param function function used to check if the check will be enforced or not. Can be null
* @return true if closed
*/
private boolean isClosedAndMaybeThrow(Function function) {
private boolean isClosedAndMaybeThrow(Function<?> function) {
boolean closed = alreadyReceivedClosed.get();
if (closed) {
if (function != null && function.getConstructor() == TdApi.Close.CONSTRUCTOR) {

View File

@ -10,11 +10,11 @@ final class NativeClientAccess extends NativeClient {
return NativeClientAccess.createNativeClient();
}
public static TdApi.Object execute(Function function) {
public static <R extends TdApi.Object> TdApi.Object execute(Function<R> function) {
return NativeClientAccess.nativeClientExecute(function);
}
public static void send(int nativeClientId, long eventId, TdApi.Function function) {
public static <R extends TdApi.Object> void send(int nativeClientId, long eventId, TdApi.Function<R> function) {
NativeClientAccess.nativeClientSend(nativeClientId, eventId, function);
}

View File

@ -185,9 +185,10 @@ public final class ResponseReceiver extends Thread implements AutoCloseable {
@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));
it.unimi.dsi.fastutil.Arrays.mergeSort(from, to,
(o1, o2) -> Integer.compare(data[sortedIndices[o1]], data[sortedIndices[o2]]),
new IntSwapper(sortedIndices)
);
return sortedIndices;
}

View File

@ -17,6 +17,8 @@
package it.tdlight.common.utils;
import java.io.IOException;
/**
* An exception that is thrown when the LoadLibrary class fails to load the library.
*/
@ -25,6 +27,18 @@ public final class CantLoadLibrary extends Exception {
* Creates a new CantLoadLibrary exception.
*/
CantLoadLibrary() {
super("FATAL: Init failed when loading TDLib native libraries, execution can't continue");
super("Init failed when loading TDLib native libraries, execution can't continue");
}
public CantLoadLibrary(String message) {
super(message);
}
public CantLoadLibrary(String message, Exception cause) {
super(message, cause);
}
public CantLoadLibrary(Exception cause) {
super(cause);
}
}

View File

@ -73,18 +73,16 @@ public final class LoadLibrary {
Os os = getOs();
if (arch == Arch.UNKNOWN) {
throw (CantLoadLibrary) new CantLoadLibrary().initCause(new IllegalStateException(
"Arch: \"" + System.getProperty("os.arch") + "\" is unknown"));
throw new CantLoadLibrary("Arch: \"" + System.getProperty("os.arch") + "\" is unknown");
}
if (os == Os.UNKNOWN) {
throw (CantLoadLibrary) new CantLoadLibrary().initCause(new IllegalStateException(
"Os: \"" + System.getProperty("os.name") + "\" is unknown"));
throw new CantLoadLibrary("Os: \"" + System.getProperty("os.name") + "\" is unknown");
}
try {
loadJarLibrary(libname, arch, os);
} catch (IOException | CantLoadLibrary | UnsatisfiedLinkError e) {
} catch (CantLoadLibrary | UnsatisfiedLinkError e) {
if (loadSysLibrary(libname)) {
return;
}
@ -102,8 +100,13 @@ public final class LoadLibrary {
return true;
}
private static void loadJarLibrary(String libname, Arch arch, Os os) throws IOException, CantLoadLibrary {
Path tempPath = Files.createDirectories(librariesPath.resolve("version-" + libsVersion).resolve(libname));
private static void loadJarLibrary(String libname, Arch arch, Os os) throws CantLoadLibrary {
Path tempPath;
try {
tempPath = Files.createDirectories(librariesPath.resolve("version-" + libsVersion).resolve(libname));
} catch (IOException e) {
throw new CantLoadLibrary("Can't create temporary files", e);
}
Path tempFile = Paths.get(tempPath.toString(), libname + getExt(os));
Class<?> classForResource = null;
switch (os) {
@ -177,7 +180,7 @@ public final class LoadLibrary {
break;
}
if (classForResource == null) {
throw new IOException("Native libraries for platform " + os + "-" + arch + " not found!");
throw new CantLoadLibrary("Native libraries for platform " + os + "-" + arch + " not found!");
}
InputStream libInputStream;
try {
@ -185,12 +188,20 @@ public final class LoadLibrary {
.getDeclaredMethod("getLibraryAsStream")
.invoke(InputStream.class));
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException | NullPointerException e) {
throw new IOException("Native libraries for platform " + os + "-" + arch + " not found!", e);
throw new CantLoadLibrary("Native libraries for platform " + os + "-" + arch + " not found!", e);
}
if (Files.notExists(tempFile)) {
Files.copy(libInputStream, tempFile);
try {
Files.copy(libInputStream, tempFile);
} catch (IOException e) {
throw new CantLoadLibrary("Can't copy native libraries into temporary files", e);
}
}
try {
libInputStream.close();
} catch (IOException e) {
throw new CantLoadLibrary("Can't load the native libraries", e);
}
libInputStream.close();
System.load(tempFile.toFile().getAbsolutePath());
}
@ -269,19 +280,4 @@ public final class LoadLibrary {
return ".so";
}
}
private static String createPath(String... path) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("/");
for (int i = 0; i < path.length; i++) {
stringBuilder.append(path[i]);
if (i < path.length - 1) {
stringBuilder.append("/");
}
}
return stringBuilder.toString();
}
}

View File

@ -3,6 +3,7 @@ package it.tdlight.common.utils;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.concurrent.locks.LockSupport;
public class SpinWaitSupport {
@ -10,5 +11,7 @@ public class SpinWaitSupport {
}
public static void onSpinWait() {
// park for 10ms
LockSupport.parkNanos(10 * 1000L * 1000L);
}
}

View File

@ -6,10 +6,11 @@ public class NativeClient {
protected static native int createNativeClient();
protected static native void nativeClientSend(int nativeClientId, long eventId, TdApi.Function function);
protected static native <R extends TdApi.Object> void nativeClientSend(int nativeClientId, long eventId,
TdApi.Function<R> function);
protected static native int nativeClientReceive(int[] clientIds, long[] eventIds, TdApi.Object[] events,
double timeout);
protected static native TdApi.Object nativeClientExecute(TdApi.Function function);
protected static native <R extends TdApi.Object> TdApi.Object nativeClientExecute(TdApi.Function<R> function);
}

View File

@ -8,7 +8,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<revision>1.0.0.0-SNAPSHOT</revision>
<api-version>3.3.162</api-version>
<api-version>3.3.163</api-version>
<natives-version>3.3.164</natives-version>
</properties>
<repositories>

View File

@ -8,7 +8,7 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<revision>1.0.0.0-SNAPSHOT</revision>
<api-version>3.3.162</api-version>
<api-version>3.3.163</api-version>
<natives-version>3.3.164</natives-version>
</properties>
<repositories>