TransferBot/src/main/java/it/cavallium/TransferUtils.java

161 lines
4.9 KiB
Java

package it.cavallium;
import it.tdlight.jni.TdApi.Chat;
import it.tdlight.jni.TdApi.ChatListMain;
import it.tdlight.jni.TdApi.ChatPosition;
import it.tdlight.jni.TdApi.Chats;
import it.tdlight.jni.TdApi.GetChat;
import it.tdlight.jni.TdApi.GetChats;
import it.tdlight.utils.MonoUtils;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
public class TransferUtils {
public static int chatIdToChatEntityId(long id) {
if (id <= -1000000000000L) {
return (int) (Math.abs(id) - 1000000000000L);
}
if (id < 0) {
return (int) Math.abs(id);
} else {
return (int) Math.abs(id);
}
}
public static long chatEntityIdToChatId(int chatEntityId, TChatType chatType) {
switch (chatType) {
case BASICGROUP:
return -Math.abs(chatEntityId);
case SUPERGROUP:
return -1000000000000L - (long) Math.abs(chatEntityId);
case USER:
return Math.abs(chatEntityId);
default:
throw new UnsupportedOperationException("Unsupported chat id type: " + chatEntityId);
}
}
private static class ChatIdAndOrderOffsets {
private final long chatIdOffset;
private final long orderOffset;
private ChatIdAndOrderOffsets(long chatIdOffset, long orderOffset) {
this.chatIdOffset = chatIdOffset;
this.orderOffset = orderOffset;
}
public long getChatIdOffset() {
return chatIdOffset;
}
public long getOrderOffset() {
return orderOffset;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ChatIdAndOrderOffsets that = (ChatIdAndOrderOffsets) o;
if (chatIdOffset != that.chatIdOffset) {
return false;
}
return orderOffset == that.orderOffset;
}
@Override
public int hashCode() {
int result = (int) (chatIdOffset ^ (chatIdOffset >>> 32));
result = 31 * result + (int) (orderOffset ^ (orderOffset >>> 32));
return result;
}
}
public static Mono<Set<Chat>> getAllHomeChatsSet(TransferClient client) {
return getAllHomeChats(client).collect(Collectors.toSet());
}
/**
* @return flux of home chats. They can repeat themselves
*/
public static Flux<Chat> getAllHomeChats(TransferClient client) {
App.getLogService().append(Level.DEBUG, "Getting the full chat list");
var singleScheduler = Schedulers.newSingle("getallchats");
return Mono
.deferWithContext((context) -> {
var offsets = Objects.requireNonNull(context.<AtomicReference<ChatIdAndOrderOffsets>>get("offsets"));
var offsetsValue = offsets.get();
App.getLogService().append(Level.TRACE, "Requesting GetChats");
return client.<Chats>send(new GetChats(new ChatListMain(),
offsetsValue.getOrderOffset(),
offsetsValue.getChatIdOffset(),
100
))
.flatMap(MonoUtils::orElseThrow)
.publishOn(singleScheduler)
.flatMapMany(chats -> Flux.fromStream(Arrays.stream(chats.chatIds).boxed()))
.flatMap(chatId -> {
App.getLogService().append(Level.TRACE, "Received ChatId: " + chatId);
return client.<Chat>send(new GetChat(chatId))
.publishOn(singleScheduler)
.flatMap(MonoUtils::orElseThrow);
})
.doOnNext(chat -> {
App.getLogService().append(Level.TRACE, "Received Chat: " + chat.toString().replace('\n', ' ').replace(" ", "").replace("\t", ""));
})
.collectList()
.doOnNext(chats -> {
App.getLogService().append(Level.TRACE, "Received Chats: " + chats.toString().replace('\n', ' ').replace(" ", "").replace("\t", ""));
if (!chats.isEmpty()) {
var lastChat = chats.get(chats.size() - 1);
getMainChatListPosition(lastChat.positions).ifPresentOrElse(lastChatPosition -> {
offsets.set(new ChatIdAndOrderOffsets(lastChat.id, lastChatPosition.order));
}, () -> {
offsets.set(new ChatIdAndOrderOffsets(lastChat.id, 0L));
});
} else {
offsets.set(new ChatIdAndOrderOffsets(9223372036854775807L, 0L));
}
})
.filter(chats1 -> !chats1.isEmpty())
.subscriberContext(context);
})
.repeatWhen(nFlux -> nFlux.takeWhile(n -> n > 0))
.flatMap(Flux::fromIterable)
.subscriberContext(ctx -> ctx.put("offsets",
new AtomicReference<>(new ChatIdAndOrderOffsets(0L, 9223372036854775807L))
))
.doOnTerminate(() -> App.getLogService().append(Level.DEBUG, "Home chats retrieved"));
}
private static Optional<ChatPosition> getMainChatListPosition(ChatPosition[] positions) {
for (ChatPosition position : positions) {
if (position.list.getConstructor() == ChatListMain.CONSTRUCTOR) {
return Optional.of(position);
}
}
return Optional.empty();
}
}