commit 0fceae3d5d465a1924120fb3ffc9e5ea99000042
parent 0ff9ad4f43e42d1b06b0838532ebbd65aafaffed
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Mon, 5 Oct 2026 16:06:58 -0400
sources: aria2c hash-checks only a resumed torrent; its DHT notice is never the failure
Seen in the live smoke: on a fresh run --check-integrity makes aria2c print
"Checksum error detected" for pieces not fetched yet, and a first run's empty
dht.dat an [ERROR] — both noise. --check-integrity is now passed only when the
file or its .aria2 control file is already in the staging dir (a cancelled
run, a run killed while seeding), and DHT lines are left out of a failed
run's reason.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
3 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/common/lib/archiveOrgTorrent-server.ts b/common/lib/archiveOrgTorrent-server.ts
@@ -148,6 +148,7 @@ export async function fetchFileByTorrent(opts: TorrentFetchOpts): Promise<Torren
userAgent: opts.userAgent,
parentPid: process.pid,
summaryIntervalSec: opts.summaryIntervalSec ?? 5,
+ resume: (await exists(target)) || (await exists(`${target}.aria2`)),
});
log(
`torrent: fetching ${label} (${pieces} pieces of ${opts.parsed.pieceLength} bytes, ` +
@@ -287,7 +288,12 @@ export async function fetchFileByTorrent(opts: TorrentFetchOpts): Promise<Torren
return { ok: true, file: target, seeded };
}
if (why) return { ok: false, reason: why.reason, ...(why.stalled ? { stalled: true } : {}) };
- const tail = lastLines.filter((l) => /ERROR|errorCode|Exception/.test(l)).slice(-2).join(" | ");
+ // aria2c's DHT routing-table complaint (an empty or first-run dht.dat) is
+ // noise, never the reason a run failed.
+ const tail = lastLines
+ .filter((l) => /ERROR|errorCode|Exception/.test(l) && !/DHT/.test(l))
+ .slice(-2)
+ .join(" | ");
return {
ok: false,
reason: `aria2c exited ${exit.code ?? exit.signal}${tail ? `: ${tail}` : ""}`,
diff --git a/common/lib/archiveOrgTorrent.test.ts b/common/lib/archiveOrgTorrent.test.ts
@@ -153,6 +153,12 @@ test("aria2c arguments: one file, seeding bounds, politeness, the hook, no word-
userAgent: "u",
});
assert.ok(none.includes("--seed-time=0"));
+ // A fresh run does not hash-check pieces that are not there; a resume does.
+ assert.ok(!args.includes("--check-integrity=true"));
+ assert.ok(
+ aria2cArgs({ torrentPath: "t", dir: "d", fileIndex: 1, settings: DEFAULT_ARCHIVE_ORG_FETCH_SETTINGS, onCompleteHook: "h", userAgent: "u", resume: true })
+ .includes("--check-integrity=true"),
+ );
assert.ok(!none.some((a) => a.startsWith("--stop-with-process")));
});
diff --git a/common/lib/archiveOrgTorrent.ts b/common/lib/archiveOrgTorrent.ts
@@ -179,6 +179,11 @@ export type Aria2cSpec = {
// leaves a seeder behind.
parentPid?: number;
summaryIntervalSec?: number;
+ // Part of the file is already in --dir (a cancelled run's partial, or a run
+ // killed while seeding): hash-check it and carry on, rather than refusing it
+ // or fetching it again. Off on a fresh run, where aria2c's check of pieces
+ // that are not there yet prints a "Checksum error" that means nothing.
+ resume?: boolean;
};
// Every flag is spelled `--name=value`, one argv entry each, so nothing here
@@ -202,10 +207,9 @@ export function aria2cArgs(spec: Aria2cSpec): string[] {
"--follow-torrent=mem",
"--file-allocation=none",
// A re-run resumes: the partial and its .aria2 control file are kept on a
- // cancel, and a complete file (a run killed while seeding) is hash-checked
- // and seeded rather than refused or fetched again.
+ // cancel (see `resume`).
"--continue=true",
- "--check-integrity=true",
+ ...(spec.resume ? ["--check-integrity=true"] : []),
"--auto-file-renaming=false",
"--bt-save-metadata=false",
`--on-bt-download-complete=${spec.onCompleteHook}`,