hackpro-sdk
Version:
236 lines • 9.87 kB
JavaScript
"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