UNPKG

hackpro-sdk

Version:
236 lines 9.87 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. */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const bluebird_1 = require("bluebird"); const _debug = require("debug"); const file_disk_1 = require("file-disk"); const partitioninfo_1 = require("partitioninfo"); const resin_image_fs_1 = require("resin-image-fs"); const constants_1 = require("../../constants"); const errors_1 = require("../../errors"); const shared_1 = require("../../sparse-stream/shared"); const sparse_filter_stream_1 = require("../../sparse-stream/sparse-filter-stream"); const sparse_read_stream_1 = require("../../sparse-stream/sparse-read-stream"); const source_source_1 = require("../source-source"); const configure_1 = require("./configure"); const debug = _debug('etcher-sdk:configured-source'); class SourceDisk extends file_disk_1.Disk { constructor(source) { super(true, // readOnly true, // recordWrites true, // recordReads true); this.source = source; } _getCapacity() { return __awaiter(this, void 0, void 0, function* () { // Don't create SourceDisks with sources that do not define a size const size = (yield this.source.getMetadata()).size; if (size === undefined) { throw new errors_1.NotCapable(); } return size; }); } _read(buffer, bufferOffset, length, fileOffset) { return __awaiter(this, void 0, void 0, function* () { return yield this.source.read(buffer, bufferOffset, length, fileOffset); }); } _write(_buffer, _bufferOffset, _length, _fileOffset) { return __awaiter(this, void 0, void 0, function* () { throw new Error("Can't write to a SourceDisk"); }); } _flush() { return __awaiter(this, void 0, void 0, function* () { // noop }); } } exports.SourceDisk = SourceDisk; class ConfiguredSource extends source_source_1.SourceSource { constructor( // source needs to implement read and createReadStream source, shouldTrimPartitions, createStreamFromDisk, configure, config, checksumType = 'xxhash64', chunkSize = constants_1.CHUNK_SIZE) { super(source); this.shouldTrimPartitions = shouldTrimPartitions; this.createStreamFromDisk = createStreamFromDisk; this.config = config; this.checksumType = checksumType; this.chunkSize = chunkSize; this.disk = new SourceDisk(source); if (configure === 'legacy') { this.configure = configure_1.configure; } else { this.configure = configure; } } getBlocks() { return __awaiter(this, void 0, void 0, function* () { // Align ranges to this.chunkSize const blocks = yield this.disk.getRanges(this.chunkSize); return blocks.map(block => ({ blocks: [block] })); }); } getBlocksWithChecksumType(generateChecksums) { return __awaiter(this, void 0, void 0, function* () { let blocks = yield this.getBlocks(); if (generateChecksums) { blocks = blocks.map(block => (Object.assign(Object.assign({}, block), { checksumType: this.checksumType }))); } return blocks; }); } canRead() { return __awaiter(this, void 0, void 0, function* () { return true; }); } canCreateReadStream() { return __awaiter(this, void 0, void 0, function* () { return true; }); } canCreateSparseReadStream() { return __awaiter(this, void 0, void 0, function* () { return true; }); } read(buffer, bufferOffset, length, sourceOffset) { return __awaiter(this, void 0, void 0, function* () { return yield this.disk.read(buffer, bufferOffset, length, sourceOffset); }); } createReadStream(...args) { return __awaiter(this, void 0, void 0, function* () { const imageStream = yield this.source.createReadStream(...args); const transform = this.disk.getTransformStream(); imageStream.on('error', (err) => { transform.emit('error', err); }); imageStream.pipe(transform); return transform; }); } createSparseReadStreamFromDisk(generateChecksums) { return __awaiter(this, void 0, void 0, function* () { return new sparse_read_stream_1.SparseReadStream(this, yield this.getBlocksWithChecksumType(generateChecksums), // blocks constants_1.CHUNK_SIZE, false, // verify generateChecksums); }); } createSparseReadStreamFromStream(generateChecksums) { return __awaiter(this, void 0, void 0, function* () { const stream = yield this.createReadStream(); const transform = new sparse_filter_stream_1.SparseFilterStream(yield this.getBlocksWithChecksumType(generateChecksums), false, // verify generateChecksums); stream.on('error', transform.emit.bind(transform, 'error')); stream.pipe(transform); return transform; }); } createSparseReadStream(generateChecksums) { return __awaiter(this, void 0, void 0, function* () { if (this.createStreamFromDisk) { return yield this.createSparseReadStreamFromDisk(generateChecksums); } else { return yield this.createSparseReadStreamFromStream(generateChecksums); } }); } _getMetadata() { return __awaiter(this, void 0, void 0, function* () { const sourceMetadata = yield this.source.getMetadata(); const blocks = yield this.getBlocks(); const blockmappedSize = shared_1.blocksLength(blocks); return Object.assign(Object.assign({}, sourceMetadata), { blocks, blockmappedSize }); }); } trimPartitions() { return __awaiter(this, void 0, void 0, function* () { let partitions; try { ({ partitions } = yield partitioninfo_1.getPartitions(this.disk, { includeExtended: false, })); } catch (error) { debug("Couldn't read partition table", error); return; } for (const partition of partitions) { try { yield bluebird_1.using(resin_image_fs_1.interact(this.disk, partition.index), (fs) => __awaiter(this, void 0, void 0, function* () { if (fs.trimAsync !== undefined) { yield fs.trimAsync(); } })); } catch (_a) { // Unsupported filesystem } } const discards = this.disk.getDiscardedChunks(); const discardedBytes = discards .map((d) => d.end - d.start + 1) .reduce((a, b) => a + b, 0); // TODO: discarededBytes in metadata ? const metadata = yield this.getMetadata(); if (metadata.size !== undefined) { const percentage = Math.round((discardedBytes / metadata.size) * 100); debug(`discarded ${discards.length} chunks, ${discardedBytes} bytes, ${percentage}% of the image`); } }); } _open() { const _super = Object.create(null, { _open: { get: () => super._open } }); return __awaiter(this, void 0, void 0, function* () { yield _super._open.call(this); if (this.configure !== undefined) { yield this.configure(this.disk, this.config); } if (this.shouldTrimPartitions) { yield this.trimPartitions(); } this.disk.recordReads = false; }); } _close() { const _super = Object.create(null, { _close: { get: () => super._close } }); return __awaiter(this, void 0, void 0, function* () { yield _super._close.call(this); }); } } exports.ConfiguredSource = ConfiguredSource; //# sourceMappingURL=configured-source.js.map