✨ feat: Improved search for file status
This commit is contained in:
parent
fe6feeb25b
commit
8086e8a485
5 changed files with 117 additions and 26 deletions
|
|
@ -298,7 +298,7 @@ public class HttpVerticle extends AbstractVerticle {
|
|||
return;
|
||||
}
|
||||
TelegramVerticle telegramVerticle = telegramVerticleOptional.get();
|
||||
telegramVerticle.stop();
|
||||
telegramVerticle.delete();
|
||||
telegramVerticles.remove(telegramVerticle);
|
||||
sessionTelegramVerticles.entrySet().removeIf(e -> e.getValue().equals(telegramVerticle));
|
||||
ctx.end();
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
|
||||
private String rootId;
|
||||
|
||||
private boolean needDelete = false;
|
||||
|
||||
public TelegramRecord telegramRecord;
|
||||
|
||||
static {
|
||||
|
|
@ -95,14 +97,13 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
client = Client.create(telegramUpdateHandler, this::handleException, this::handleException);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if (!this.authorized || this.telegramRecord == null) {
|
||||
File root = FileUtil.file(this.rootPath);
|
||||
if (root.exists()) {
|
||||
FileUtil.del(root);
|
||||
}
|
||||
}
|
||||
public void delete() {
|
||||
this.execute(new TdApi.Close())
|
||||
.onSuccess(r -> {
|
||||
log.info("[%s] Telegram account closed".formatted(this.getRootId()));
|
||||
this.needDelete = true;
|
||||
})
|
||||
.onFailure(e -> log.error("[%s] Failed to close telegram account: %s".formatted(this.getRootId(), e.getMessage())));
|
||||
}
|
||||
|
||||
public boolean check() {
|
||||
|
|
@ -192,19 +193,30 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
}
|
||||
|
||||
public Future<JsonObject> getChatFiles(long chatId, MultiMap filter) {
|
||||
TdApi.SearchChatMessages searchChatMessages = new TdApi.SearchChatMessages();
|
||||
searchChatMessages.chatId = chatId;
|
||||
searchChatMessages.query = filter.get("search");
|
||||
searchChatMessages.fromMessageId = Convert.toLong(filter.get("fromMessageId"), 0L);
|
||||
searchChatMessages.offset = Convert.toInt(filter.get("offset"), 0);
|
||||
searchChatMessages.limit = Convert.toInt(filter.get("limit"), 20);
|
||||
searchChatMessages.filter = TdApiHelp.getSearchMessagesFilter(filter.get("type"));
|
||||
String status = filter.get("status");
|
||||
if (Arrays.asList("downloading", "paused", "completed", "error").contains(status)) {
|
||||
return DataVerticle.fileRepository.getFiles(chatId, filter)
|
||||
.map(tuple -> new JsonObject()
|
||||
.put("files", tuple.v1)
|
||||
.put("nextFromMessageId", tuple.v2)
|
||||
.put("count", tuple.v3)
|
||||
.put("size", tuple.v1.size())
|
||||
);
|
||||
} else {
|
||||
TdApi.SearchChatMessages searchChatMessages = new TdApi.SearchChatMessages();
|
||||
searchChatMessages.chatId = chatId;
|
||||
searchChatMessages.query = filter.get("search");
|
||||
searchChatMessages.fromMessageId = Convert.toLong(filter.get("fromMessageId"), 0L);
|
||||
searchChatMessages.offset = Convert.toInt(filter.get("offset"), 0);
|
||||
searchChatMessages.limit = Convert.toInt(filter.get("limit"), 20);
|
||||
searchChatMessages.filter = TdApiHelp.getSearchMessagesFilter(filter.get("type"));
|
||||
|
||||
return this.execute(searchChatMessages)
|
||||
.compose(foundChatMessages ->
|
||||
DataVerticle.fileRepository.getFilesByUniqueId(TdApiHelp.getFileUniqueIds(Arrays.asList(foundChatMessages.messages)))
|
||||
.map(fileRecords -> Tuple.tuple(foundChatMessages, fileRecords)))
|
||||
.compose(this::convertFiles);
|
||||
return this.execute(searchChatMessages)
|
||||
.compose(foundChatMessages ->
|
||||
DataVerticle.fileRepository.getFilesByUniqueId(TdApiHelp.getFileUniqueIds(Arrays.asList(foundChatMessages.messages)))
|
||||
.map(fileRecords -> Tuple.tuple(foundChatMessages, fileRecords)))
|
||||
.compose(r -> this.convertFiles(r, filter));
|
||||
}
|
||||
}
|
||||
|
||||
public Future<JsonObject> getChatFilesCount(long chatId) {
|
||||
|
|
@ -394,10 +406,10 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
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;
|
||||
}
|
||||
// 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);
|
||||
|
|
@ -512,6 +524,13 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
case TdApi.AuthorizationStateClosing.CONSTRUCTOR:
|
||||
break;
|
||||
case TdApi.AuthorizationStateClosed.CONSTRUCTOR:
|
||||
if (needDelete) {
|
||||
File root = FileUtil.file(this.rootPath);
|
||||
if (root.exists()) {
|
||||
FileUtil.del(root);
|
||||
}
|
||||
log.info("[%s] Telegram account deleted".formatted(this.getRootId()));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log.warn("[%s] Unsupported authorization state received:%s".formatted(this.getRootId(), authorizationState));
|
||||
|
|
@ -586,9 +605,10 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
));
|
||||
}
|
||||
|
||||
private Future<JsonObject> convertFiles(Tuple2<TdApi.FoundChatMessages, Map<String, FileRecord>> tuple) {
|
||||
private Future<JsonObject> convertFiles(Tuple2<TdApi.FoundChatMessages, Map<String, FileRecord>> tuple, MultiMap filter) {
|
||||
TdApi.FoundChatMessages foundChatMessages = tuple.v1;
|
||||
Map<String, FileRecord> fileRecords = tuple.v2;
|
||||
boolean searchIdle = Objects.equals(filter.get("status"), FileRecord.DownloadStatus.idle.name());
|
||||
|
||||
return DataVerticle.settingRepository.<Boolean>getByKey(SettingKey.uniqueOnly)
|
||||
.map(uniqueOnly -> {
|
||||
|
|
@ -613,6 +633,10 @@ public class TelegramVerticle extends AbstractVerticle {
|
|||
} else {
|
||||
fileRecord = fileRecord.withSourceField(source.id(), source.downloadedSize());
|
||||
}
|
||||
if (searchIdle && !Objects.equals(fileRecord.downloadStatus(), FileRecord.DownloadStatus.idle.name())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//TODO Processing of the same file under different accounts
|
||||
|
||||
JsonObject fileObject = JsonObject.mapFrom(fileRecord);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package telegram.files.repository;
|
||||
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.MultiMap;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import org.jooq.lambda.tuple.Tuple3;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -13,6 +15,8 @@ public interface FileRepository {
|
|||
|
||||
Future<Map<Integer, FileRecord>> getFiles(long chatId, List<Integer> fileIds);
|
||||
|
||||
Future<Tuple3<List<FileRecord>, Long, Long>> getFiles(long chatId, MultiMap filter);
|
||||
|
||||
Future<Map<String, FileRecord>> getFilesByUniqueId(List<String> uniqueIds);
|
||||
|
||||
Future<FileRecord> getByPrimaryKey(int fileId, String uniqueId);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
package telegram.files.repository.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.IterUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.log.Log;
|
||||
import cn.hutool.log.LogFactory;
|
||||
import io.vertx.core.Future;
|
||||
import io.vertx.core.MultiMap;
|
||||
import io.vertx.core.json.JsonObject;
|
||||
import io.vertx.jdbcclient.JDBCPool;
|
||||
import io.vertx.sqlclient.templates.SqlTemplate;
|
||||
import org.jooq.lambda.tuple.Tuple;
|
||||
import org.jooq.lambda.tuple.Tuple3;
|
||||
import telegram.files.repository.FileRecord;
|
||||
import telegram.files.repository.FileRepository;
|
||||
|
||||
|
|
@ -84,6 +89,60 @@ public class FileRepositoryImpl implements FileRepository {
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Tuple3<List<FileRecord>, Long, Long>> getFiles(long chatId, MultiMap filter) {
|
||||
String status = filter.get("status");
|
||||
String search = filter.get("search");
|
||||
Long fromMessageId = Convert.toLong(filter.get("fromMessageId"), 0L);
|
||||
String type = filter.get("type");
|
||||
|
||||
String whereClause = "chat_id = #{chatId}";
|
||||
Map<String, Object> params = MapUtil.of("chatId", chatId);
|
||||
if (StrUtil.isNotBlank(status)) {
|
||||
whereClause += " AND download_status = #{status}";
|
||||
params.put("status", status);
|
||||
}
|
||||
if (StrUtil.isNotBlank(search)) {
|
||||
whereClause += " AND (file_name LIKE #{search} OR caption LIKE #{search})";
|
||||
params.put("search", "%%" + search + "%%");
|
||||
}
|
||||
if (fromMessageId > 0) {
|
||||
whereClause += " AND message_id > #{fromMessageId}";
|
||||
params.put("fromMessageId", fromMessageId);
|
||||
}
|
||||
if (StrUtil.isNotBlank(type)) {
|
||||
if (Objects.equals(type, "media")) {
|
||||
whereClause += " AND type IN ('photo', 'video')";
|
||||
} else {
|
||||
whereClause += " AND type = #{type}";
|
||||
params.put("type", type);
|
||||
}
|
||||
}
|
||||
return Future.all(
|
||||
SqlTemplate
|
||||
.forQuery(pool, """
|
||||
SELECT * FROM file_record WHERE %s ORDER BY date DESC
|
||||
""".formatted(whereClause))
|
||||
.mapTo(FileRecord.ROW_MAPPER)
|
||||
.execute(params)
|
||||
.onFailure(err -> log.error("Failed to get file record: %s".formatted(err.getMessage())))
|
||||
.map(IterUtil::toList)
|
||||
,
|
||||
SqlTemplate
|
||||
.forQuery(pool, """
|
||||
SELECT COUNT(*) FROM file_record WHERE %s
|
||||
""".formatted(whereClause))
|
||||
.mapTo(rs -> rs.getLong(0))
|
||||
.execute(params)
|
||||
.onFailure(err -> log.error("Failed to get file record count: %s".formatted(err.getMessage())))
|
||||
.map(rs -> rs.size() > 0 ? rs.iterator().next() : 0L)
|
||||
).map(r -> {
|
||||
List<FileRecord> fileRecords = r.resultAt(0);
|
||||
long nextFromMessageId = CollUtil.isEmpty(fileRecords) ? 0 : fileRecords.getLast().messageId();
|
||||
return Tuple.tuple(fileRecords, nextFromMessageId, r.resultAt(1));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Future<Map<String, FileRecord>> getFilesByUniqueId(List<String> uniqueIds) {
|
||||
uniqueIds = uniqueIds.stream()
|
||||
|
|
|
|||
|
|
@ -60,6 +60,10 @@ Cookie: {{tf}}
|
|||
GET http://{{server}}/telegram/{{telegramId}}/chat/{{chatId}}/files?fromMessageId=0&type=media&status=all
|
||||
Cookie: {{tf}}
|
||||
|
||||
### Get download completed chat files
|
||||
GET http://{{server}}/telegram/{{telegramId}}/chat/{{chatId}}/files?fromMessageId=0&type=media&status=completed
|
||||
Cookie: {{tf}}
|
||||
|
||||
### Get chat files count
|
||||
GET http://{{server}}/telegram/{{telegramId}}/chat/{{chatId}}/files/count
|
||||
Cookie: {{tf}}
|
||||
|
|
|
|||
Loading…
Reference in a new issue