UNPKG

etcher-sdk

Version:
150 lines 5.67 kB
"use strict"; /* * Copyright 2018 balena.io * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Http = void 0; const axios_1 = require("axios"); const path_1 = require("path"); const querystring_1 = require("querystring"); const url_1 = require("url"); const axios_http2_adapter_1 = require("axios-http2-adapter"); const stream_limiter_1 = require("../stream-limiter"); const source_destination_1 = require("./source-destination"); class Http extends source_destination_1.SourceDestination { constructor({ url, avoidRandomAccess = false, axiosInstance = axios_1.default.create(), auth, }) { super(); this.url = url; this.avoidRandomAccess = avoidRandomAccess; this.axiosInstance = axiosInstance; if (auth) { this.axiosInstance.defaults.auth = auth; } this.axiosInstance.defaults.adapter = (0, axios_http2_adapter_1.createHTTP2Adapter)(); this.ready = this.getInfo(); } async getInfo() { var _a, _b, _c; try { let response; try { response = await this.axiosInstance({ method: 'head', url: this.url }); } catch (error) { // We use GET instead of HEAD as some servers will respond with a 403 to HEAD requests response = await this.axiosInstance({ method: 'get', url: this.url, responseType: 'stream', }); response.data.destroy(); } this.redirectUrl = response.request.res.responseUrl; this.size = parseInt(response.headers['content-length'], 10); if (Number.isNaN(this.size)) { this.size = undefined; } const regExpFilename = /filename="(?<filename>.*)"/; this.fileName = (_c = (_b = (_a = regExpFilename.exec(response.headers['content-disposition'])) === null || _a === void 0 ? void 0 : _a.groups) === null || _b === void 0 ? void 0 : _b.filename) !== null && _c !== void 0 ? _c : undefined; this.acceptsRange = response.headers['accept-ranges'] === 'bytes'; } catch (error) { this.error = error; } } async canRead() { await this.ready; if (this.error) { throw this.error; } return !this.avoidRandomAccess && this.acceptsRange; } async canCreateReadStream() { return true; } async _getMetadata() { await this.ready; if (this.error) { throw this.error; } const pathname = (0, url_1.parse)(this.redirectUrl).pathname; if (!this.fileName && pathname !== undefined && pathname !== null) { this.fileName = (0, path_1.basename)((0, querystring_1.unescape)(pathname)); } return { size: this.size, name: this.fileName, }; } getRange(start = 0, end) { // start and end are inclusive let range = `bytes=${start}-`; if (end !== undefined) { range += end; } return range; } async read(buffer, bufferOffset, length, sourceOffset) { const response = await this.axiosInstance({ method: this.axiosInstance.defaults.method || 'get', url: this.redirectUrl, responseType: 'arraybuffer', headers: { Range: this.getRange(sourceOffset, sourceOffset + length - 1), 'accept-encoding': 'gzip', }, }); const bytesRead = response.data.length; // TODO: it would be nice to avoid copying here but it would require modifying axios response.data.copy(buffer, bufferOffset); return { bytesRead, buffer }; } async createReadStream({ emitProgress = false, start = 0, end, } = {}) { const response = await this.axiosInstance({ method: this.axiosInstance.defaults.method || 'get', url: this.redirectUrl, headers: { Range: this.getRange(start, end), 'accept-encoding': 'gzip', }, responseType: 'stream', }); if (emitProgress) { let bytes = 0; let lastTime = Date.now(); response.data.on('data', (chunk) => { const now = Date.now(); const length = chunk.length; bytes += length; const speed = length / ((now - lastTime) / 1000); lastTime = now; response.data.emit('progress', { position: bytes, bytes, speed, }); }); response.data.pause(); } if (end !== undefined) { // +1 because start and end are inclusive return new stream_limiter_1.StreamLimiter(response.data, end - start + 1); } return response.data; } } exports.Http = Http; //# sourceMappingURL=http.js.map