✨ feat: Support remove file after downloaded
This commit is contained in:
parent
c30e318186
commit
1575a84a9b
5 changed files with 91 additions and 10 deletions
|
|
@ -155,6 +155,7 @@ public class HttpVerticle extends AbstractVerticle {
|
||||||
router.post("/file/start-download-multiple").handler(this::handleFileStartDownloadMultiple);
|
router.post("/file/start-download-multiple").handler(this::handleFileStartDownloadMultiple);
|
||||||
router.post("/file/cancel-download").handler(this::handleFileCancelDownload);
|
router.post("/file/cancel-download").handler(this::handleFileCancelDownload);
|
||||||
router.post("/file/toggle-pause-download").handler(this::handleFileTogglePauseDownload);
|
router.post("/file/toggle-pause-download").handler(this::handleFileTogglePauseDownload);
|
||||||
|
router.post("/file/remove").handler(this::handleFileRemove);
|
||||||
router.post("/file/auto-download").handler(this::handleAutoDownload);
|
router.post("/file/auto-download").handler(this::handleAutoDownload);
|
||||||
|
|
||||||
router.route()
|
router.route()
|
||||||
|
|
@ -673,6 +674,24 @@ public class HttpVerticle extends AbstractVerticle {
|
||||||
.onFailure(ctx::fail);
|
.onFailure(ctx::fail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleFileRemove(RoutingContext ctx) {
|
||||||
|
TelegramVerticle telegramVerticle = getTelegramVerticle(ctx);
|
||||||
|
if (telegramVerticle == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject jsonObject = ctx.body().asJsonObject();
|
||||||
|
Integer fileId = jsonObject.getInteger("fileId");
|
||||||
|
if (fileId == null) {
|
||||||
|
ctx.fail(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
telegramVerticle.removeFile(fileId)
|
||||||
|
.onSuccess(r -> ctx.end())
|
||||||
|
.onFailure(ctx::fail);
|
||||||
|
}
|
||||||
|
|
||||||
private void handleAutoDownload(RoutingContext ctx) {
|
private void handleAutoDownload(RoutingContext ctx) {
|
||||||
TelegramVerticle telegramVerticle = getTelegramVerticle(ctx);
|
TelegramVerticle telegramVerticle = getTelegramVerticle(ctx);
|
||||||
if (telegramVerticle == null) {
|
if (telegramVerticle == null) {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ import cn.hutool.log.Log;
|
||||||
import cn.hutool.log.LogFactory;
|
import cn.hutool.log.LogFactory;
|
||||||
import io.vertx.core.AbstractVerticle;
|
import io.vertx.core.AbstractVerticle;
|
||||||
import io.vertx.core.Future;
|
import io.vertx.core.Future;
|
||||||
import io.vertx.core.MultiMap;
|
|
||||||
import io.vertx.core.Promise;
|
import io.vertx.core.Promise;
|
||||||
import io.vertx.core.impl.NoStackTraceException;
|
import io.vertx.core.impl.NoStackTraceException;
|
||||||
import io.vertx.core.json.Json;
|
import io.vertx.core.json.Json;
|
||||||
|
|
@ -452,6 +451,40 @@ public class TelegramVerticle extends AbstractVerticle {
|
||||||
.mapEmpty();
|
.mapEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Future<Void> removeFile(Integer fileId) {
|
||||||
|
return client.execute(new TdApi.GetFile(fileId))
|
||||||
|
.compose(file -> DataVerticle.fileRepository
|
||||||
|
.getByUniqueId(file.remote.uniqueId)
|
||||||
|
.map(fileRecord -> Tuple.tuple(file, fileRecord))
|
||||||
|
)
|
||||||
|
.compose(tuple2 -> {
|
||||||
|
TdApi.File file = tuple2.v1;
|
||||||
|
FileRecord fileRecord = tuple2.v2;
|
||||||
|
if (fileRecord == null) {
|
||||||
|
return Future.failedFuture("File not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileRecord.isTransferStatus(FileRecord.TransferStatus.completed)) {
|
||||||
|
if (FileUtil.del(fileRecord.localPath())) {
|
||||||
|
log.debug("[%s] Remove file success: %s".formatted(this.getRootId(), fileRecord.localPath()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.local != null && StrUtil.isNotBlank(file.local.path)) {
|
||||||
|
return client.execute(new TdApi.DeleteFile(fileId))
|
||||||
|
.map(file);
|
||||||
|
}
|
||||||
|
return Future.succeededFuture(file);
|
||||||
|
})
|
||||||
|
.compose(file -> DataVerticle.fileRepository.deleteByUniqueId(file.remote.uniqueId).map(file))
|
||||||
|
.onSuccess(file -> sendEvent(EventPayload.build(EventPayload.TYPE_FILE_STATUS, new JsonObject()
|
||||||
|
.put("fileId", fileId)
|
||||||
|
.put("uniqueId", file.remote.uniqueId)
|
||||||
|
.put("removed", true)
|
||||||
|
)))
|
||||||
|
.mapEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
public Future<Void> toggleAutoDownload(Long chatId, JsonObject params) {
|
public Future<Void> toggleAutoDownload(Long chatId, JsonObject params) {
|
||||||
return DataVerticle.settingRepository.<SettingAutoRecords>getByKey(SettingKey.autoDownload)
|
return DataVerticle.settingRepository.<SettingAutoRecords>getByKey(SettingKey.autoDownload)
|
||||||
.compose(settingAutoRecords -> {
|
.compose(settingAutoRecords -> {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { type DownloadStatus, type TelegramFile } from "@/lib/types";
|
import { type DownloadStatus, type TelegramFile } from "@/lib/types";
|
||||||
import { useFileControl } from "@/hooks/use-file-control";
|
import { useFileControl } from "@/hooks/use-file-control";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { ArrowDown, Loader2, Pause, SquareX, StepForward } from "lucide-react";
|
import {ArrowDown, FileX, Loader2, Pause, SquareX, StepForward} from "lucide-react";
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
TooltipContent,
|
TooltipContent,
|
||||||
|
|
@ -52,13 +52,9 @@ export default function FileControl({
|
||||||
!hovered &&
|
!hovered &&
|
||||||
(file.downloadStatus === "downloading" || file.downloadStatus === "paused");
|
(file.downloadStatus === "downloading" || file.downloadStatus === "paused");
|
||||||
|
|
||||||
const { start, starting, togglePause, togglingPause, cancel, cancelling } =
|
const { start, starting, togglePause, togglingPause, cancel, cancelling, remove, removing } =
|
||||||
useFileControl(file);
|
useFileControl(file);
|
||||||
|
|
||||||
if (file.downloadStatus === "completed") {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const statusMapping: Record<DownloadStatus, ActionButtonProps[]> = {
|
const statusMapping: Record<DownloadStatus, ActionButtonProps[]> = {
|
||||||
idle: [
|
idle: [
|
||||||
{
|
{
|
||||||
|
|
@ -104,7 +100,14 @@ export default function FileControl({
|
||||||
loading: cancelling,
|
loading: cancelling,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
completed: [],
|
completed: [
|
||||||
|
{
|
||||||
|
onClick: () => remove(file.id),
|
||||||
|
tooltipText: "Remove",
|
||||||
|
icon: <FileX className="h-4 w-4" />,
|
||||||
|
loading: removing,
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const actionButtons = (
|
const actionButtons = (
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,10 @@ export function useFileControl(file: TelegramFile) {
|
||||||
(key, { arg }: { arg: { fileId: number; isPaused: boolean } }) =>
|
(key, { arg }: { arg: { fileId: number; isPaused: boolean } }) =>
|
||||||
POST(key, arg),
|
POST(key, arg),
|
||||||
);
|
);
|
||||||
|
const { trigger: removeFile, isMutating: removing } = useSWRMutation(
|
||||||
|
"/file/remove",
|
||||||
|
(key, { arg }: { arg: { fileId: number } }) => POST(key, arg),
|
||||||
|
);
|
||||||
|
|
||||||
const downloadControl = {
|
const downloadControl = {
|
||||||
cancel: (fileId: number) => {
|
cancel: (fileId: number) => {
|
||||||
|
|
@ -59,9 +63,15 @@ export function useFileControl(file: TelegramFile) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
remove: (fileId: number) => {
|
||||||
|
if (file && file.downloadStatus === "completed") {
|
||||||
|
void removeFile({ fileId });
|
||||||
|
}
|
||||||
|
},
|
||||||
cancelling,
|
cancelling,
|
||||||
starting,
|
starting,
|
||||||
togglingPause,
|
togglingPause,
|
||||||
|
removing,
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,8 @@ export function useFiles(accountId: string, chatId: string) {
|
||||||
{
|
{
|
||||||
fileId: number;
|
fileId: number;
|
||||||
downloadStatus: DownloadStatus;
|
downloadStatus: DownloadStatus;
|
||||||
localPath: string;
|
localPath?: string;
|
||||||
completionDate: number;
|
completionDate?: number;
|
||||||
downloadedSize: number;
|
downloadedSize: number;
|
||||||
transferStatus?: TransferStatus;
|
transferStatus?: TransferStatus;
|
||||||
}
|
}
|
||||||
|
|
@ -89,8 +89,24 @@ export function useFiles(accountId: string, chatId: string) {
|
||||||
completionDate: number;
|
completionDate: number;
|
||||||
downloadedSize: number;
|
downloadedSize: number;
|
||||||
transferStatus?: TransferStatus;
|
transferStatus?: TransferStatus;
|
||||||
|
removed?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (data.removed) {
|
||||||
|
setLatestFileStatus((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[data.uniqueId]: {
|
||||||
|
fileId: data.fileId,
|
||||||
|
downloadStatus: "idle",
|
||||||
|
localPath: undefined,
|
||||||
|
completionDate: undefined,
|
||||||
|
downloadedSize: 0,
|
||||||
|
transferStatus: "idle",
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setLatestFileStatus((prev) => ({
|
setLatestFileStatus((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
[data.uniqueId]: {
|
[data.uniqueId]: {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue