41 lines
1.1 KiB
JavaScript
41 lines
1.1 KiB
JavaScript
'use strict';
|
|
|
|
const fs = require('fs').promises;
|
|
const path = require('path');
|
|
const { createWriteStream } = require('fs');
|
|
const { pipeline } = require('stream/promises');
|
|
const { Readable } = require('stream');
|
|
|
|
async function downloadBodyToFile(res, destPath) {
|
|
if (!res.ok) {
|
|
const errText = await res.text().catch(() => '');
|
|
throw new Error(`HTTP ${res.status}: ${errText.slice(0, 500)}`);
|
|
}
|
|
if (!res.body) {
|
|
throw new Error('download has no body');
|
|
}
|
|
await fs.mkdir(path.dirname(destPath), { recursive: true });
|
|
const tmp = destPath + '.downloading';
|
|
let body = res.body;
|
|
if (body && typeof body.pipe !== 'function') {
|
|
body = Readable.fromWeb(body);
|
|
}
|
|
await pipeline(body, createWriteStream(tmp));
|
|
const st = await fs.stat(tmp);
|
|
if (st.size === 0) {
|
|
await fs.unlink(tmp).catch(() => {});
|
|
throw new Error('empty download');
|
|
}
|
|
await fs.rename(tmp, destPath);
|
|
}
|
|
|
|
async function fetchToFile(url, headers, destPath) {
|
|
const res = await fetch(url, {
|
|
headers,
|
|
redirect: 'follow',
|
|
});
|
|
await downloadBodyToFile(res, destPath);
|
|
}
|
|
|
|
module.exports = { fetchToFile, downloadBodyToFile };
|