Reduce cancel lag with non-blocking cleanup in v1.1.25
Some checks are pending
Build and Release / build (push) Waiting to run
Some checks are pending
Build and Release / build (push) Waiting to run
This commit is contained in:
parent
4548d809f9
commit
0f61b0be08
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "real-debrid-downloader",
|
"name": "real-debrid-downloader",
|
||||||
"version": "1.1.24",
|
"version": "1.1.25",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "real-debrid-downloader",
|
"name": "real-debrid-downloader",
|
||||||
"version": "1.1.24",
|
"version": "1.1.25",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"adm-zip": "^0.5.16",
|
"adm-zip": "^0.5.16",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "real-debrid-downloader",
|
"name": "real-debrid-downloader",
|
||||||
"version": "1.1.24",
|
"version": "1.1.25",
|
||||||
"description": "Real-Debrid Downloader Desktop (Electron + React + TypeScript)",
|
"description": "Real-Debrid Downloader Desktop (Electron + React + TypeScript)",
|
||||||
"main": "build/main/main/main.js",
|
"main": "build/main/main/main.js",
|
||||||
"author": "Sucukdeluxe",
|
"author": "Sucukdeluxe",
|
||||||
|
|||||||
@ -2,6 +2,12 @@ import fs from "node:fs";
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { ARCHIVE_TEMP_EXTENSIONS, LINK_ARTIFACT_EXTENSIONS, RAR_SPLIT_RE, SAMPLE_DIR_NAMES, SAMPLE_TOKEN_RE, SAMPLE_VIDEO_EXTENSIONS } from "./constants";
|
import { ARCHIVE_TEMP_EXTENSIONS, LINK_ARTIFACT_EXTENSIONS, RAR_SPLIT_RE, SAMPLE_DIR_NAMES, SAMPLE_TOKEN_RE, SAMPLE_VIDEO_EXTENSIONS } from "./constants";
|
||||||
|
|
||||||
|
async function yieldToLoop(): Promise<void> {
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
setTimeout(resolve, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function isArchiveOrTempFile(filePath: string): boolean {
|
export function isArchiveOrTempFile(filePath: string): boolean {
|
||||||
const lower = filePath.toLowerCase();
|
const lower = filePath.toLowerCase();
|
||||||
const ext = path.extname(lower);
|
const ext = path.extname(lower);
|
||||||
@ -39,6 +45,47 @@ export function cleanupCancelledPackageArtifacts(packageDir: string): number {
|
|||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function cleanupCancelledPackageArtifactsAsync(packageDir: string): Promise<number> {
|
||||||
|
try {
|
||||||
|
await fs.promises.access(packageDir, fs.constants.F_OK);
|
||||||
|
} catch {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let removed = 0;
|
||||||
|
let touched = 0;
|
||||||
|
const stack = [packageDir];
|
||||||
|
while (stack.length > 0) {
|
||||||
|
const current = stack.pop() as string;
|
||||||
|
let entries: fs.Dirent[] = [];
|
||||||
|
try {
|
||||||
|
entries = await fs.promises.readdir(current, { withFileTypes: true });
|
||||||
|
} catch {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const entry of entries) {
|
||||||
|
const full = path.join(current, entry.name);
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
stack.push(full);
|
||||||
|
} else if (entry.isFile() && isArchiveOrTempFile(full)) {
|
||||||
|
try {
|
||||||
|
await fs.promises.rm(full, { force: true });
|
||||||
|
removed += 1;
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
touched += 1;
|
||||||
|
if (touched % 80 === 0) {
|
||||||
|
await yieldToLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
export function removeDownloadLinkArtifacts(extractDir: string): number {
|
export function removeDownloadLinkArtifacts(extractDir: string): number {
|
||||||
if (!fs.existsSync(extractDir)) {
|
if (!fs.existsSync(extractDir)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import os from "node:os";
|
|||||||
import { AppSettings } from "../shared/types";
|
import { AppSettings } from "../shared/types";
|
||||||
|
|
||||||
export const APP_NAME = "Debrid Download Manager";
|
export const APP_NAME = "Debrid Download Manager";
|
||||||
export const APP_VERSION = "1.1.24";
|
export const APP_VERSION = "1.1.25";
|
||||||
export const API_BASE_URL = "https://api.real-debrid.com/rest/1.0";
|
export const API_BASE_URL = "https://api.real-debrid.com/rest/1.0";
|
||||||
|
|
||||||
export const DCRYPT_UPLOAD_URL = "https://dcrypt.it/decrypt/upload";
|
export const DCRYPT_UPLOAD_URL = "https://dcrypt.it/decrypt/upload";
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { EventEmitter } from "node:events";
|
|||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import { AppSettings, DownloadItem, DownloadSummary, DownloadStatus, PackageEntry, ParsedPackageInput, SessionState, UiSnapshot } from "../shared/types";
|
import { AppSettings, DownloadItem, DownloadSummary, DownloadStatus, PackageEntry, ParsedPackageInput, SessionState, UiSnapshot } from "../shared/types";
|
||||||
import { CHUNK_SIZE, REQUEST_RETRIES } from "./constants";
|
import { CHUNK_SIZE, REQUEST_RETRIES } from "./constants";
|
||||||
import { cleanupCancelledPackageArtifacts, removeDownloadLinkArtifacts, removeSampleArtifacts } from "./cleanup";
|
import { cleanupCancelledPackageArtifactsAsync } from "./cleanup";
|
||||||
import { DebridService, MegaWebUnrestrictor } from "./debrid";
|
import { DebridService, MegaWebUnrestrictor } from "./debrid";
|
||||||
import { extractPackageArchives } from "./extractor";
|
import { extractPackageArchives } from "./extractor";
|
||||||
import { validateFileAgainstManifest } from "./integrity";
|
import { validateFileAgainstManifest } from "./integrity";
|
||||||
@ -112,6 +112,8 @@ export class DownloadManager extends EventEmitter {
|
|||||||
|
|
||||||
private speedBytesLastWindow = 0;
|
private speedBytesLastWindow = 0;
|
||||||
|
|
||||||
|
private cleanupQueue: Promise<void> = Promise.resolve();
|
||||||
|
|
||||||
private reservedTargetPaths = new Map<string, string>();
|
private reservedTargetPaths = new Map<string, string>();
|
||||||
|
|
||||||
private claimedTargetPathByItem = new Map<string, string>();
|
private claimedTargetPathByItem = new Map<string, string>();
|
||||||
@ -332,6 +334,8 @@ export class DownloadManager extends EventEmitter {
|
|||||||
if (!pkg) {
|
if (!pkg) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const packageName = pkg.name;
|
||||||
|
const outputDir = pkg.outputDir;
|
||||||
const itemIds = [...pkg.itemIds];
|
const itemIds = [...pkg.itemIds];
|
||||||
|
|
||||||
for (const itemId of itemIds) {
|
for (const itemId of itemIds) {
|
||||||
@ -347,11 +351,18 @@ export class DownloadManager extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const removed = cleanupCancelledPackageArtifacts(pkg.outputDir);
|
|
||||||
this.removePackageFromSession(packageId, itemIds);
|
this.removePackageFromSession(packageId, itemIds);
|
||||||
logger.info(`Paket ${pkg.name} abgebrochen, ${removed} Artefakte gelöscht`);
|
|
||||||
this.persistSoon();
|
this.persistSoon();
|
||||||
this.emitState(true);
|
this.emitState(true);
|
||||||
|
|
||||||
|
this.cleanupQueue = this.cleanupQueue
|
||||||
|
.then(async () => {
|
||||||
|
const removed = await cleanupCancelledPackageArtifactsAsync(outputDir);
|
||||||
|
logger.info(`Paket ${packageName} abgebrochen, ${removed} Artefakte gelöscht`);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
logger.warn(`Cleanup für Paket ${packageName} fehlgeschlagen: ${compactErrorText(error)}`);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public start(): void {
|
public start(): void {
|
||||||
|
|||||||
@ -193,7 +193,9 @@ async function main(): Promise<void> {
|
|||||||
assert(cancelItem?.status === "cancelled" || cancelItem?.status === "queued", "Paketabbruch nicht wirksam");
|
assert(cancelItem?.status === "cancelled" || cancelItem?.status === "queued", "Paketabbruch nicht wirksam");
|
||||||
}
|
}
|
||||||
const packageDir = path.join(path.join(tempRoot, "downloads-cancel"), "cancel");
|
const packageDir = path.join(path.join(tempRoot, "downloads-cancel"), "cancel");
|
||||||
assert(!fs.existsSync(path.join(packageDir, "release.part1.rar")), "RAR-Artefakt wurde nicht gelöscht");
|
const cancelArtifact = path.join(packageDir, "release.part1.rar");
|
||||||
|
await waitFor(() => !fs.existsSync(cancelArtifact), 10000);
|
||||||
|
assert(!fs.existsSync(cancelArtifact), "RAR-Artefakt wurde nicht gelöscht");
|
||||||
|
|
||||||
console.log("Node self-check erfolgreich");
|
console.log("Node self-check erfolgreich");
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user