🐛 fix: Fix the problem of not being able to find chats (#14)
This commit is contained in:
parent
b20834ac70
commit
374ebeea44
7 changed files with 350 additions and 120 deletions
|
|
@ -147,7 +147,7 @@ public class AutoDownloadVerticle extends AbstractVerticle {
|
|||
searchChatMessages.fromMessageId = auto.nextFromMessageId;
|
||||
searchChatMessages.limit = Math.min(MAX_WAITING_LENGTH, 100);
|
||||
searchChatMessages.filter = TdApiHelp.getSearchMessagesFilter(auto.nextFileType);
|
||||
TdApi.FoundChatMessages foundChatMessages = Future.await(telegramVerticle.execute(searchChatMessages)
|
||||
TdApi.FoundChatMessages foundChatMessages = Future.await(telegramVerticle.client.execute(searchChatMessages)
|
||||
.onFailure(r -> log.error("Search chat messages failed! TelegramId: %d ChatId: %d".formatted(auto.telegramId, auto.chatId), r))
|
||||
);
|
||||
if (foundChatMessages == null) {
|
||||
|
|
@ -307,7 +307,7 @@ public class AutoDownloadVerticle extends AbstractVerticle {
|
|||
.flatMap(item -> HttpVerticle.getTelegramVerticle(telegramId))
|
||||
.ifPresent(telegramVerticle -> {
|
||||
if (telegramVerticle.authorized) {
|
||||
telegramVerticle.execute(new TdApi.GetMessage(chatId, messageId))
|
||||
telegramVerticle.client.execute(new TdApi.GetMessage(chatId, messageId))
|
||||
.onSuccess(message -> addWaitingDownloadMessages(telegramId, List.of(message), true))
|
||||
.onFailure(e -> log.error("Auto download fail. Get message failed: %s".formatted(e.getMessage())));
|
||||
}
|
||||
|
|
|
|||
194
api/src/main/java/telegram/files/TelegramChats.java
Normal file
194
api/src/main/java/telegram/files/TelegramChats.java
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
package telegram.files;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.log.Log;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import org.drinkless.tdlib.TdApi;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class TelegramChats {
|
||||
private static final Log log = LogFactory.get();
|
||||
|
||||
private final TelegramClient client;
|
||||
|
||||
private final ConcurrentMap<Long, TdApi.Chat> chats = new ConcurrentHashMap<>();
|
||||
|
||||
private final NavigableSet<OrderedChat> mainChatList = new TreeSet<>();
|
||||
|
||||
private boolean haveFullMainChatList = false;
|
||||
|
||||
public TelegramChats(TelegramClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public List<TdApi.Chat> getMainChatList(Long activatedChatId, String query, int limit) {
|
||||
List<TdApi.Chat> chatList = mainChatList.stream()
|
||||
.map(OrderedChat::chatId)
|
||||
.map(chats::get)
|
||||
.filter(Objects::nonNull)
|
||||
.filter(chat -> StrUtil.isBlank(query) || chat.title.contains(query))
|
||||
.limit(limit)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (activatedChatId != null) {
|
||||
TdApi.Chat activatedChat = chats.get(activatedChatId);
|
||||
if (activatedChat != null && !chatList.contains(activatedChat)) {
|
||||
chatList.addFirst(activatedChat);
|
||||
}
|
||||
}
|
||||
|
||||
return chatList;
|
||||
}
|
||||
|
||||
public void loadMainChatList() {
|
||||
synchronized (mainChatList) {
|
||||
if (!haveFullMainChatList) {
|
||||
// send LoadChats request if there are some unknown chats and have not enough known chats
|
||||
client.execute(new TdApi.LoadChats(new TdApi.ChatListMain(), 100))
|
||||
.onSuccess(object -> {
|
||||
// chats had already been received through updates, let's retry request
|
||||
loadMainChatList();
|
||||
})
|
||||
.onFailure(error -> {
|
||||
if (((TelegramRunException) error).getError().code == 404) {
|
||||
synchronized (mainChatList) {
|
||||
haveFullMainChatList = true;
|
||||
log.debug("Main chat list is loaded, size: %d".formatted(mainChatList.size()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onChatUpdated(TdApi.Object object) {
|
||||
switch (object.getConstructor()) {
|
||||
case TdApi.UpdateNewChat.CONSTRUCTOR: {
|
||||
TdApi.UpdateNewChat updateNewChat = (TdApi.UpdateNewChat) object;
|
||||
TdApi.Chat chat = updateNewChat.chat;
|
||||
synchronized (chat) {
|
||||
chats.put(chat.id, chat);
|
||||
|
||||
TdApi.ChatPosition[] positions = chat.positions;
|
||||
chat.positions = new TdApi.ChatPosition[0];
|
||||
setChatPositions(chat, positions);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatTitle.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatTitle updateChat = (TdApi.UpdateChatTitle) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.title = updateChat.title;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatPhoto.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatPhoto updateChat = (TdApi.UpdateChatPhoto) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.photo = updateChat.photo;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatReadInbox.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatReadInbox updateChat = (TdApi.UpdateChatReadInbox) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.lastReadInboxMessageId = updateChat.lastReadInboxMessageId;
|
||||
chat.unreadCount = updateChat.unreadCount;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatLastMessage.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatLastMessage updateChat = (TdApi.UpdateChatLastMessage) object;
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
chat.lastMessage = updateChat.lastMessage;
|
||||
setChatPositions(chat, updateChat.positions);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TdApi.UpdateChatPosition.CONSTRUCTOR: {
|
||||
TdApi.UpdateChatPosition updateChat = (TdApi.UpdateChatPosition) object;
|
||||
if (updateChat.position.list.getConstructor() != TdApi.ChatListMain.CONSTRUCTOR) {
|
||||
break;
|
||||
}
|
||||
|
||||
TdApi.Chat chat = chats.get(updateChat.chatId);
|
||||
synchronized (chat) {
|
||||
int i;
|
||||
for (i = 0; i < chat.positions.length; i++) {
|
||||
if (chat.positions[i].list.getConstructor() == TdApi.ChatListMain.CONSTRUCTOR) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
TdApi.ChatPosition[] new_positions = new TdApi.ChatPosition[chat.positions.length + (updateChat.position.order == 0 ? 0 : 1) - (i < chat.positions.length ? 1 : 0)];
|
||||
int pos = 0;
|
||||
if (updateChat.position.order != 0) {
|
||||
new_positions[pos++] = updateChat.position;
|
||||
}
|
||||
for (int j = 0; j < chat.positions.length; j++) {
|
||||
if (j != i) {
|
||||
new_positions[pos++] = chat.positions[j];
|
||||
}
|
||||
}
|
||||
assert pos == new_positions.length;
|
||||
|
||||
setChatPositions(chat, new_positions);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setChatPositions(TdApi.Chat chat, TdApi.ChatPosition[] positions) {
|
||||
synchronized (mainChatList) {
|
||||
synchronized (chat) {
|
||||
for (TdApi.ChatPosition position : chat.positions) {
|
||||
if (position.list.getConstructor() == TdApi.ChatListMain.CONSTRUCTOR) {
|
||||
if (!mainChatList.remove(new OrderedChat(chat.id, position))) {
|
||||
log.warn("Chat %d was not found in mainChatList".formatted(chat.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chat.positions = positions;
|
||||
|
||||
for (TdApi.ChatPosition position : chat.positions) {
|
||||
if (position.list.getConstructor() == TdApi.ChatListMain.CONSTRUCTOR) {
|
||||
if (!mainChatList.add(new OrderedChat(chat.id, position))) {
|
||||
log.warn("Chat %d was already in mainChatList".formatted(chat.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private record OrderedChat(long chatId, TdApi.ChatPosition position) implements Comparable<OrderedChat> {
|
||||
|
||||
@Override
|
||||
public int compareTo(OrderedChat o) {
|
||||
if (this.position.order != o.position.order) {
|
||||
return o.position.order < this.position.order ? -1 : 1;
|
||||
}
|
||||
if (this.chatId != o.chatId) {
|
||||
return o.chatId < this.chatId ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof OrderedChat(long id, TdApi.ChatPosition position1)) {
|
||||
return this.chatId == id && this.position.order == position1.order;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
67
api/src/main/java/telegram/files/TelegramClient.java
Normal file
67
api/src/main/java/telegram/files/TelegramClient.java
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
package telegram.files;
|
||||
|
||||
import cn.hutool.core.util.TypeUtil;
|
||||
import cn.hutool.log.Log;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import io.vertx.core.Future;
|
||||
import org.drinkless.tdlib.Client;
|
||||
import org.drinkless.tdlib.TdApi;
|
||||
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
|
||||
public class TelegramClient {
|
||||
private static final Log log = LogFactory.get();
|
||||
|
||||
private Client client;
|
||||
|
||||
private boolean initialized = false;
|
||||
|
||||
static {
|
||||
Client.setLogMessageHandler(0, new LogMessageHandler());
|
||||
|
||||
try {
|
||||
Client.execute(new TdApi.SetLogVerbosityLevel(Config.TELEGRAM_LOG_LEVEL));
|
||||
Client.execute(new TdApi.SetLogStream(new TdApi.LogStreamFile("tdlib.log", 1 << 27, false)));
|
||||
} catch (Client.ExecutionException error) {
|
||||
throw new IOError(new IOException("Write access to the current directory is required"));
|
||||
}
|
||||
}
|
||||
|
||||
public void initialize(Client.ResultHandler updateHandler,
|
||||
Client.ExceptionHandler updateExceptionHandler,
|
||||
Client.ExceptionHandler defaultExceptionHandler) {
|
||||
synchronized (this) {
|
||||
if (!initialized) {
|
||||
client = Client.create(updateHandler, updateExceptionHandler, defaultExceptionHandler);
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <R extends TdApi.Object> Future<R> execute(TdApi.Function<R> method) {
|
||||
log.trace("Execute method: %s".formatted(TypeUtil.getTypeArgument(method.getClass())));
|
||||
if (!initialized) {
|
||||
throw new IllegalStateException("Client is not initialized");
|
||||
}
|
||||
return Future.future(promise -> client.send(method, object -> {
|
||||
if (object.getConstructor() == TdApi.Error.CONSTRUCTOR) {
|
||||
promise.fail(new TelegramRunException((TdApi.Error) object));
|
||||
} else {
|
||||
promise.complete((R) object);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public Client getNativeClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
private static class LogMessageHandler implements Client.LogMessageHandler {
|
||||
@Override
|
||||
public void onLogMessage(int verbosityLevel, String message) {
|
||||
log.debug("TDLib: %s".formatted(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
16
api/src/main/java/telegram/files/TelegramRunException.java
Normal file
16
api/src/main/java/telegram/files/TelegramRunException.java
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package telegram.files;
|
||||
|
||||
import org.drinkless.tdlib.TdApi;
|
||||
|
||||
public class TelegramRunException extends RuntimeException {
|
||||
private final TdApi.Error error;
|
||||
|
||||
public TelegramRunException(TdApi.Error error) {
|
||||
super(error.message);
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public TdApi.Error getError() {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,8 @@ public class TelegramUpdateHandler implements Client.ResultHandler {
|
|||
|
||||
private Consumer<TdApi.UpdateFileDownloads> onFileDownloadsUpdated;
|
||||
|
||||
private Consumer<TdApi.Object> onChatUpdated;
|
||||
|
||||
private Consumer<TdApi.Message> onMessageReceived;
|
||||
|
||||
@Override
|
||||
|
|
@ -40,6 +42,15 @@ public class TelegramUpdateHandler implements Client.ResultHandler {
|
|||
if (onMessageReceived != null) {
|
||||
onMessageReceived.accept(((TdApi.UpdateNewMessage) object).message);
|
||||
}
|
||||
case TdApi.UpdateNewChat.CONSTRUCTOR:
|
||||
case TdApi.UpdateChatTitle.CONSTRUCTOR:
|
||||
case TdApi.UpdateChatPhoto.CONSTRUCTOR:
|
||||
case TdApi.UpdateChatReadInbox.CONSTRUCTOR:
|
||||
case TdApi.UpdateChatLastMessage.CONSTRUCTOR:
|
||||
case TdApi.UpdateChatPosition.CONSTRUCTOR:
|
||||
if (onChatUpdated != null) {
|
||||
onChatUpdated.accept(object);
|
||||
}
|
||||
default:
|
||||
log.trace("Unsupported telegram update: %s".formatted(object));
|
||||
}
|
||||
|
|
@ -57,6 +68,10 @@ public class TelegramUpdateHandler implements Client.ResultHandler {
|
|||
this.onFileDownloadsUpdated = onFileDownloadsUpdated;
|
||||
}
|
||||
|
||||
public void setOnChatUpdated(Consumer<TdApi.Object> onChatUpdated) {
|
||||
this.onChatUpdated = onChatUpdated;
|
||||
}
|
||||
|
||||
public void setOnMessageReceived(Consumer<TdApi.Message> onMessageReceived) {
|
||||
this.onMessageReceived = onMessageReceived;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,25 +13,23 @@ import cn.hutool.core.io.FileUtil;
|
|||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.TypeUtil;
|
||||
import cn.hutool.log.Log;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import io.vertx.core.*;
|
||||
import io.vertx.core.AbstractVerticle;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.MultiMap;
|
||||
import io.vertx.core.Promise;
|
||||
import io.vertx.core.impl.NoStackTraceException;
|
||||
import io.vertx.core.json.Json;
|
||||
import io.vertx.core.json.JsonArray;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import org.drinkless.tdlib.Client;
|
||||
import org.drinkless.tdlib.TdApi;
|
||||
import org.jooq.lambda.tuple.Tuple;
|
||||
import org.jooq.lambda.tuple.Tuple2;
|
||||
import telegram.files.repository.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
|
@ -40,7 +38,9 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
|
||||
private static final Log log = LogFactory.get();
|
||||
|
||||
private Client client;
|
||||
public TelegramClient client;
|
||||
|
||||
private TelegramChats telegramChats;
|
||||
|
||||
public boolean authorized = false;
|
||||
|
||||
|
|
@ -64,17 +64,6 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
|
||||
private long lastFileDownloadEventTime;
|
||||
|
||||
static {
|
||||
Client.setLogMessageHandler(0, new LogMessageHandler());
|
||||
|
||||
try {
|
||||
Client.execute(new TdApi.SetLogVerbosityLevel(Config.TELEGRAM_LOG_LEVEL));
|
||||
Client.execute(new TdApi.SetLogStream(new TdApi.LogStreamFile("tdlib.log", 1 << 27, false)));
|
||||
} catch (Client.ExecutionException error) {
|
||||
throw new IOError(new IOException("Write access to the current directory is required"));
|
||||
}
|
||||
}
|
||||
|
||||
public TelegramVerticle(String rootPath) {
|
||||
this.rootPath = rootPath;
|
||||
}
|
||||
|
|
@ -102,13 +91,16 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
|
||||
@Override
|
||||
public void start(Promise<Void> startPromise) {
|
||||
client = new TelegramClient();
|
||||
telegramChats = new TelegramChats(client);
|
||||
TelegramUpdateHandler telegramUpdateHandler = new TelegramUpdateHandler();
|
||||
telegramUpdateHandler.setOnAuthorizationStateUpdated(this::onAuthorizationStateUpdated);
|
||||
telegramUpdateHandler.setOnFileUpdated(this::onFileUpdated);
|
||||
telegramUpdateHandler.setOnFileDownloadsUpdated(this::onFileDownloadsUpdated);
|
||||
telegramUpdateHandler.setOnChatUpdated(telegramChats::onChatUpdated);
|
||||
telegramUpdateHandler.setOnMessageReceived(this::onMessageReceived);
|
||||
client = Client.create(telegramUpdateHandler, this::handleException, this::handleException);
|
||||
|
||||
client.initialize(telegramUpdateHandler, this::handleException, this::handleException);
|
||||
Future.all(initEventConsumer(), initAvgSpeed())
|
||||
.compose(r -> this.enableProxy(this.proxyName))
|
||||
.onSuccess(r -> startPromise.complete())
|
||||
|
|
@ -122,7 +114,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
}
|
||||
|
||||
public Future<Void> close(boolean needDelete) {
|
||||
return this.execute(new TdApi.Close())
|
||||
return client.execute(new TdApi.Close())
|
||||
.onSuccess(r -> {
|
||||
log.info("[%s] Telegram account closed".formatted(this.getRootId()));
|
||||
this.needDelete = needDelete;
|
||||
|
|
@ -159,7 +151,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
promise.complete(jsonObject);
|
||||
return;
|
||||
}
|
||||
this.execute(new TdApi.GetMe())
|
||||
client.execute(new TdApi.GetMe())
|
||||
.onSuccess(user -> {
|
||||
JsonObject result = new JsonObject()
|
||||
.put("id", Convert.toStr(user.id))
|
||||
|
|
@ -180,42 +172,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
}
|
||||
|
||||
public Future<JsonArray> getChats(Long activatedChatId, String query) {
|
||||
Consumer<TdApi.Chats> insertActivatedChatId = chats -> {
|
||||
if (chats == null || ArrayUtil.isEmpty(chats.chatIds)) {
|
||||
return;
|
||||
}
|
||||
long[] chatIds = chats.chatIds;
|
||||
if (activatedChatId != null && !ArrayUtil.contains(chatIds, activatedChatId)) {
|
||||
chatIds = (long[]) ArrayUtil.insert(chatIds, 0, activatedChatId);
|
||||
chats.chatIds = chatIds;
|
||||
}
|
||||
};
|
||||
|
||||
if (StrUtil.isBlank(query)) {
|
||||
return this.execute(new TdApi.GetChats(new TdApi.ChatListMain(), 10))
|
||||
.map(chats -> {
|
||||
insertActivatedChatId.accept(chats);
|
||||
return chats;
|
||||
})
|
||||
.compose(chats -> Future.all(Arrays.stream(chats.chatIds)
|
||||
.mapToObj(chatId -> this.execute(new TdApi.GetChat(chatId)))
|
||||
.toList())
|
||||
)
|
||||
.map(CompositeFuture::<TdApi.Chat>list)
|
||||
.compose(this::convertChat);
|
||||
} else {
|
||||
return this.execute(new TdApi.SearchChatsOnServer(query, 10))
|
||||
.map(chats -> {
|
||||
insertActivatedChatId.accept(chats);
|
||||
return chats;
|
||||
})
|
||||
.compose(chats -> Future.all(Arrays.stream(chats.chatIds)
|
||||
.mapToObj(chatId -> this.execute(new TdApi.GetChat(chatId)))
|
||||
.toList())
|
||||
)
|
||||
.map(CompositeFuture::<TdApi.Chat>list)
|
||||
.compose(this::convertChat);
|
||||
}
|
||||
return this.convertChat(telegramChats.getMainChatList(activatedChatId, query, 100));
|
||||
}
|
||||
|
||||
public Future<JsonObject> getChatFiles(long chatId, MultiMap filter) {
|
||||
|
|
@ -224,7 +181,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
return DataVerticle.fileRepository.getFiles(chatId, filter)
|
||||
.compose(r -> {
|
||||
long[] messageIds = r.v1.stream().mapToLong(FileRecord::messageId).toArray();
|
||||
return this.execute(new TdApi.GetMessages(chatId, messageIds))
|
||||
return client.execute(new TdApi.GetMessages(chatId, messageIds))
|
||||
.map(m -> {
|
||||
Map<Long, TdApi.Message> messageMap = Arrays.stream(m.messages)
|
||||
.filter(Objects::nonNull)
|
||||
|
|
@ -261,7 +218,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
|
||||
return (Objects.equals(filter.get("status"), FileRecord.DownloadStatus.idle.name()) ?
|
||||
this.getIdleChatFiles(searchChatMessages, 0) :
|
||||
this.execute(searchChatMessages))
|
||||
client.execute(searchChatMessages))
|
||||
.compose(foundChatMessages ->
|
||||
DataVerticle.fileRepository.getFilesByUniqueId(TdApiHelp.getFileUniqueIds(Arrays.asList(foundChatMessages.messages)))
|
||||
.map(fileRecords -> Tuple.tuple(foundChatMessages, fileRecords)))
|
||||
|
|
@ -274,7 +231,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
// Increase the limit and reduce the number of requests
|
||||
searchChatMessages.limit = 100;
|
||||
}
|
||||
return this.execute(searchChatMessages)
|
||||
return client.execute(searchChatMessages)
|
||||
.compose(foundChatMessages -> {
|
||||
TdApi.Message[] messages = Stream.of(foundChatMessages.messages)
|
||||
.filter(message ->
|
||||
|
|
@ -305,7 +262,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
new TdApi.SearchMessagesFilterVideo(),
|
||||
new TdApi.SearchMessagesFilterAudio(),
|
||||
new TdApi.SearchMessagesFilterDocument())
|
||||
.map(filter -> this.execute(
|
||||
.map(filter -> client.execute(
|
||||
new TdApi.GetChatMessageCount(chatId,
|
||||
filter,
|
||||
0,
|
||||
|
|
@ -331,7 +288,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
if (!(boolean) needToLoadImages) {
|
||||
return Future.failedFuture("Need to load images is disabled");
|
||||
}
|
||||
return this.execute(new TdApi.GetMessage(chatId, messageId));
|
||||
return client.execute(new TdApi.GetMessage(chatId, messageId));
|
||||
})
|
||||
.compose(message -> {
|
||||
TdApiHelp.FileHandler<? extends TdApi.MessageContent> fileHandler = TdApiHelp.getFileHandler(message)
|
||||
|
|
@ -356,7 +313,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
downloadFile.priority = 32;
|
||||
downloadFile.synchronous = true;
|
||||
|
||||
return this.execute(downloadFile)
|
||||
return client.execute(downloadFile)
|
||||
.map(file.id);
|
||||
});
|
||||
});
|
||||
|
|
@ -386,8 +343,8 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
|
||||
public Future<TdApi.File> startDownload(Long chatId, Long messageId, Integer fileId) {
|
||||
return Future.all(
|
||||
this.execute(new TdApi.GetFile(fileId)),
|
||||
this.execute(new TdApi.GetMessage(chatId, messageId))
|
||||
client.execute(new TdApi.GetFile(fileId)),
|
||||
client.execute(new TdApi.GetMessage(chatId, messageId))
|
||||
)
|
||||
.compose(results -> {
|
||||
TdApi.File file = results.resultAt(0);
|
||||
|
|
@ -413,7 +370,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
FileRecord fileRecord = fileHandler.convertFileRecord(telegramRecord.id());
|
||||
return DataVerticle.fileRepository.create(fileRecord)
|
||||
.compose(r ->
|
||||
this.execute(new TdApi.AddFileToDownloads(fileId, chatId, messageId, 32))
|
||||
client.execute(new TdApi.AddFileToDownloads(fileId, chatId, messageId, 32))
|
||||
)
|
||||
.onSuccess(r ->
|
||||
sendHttpEvent(EventPayload.build(EventPayload.TYPE_FILE_STATUS, new JsonObject()
|
||||
|
|
@ -425,7 +382,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
}
|
||||
|
||||
public Future<Void> cancelDownload(Integer fileId) {
|
||||
return this.execute(new TdApi.GetFile(fileId))
|
||||
return client.execute(new TdApi.GetFile(fileId))
|
||||
.compose(file -> DataVerticle.fileRepository
|
||||
.updateFileId(file.id, file.remote.uniqueId)
|
||||
.map(file)
|
||||
|
|
@ -435,10 +392,10 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
return Future.failedFuture("File not started downloading");
|
||||
}
|
||||
|
||||
return this.execute(new TdApi.CancelDownloadFile(fileId, false))
|
||||
return client.execute(new TdApi.CancelDownloadFile(fileId, false))
|
||||
.map(file);
|
||||
})
|
||||
.compose(file -> this.execute(new TdApi.DeleteFile(fileId)).map(file))
|
||||
.compose(file -> client.execute(new TdApi.DeleteFile(fileId)).map(file))
|
||||
.compose(file -> DataVerticle.fileRepository.deleteByUniqueId(file.remote.uniqueId))
|
||||
.onSuccess(r ->
|
||||
sendHttpEvent(EventPayload.build(EventPayload.TYPE_FILE_STATUS, new JsonObject()
|
||||
|
|
@ -449,7 +406,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
}
|
||||
|
||||
public Future<Void> togglePauseDownload(Integer fileId, boolean isPaused) {
|
||||
return this.execute(new TdApi.GetFile(fileId))
|
||||
return client.execute(new TdApi.GetFile(fileId))
|
||||
.compose(file -> DataVerticle.fileRepository
|
||||
.updateFileId(file.id, file.remote.uniqueId)
|
||||
.map(file)
|
||||
|
|
@ -481,7 +438,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
return Future.failedFuture("File is downloading");
|
||||
}
|
||||
|
||||
return this.execute(new TdApi.ToggleDownloadIsPaused(fileId, isPaused));
|
||||
return client.execute(new TdApi.ToggleDownloadIsPaused(fileId, isPaused));
|
||||
})
|
||||
.mapEmpty();
|
||||
}
|
||||
|
|
@ -512,7 +469,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
|
||||
public Future<JsonObject> getDownloadStatistics() {
|
||||
return Future.all(DataVerticle.fileRepository.getDownloadStatistics(this.telegramRecord.id()),
|
||||
this.execute(new TdApi.GetNetworkStatistics())
|
||||
client.execute(new TdApi.GetNetworkStatistics())
|
||||
).map(r -> {
|
||||
JsonObject jsonObject = r.resultAt(0);
|
||||
TdApi.NetworkStatistics networkStatistics = r.resultAt(1);
|
||||
|
|
@ -587,8 +544,8 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
} else {
|
||||
return Future.failedFuture("Unsupported proxy type: %s".formatted(proxy.type));
|
||||
}
|
||||
return edit ? this.execute(new TdApi.EditProxy(tdProxy.id, proxy.server, proxy.port, true, proxyType))
|
||||
: this.execute(new TdApi.AddProxy(proxy.server, proxy.port, true, proxyType));
|
||||
return edit ? client.execute(new TdApi.EditProxy(tdProxy.id, proxy.server, proxy.port, true, proxyType))
|
||||
: client.execute(new TdApi.AddProxy(proxy.server, proxy.port, true, proxyType));
|
||||
})
|
||||
.compose(r -> {
|
||||
if (this.telegramRecord != null) {
|
||||
|
|
@ -611,7 +568,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
|
||||
if (StrUtil.isBlank(toggleProxyName) && StrUtil.isNotBlank(this.proxyName)) {
|
||||
// disable proxy
|
||||
return this.execute(new TdApi.DisableProxy())
|
||||
return client.execute(new TdApi.DisableProxy())
|
||||
.compose(r -> DataVerticle.telegramRepository.update(this.telegramRecord.withProxy(null)))
|
||||
.andThen(r -> {
|
||||
this.proxyName = null;
|
||||
|
|
@ -624,7 +581,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
}
|
||||
|
||||
public Future<TdApi.Proxy> getTdProxy(SettingProxyRecords.Item proxy) {
|
||||
return this.execute(new TdApi.GetProxies())
|
||||
return client.execute(new TdApi.GetProxies())
|
||||
.map(proxies -> Stream.of(proxies.proxies)
|
||||
.filter(proxy::equalsTdProxy)
|
||||
.findFirst()
|
||||
|
|
@ -632,7 +589,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
}
|
||||
|
||||
public Future<TdApi.Proxy> getTdProxy() {
|
||||
return this.execute(new TdApi.GetProxies())
|
||||
return client.execute(new TdApi.GetProxies())
|
||||
.map(proxies -> Stream.of(proxies.proxies)
|
||||
.filter(p -> p.isEnabled)
|
||||
.findFirst()
|
||||
|
|
@ -641,28 +598,10 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
|
||||
public Future<Double> ping() {
|
||||
return this.getTdProxy()
|
||||
.compose(proxy -> this.execute(new TdApi.PingProxy(proxy == null ? 0 : proxy.id)))
|
||||
.compose(proxy -> client.execute(new TdApi.PingProxy(proxy == null ? 0 : proxy.id)))
|
||||
.map(r -> r.seconds);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <R extends TdApi.Object> Future<R> execute(TdApi.Function<R> method) {
|
||||
log.trace("[%s] Execute method: %s".formatted(getRootId(), TypeUtil.getTypeArgument(method.getClass())));
|
||||
return Future.future(promise -> {
|
||||
// if (!authorized) {
|
||||
// promise.fail("Telegram account not found or not authorized");
|
||||
// return;
|
||||
// }
|
||||
client.send(method, object -> {
|
||||
if (object.getConstructor() == TdApi.Error.CONSTRUCTOR) {
|
||||
promise.fail("Execute method failed. " + object);
|
||||
} else {
|
||||
promise.complete((R) object);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public Future<String> execute(String method, Object params) {
|
||||
String code = RandomUtil.randomString(10);
|
||||
log.trace("[%s] Execute code: %s method: %s, params: %s".formatted(getRootId(), code, method, params));
|
||||
|
|
@ -672,7 +611,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
promise.fail("Unsupported method: " + method);
|
||||
return;
|
||||
}
|
||||
client.send(func, object -> {
|
||||
client.getNativeClient().send(func, object -> {
|
||||
log.debug("[%s] Execute: [%s] Receive result: %s".formatted(getRootId(), code, object));
|
||||
handleDefaultResult(object, code);
|
||||
});
|
||||
|
|
@ -786,7 +725,7 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
request.applicationVersion = Start.VERSION;
|
||||
log.trace("[%s] Send SetTdlibParameters: %s".formatted(getRootId(), request));
|
||||
|
||||
client.send(request, this::handleAuthorizationResult);
|
||||
client.execute(request).onSuccess(this::handleAuthorizationResult);
|
||||
break;
|
||||
case TdApi.AuthorizationStateWaitPhoneNumber.CONSTRUCTOR:
|
||||
case TdApi.AuthorizationStateWaitOtherDeviceConfirmation.CONSTRUCTOR:
|
||||
|
|
@ -800,20 +739,17 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
case TdApi.AuthorizationStateReady.CONSTRUCTOR:
|
||||
authorized = true;
|
||||
if (telegramRecord == null) {
|
||||
this.execute(new TdApi.GetMe())
|
||||
client.execute(new TdApi.GetMe())
|
||||
.compose(user ->
|
||||
DataVerticle.telegramRepository.create(new TelegramRecord(user.id, user.firstName, this.rootPath, this.proxyName))
|
||||
)
|
||||
.compose(record -> {
|
||||
telegramRecord = record;
|
||||
return this.execute(new TdApi.LoadChats(new TdApi.ChatListMain(), 10));
|
||||
})
|
||||
.onSuccess(o -> log.info("[%s] %s Authorization Ready".formatted(getRootId(), this.telegramRecord.firstName())))
|
||||
.onFailure(e -> log.error("[%s] Authorization Ready, but failed to create telegram record: %s".formatted(getRootId(), e.getMessage())));
|
||||
} else {
|
||||
log.info("[%s] %s Authorization Ready".formatted(getRootId(), this.telegramRecord.firstName()));
|
||||
}
|
||||
sendHttpEvent(EventPayload.build(EventPayload.TYPE_AUTHORIZATION, authorizationState));
|
||||
telegramChats.loadMainChatList();
|
||||
break;
|
||||
case TdApi.AuthorizationStateLoggingOut.CONSTRUCTOR:
|
||||
break;
|
||||
|
|
@ -839,7 +775,6 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
if (file != null) {
|
||||
String localPath = null;
|
||||
Long completionDate = null;
|
||||
long downloadedSize = file.local == null ? 0 : file.local.downloadedSize;
|
||||
if (file.local != null && file.local.isDownloadingCompleted) {
|
||||
localPath = file.local.path;
|
||||
completionDate = System.currentTimeMillis();
|
||||
|
|
@ -876,14 +811,6 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
);
|
||||
}
|
||||
|
||||
private static class LogMessageHandler implements Client.LogMessageHandler {
|
||||
|
||||
@Override
|
||||
public void onLogMessage(int verbosityLevel, String message) {
|
||||
log.debug("TDLib: %s".formatted(message));
|
||||
}
|
||||
}
|
||||
|
||||
//<-----------------------------convert---------------------------------->
|
||||
|
||||
private Future<JsonArray> convertChat(List<TdApi.Chat> chats) {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export default function ChatSelect({ disabled }: { disabled: boolean }) {
|
|||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
className="w-full md:w-[250px] justify-between"
|
||||
className="w-full justify-between md:w-[250px]"
|
||||
>
|
||||
{selectedChat ? (
|
||||
<div className="flex items-center gap-2">
|
||||
|
|
@ -45,10 +45,15 @@ export default function ChatSelect({ disabled }: { disabled: boolean }) {
|
|||
<AvatarImage
|
||||
src={`data:image/png;base64,${selectedChat.avatar}`}
|
||||
/>
|
||||
<AvatarFallback>{selectedChat.name[0]}</AvatarFallback>
|
||||
<AvatarFallback>
|
||||
{" "}
|
||||
{selectedChat.name[0] ?? selectedChat.id[0]}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<span className="max-w-[170px] overflow-hidden truncate">
|
||||
{selectedChat.name}
|
||||
{(selectedChat.name ?? "").length > 0
|
||||
? selectedChat.name
|
||||
: selectedChat.id}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
|
|
@ -73,7 +78,9 @@ export default function ChatSelect({ disabled }: { disabled: boolean }) {
|
|||
</div>
|
||||
</CommandLoading>
|
||||
)}
|
||||
<CommandEmpty>{!isLoading && chats.length === 0 && "No chat found."}</CommandEmpty>
|
||||
<CommandEmpty>
|
||||
{!isLoading && chats.length === 0 && "No chat found."}
|
||||
</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{chats.map((chat) => (
|
||||
<CommandItem
|
||||
|
|
@ -97,10 +104,14 @@ export default function ChatSelect({ disabled }: { disabled: boolean }) {
|
|||
<AvatarImage
|
||||
src={`data:image/png;base64,${chat.avatar}`}
|
||||
/>
|
||||
<AvatarFallback>{chat.name[0]}</AvatarFallback>
|
||||
<AvatarFallback>
|
||||
{chat.name[0] ?? chat.id[0]}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">{chat.name}</span>
|
||||
<span className="font-medium">
|
||||
{(chat.name ?? "").length > 0 ? chat.name : chat.id}
|
||||
</span>
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{chat.type} • {chat.unreadCount ?? 0} unread
|
||||
</span>
|
||||
|
|
|
|||
Loading…
Reference in a new issue