@microsoft/microsoft-graph-client
Version:
Microsoft Graph Client Library
132 lines • 7.24 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StreamUpload = void 0;
var tslib_1 = require("tslib");
var GraphClientError_1 = require("../../../GraphClientError");
/**
* @class
* FileObject class for Readable Stream upload
*/
var StreamUpload = /** @class */ (function () {
function StreamUpload(content, name, size) {
this.content = content;
this.name = name;
this.size = size;
if (!content || !name || !size) {
throw new GraphClientError_1.GraphClientError("Please provide the Readable Stream content, name of the file and size of the file");
}
}
/**
* @public
* Slices the file content to the given range
* @param {Range} range - The range value
* @returns The sliced file part
*/
StreamUpload.prototype.sliceFile = function (range) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var rangeSize, bufs, previousRangeMin, previousRangeMax, _a, _b, slicedChunk;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
rangeSize = range.maxValue - range.minValue + 1;
bufs = [];
/**
* The sliceFile reads the first `rangeSize` number of bytes from the stream.
* The previousSlice property is used to seek the range of bytes in the previous slice.
* Suppose, the sliceFile reads bytes from `10 - 20` from the stream but the upload of this slice fails.
* When the user resumes, the stream will have bytes from position 21.
* The previousSlice.Range is used to compare if the requested range is cached in the previousSlice property or present in the Readable Stream.
*/
if (this.previousSlice) {
if (range.minValue < this.previousSlice.range.minValue) {
throw new GraphClientError_1.GraphClientError("An error occurred while uploading the stream. Please restart the stream upload from the first byte of the file.");
}
if (range.minValue < this.previousSlice.range.maxValue) {
previousRangeMin = this.previousSlice.range.minValue;
previousRangeMax = this.previousSlice.range.maxValue;
// Check if the requested range is same as previously sliced range
if (range.minValue === previousRangeMin && range.maxValue === previousRangeMax) {
return [2 /*return*/, this.previousSlice.fileSlice];
}
/**
* The following check considers a possibility
* of an upload failing after some of the bytes of the previous slice
* were successfully uploaded.
* Example - Previous slice range - `10 - 20`. Current requested range is `15 - 20`.
*/
if (range.maxValue === previousRangeMax) {
return [2 /*return*/, this.previousSlice.fileSlice.slice(range.minValue, range.maxValue + 1)];
}
/**
* If an upload fails after some of the bytes of the previous slice
* were successfully uploaded and the new Range.Maximum is greater than the previous Range.Maximum
* Example - Previous slice range - `10 - 20`. Current requested range is `15 - 25`,
* then read the bytes from position 15 to 20 from previousSlice.fileSlice and read bytes from position 21 to 25 from the Readable Stream
*/
bufs.push(this.previousSlice.fileSlice.slice(range.minValue, previousRangeMax + 1));
rangeSize = range.maxValue - previousRangeMax;
}
}
if (!(this.content && this.content.readable)) return [3 /*break*/, 4];
if (!(this.content.readableLength >= rangeSize)) return [3 /*break*/, 1];
bufs.push(this.content.read(rangeSize));
return [3 /*break*/, 3];
case 1:
_b = (_a = bufs).push;
return [4 /*yield*/, this.readNBytesFromStream(rangeSize)];
case 2:
_b.apply(_a, [_c.sent()]);
_c.label = 3;
case 3: return [3 /*break*/, 5];
case 4: throw new GraphClientError_1.GraphClientError("Stream is not readable.");
case 5:
slicedChunk = Buffer.concat(bufs);
this.previousSlice = { fileSlice: slicedChunk, range: range };
return [2 /*return*/, slicedChunk];
}
});
});
};
/**
* @private
* Reads the specified byte size from the stream
* @param {number} size - The size of bytes to be read
* @returns Buffer with the given length of data.
*/
StreamUpload.prototype.readNBytesFromStream = function (size) {
var _this = this;
return new Promise(function (resolve, reject) {
var chunks = [];
var remainder = size;
var length = 0;
_this.content.on("end", function () {
if (remainder > 0) {
return reject(new GraphClientError_1.GraphClientError("Stream ended before reading required range size"));
}
});
_this.content.on("readable", function () {
/**
* (chunk = this.content.read(size)) can return null if size of stream is less than 'size' parameter.
* Read the remainder number of bytes from the stream iteratively as they are available.
*/
var chunk;
while (length < size && (chunk = _this.content.read(remainder)) !== null) {
length += chunk.length;
chunks.push(chunk);
if (remainder > 0) {
remainder = size - length;
}
}
if (length === size) {
return resolve(Buffer.concat(chunks));
}
if (!_this.content || !_this.content.readable) {
return reject(new GraphClientError_1.GraphClientError("Error encountered while reading the stream during the upload"));
}
});
});
};
return StreamUpload;
}());
exports.StreamUpload = StreamUpload;
//# sourceMappingURL=StreamUpload.js.map