release: candidate downloads go through Cloudflare first (the direct route to the origin was throttled per connection: one AppImage took 20+ min there, 3 MB/s through Cloudflare), the origin only as a fallback; a heartbeat logs the bytes every 30 s

This commit is contained in:
CRTkafa 2026-10-17 15:59:44 +08:00
parent 37cda2a39a
commit 9ba97b7e29

View file

@ -162,15 +162,32 @@ export async function api<T>(method: string, path: string, body?: unknown, raw =
}
}
/** Download one asset (drafts need the token) to a file; through the origin like uploads when it is set. */
/** Download one asset (drafts need the token) to a file. Through Cloudflare first: its 100 MB limit is on request
* bodies (uploads), and the direct route to the origin was throttled per connection to ~30 KB/s (an 0.8.11 release
* sat 20 minutes on one AppImage while Cloudflare gave 3 MB/s). The origin is the fallback. A heartbeat logs the
* bytes every 30 s; curl's own --max-time bounds each try. */
export async function downloadAsset(url: string, dest: string): Promise<void> {
const ip = origin();
const dir = mkdtempSync(join(tmpdir(), 'forgejo-dl-'));
try {
writeFileSync(join(dir, 'h'), `Authorization: ${auth()}\n`, { mode: 0o600 });
const host = new URL(BASE).host;
const r = spawnSync('curl', ['-sS', '-L', '--fail', '--max-time', '1800', ...(ip ? ['--resolve', `${host}:443:${ip.includes(':') ? `[${ip}]` : ip}`] : []), '-H', `@${join(dir, 'h')}`, '-o', dest, url], { encoding: 'utf8' });
if (r.status !== 0) fail(`download ${basename(dest)}: curl exit ${r.status}: ${r.stderr.slice(0, 300)}`);
const routes: string[][] = [[], ...(ip ? [['--resolve', `${host}:443:${ip.includes(':') ? `[${ip}]` : ip}`]] : [])];
let last = '';
for (const [i, route] of routes.entries()) {
const t0 = Date.now();
const p = Bun.spawn(['curl', '-sS', '-L', '--fail', '--max-time', '1800', ...route, '-H', `@${join(dir, 'h')}`, '-o', dest, url], { stdout: 'ignore', stderr: 'pipe' });
const beat = setInterval(() => {
let n = 0; try { n = statSync(dest).size; } catch { /* not started */ }
console.log(` download ${basename(dest)} (${i ? 'origin' : 'cloudflare'}): ${(n / 1e6).toFixed(1)} MB after ${Math.round((Date.now() - t0) / 1000)} s`);
}, 30_000);
const code = await p.exited;
clearInterval(beat);
if (code === 0) return;
last = `curl exit ${code}: ${(await new Response(p.stderr).text()).slice(0, 300)}`;
if (i + 1 < routes.length) console.log(` download ${basename(dest)}: ${last}; trying the origin`);
}
fail(`download ${basename(dest)}: ${last}`);
} finally { rmSync(dir, { recursive: true, force: true }); }
}