mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-11 05:46:17 +00:00
refactor: improve download initiation and error handling in DownloadManager
This commit is contained in:
@@ -85,8 +85,18 @@ const startGameDownload = async (
|
|||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await DownloadManager.startDownload(download).then(() => {
|
// Save download to DB immediately so UI can show it
|
||||||
return downloadsSublevel.put(gameKey, download);
|
await downloadsSublevel.put(gameKey, download);
|
||||||
|
|
||||||
|
// Start download asynchronously (don't await) to avoid blocking UI
|
||||||
|
// This is especially important for Gofile/Mediafire which make API calls
|
||||||
|
DownloadManager.startDownload(download).catch((err) => {
|
||||||
|
logger.error("Failed to start download after save:", err);
|
||||||
|
// Update download status to error
|
||||||
|
downloadsSublevel.put(gameKey, {
|
||||||
|
...download,
|
||||||
|
status: "error",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const updatedGame = await gamesSublevel.get(gameKey);
|
const updatedGame = await gamesSublevel.get(gameKey);
|
||||||
|
|||||||
@@ -770,21 +770,66 @@ export class DownloadManager {
|
|||||||
|
|
||||||
if (useJsDownloader && isHttp) {
|
if (useJsDownloader && isHttp) {
|
||||||
logger.log("[DownloadManager] Using JS HTTP downloader");
|
logger.log("[DownloadManager] Using JS HTTP downloader");
|
||||||
|
this.downloadingGameId = levelKeys.game(download.shop, download.objectId);
|
||||||
|
|
||||||
|
// Get download options (this includes API calls for Gofile/Mediafire)
|
||||||
|
// We still await this to catch errors, but start actual download async
|
||||||
const options = await this.getJsDownloadOptions(download);
|
const options = await this.getJsDownloadOptions(download);
|
||||||
|
|
||||||
if (!options) {
|
if (!options) {
|
||||||
throw new Error("Failed to get download options for JS downloader");
|
throw new Error("Failed to get download options for JS downloader");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to get file size from HEAD request before starting download
|
||||||
|
// This ensures UI shows file size immediately instead of waiting
|
||||||
|
try {
|
||||||
|
const headResponse = await fetch(options.url, {
|
||||||
|
method: "HEAD",
|
||||||
|
headers: options.headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (headResponse.ok) {
|
||||||
|
const contentLength = headResponse.headers.get("content-length");
|
||||||
|
if (contentLength) {
|
||||||
|
const fileSize = Number.parseInt(contentLength, 10);
|
||||||
|
const downloadId = this.downloadingGameId;
|
||||||
|
const currentDownload = await downloadsSublevel.get(downloadId);
|
||||||
|
if (currentDownload) {
|
||||||
|
await downloadsSublevel.put(downloadId, {
|
||||||
|
...currentDownload,
|
||||||
|
fileSize,
|
||||||
|
});
|
||||||
|
logger.log(
|
||||||
|
`[DownloadManager] Pre-fetched file size: ${fileSize} bytes`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// If HEAD request fails, continue anyway - file size will be known from actual download
|
||||||
|
logger.log(
|
||||||
|
"[DownloadManager] Could not pre-fetch file size, will get from download response"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start download asynchronously (don't await) so UI returns immediately
|
||||||
this.jsDownloader = new JsHttpDownloader();
|
this.jsDownloader = new JsHttpDownloader();
|
||||||
this.usingJsDownloader = true;
|
this.usingJsDownloader = true;
|
||||||
this.downloadingGameId = levelKeys.game(download.shop, download.objectId);
|
|
||||||
|
|
||||||
|
// Start download in background
|
||||||
this.jsDownloader.startDownload(options).catch((err) => {
|
this.jsDownloader.startDownload(options).catch((err) => {
|
||||||
logger.error("[DownloadManager] JS download error:", err);
|
logger.error("[DownloadManager] JS download error:", err);
|
||||||
this.usingJsDownloader = false;
|
this.usingJsDownloader = false;
|
||||||
this.jsDownloader = null;
|
this.jsDownloader = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Poll status immediately after a short delay to get file size from response headers
|
||||||
|
// This ensures UI shows file size quickly instead of waiting for watchDownloads loop (2s interval)
|
||||||
|
setTimeout(() => {
|
||||||
|
this.getDownloadStatusFromJs().catch(() => {
|
||||||
|
// Ignore errors - status will be updated by watchDownloads loop
|
||||||
|
});
|
||||||
|
}, 500);
|
||||||
} else {
|
} else {
|
||||||
logger.log("[DownloadManager] Using Python RPC downloader");
|
logger.log("[DownloadManager] Using Python RPC downloader");
|
||||||
const payload = await this.getDownloadPayload(download);
|
const payload = await this.getDownloadPayload(download);
|
||||||
|
|||||||
Reference in New Issue
Block a user