const { isArray } = require('./utils/isArray');
							 | 
						|
								
							 | 
						|
								const proto = exports;
							 | 
						|
								
							 | 
						|
								proto._parallelNode = async function _parallelNode(todo, parallel, fn, sourceData) {
							 | 
						|
								  const that = this;
							 | 
						|
								  // upload in parallel
							 | 
						|
								  const jobErr = [];
							 | 
						|
								  let jobs = [];
							 | 
						|
								  const tempBatch = todo.length / parallel;
							 | 
						|
								  const remainder = todo.length % parallel;
							 | 
						|
								  const batch = remainder === 0 ? tempBatch : (todo.length - remainder) / parallel + 1;
							 | 
						|
								  let taskIndex = 1;
							 | 
						|
								  for (let i = 0; i < todo.length; i++) {
							 | 
						|
								    if (that.isCancel()) {
							 | 
						|
								      break;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (sourceData) {
							 | 
						|
								      jobs.push(fn(that, todo[i], sourceData));
							 | 
						|
								    } else {
							 | 
						|
								      jobs.push(fn(that, todo[i]));
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (jobs.length === parallel || (taskIndex === batch && i === todo.length - 1)) {
							 | 
						|
								      try {
							 | 
						|
								        taskIndex += 1;
							 | 
						|
								        /* eslint no-await-in-loop: [0] */
							 | 
						|
								        await Promise.all(jobs);
							 | 
						|
								      } catch (err) {
							 | 
						|
								        jobErr.push(err);
							 | 
						|
								      }
							 | 
						|
								      jobs = [];
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  return jobErr;
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								proto._parallel = function _parallel(todo, parallel, jobPromise) {
							 | 
						|
								  const that = this;
							 | 
						|
								  return new Promise(resolve => {
							 | 
						|
								    const _jobErr = [];
							 | 
						|
								    if (parallel <= 0 || !todo) {
							 | 
						|
								      resolve(_jobErr);
							 | 
						|
								      return;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    function onlyOnce(fn) {
							 | 
						|
								      return function (...args) {
							 | 
						|
								        if (fn === null) throw new Error('Callback was already called.');
							 | 
						|
								        const callFn = fn;
							 | 
						|
								        fn = null;
							 | 
						|
								        callFn.apply(this, args);
							 | 
						|
								      };
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    function createArrayIterator(coll) {
							 | 
						|
								      let i = -1;
							 | 
						|
								      const len = coll.length;
							 | 
						|
								      return function next() {
							 | 
						|
								        return ++i < len && !that.isCancel() ? { value: coll[i], key: i } : null;
							 | 
						|
								      };
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    const nextElem = createArrayIterator(todo);
							 | 
						|
								    let done = false;
							 | 
						|
								    let running = 0;
							 | 
						|
								    let looping = false;
							 | 
						|
								
							 | 
						|
								    function iterateeCallback(err) {
							 | 
						|
								      running -= 1;
							 | 
						|
								      if (err) {
							 | 
						|
								        done = true;
							 | 
						|
								        _jobErr.push(err);
							 | 
						|
								        resolve(_jobErr);
							 | 
						|
								      } else if (done && running <= 0) {
							 | 
						|
								        done = true;
							 | 
						|
								        resolve(_jobErr);
							 | 
						|
								      } else if (!looping) {
							 | 
						|
								        /* eslint no-use-before-define: [0] */
							 | 
						|
								        if (that.isCancel()) {
							 | 
						|
								          resolve(_jobErr);
							 | 
						|
								        } else {
							 | 
						|
								          replenish();
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    function iteratee(value, callback) {
							 | 
						|
								      jobPromise(value)
							 | 
						|
								        .then(result => {
							 | 
						|
								          callback(null, result);
							 | 
						|
								        })
							 | 
						|
								        .catch(err => {
							 | 
						|
								          callback(err);
							 | 
						|
								        });
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    function replenish() {
							 | 
						|
								      looping = true;
							 | 
						|
								      while (running < parallel && !done && !that.isCancel()) {
							 | 
						|
								        const elem = nextElem();
							 | 
						|
								        if (elem === null || _jobErr.length > 0) {
							 | 
						|
								          done = true;
							 | 
						|
								          if (running <= 0) {
							 | 
						|
								            resolve(_jobErr);
							 | 
						|
								          }
							 | 
						|
								          return;
							 | 
						|
								        }
							 | 
						|
								        running += 1;
							 | 
						|
								        iteratee(elem.value, onlyOnce(iterateeCallback));
							 | 
						|
								      }
							 | 
						|
								      looping = false;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    replenish();
							 | 
						|
								  });
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * cancel operation, now can use with multipartUpload
							 | 
						|
								 * @param {Object} abort
							 | 
						|
								 *        {String} anort.name object key
							 | 
						|
								 *        {String} anort.uploadId upload id
							 | 
						|
								 *        {String} anort.options timeout
							 | 
						|
								 */
							 | 
						|
								proto.cancel = function cancel(abort) {
							 | 
						|
								  this.options.cancelFlag = true;
							 | 
						|
								
							 | 
						|
								  if (isArray(this.multipartUploadStreams)) {
							 | 
						|
								    this.multipartUploadStreams.forEach(_ => {
							 | 
						|
								      if (_.destroyed === false) {
							 | 
						|
								        const err = {
							 | 
						|
								          name: 'cancel',
							 | 
						|
								          message: 'cancel'
							 | 
						|
								        };
							 | 
						|
								        _.destroy(err);
							 | 
						|
								      }
							 | 
						|
								    });
							 | 
						|
								  }
							 | 
						|
								  this.multipartUploadStreams = [];
							 | 
						|
								  if (abort) {
							 | 
						|
								    this.abortMultipartUpload(abort.name, abort.uploadId, abort.options);
							 | 
						|
								  }
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								proto.isCancel = function isCancel() {
							 | 
						|
								  return this.options.cancelFlag;
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								proto.resetCancelFlag = function resetCancelFlag() {
							 | 
						|
								  this.options.cancelFlag = false;
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								proto._stop = function _stop() {
							 | 
						|
								  this.options.cancelFlag = true;
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								// cancel is not error , so create an object
							 | 
						|
								proto._makeCancelEvent = function _makeCancelEvent() {
							 | 
						|
								  const cancelEvent = {
							 | 
						|
								    status: 0,
							 | 
						|
								    name: 'cancel'
							 | 
						|
								  };
							 | 
						|
								  return cancelEvent;
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								// abort is not error , so create an object
							 | 
						|
								proto._makeAbortEvent = function _makeAbortEvent() {
							 | 
						|
								  const abortEvent = {
							 | 
						|
								    status: 0,
							 | 
						|
								    name: 'abort',
							 | 
						|
								    message: 'upload task has been abort'
							 | 
						|
								  };
							 | 
						|
								  return abortEvent;
							 | 
						|
								};
							 |