| 
						 | 
						- /* eslint-disable no-async-promise-executor */
 - 
 - const debug = require('debug')('ali-oss:multipart-copy');
 - const copy = require('copy-to');
 - 
 - const proto = exports;
 - 
 - /**
 -  * Upload a part copy in a multipart from the source bucket/object
 -  * used with initMultipartUpload and completeMultipartUpload.
 -  * @param {String} name copy object name
 -  * @param {String} uploadId the upload id
 -  * @param {Number} partNo the part number
 -  * @param {String} range  like 0-102400  part size need to copy
 -  * @param {Object} sourceData
 -  *        {String} sourceData.sourceKey  the source object name
 -  *        {String} sourceData.sourceBucketName  the source bucket name
 -  * @param {Object} options
 -  */
 - /* eslint max-len: [0] */
 - proto.uploadPartCopy = async function uploadPartCopy(name, uploadId, partNo, range, sourceData, options = {}) {
 -   options.headers = options.headers || {};
 -   const versionId = options.versionId || (options.subres && options.subres.versionId) || null;
 -   let copySource;
 -   if (versionId) {
 -     copySource = `/${sourceData.sourceBucketName}/${encodeURIComponent(sourceData.sourceKey)}?versionId=${versionId}`;
 -   } else {
 -     copySource = `/${sourceData.sourceBucketName}/${encodeURIComponent(sourceData.sourceKey)}`;
 -   }
 - 
 -   options.headers['x-oss-copy-source'] = copySource;
 -   if (range) {
 -     options.headers['x-oss-copy-source-range'] = `bytes=${range}`;
 -   }
 - 
 -   options.subres = {
 -     partNumber: partNo,
 -     uploadId
 -   };
 -   const params = this._objectRequestParams('PUT', name, options);
 -   params.mime = options.mime;
 -   params.successStatuses = [200];
 - 
 -   const result = await this.request(params);
 - 
 -   return {
 -     name,
 -     etag: result.res.headers.etag,
 -     res: result.res
 -   };
 - };
 - 
 - /**
 -  * @param {String} name copy object name
 -  * @param {Object} sourceData
 -  *        {String} sourceData.sourceKey  the source object name
 -  *        {String} sourceData.sourceBucketName  the source bucket name
 -  *        {Number} sourceData.startOffset  data copy start byte offset, e.g: 0
 -  *        {Number} sourceData.endOffset  data copy end byte offset, e.g: 102400
 -  * @param {Object} options
 -  *        {Number} options.partSize
 -  */
 - proto.multipartUploadCopy = async function multipartUploadCopy(name, sourceData, options = {}) {
 -   this.resetCancelFlag();
 -   const { versionId = null } = options;
 -   const metaOpt = {
 -     versionId
 -   };
 -   const objectMeta = await this._getObjectMeta(sourceData.sourceBucketName, sourceData.sourceKey, metaOpt);
 -   const fileSize = objectMeta.res.headers['content-length'];
 -   sourceData.startOffset = sourceData.startOffset || 0;
 -   sourceData.endOffset = sourceData.endOffset || fileSize;
 - 
 -   if (options.checkpoint && options.checkpoint.uploadId) {
 -     return await this._resumeMultipartCopy(options.checkpoint, sourceData, options);
 -   }
 - 
 -   const minPartSize = 100 * 1024;
 - 
 -   const copySize = sourceData.endOffset - sourceData.startOffset;
 -   if (copySize < minPartSize) {
 -     throw new Error(`copySize must not be smaller than ${minPartSize}`);
 -   }
 - 
 -   if (options.partSize && options.partSize < minPartSize) {
 -     throw new Error(`partSize must not be smaller than ${minPartSize}`);
 -   }
 - 
 -   const init = await this.initMultipartUpload(name, options);
 -   const { uploadId } = init;
 -   const partSize = this._getPartSize(copySize, options.partSize);
 - 
 -   const checkpoint = {
 -     name,
 -     copySize,
 -     partSize,
 -     uploadId,
 -     doneParts: []
 -   };
 - 
 -   if (options && options.progress) {
 -     await options.progress(0, checkpoint, init.res);
 -   }
 - 
 -   return await this._resumeMultipartCopy(checkpoint, sourceData, options);
 - };
 - 
 - /*
 -  * Resume multipart copy from checkpoint. The checkpoint will be
 -  * updated after each successful part copy.
 -  * @param {Object} checkpoint the checkpoint
 -  * @param {Object} options
 -  */
 - proto._resumeMultipartCopy = async function _resumeMultipartCopy(checkpoint, sourceData, options) {
 -   if (this.isCancel()) {
 -     throw this._makeCancelEvent();
 -   }
 -   const { versionId = null } = options;
 -   const metaOpt = {
 -     versionId
 -   };
 -   const { copySize, partSize, uploadId, doneParts, name } = checkpoint;
 - 
 -   const partOffs = this._divideMultipartCopyParts(copySize, partSize, sourceData.startOffset);
 -   const numParts = partOffs.length;
 - 
 -   const uploadPartCopyOptions = {
 -     headers: {}
 -   };
 - 
 -   if (options.copyheaders) {
 -     copy(options.copyheaders).to(uploadPartCopyOptions.headers);
 -   }
 -   if (versionId) {
 -     copy(metaOpt).to(uploadPartCopyOptions);
 -   }
 - 
 -   const uploadPartJob = function uploadPartJob(self, partNo, source) {
 -     return new Promise(async (resolve, reject) => {
 -       try {
 -         if (!self.isCancel()) {
 -           const pi = partOffs[partNo - 1];
 -           const range = `${pi.start}-${pi.end - 1}`;
 - 
 -           let result;
 -           try {
 -             result = await self.uploadPartCopy(name, uploadId, partNo, range, source, uploadPartCopyOptions);
 -           } catch (error) {
 -             if (error.status === 404) {
 -               throw self._makeAbortEvent();
 -             }
 -             throw error;
 -           }
 -           if (!self.isCancel()) {
 -             debug(`content-range ${result.res.headers['content-range']}`);
 -             doneParts.push({
 -               number: partNo,
 -               etag: result.res.headers.etag
 -             });
 -             checkpoint.doneParts = doneParts;
 - 
 -             if (options && options.progress) {
 -               await options.progress(doneParts.length / numParts, checkpoint, result.res);
 -             }
 -           }
 -         }
 -         resolve();
 -       } catch (err) {
 -         err.partNum = partNo;
 -         reject(err);
 -       }
 -     });
 -   };
 - 
 -   const all = Array.from(new Array(numParts), (x, i) => i + 1);
 -   const done = doneParts.map(p => p.number);
 -   const todo = all.filter(p => done.indexOf(p) < 0);
 -   const defaultParallel = 5;
 -   const parallel = options.parallel || defaultParallel;
 - 
 -   if (this.checkBrowserAndVersion('Internet Explorer', '10') || parallel === 1) {
 -     for (let i = 0; i < todo.length; i++) {
 -       if (this.isCancel()) {
 -         throw this._makeCancelEvent();
 -       }
 -       /* eslint no-await-in-loop: [0] */
 -       await uploadPartJob(this, todo[i], sourceData);
 -     }
 -   } else {
 -     // upload in parallel
 -     const errors = await this._parallelNode(todo, parallel, uploadPartJob, sourceData);
 - 
 -     const abortEvent = errors.find(err => err.name === 'abort');
 -     if (abortEvent) throw abortEvent;
 - 
 -     if (this.isCancel()) {
 -       throw this._makeCancelEvent();
 -     }
 - 
 -     // check errors after all jobs are completed
 -     if (errors && errors.length > 0) {
 -       const err = errors[0];
 -       err.message = `Failed to copy some parts with error: ${err.toString()} part_num: ${err.partNum}`;
 -       throw err;
 -     }
 -   }
 - 
 -   return await this.completeMultipartUpload(name, uploadId, doneParts, options);
 - };
 - 
 - proto._divideMultipartCopyParts = function _divideMultipartCopyParts(fileSize, partSize, startOffset) {
 -   const numParts = Math.ceil(fileSize / partSize);
 - 
 -   const partOffs = [];
 -   for (let i = 0; i < numParts; i++) {
 -     const start = partSize * i + startOffset;
 -     const end = Math.min(start + partSize, fileSize + startOffset);
 - 
 -     partOffs.push({
 -       start,
 -       end
 -     });
 -   }
 - 
 -   return partOffs;
 - };
 - 
 - /**
 -  * Get Object Meta
 -  * @param {String} bucket  bucket name
 -  * @param {String} name   object name
 -  * @param {Object} options
 -  */
 - proto._getObjectMeta = async function _getObjectMeta(bucket, name, options) {
 -   const currentBucket = this.getBucket();
 -   this.setBucket(bucket);
 -   const data = await this.head(name, options);
 -   this.setBucket(currentBucket);
 -   return data;
 - };
 
 
  |