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> getAllHomeChatsSet(TransferClient client) { return getAllHomeChats(client).collect(Collectors.toSet()); } /** * @return flux of home chats. They can repeat themselves */ public static Flux 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.>get("offsets")); var offsetsValue = offsets.get(); App.getLogService().append(Level.TRACE, "Requesting GetChats"); return client.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.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 getMainChatListPosition(ChatPosition[] positions) { for (ChatPosition position : positions) { if (position.list.getConstructor() == ChatListMain.CONSTRUCTOR) { return Optional.of(position); } } return Optional.empty(); } }