"use strict";
/*
 * Copyright (c) 2019 by Filestack.
 * Some rights reserved.
 *
 * 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 });
var tslib_1 = require("tslib");
var p_queue_1 = require("p-queue");
var debug_1 = require("debug");
var request_1 = require("./../../request");
var utils_1 = require("./../../../utils");
var abstract_1 = require("./abstract");
var filestack_error_1 = require("./../../../../filestack_error");
var debug = debug_1.default('fs:upload:s3');
var COMPLETE_TIMEOUT = 1000 * 1;
var S3Uploader = /** @class */ (function (_super) {
    tslib_1.__extends(S3Uploader, _super);
    function S3Uploader(storeOptions, concurrency) {
        var _this = _super.call(this, storeOptions, concurrency) || this;
        _this.payloads = {};
        _this.partsQueue = new p_queue_1.default({
            autoStart: false,
            concurrency: _this.concurrency,
        });
        // setup cancel token
        var CancelToken = request_1.request.CancelToken;
        _this.cancelToken = CancelToken.source();
        return _this;
    }
    /**
     * Pause upload queue
     *
     * @memberof S3Uploader
     */
    S3Uploader.prototype.pause = function () {
        this.partsQueue.pause();
    };
    /**
     * resume upload queue if its paused
     *
     * @memberof S3Uploader
     */
    S3Uploader.prototype.resume = function () {
        /* istanbul ignore next */
        if (this.partsQueue.isPaused) {
            this.partsQueue.start();
        }
    };
    /**
     * Aborts queue (all pending requests with will be aborted)
     *
     * @memberof S3Uploader
     */
    S3Uploader.prototype.abort = function (msg) {
        this.cancelToken.cancel(msg || 'Aborted by user');
        this.partsQueue.clear();
    };
    /**
     * Execute all queued files
     *
     * @returns {Promise<any>}
     * @memberof S3Uploader
     */
    S3Uploader.prototype.execute = function () {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var tasks;
            var _this = this;
            return tslib_1.__generator(this, function (_a) {
                tasks = Object.keys(this.payloads).map(function (id) {
                    return new Promise(function (resolve) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
                        var e_1, file;
                        return tslib_1.__generator(this, function (_a) {
                            switch (_a.label) {
                                case 0:
                                    _a.trys.push([0, 5, , 6]);
                                    return [4 /*yield*/, this.startRequest(id)];
                                case 1:
                                    _a.sent();
                                    return [4 /*yield*/, this.prepareParts(id)];
                                case 2:
                                    _a.sent();
                                    return [4 /*yield*/, this.startPartsQueue(id)];
                                case 3:
                                    _a.sent();
                                    return [4 /*yield*/, this.completeRequest(id)];
                                case 4:
                                    _a.sent();
                                    return [3 /*break*/, 6];
                                case 5:
                                    e_1 = _a.sent();
                                    /* istanbul ignore next */
                                    this.emit('error', e_1);
                                    debug("[" + id + "] File upload failed. %O, \nDetails: %O ", e_1.message, e_1.details);
                                    return [3 /*break*/, 6];
                                case 6:
                                    file = this.getPayloadById(id).file;
                                    // release file buffer
                                    file.release();
                                    // cleanup payloads
                                    delete this.payloads[id];
                                    resolve(file);
                                    return [2 /*return*/];
                            }
                        });
                    }); });
                });
                return [2 /*return*/, Promise.all(tasks).then(function (res) {
                        // prevent cancel token memory leak
                        try {
                            _this.cancelToken.cancel();
                        }
                        catch (e) {
                            /* istanbul ignore next */
                            debug("Cannot cleanup cancel token %O", e.message);
                        }
                        return res;
                    })];
            });
        });
    };
    /**
     * Add file to upload queue
     *
     * @param {File} file
     * @returns
     * @memberof S3Uploader
     */
    S3Uploader.prototype.addFile = function (file) {
        debug('Add file to queue: \n %o', file);
        var id = utils_1.uniqueId(15) + "_" + utils_1.uniqueTime();
        file.status = "Initialized" /* INIT */;
        // split file into parts and set it as waiting
        this.payloads[id] = {
            file: file,
            parts: [],
        };
        return id;
    };
    /**
     * Returns host for upload (region based)
     *
     * @private
     * @returns
     * @memberof S3Uploader
     */
    S3Uploader.prototype.getUploadUrl = function (id) {
        var location_url = this.getDefaultFields(id, ['location_url']).location_url;
        return location_url.indexOf('http') === 0 ? location_url : "https://" + location_url;
    };
    /**
     * Returns formatted store options
     *
     * @private
     * @returns
     * @memberof S3Uploader
     */
    S3Uploader.prototype.getStoreOptions = function () {
        return tslib_1.__assign({ location: abstract_1.DEFAULT_STORE_LOCATION }, this.storeOptions);
    };
    /**
     * Returns all default fields for filestack requests
     *
     * @private
     * @returns
     * @memberof S3Uploader
     */
    S3Uploader.prototype.getDefaultFields = function (id, requiredFields, fiiFallback) {
        if (fiiFallback === void 0) { fiiFallback = false; }
        var payload = this.getPayloadById(id);
        var fields = tslib_1.__assign({}, this.security, { apikey: this.apikey, uri: payload.uri, location_url: payload.location_url, upload_id: payload.upload_id, region: payload.region });
        if (this.uploadMode === "intelligent" /* INTELLIGENT */ || (this.uploadMode === "fallback" /* FALLBACK */ && fiiFallback)) {
            fields['fii'] = true;
        }
        return tslib_1.__assign({}, utils_1.filterObject(fields, requiredFields), { store: this.getStoreOptions() });
    };
    /**
     * Returns default headers needed for filestack request
     *
     * @private
     * @returns
     * @memberof S3Uploader
     */
    S3Uploader.prototype.getDefaultHeaders = function (id) {
        var headers = {};
        var file = this.getPayloadById(id);
        if (file.location_region) {
            headers['Filestack-Upload-Region'] = file.location_region;
        }
        return headers;
    };
    S3Uploader.prototype.getPayloadById = function (id) {
        return this.payloads[id];
    };
    /**
     * Split file onto parts for uploading with multipart mechanism and setup start
     *
     * @private
     * @memberof S3Uploader
     */
    S3Uploader.prototype.prepareParts = function (id) {
        var file = this.getPayloadById(id).file;
        // for intelligent or fallback mode we cant overwrite part size - requires 8MB
        if (["intelligent" /* INTELLIGENT */, "fallback" /* FALLBACK */].indexOf(this.uploadMode) > -1) {
            this.partSize = abstract_1.INTELLIGENT_CHUNK_SIZE;
        }
        var partsCount = file.getPartsCount(this.partSize);
        var parts = [];
        for (var i = 0; i < partsCount; i++) {
            parts[i] = tslib_1.__assign({}, file.getPartMetadata(i, this.partSize), { offset: 0 });
        }
        // split file into parts and set it as waiting
        this.payloads[id].parts = parts;
        return Promise.resolve();
    };
    /**
     * Make start request for getting needed upload fields
     *
     * @private
     * @returns {Promise<any>}
     * @memberof S3Uploader
     */
    S3Uploader.prototype.startRequest = function (id) {
        var _this = this;
        var payload = this.getPayloadById(id);
        debug("[" + id + "] Make start request");
        return request_1.postWithRetry(this.getUrl() + "/multipart/start", tslib_1.__assign({ filename: payload.file.name, mimetype: payload.file.type, size: payload.file.size }, this.getDefaultFields(id, ['apikey', 'policy', 'signature', 'fii'], true)), {
            timeout: this.timeout,
            cancelToken: this.cancelToken.token,
            headers: this.getDefaultHeaders(id),
        }, this.retryConfig)
            .then(function (_a) {
            var data = _a.data;
            if (!data || !data.location_url || !data.region || !data.upload_id || !data.uri) {
                debug("[" + id + "] Incorrect start response: \n%O\n", data);
                _this.setPayloadStatus(id, "Failed" /* FAILED */);
                return Promise.reject(new filestack_error_1.FilestackError('Incorrect start response', data, filestack_error_1.FilestackErrorType.REQUEST));
            }
            debug("[" + id + "] Assign payload data: \n%O\n", data);
            _this.updatePayload(id, data);
            // ii is not enabled in backend switch back to default upload mode
            if (["intelligent" /* INTELLIGENT */, "fallback" /* FALLBACK */].indexOf(_this.uploadMode) > -1 && (!data.upload_type || data.upload_type !== 'intelligent_ingestion')) {
                debug("[" + id + "] Intelligent Ingestion is not enabled on account, switch back to regular upload and lock mode change");
                _this.setUploadMode("default" /* DEFAULT */, true);
            }
            return data;
        })
            .catch(function (err) {
            debug("[" + id + "] Start request error %O", err);
            _this.setPayloadStatus(id, "Failed" /* FAILED */);
            return Promise.reject(new filestack_error_1.FilestackError('Cannot upload file', err.data, filestack_error_1.FilestackErrorType.REQUEST));
        });
    };
    /**
     * Enqueue file parts to upload
     *
     * @private
     * @returns
     * @memberof S3Uploader
     */
    S3Uploader.prototype.startPartsQueue = function (id) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var payload, parts, waitingLength;
            var _this = this;
            return tslib_1.__generator(this, function (_a) {
                payload = this.getPayloadById(id);
                parts = payload.parts;
                waitingLength = parts.length;
                debug("[" + id + "] Create uploading queue from file. parts count - %d", waitingLength);
                parts.forEach(function (part) {
                    return _this.partsQueue
                        .add(function () { return _this.startPart(id, part.partNumber); })
                        .catch(function (e) {
                        _this.setPayloadStatus(id, "Failed" /* FAILED */);
                        debug("[" + id + "] Failed to upload part %s", e.message);
                    });
                });
                debug("[" + id + "] All tasks for %s enqueued. Start processing main upload queue", id);
                this.partsQueue.start();
                return [2 /*return*/, this.partsQueue.onIdle()];
            });
        });
    };
    /**
     * Decide if upload should be made using ii or regular upload
     * It allows change upload mode during upload queue
     *
     * @private
     * @param {number} partNumber
     * @returns {Promise<any>}
     * @memberof S3Uploader
     */
    S3Uploader.prototype.startPart = function (id, partNumber) {
        debug("[" + id + "] Start processing part " + partNumber + " with mode " + this.uploadMode);
        var payload = this.getPayloadById(id);
        payload.file.status = "Progress" /* PROGRESS */;
        return (this.uploadMode !== "intelligent" /* INTELLIGENT */ ? this.uploadRegular : this.uploadIntelligent).apply(this, [id, partNumber]);
    };
    /**
     * Returns part data needed for upload
     *
     * @private
     * @param {string} id - id of a currently uploading file
     * @param {FilePart} part
     * @returns
     * @memberof S3Uploader
     */
    S3Uploader.prototype.getS3PartMetadata = function (id, part, offset) {
        var _this = this;
        var url = this.getUploadUrl(id);
        debug("[" + id + "] Get data for part " + part.partNumber + ", url " + url + ", Md5: " + part.md5 + ", Size: " + part.size);
        return request_1.postWithRetry(url + "/multipart/upload", tslib_1.__assign({}, this.getDefaultFields(id, ['apikey', 'uri', 'region', 'signature', 'policy', 'upload_id', 'fii']), { 
            // method specific keys
            part: part.partNumber + 1, md5: part.md5, size: part.size, offset: offset }), {
            headers: this.getDefaultHeaders(id),
            cancelToken: this.cancelToken.token,
            timeout: this.timeout,
        }, this.retryConfig).catch(function (err) {
            _this.setPayloadStatus(id, "Failed" /* FAILED */);
            return Promise.reject(new filestack_error_1.FilestackError('Cannot get part metadata', err.data, filestack_error_1.FilestackErrorType.REQUEST));
        });
    };
    /**
     * Regular multipart request to amazon
     *
     * @private
     * @param {number} partNumber
     * @returns {Promise<any>}
     * @memberof S3Uploader
     */
    S3Uploader.prototype.uploadRegular = function (id, partNumber) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var payload, partMetadata, part, _a, data, headers;
            var _this = this;
            return tslib_1.__generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        payload = this.getPayloadById(id);
                        partMetadata = payload.parts[partNumber];
                        part = payload.file.getPartByMetadata(partMetadata);
                        return [4 /*yield*/, this.getS3PartMetadata(id, part)];
                    case 1:
                        _a = _b.sent(), data = _a.data, headers = _a.headers;
                        debug("[" + id + "] Received part " + partNumber + " info body: \n%O\n headers: \n%O\n", data, headers);
                        // retry only in regular upload mode
                        if (this.retryConfig && this.uploadMode !== "fallback" /* FALLBACK */) {
                            request_1.useRetryPolicy(request_1.request, this.retryConfig);
                        }
                        return [2 /*return*/, request_1.request
                                .put(data.url, part.buffer, {
                                cancelToken: this.cancelToken.token,
                                timeout: this.timeout,
                                headers: data.headers,
                                // for now we cant test progress callback from upload
                                /* istanbul ignore next */
                                onUploadProgress: function (pr) { return _this.onProgressUpdate(id, partNumber, pr.loaded); },
                            })
                                .then(function (res) {
                                if (res.headers.etag) {
                                    _this.setPartETag(id, partNumber, res.headers.etag);
                                }
                                debug("[" + id + "] S3 Upload response headers for " + partNumber + ": \n%O\n", res.headers);
                                _this.onProgressUpdate(id, partNumber, part.size);
                                return res;
                            })
                                .catch(function (err) {
                                // reset upload progress on failed part
                                _this.onProgressUpdate(id, partNumber, 0);
                                // if fallback, set upload mode to intelligent and restart current part
                                if ((_this.uploadMode === "fallback" /* FALLBACK */ && !_this.isModeLocked) || _this.uploadMode === "intelligent" /* INTELLIGENT */) {
                                    debug("[" + id + "] Regular upload failed. Switching to intelligent ingestion mode");
                                    _this.setUploadMode("intelligent" /* INTELLIGENT */);
                                    // restart part
                                    return _this.startPart(id, partNumber);
                                }
                                return Promise.reject(new filestack_error_1.FilestackError('Cannot upload file part', err.data, filestack_error_1.FilestackErrorType.REQUEST));
                            })];
                }
            });
        });
    };
    /**
     * Upload file using intelligent mechanism
     *
     * @private
     * @param {string} id
     * @param {number} partNumber
     * @returns {Promise<any>}
     * @memberof S3Uploader
     */
    S3Uploader.prototype.uploadIntelligent = function (id, partNumber) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var _this = this;
            return tslib_1.__generator(this, function (_a) {
                return [2 /*return*/, this.uploadNextChunk(id, partNumber).then(function () { return _this.commitPart(id, partNumber); })];
            });
        });
    };
    /**
     * Recursively upload file in chunk mode (intelligent ingession)
     *
     * @private
     * @param {string} id
     * @param {number} partNumber
     * @param {number} chunkSize
     * @returns
     * @memberof S3Uploader
     */
    S3Uploader.prototype.uploadNextChunk = function (id, partNumber, chunkSize) {
        if (chunkSize === void 0) { chunkSize = this.intelligentChunkSize; }
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var payload, part, chunk, data;
            var _this = this;
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        payload = this.getPayloadById(id);
                        part = payload.parts[partNumber];
                        chunkSize = Math.min(chunkSize, part.size - part.offset);
                        chunk = payload.file.getChunkByMetadata(part, part.offset, chunkSize);
                        debug("[" + id + "] PartNum: " + partNumber + ", PartSize: " + part.size + ", StartByte: " + part.startByte + ", Offset: " + part.offset + ", ChunkSize: " + chunk.size + ",\n       Left: " + (part.size - part.offset - chunk.size));
                        return [4 /*yield*/, this.getS3PartMetadata(id, chunk, part.offset).catch(function (err) {
                                debug("[" + id + "] Getting chunk data for ii failed %O, Chunk size: " + chunkSize + ", offset " + part.offset + ", part " + partNumber, err);
                                return Promise.reject(err);
                            })];
                    case 1:
                        data = (_a.sent()).data;
                        return [2 /*return*/, request_1.request
                                .put(data.url, chunk.buffer, {
                                cancelToken: this.cancelToken.token,
                                timeout: this.timeout,
                                headers: data.headers,
                                // for now we cant test progress callback from upload
                                /* istanbul ignore next */
                                onUploadProgress: function (pr) { return _this.onProgressUpdate(id, partNumber, part.offset + pr.loaded); },
                            })
                                .then(function (res) {
                                _this.onProgressUpdate(id, partNumber, part.offset + chunk.size);
                                var newOffset = Math.min(part.offset + chunkSize, part.size);
                                debug("[" + id + "] S3 Chunk uploaded! offset: " + part.offset + ", part " + partNumber + "! response headers for " + partNumber + ": \n%O\n", res.headers);
                                _this.setPartData(id, partNumber, 'offset', newOffset);
                                // if all chunks was uploaded then return resolve
                                if (newOffset === part.size) {
                                    return Promise.resolve(res);
                                }
                                return _this.uploadNextChunk(id, partNumber, chunkSize);
                            })
                                .catch(function (err) {
                                // reset progress on failed upload
                                _this.onProgressUpdate(id, partNumber, part.offset);
                                var nextChunkSize = chunkSize / 2;
                                if (nextChunkSize < abstract_1.MIN_CHUNK_SIZE) {
                                    debug("[" + id + "] Minimal chunk size limit. Upload file failed!");
                                    return Promise.reject(new filestack_error_1.FilestackError('Min chunk size reached', err.data, filestack_error_1.FilestackErrorType.REQUEST));
                                }
                                if (request_1.shouldRetry(err)) {
                                    debug("[" + id + "] Request network error. Retry with new chunk size: " + nextChunkSize);
                                    return _this.uploadNextChunk(id, partNumber, nextChunkSize);
                                }
                                return Promise.reject(new filestack_error_1.FilestackError('Cannot upload file part', err.data, filestack_error_1.FilestackErrorType.REQUEST));
                            })
                                .finally(function () {
                                part = null;
                                chunk = null;
                            })];
                }
            });
        });
    };
    /**
     * Commit after upload all chunks of the part in ii mode
     *
     * @private
     * @param {string} id
     * @param {FilePart} part
     * @returns
     * @memberof S3Uploader
     */
    S3Uploader.prototype.commitPart = function (id, partNumber) {
        var payload = this.getPayloadById(id);
        var part = payload.parts[partNumber];
        return request_1.postWithRetry(this.getUploadUrl(id) + "/multipart/commit", tslib_1.__assign({}, this.getDefaultFields(id, ['apikey', 'region', 'upload_id', 'policy', 'signature', 'uri']), { size: payload.file.size, part: part.partNumber + 1 }), {
            cancelToken: this.cancelToken.token,
            timeout: this.timeout,
            headers: this.getDefaultHeaders(id),
        }, this.retryConfig).then(function (res) {
            debug("[" + id + "] Commit Part number " + part.partNumber + ". Response: %O", res.data);
            return res;
        });
    };
    /**
     * Complete request to merge all parts and get file handle etc
     *
     * @private
     * @returns
     * @memberof S3Uploader
     */
    S3Uploader.prototype.completeRequest = function (id) {
        var _this = this;
        var payload = this.getPayloadById(id);
        var parts = [];
        if (payload.file.status === "Failed" /* FAILED */) {
            return Promise.resolve();
        }
        debug("[" + id + "] Run complete request");
        var partsHandle = payload.parts;
        var partLen = partsHandle.length;
        for (var i = 0; i < partLen; i++) {
            if (partsHandle[i].etag) {
                parts.push({ part_number: i + 1, etag: partsHandle[i].etag });
            }
        }
        debug("[" + id + "] Etags %O", parts);
        return request_1.postWithRetry(this.getUrl() + "/multipart/complete", tslib_1.__assign({}, this.getDefaultFields(id, ['apikey', 'policy', 'signature', 'uri', 'region', 'upload_id', 'fii'], true), { 
            // method specific keys
            filename: payload.file.name, mimetype: payload.file.type, size: payload.file.size, parts: parts.length ? parts : undefined }), {
            timeout: this.timeout,
            cancelToken: this.cancelToken.token,
            headers: this.getDefaultHeaders(id),
        }, this.retryConfig)
            .then(function (res) {
            // if parts hasnt been merged, retry complete request again
            if (res.status === 202) {
                return new Promise(function (resolve, reject) {
                    setTimeout(function () {
                        return _this.completeRequest(id)
                            .then(resolve)
                            .catch(reject);
                    }, COMPLETE_TIMEOUT);
                });
            }
            // update file object
            var file = _this.getPayloadById(id).file;
            file.handle = res.data.handle;
            file.url = res.data.url;
            file.container = res.data.container;
            file.key = res.data.key;
            file.workflows = res.data.workflows;
            file.status = res.data.status;
            return file;
        })
            .catch(function (err) {
            _this.setPayloadStatus(id, "Failed" /* FAILED */);
            return Promise.reject(new filestack_error_1.FilestackError('Cannot complete file', err.data, filestack_error_1.FilestackErrorType.REQUEST));
        });
    };
    /**
     * UUpgrade upload progress and run progress event
     *
     * @private
     * @param {string} id
     * @param {number} partNumber
     * @param {number} loaded
     * @memberof S3Uploader
     */
    S3Uploader.prototype.onProgressUpdate = function (id, partNumber, loaded) {
        this.setPartData(id, partNumber, 'progress', loaded);
        this.emitProgress();
    };
    /**
     * Emits normalized progress event
     *
     * @private
     * @memberof S3Uploader
     */
    S3Uploader.prototype.emitProgress = function () {
        var totalSize = 0;
        var totalBytes = 0;
        var filesProgress = {};
        for (var i in this.payloads) {
            var payload = this.payloads[i];
            // omit all failed files in progress event
            // this shouldn't happend because of promises rejection in execute. Left to be sure
            /* istanbul ignore next */
            if (payload.file.status === "Failed" /* FAILED */) {
                continue;
            }
            var partsProgress = payload.parts.map(function (p) { return p.progress || 0; });
            var totalParts = partsProgress.reduce(function (a, b) { return a + b; });
            totalBytes = totalBytes + totalParts;
            filesProgress[i] = {
                totalBytes: totalParts || 0,
                totalPercent: Math.round((totalParts * 100) / payload.file.size) || 0,
            };
            totalSize = totalSize + payload.file.size;
        }
        var res = {
            totalBytes: totalBytes || 0,
            totalPercent: Math.round((totalBytes * 100) / totalSize) || 0,
            files: filesProgress,
        };
        debug("Upload progress %O", res);
        this.emit('progress', res);
    };
    /**
     * Apply provided data to given payload
     *
     * @private
     * @param {string} id
     * @param {*} data
     * @memberof S3Uploader
     */
    S3Uploader.prototype.updatePayload = function (id, data) {
        this.payloads[id] = tslib_1.__assign({}, this.payloads[id], data);
    };
    /**
     * Sets etag for part
     *
     * @private
     * @param {number} partNumber
     * @param {string} etag
     * @memberof S3Uploader
     */
    S3Uploader.prototype.setPartETag = function (id, partNumber, etag) {
        debug("[" + id + "] Set " + etag + " etag for part " + partNumber);
        this.getPayloadById(id).parts[partNumber].etag = etag;
    };
    /**
     * Sets part value for a key
     *
     * @private
     * @param {number} partNumber
     * @param {string} etag
     * @memberof S3Uploader
     */
    S3Uploader.prototype.setPartData = function (id, partNumber, key, value) {
        debug("[" + id + "] Set " + key + " = " + value + " for part " + partNumber);
        this.getPayloadById(id).parts[partNumber][key] = value;
    };
    /**
     * Set payload file state
     *
     * @param id
     * @param status
     */
    S3Uploader.prototype.setPayloadStatus = function (id, status) {
        debug("[" + id + "] Set payload status to " + status);
        this.payloads[id].file.status = status;
    };
    return S3Uploader;
}(abstract_1.UploaderAbstract));
exports.S3Uploader = S3Uploader;
