2020-10-13 01:31:32 +02:00
|
|
|
package it.tdlight.common;
|
|
|
|
|
2020-11-15 20:10:54 +01:00
|
|
|
import static it.tdlight.common.InternalClient.clientInitializationLock;
|
|
|
|
|
2020-10-13 23:22:21 +02:00
|
|
|
import it.tdlight.common.utils.IntSwapper;
|
2020-10-13 01:31:32 +02:00
|
|
|
import it.tdlight.jni.TdApi;
|
2020-10-13 18:33:06 +02:00
|
|
|
import it.tdlight.jni.TdApi.Object;
|
|
|
|
import java.util.ArrayList;
|
2020-10-13 01:31:32 +02:00
|
|
|
import java.util.Arrays;
|
2020-11-14 11:12:52 +01:00
|
|
|
import java.util.HashSet;
|
2020-10-13 18:33:06 +02:00
|
|
|
import java.util.List;
|
|
|
|
import java.util.Set;
|
2020-11-14 11:12:52 +01:00
|
|
|
import java.util.concurrent.ConcurrentSkipListSet;
|
2020-10-13 01:31:32 +02:00
|
|
|
import java.util.concurrent.CountDownLatch;
|
2020-10-13 18:33:06 +02:00
|
|
|
import java.util.stream.Collectors;
|
2020-10-13 01:31:32 +02:00
|
|
|
|
|
|
|
public class ResponseReceiver extends Thread implements AutoCloseable {
|
|
|
|
|
2020-10-13 18:33:06 +02:00
|
|
|
private static final boolean USE_OPTIMIZED_DISPATCHER = Boolean.parseBoolean(System.getProperty(
|
|
|
|
"tdlight.dispatcher.use_optimized_dispatcher",
|
|
|
|
"true"
|
|
|
|
));
|
2020-10-13 01:31:32 +02:00
|
|
|
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);
|
2020-11-14 11:12:52 +01:00
|
|
|
private final Set<Integer> registeredClients = new ConcurrentSkipListSet<>();
|
2020-10-14 19:16:21 +02:00
|
|
|
private volatile boolean closeRequested = false;
|
2020-10-13 01:31:32 +02:00
|
|
|
|
|
|
|
|
|
|
|
public ResponseReceiver(EventsHandler eventsHandler) {
|
|
|
|
super("TDLib thread");
|
|
|
|
this.eventsHandler = eventsHandler;
|
|
|
|
|
|
|
|
this.setDaemon(true);
|
|
|
|
|
|
|
|
this.start();
|
|
|
|
}
|
|
|
|
|
2020-11-14 11:12:52 +01:00
|
|
|
@SuppressWarnings({"UnnecessaryLocalVariable"})
|
2020-10-13 01:31:32 +02:00
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
int[] sortIndex;
|
|
|
|
try {
|
2020-11-14 11:12:52 +01:00
|
|
|
while(!closeRequested || !registeredClients.isEmpty()) {
|
2020-10-13 18:33:06 +02:00
|
|
|
int resultsCount;
|
2020-11-15 20:10:54 +01:00
|
|
|
clientInitializationLock.readLock().lock();
|
|
|
|
try {
|
2020-11-15 20:11:37 +01:00
|
|
|
resultsCount = NativeClientAccess.receive(clientIds, eventIds, events, 2.0 /*seconds*/);
|
2020-11-15 20:10:54 +01:00
|
|
|
} finally {
|
|
|
|
clientInitializationLock.readLock().unlock();
|
|
|
|
};
|
2020-10-13 01:31:32 +02:00
|
|
|
|
|
|
|
if (resultsCount <= 0)
|
|
|
|
continue;
|
|
|
|
|
2020-11-14 11:12:52 +01:00
|
|
|
Set<Integer> closedClients = new HashSet<>();
|
2020-10-14 19:16:21 +02:00
|
|
|
|
2020-10-13 18:33:06 +02:00
|
|
|
if (USE_OPTIMIZED_DISPATCHER) {
|
|
|
|
// 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;
|
2020-11-14 11:12:52 +01:00
|
|
|
closedClients.add(clientId);
|
2020-10-13 18:33:06 +02:00
|
|
|
}
|
2020-10-13 01:31:32 +02:00
|
|
|
}
|
|
|
|
}
|
2020-10-13 18:33:06 +02:00
|
|
|
|
|
|
|
eventsHandler.handleClientEvents(clientId, lastClientClosed, clientEventIds, clientEvents);
|
2020-10-13 01:31:32 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 18:33:06 +02:00
|
|
|
if (i < resultsCount) {
|
|
|
|
lastClientId = clientIds[sortIndex[i]];
|
|
|
|
lastClientIdEventsCount = 0;
|
|
|
|
lastClientClosed = false;
|
|
|
|
}
|
2020-10-13 01:31:32 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 03:00:17 +02:00
|
|
|
if (i < resultsCount) {
|
2020-10-13 18:33:06 +02:00
|
|
|
lastClientIdEventsCount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
class Event {
|
|
|
|
|
|
|
|
public final int clientId;
|
|
|
|
public final long eventId;
|
|
|
|
public final Object event;
|
|
|
|
|
|
|
|
public Event(int clientId, long eventId, Object event) {
|
|
|
|
this.clientId = clientId;
|
|
|
|
this.eventId = eventId;
|
|
|
|
this.event = event;
|
2020-10-13 03:00:17 +02:00
|
|
|
}
|
2020-10-13 01:31:32 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 18:33:06 +02:00
|
|
|
List<Event> eventsList = new ArrayList<>(resultsCount);
|
|
|
|
for (int i = 0; i < resultsCount; i++) {
|
|
|
|
eventsList.add(new Event(clientIds[i], eventIds[i], events[i]));
|
|
|
|
}
|
|
|
|
Set<Integer> clientIds = eventsList.stream().map(e -> e.clientId).collect(Collectors.toSet());
|
|
|
|
for (int clientId : clientIds) {
|
|
|
|
List<Event> clientEventsList = eventsList.stream().filter(e -> e.clientId == clientId).collect(Collectors.toList());
|
|
|
|
long[] clientEventIds = new long[clientEventsList.size()];
|
|
|
|
Object[] clientEvents = new Object[clientEventsList.size()];
|
|
|
|
boolean closed = false;
|
|
|
|
for (int i = 0; i < clientEventsList.size(); i++) {
|
|
|
|
Event e = clientEventsList.get(i);
|
|
|
|
clientEventIds[i] = e.eventId;
|
|
|
|
clientEvents[i] = e.event;
|
|
|
|
|
|
|
|
if (e.eventId == 0 && e.event instanceof TdApi.UpdateAuthorizationState) {
|
|
|
|
TdApi.AuthorizationState authorizationState = ((TdApi.UpdateAuthorizationState) e.event).authorizationState;
|
|
|
|
if (authorizationState instanceof TdApi.AuthorizationStateClosed) {
|
|
|
|
closed = true;
|
2020-11-14 11:12:52 +01:00
|
|
|
closedClients.add(clientId);
|
2020-10-13 18:33:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
eventsHandler.handleClientEvents(clientId, closed, clientEventIds, clientEvents);
|
2020-10-13 03:00:17 +02:00
|
|
|
}
|
2020-10-13 01:31:32 +02:00
|
|
|
}
|
2020-10-14 19:16:21 +02:00
|
|
|
|
2020-10-13 18:33:06 +02:00
|
|
|
Arrays.fill(clientIds, 0);
|
|
|
|
Arrays.fill(eventIds, 0);
|
2020-10-13 01:31:32 +02:00
|
|
|
Arrays.fill(events, null);
|
2020-10-14 19:16:21 +02:00
|
|
|
|
2020-11-14 11:12:52 +01:00
|
|
|
if (!closedClients.isEmpty()) {
|
|
|
|
this.registeredClients.addAll(closedClients);
|
2020-10-14 19:16:21 +02:00
|
|
|
}
|
2020-10-13 01:31:32 +02:00
|
|
|
}
|
|
|
|
} 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;
|
|
|
|
}
|
|
|
|
|
2020-11-14 11:12:52 +01:00
|
|
|
public void registerClient(int clientId) {
|
|
|
|
registeredClients.add(clientId);
|
2020-10-14 19:16:21 +02:00
|
|
|
}
|
|
|
|
|
2020-10-13 01:31:32 +02:00
|
|
|
@Override
|
|
|
|
public void close() throws InterruptedException {
|
2020-10-14 19:16:21 +02:00
|
|
|
this.closeRequested = true;
|
2020-10-13 01:31:32 +02:00
|
|
|
this.closeWait.await();
|
|
|
|
}
|
|
|
|
}
|