forked from olcxjas-softworks/LarpixClient
Update gitignore (sorry)
This commit is contained in:
parent
a8f8c4d7ad
commit
cca8b02fea
6604 changed files with 1219661 additions and 4 deletions
261
electron/node_modules/electron-updater/out/differentialDownloader/DifferentialDownloader.js
generated
vendored
Normal file
261
electron/node_modules/electron-updater/out/differentialDownloader/DifferentialDownloader.js
generated
vendored
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.DifferentialDownloader = void 0;
|
||||
const builder_util_runtime_1 = require("builder-util-runtime");
|
||||
const fs_extra_1 = require("fs-extra");
|
||||
const fs_1 = require("fs");
|
||||
const DataSplitter_1 = require("./DataSplitter");
|
||||
const url_1 = require("url");
|
||||
const downloadPlanBuilder_1 = require("./downloadPlanBuilder");
|
||||
const multipleRangeDownloader_1 = require("./multipleRangeDownloader");
|
||||
const ProgressDifferentialDownloadCallbackTransform_1 = require("./ProgressDifferentialDownloadCallbackTransform");
|
||||
class DifferentialDownloader {
|
||||
// noinspection TypeScriptAbstractClassConstructorCanBeMadeProtected
|
||||
constructor(blockAwareFileInfo, httpExecutor, options) {
|
||||
this.blockAwareFileInfo = blockAwareFileInfo;
|
||||
this.httpExecutor = httpExecutor;
|
||||
this.options = options;
|
||||
this.fileMetadataBuffer = null;
|
||||
this.logger = options.logger;
|
||||
}
|
||||
createRequestOptions() {
|
||||
const result = {
|
||||
headers: {
|
||||
...this.options.requestHeaders,
|
||||
accept: "*/*",
|
||||
},
|
||||
};
|
||||
builder_util_runtime_1.configureRequestUrl(this.options.newUrl, result);
|
||||
// user-agent, cache-control and other common options
|
||||
builder_util_runtime_1.configureRequestOptions(result);
|
||||
return result;
|
||||
}
|
||||
doDownload(oldBlockMap, newBlockMap) {
|
||||
// we don't check other metadata like compressionMethod - generic check that it is make sense to differentially update is suitable for it
|
||||
if (oldBlockMap.version !== newBlockMap.version) {
|
||||
throw new Error(`version is different (${oldBlockMap.version} - ${newBlockMap.version}), full download is required`);
|
||||
}
|
||||
const logger = this.logger;
|
||||
const operations = downloadPlanBuilder_1.computeOperations(oldBlockMap, newBlockMap, logger);
|
||||
if (logger.debug != null) {
|
||||
logger.debug(JSON.stringify(operations, null, 2));
|
||||
}
|
||||
let downloadSize = 0;
|
||||
let copySize = 0;
|
||||
for (const operation of operations) {
|
||||
const length = operation.end - operation.start;
|
||||
if (operation.kind === downloadPlanBuilder_1.OperationKind.DOWNLOAD) {
|
||||
downloadSize += length;
|
||||
}
|
||||
else {
|
||||
copySize += length;
|
||||
}
|
||||
}
|
||||
const newSize = this.blockAwareFileInfo.size;
|
||||
if (downloadSize + copySize + (this.fileMetadataBuffer == null ? 0 : this.fileMetadataBuffer.length) !== newSize) {
|
||||
throw new Error(`Internal error, size mismatch: downloadSize: ${downloadSize}, copySize: ${copySize}, newSize: ${newSize}`);
|
||||
}
|
||||
logger.info(`Full: ${formatBytes(newSize)}, To download: ${formatBytes(downloadSize)} (${Math.round(downloadSize / (newSize / 100))}%)`);
|
||||
return this.downloadFile(operations);
|
||||
}
|
||||
downloadFile(tasks) {
|
||||
const fdList = [];
|
||||
const closeFiles = () => {
|
||||
return Promise.all(fdList.map(openedFile => {
|
||||
return fs_extra_1.close(openedFile.descriptor).catch(e => {
|
||||
this.logger.error(`cannot close file "${openedFile.path}": ${e}`);
|
||||
});
|
||||
}));
|
||||
};
|
||||
return this.doDownloadFile(tasks, fdList)
|
||||
.then(closeFiles)
|
||||
.catch(e => {
|
||||
// then must be after catch here (since then always throws error)
|
||||
return closeFiles()
|
||||
.catch(closeFilesError => {
|
||||
// closeFiles never throw error, but just to be sure
|
||||
try {
|
||||
this.logger.error(`cannot close files: ${closeFilesError}`);
|
||||
}
|
||||
catch (errorOnLog) {
|
||||
try {
|
||||
console.error(errorOnLog);
|
||||
}
|
||||
catch (ignored) {
|
||||
// ok, give up and ignore error
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
})
|
||||
.then(() => {
|
||||
throw e;
|
||||
});
|
||||
});
|
||||
}
|
||||
async doDownloadFile(tasks, fdList) {
|
||||
const oldFileFd = await fs_extra_1.open(this.options.oldFile, "r");
|
||||
fdList.push({ descriptor: oldFileFd, path: this.options.oldFile });
|
||||
const newFileFd = await fs_extra_1.open(this.options.newFile, "w");
|
||||
fdList.push({ descriptor: newFileFd, path: this.options.newFile });
|
||||
const fileOut = fs_1.createWriteStream(this.options.newFile, { fd: newFileFd });
|
||||
await new Promise((resolve, reject) => {
|
||||
const streams = [];
|
||||
// Create our download info transformer if we have one
|
||||
let downloadInfoTransform = undefined;
|
||||
if (!this.options.isUseMultipleRangeRequest && this.options.onProgress) {
|
||||
// TODO: Does not support multiple ranges (someone feel free to PR this!)
|
||||
const expectedByteCounts = [];
|
||||
let grandTotalBytes = 0;
|
||||
for (const task of tasks) {
|
||||
if (task.kind === downloadPlanBuilder_1.OperationKind.DOWNLOAD) {
|
||||
expectedByteCounts.push(task.end - task.start);
|
||||
grandTotalBytes += task.end - task.start;
|
||||
}
|
||||
}
|
||||
const progressDifferentialDownloadInfo = {
|
||||
expectedByteCounts: expectedByteCounts,
|
||||
grandTotal: grandTotalBytes,
|
||||
};
|
||||
downloadInfoTransform = new ProgressDifferentialDownloadCallbackTransform_1.ProgressDifferentialDownloadCallbackTransform(progressDifferentialDownloadInfo, this.options.cancellationToken, this.options.onProgress);
|
||||
streams.push(downloadInfoTransform);
|
||||
}
|
||||
const digestTransform = new builder_util_runtime_1.DigestTransform(this.blockAwareFileInfo.sha512);
|
||||
// to simply debug, do manual validation to allow file to be fully written
|
||||
digestTransform.isValidateOnEnd = false;
|
||||
streams.push(digestTransform);
|
||||
// noinspection JSArrowFunctionCanBeReplacedWithShorthand
|
||||
fileOut.on("finish", () => {
|
||||
;
|
||||
fileOut.close(() => {
|
||||
// remove from fd list because closed successfully
|
||||
fdList.splice(1, 1);
|
||||
try {
|
||||
digestTransform.validate();
|
||||
}
|
||||
catch (e) {
|
||||
reject(e);
|
||||
return;
|
||||
}
|
||||
resolve(undefined);
|
||||
});
|
||||
});
|
||||
streams.push(fileOut);
|
||||
let lastStream = null;
|
||||
for (const stream of streams) {
|
||||
stream.on("error", reject);
|
||||
if (lastStream == null) {
|
||||
lastStream = stream;
|
||||
}
|
||||
else {
|
||||
lastStream = lastStream.pipe(stream);
|
||||
}
|
||||
}
|
||||
const firstStream = streams[0];
|
||||
let w;
|
||||
if (this.options.isUseMultipleRangeRequest) {
|
||||
w = multipleRangeDownloader_1.executeTasksUsingMultipleRangeRequests(this, tasks, firstStream, oldFileFd, reject);
|
||||
w(0);
|
||||
return;
|
||||
}
|
||||
let downloadOperationCount = 0;
|
||||
let actualUrl = null;
|
||||
this.logger.info(`Differential download: ${this.options.newUrl}`);
|
||||
const requestOptions = this.createRequestOptions();
|
||||
requestOptions.redirect = "manual";
|
||||
w = (index) => {
|
||||
var _a, _b;
|
||||
if (index >= tasks.length) {
|
||||
if (this.fileMetadataBuffer != null) {
|
||||
firstStream.write(this.fileMetadataBuffer);
|
||||
}
|
||||
firstStream.end();
|
||||
return;
|
||||
}
|
||||
const operation = tasks[index++];
|
||||
if (operation.kind === downloadPlanBuilder_1.OperationKind.COPY) {
|
||||
// We are copying, let's not send status updates to the UI
|
||||
if (downloadInfoTransform) {
|
||||
downloadInfoTransform.beginFileCopy();
|
||||
}
|
||||
DataSplitter_1.copyData(operation, firstStream, oldFileFd, reject, () => w(index));
|
||||
return;
|
||||
}
|
||||
const range = `bytes=${operation.start}-${operation.end - 1}`;
|
||||
requestOptions.headers.range = range;
|
||||
(_b = (_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug) === null || _b === void 0 ? void 0 : _b.call(_a, `download range: ${range}`);
|
||||
// We are starting to download
|
||||
if (downloadInfoTransform) {
|
||||
downloadInfoTransform.beginRangeDownload();
|
||||
}
|
||||
const request = this.httpExecutor.createRequest(requestOptions, response => {
|
||||
// Electron net handles redirects automatically, our NodeJS test server doesn't use redirects - so, we don't check 3xx codes.
|
||||
if (response.statusCode >= 400) {
|
||||
reject(builder_util_runtime_1.createHttpError(response));
|
||||
}
|
||||
response.pipe(firstStream, {
|
||||
end: false,
|
||||
});
|
||||
response.once("end", () => {
|
||||
// Pass on that we are downloading a segment
|
||||
if (downloadInfoTransform) {
|
||||
downloadInfoTransform.endRangeDownload();
|
||||
}
|
||||
if (++downloadOperationCount === 100) {
|
||||
downloadOperationCount = 0;
|
||||
setTimeout(() => w(index), 1000);
|
||||
}
|
||||
else {
|
||||
w(index);
|
||||
}
|
||||
});
|
||||
});
|
||||
request.on("redirect", (statusCode, method, redirectUrl) => {
|
||||
this.logger.info(`Redirect to ${removeQuery(redirectUrl)}`);
|
||||
actualUrl = redirectUrl;
|
||||
builder_util_runtime_1.configureRequestUrl(new url_1.URL(actualUrl), requestOptions);
|
||||
request.followRedirect();
|
||||
});
|
||||
this.httpExecutor.addErrorAndTimeoutHandlers(request, reject);
|
||||
request.end();
|
||||
};
|
||||
w(0);
|
||||
});
|
||||
}
|
||||
async readRemoteBytes(start, endInclusive) {
|
||||
const buffer = Buffer.allocUnsafe(endInclusive + 1 - start);
|
||||
const requestOptions = this.createRequestOptions();
|
||||
requestOptions.headers.range = `bytes=${start}-${endInclusive}`;
|
||||
let position = 0;
|
||||
await this.request(requestOptions, chunk => {
|
||||
chunk.copy(buffer, position);
|
||||
position += chunk.length;
|
||||
});
|
||||
if (position !== buffer.length) {
|
||||
throw new Error(`Received data length ${position} is not equal to expected ${buffer.length}`);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
request(requestOptions, dataHandler) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = this.httpExecutor.createRequest(requestOptions, response => {
|
||||
if (!multipleRangeDownloader_1.checkIsRangesSupported(response, reject)) {
|
||||
return;
|
||||
}
|
||||
response.on("data", dataHandler);
|
||||
response.on("end", () => resolve());
|
||||
});
|
||||
this.httpExecutor.addErrorAndTimeoutHandlers(request, reject);
|
||||
request.end();
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.DifferentialDownloader = DifferentialDownloader;
|
||||
function formatBytes(value, symbol = " KB") {
|
||||
return new Intl.NumberFormat("en").format((value / 1024).toFixed(2)) + symbol;
|
||||
}
|
||||
// safety
|
||||
function removeQuery(url) {
|
||||
const index = url.indexOf("?");
|
||||
return index < 0 ? url : url.substring(0, index);
|
||||
}
|
||||
//# sourceMappingURL=DifferentialDownloader.js.map
|
||||
Loading…
Add table
Add a link
Reference in a new issue