🐛 fix: Fix the problem of not being able to find chats (#14)

This commit is contained in:
jarvis2f 2025-01-17 10:46:13 +08:00
parent b20834ac70
commit 374ebeea44
7 changed files with 350 additions and 120 deletions

View file

@ -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())));
}

View 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;
}
}
}

View 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));
}
}
}

View 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;
}
}

View file

@ -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;
}

View file

@ -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) {

View file

@ -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>