codekingpro/portable-devtools
115k
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6exports.DefaultFetcher = exports.BaseFetcher = void 0;
7const debug_1 = __importDefault(require("debug"));
8const fs_1 = __importDefault(require("fs"));
9const make_fetch_happen_1 = __importDefault(require("make-fetch-happen"));
10const util_1 = __importDefault(require("util"));
11const error_1 = require("./error");
12const tmpfile_1 = require("./utils/tmpfile");
13const log = (0, debug_1.default)('tuf:fetch');
14const USER_AGENT_HEADER = 'User-Agent';
15class BaseFetcher {
16 // Download file from given URL. The file is downloaded to a temporary
17 // location and then passed to the given handler. The handler is responsible
18 // for moving the file to its final location. The temporary file is deleted
19 // after the handler returns.
20 async downloadFile(url, maxLength, handler) {
21 return (0, tmpfile_1.withTempFile)(async (tmpFile) => {
22 const reader = await this.fetch(url);
23 let numberOfBytesReceived = 0;
24 const fileStream = fs_1.default.createWriteStream(tmpFile);
25 // Read the stream a chunk at a time so that we can check
26 // the length of the file as we go
27 try {
28 for await (const chunk of reader) {
29 numberOfBytesReceived += chunk.length;
30 if (numberOfBytesReceived > maxLength) {
31 throw new error_1.DownloadLengthMismatchError('Max length reached');
32 }
33 await writeBufferToStream(fileStream, chunk);
34 }
35 }
36 finally {
37 // Make sure we always close the stream
38 // eslint-disable-next-line @typescript-eslint/unbound-method
39 await util_1.default.promisify(fileStream.close).bind(fileStream)();
40 }
41 return handler(tmpFile);
42 });
43 }
44 // Download bytes from given URL.
45 async downloadBytes(url, maxLength) {
46 return this.downloadFile(url, maxLength, async (file) => {
47 const stream = fs_1.default.createReadStream(file);
48 const chunks = [];
49 for await (const chunk of stream) {
50 chunks.push(chunk);
51 }
52 return Buffer.concat(chunks);
53 });
54 }
55}
56exports.BaseFetcher = BaseFetcher;
57class DefaultFetcher extends BaseFetcher {
58 userAgent;
59 timeout;
60 retry;
61 constructor(options = {}) {
62 super();
63 this.userAgent = options.userAgent;
64 this.timeout = options.timeout;
65 this.retry = options.retry;
66 }
67 async fetch(url) {
68 log('GET %s', url);
69 const response = await (0, make_fetch_happen_1.default)(url, {
70 headers: {
71 [USER_AGENT_HEADER]: this.userAgent || '',
72 },
73 timeout: this.timeout,
74 retry: this.retry,
75 });
76 if (!response.ok || !response?.body) {
77 throw new error_1.DownloadHTTPError('Failed to download', response.status);
78 }
79 return response.body;
80 }
81}
82exports.DefaultFetcher = DefaultFetcher;
83const writeBufferToStream = async (stream, buffer) => {
84 return new Promise((resolve, reject) => {
85 stream.write(buffer, (err) => {
86 if (err) {
87 reject(err);
88 }
89 resolve(true);
90 });
91 });
92};
93 