feat: Improve multiple file download function.

This commit is contained in:
jarvis2f 2024-12-30 13:49:22 +08:00
parent da459e2253
commit 95481b89f0
2 changed files with 94 additions and 14 deletions

View file

@ -13,6 +13,7 @@ import io.vertx.core.http.CookieSameSite;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.healthchecks.HealthCheckHandler;
import io.vertx.ext.healthchecks.HealthChecks;
@ -140,6 +141,7 @@ public class HttpVerticle extends AbstractVerticle {
router.get("/file/preview").handler(this::handleFilePreview);
router.post("/file/start-download").handler(this::handleFileStartDownload);
router.post("/file/start-download-multiple").handler(this::handleFileStartDownloadMultiple);
router.post("/file/cancel-download").handler(this::handleFileCancelDownload);
router.post("/file/toggle-pause-download").handler(this::handleFileTogglePauseDownload);
router.post("/file/auto-download").handler(this::handleAutoDownload);
@ -315,11 +317,11 @@ public class HttpVerticle extends AbstractVerticle {
}
TelegramVerticle telegramVerticle = telegramVerticleOptional.get();
telegramVerticle.close(true)
.onSuccess(r -> {
telegramVerticles.remove(telegramVerticle);
sessionTelegramVerticles.entrySet().removeIf(e -> e.getValue().equals(telegramVerticle));
ctx.end();
});
.onSuccess(r -> {
telegramVerticles.remove(telegramVerticle);
sessionTelegramVerticles.entrySet().removeIf(e -> e.getValue().equals(telegramVerticle));
ctx.end();
});
}
private void handleTelegrams(RoutingContext ctx) {
@ -511,6 +513,36 @@ public class HttpVerticle extends AbstractVerticle {
.onFailure(ctx::fail);
}
private void handleFileStartDownloadMultiple(RoutingContext ctx) {
TelegramVerticle telegramVerticle = getTelegramVerticle(ctx);
if (telegramVerticle == null) {
return;
}
JsonObject jsonObject = ctx.body().asJsonObject();
Long chatId = jsonObject.getLong("chatId");
JsonArray files = jsonObject.getJsonArray("files");
if (chatId == null || CollUtil.isEmpty(files)) {
ctx.fail(400);
return;
}
Future.any(files.stream()
.map(f -> {
JsonObject file = (JsonObject) f;
Long messageId = file.getLong("messageId");
Integer fileId = file.getInteger("fileId");
return telegramVerticle.startDownload(chatId, messageId, fileId);
})
.toList())
.onSuccess(ctx::json)
.onFailure(r -> {
log.error(r, "Failed to start download multiple files");
ctx.json(JsonObject.of("error", "Part of the files failed to start download"));
ctx.response().setStatusCode(400).end();
});
}
private void handleFileCancelDownload(RoutingContext ctx) {
TelegramVerticle telegramVerticle = getTelegramVerticle(ctx);
if (telegramVerticle == null) {

View file

@ -24,6 +24,7 @@ import {
FileAudioIcon,
FileIcon,
ImageIcon,
LoaderCircle,
LoaderPinwheel,
VideoIcon,
} from "lucide-react";
@ -51,6 +52,8 @@ import FileNotFount from "@/components/file-not-found";
import FileExtra from "@/components/file-extra";
import useIsMobile from "@/hooks/use-is-mobile";
import FileStatus from "@/components/file-status";
import useSWRMutation from "swr/mutation";
import { POST } from "@/lib/api";
interface FileListProps {
accountId: string;
@ -112,6 +115,28 @@ export function FileList({ accountId, chatId }: FileListProps) {
);
const { filters, handleFilterChange, isLoading, files, handleLoadMore } =
useFiles(accountId, chatId);
const {
trigger: startDownloadMultiple,
isMutating: startDownloadMultipleMutating,
} = useSWRMutation(
"/file/start-download-multiple",
(
key,
{
arg,
}: {
arg: {
chatId: number;
files: Array<{ messageId: number; fileId: number }>;
};
},
) => POST(key, arg),
{
onSuccess: () => {
setSelectedFiles(new Set());
},
},
);
useEffect(() => {
const observer = new IntersectionObserver(
@ -182,7 +207,13 @@ export function FileList({ accountId, chatId }: FileListProps) {
if (selectedFiles.size === files.length) {
setSelectedFiles(new Set());
} else {
setSelectedFiles(new Set(files.map((file) => file.id)));
setSelectedFiles(
new Set(
files
.filter((file) => file.downloadStatus === "idle")
.map((file) => file.id),
),
);
}
};
@ -296,16 +327,32 @@ export function FileList({ accountId, chatId }: FileListProps) {
<Button
size="sm"
onClick={() => {
//TODO implement download selected
void startDownloadMultiple({
chatId: Number(chatId),
files: Array.from(selectedFiles).map((id) => {
const file = files.find((f) => f.id === id);
return {
messageId: file?.messageId ?? 0,
fileId: file?.id ?? 0,
};
}),
});
}}
disabled={Array.from(selectedFiles).every(
(id) =>
files.find((f) => f.id === id)?.downloadStatus ===
"downloading",
)}
disabled={
selectedFiles.size === 0 || startDownloadMultipleMutating
}
>
<Download className="mr-2 h-4 w-4" />
Download Selected
{startDownloadMultipleMutating ? (
<LoaderCircle
className="mr-2 h-4 w-4 animate-spin"
style={{ strokeWidth: "0.8px" }}
/>
) : (
<>
<Download className="mr-2 h-4 w-4" />
Download Selected
</>
)}
</Button>
</div>
)}
@ -350,6 +397,7 @@ export function FileList({ accountId, chatId }: FileListProps) {
<Checkbox
checked={selectedFiles.has(file.id)}
onCheckedChange={() => handleSelectFile(file.id)}
disabled={file.downloadStatus !== "idle"}
/>
</TableCell>
{columns.map((col) =>