const copy = require('copy-to');
							 | 
						|
								const callback = require('./callback');
							 | 
						|
								const { deepCopyWith } = require('./utils/deepCopy');
							 | 
						|
								const { isBuffer } = require('./utils/isBuffer');
							 | 
						|
								const { omit } = require('./utils/omit');
							 | 
						|
								
							 | 
						|
								const proto = exports;
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * List the on-going multipart uploads
							 | 
						|
								 * https://help.aliyun.com/document_detail/31997.html
							 | 
						|
								 * @param {Object} options
							 | 
						|
								 * @return {Array} the multipart uploads
							 | 
						|
								 */
							 | 
						|
								proto.listUploads = async function listUploads(query, options) {
							 | 
						|
								  options = options || {};
							 | 
						|
								  const opt = {};
							 | 
						|
								  copy(options).to(opt);
							 | 
						|
								  opt.subres = 'uploads';
							 | 
						|
								  const params = this._objectRequestParams('GET', '', opt);
							 | 
						|
								  params.query = query;
							 | 
						|
								  params.xmlResponse = true;
							 | 
						|
								  params.successStatuses = [200];
							 | 
						|
								
							 | 
						|
								  const result = await this.request(params);
							 | 
						|
								  let uploads = result.data.Upload || [];
							 | 
						|
								  if (!Array.isArray(uploads)) {
							 | 
						|
								    uploads = [uploads];
							 | 
						|
								  }
							 | 
						|
								  uploads = uploads.map(up => ({
							 | 
						|
								    name: up.Key,
							 | 
						|
								    uploadId: up.UploadId,
							 | 
						|
								    initiated: up.Initiated
							 | 
						|
								  }));
							 | 
						|
								
							 | 
						|
								  return {
							 | 
						|
								    res: result.res,
							 | 
						|
								    uploads,
							 | 
						|
								    bucket: result.data.Bucket,
							 | 
						|
								    nextKeyMarker: result.data.NextKeyMarker,
							 | 
						|
								    nextUploadIdMarker: result.data.NextUploadIdMarker,
							 | 
						|
								    isTruncated: result.data.IsTruncated === 'true'
							 | 
						|
								  };
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * List the done uploadPart parts
							 | 
						|
								 * @param {String} name object name
							 | 
						|
								 * @param {String} uploadId multipart upload id
							 | 
						|
								 * @param {Object} query
							 | 
						|
								 * {Number} query.max-parts The maximum part number in the response of the OSS. Default value: 1000
							 | 
						|
								 * {Number} query.part-number-marker Starting position of a specific list.
							 | 
						|
								 * {String} query.encoding-type Specify the encoding of the returned content and the encoding type.
							 | 
						|
								 * @param {Object} options
							 | 
						|
								 * @return {Object} result
							 | 
						|
								 */
							 | 
						|
								proto.listParts = async function listParts(name, uploadId, query, options) {
							 | 
						|
								  options = options || {};
							 | 
						|
								  const opt = {};
							 | 
						|
								  copy(options).to(opt);
							 | 
						|
								  opt.subres = {
							 | 
						|
								    uploadId
							 | 
						|
								  };
							 | 
						|
								  const params = this._objectRequestParams('GET', name, opt);
							 | 
						|
								  params.query = query;
							 | 
						|
								  params.xmlResponse = true;
							 | 
						|
								  params.successStatuses = [200];
							 | 
						|
								
							 | 
						|
								  const result = await this.request(params);
							 | 
						|
								
							 | 
						|
								  return {
							 | 
						|
								    res: result.res,
							 | 
						|
								    uploadId: result.data.UploadId,
							 | 
						|
								    bucket: result.data.Bucket,
							 | 
						|
								    name: result.data.Key,
							 | 
						|
								    partNumberMarker: result.data.PartNumberMarker,
							 | 
						|
								    nextPartNumberMarker: result.data.NextPartNumberMarker,
							 | 
						|
								    maxParts: result.data.MaxParts,
							 | 
						|
								    isTruncated: result.data.IsTruncated,
							 | 
						|
								    parts: result.data.Part || []
							 | 
						|
								  };
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Abort a multipart upload transaction
							 | 
						|
								 * @param {String} name the object name
							 | 
						|
								 * @param {String} uploadId the upload id
							 | 
						|
								 * @param {Object} options
							 | 
						|
								 */
							 | 
						|
								proto.abortMultipartUpload = async function abortMultipartUpload(name, uploadId, options) {
							 | 
						|
								  this._stop();
							 | 
						|
								  options = options || {};
							 | 
						|
								  const opt = {};
							 | 
						|
								  copy(options).to(opt);
							 | 
						|
								  opt.subres = { uploadId };
							 | 
						|
								  const params = this._objectRequestParams('DELETE', name, opt);
							 | 
						|
								  params.successStatuses = [204];
							 | 
						|
								
							 | 
						|
								  const result = await this.request(params);
							 | 
						|
								  return {
							 | 
						|
								    res: result.res
							 | 
						|
								  };
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Initiate a multipart upload transaction
							 | 
						|
								 * @param {String} name the object name
							 | 
						|
								 * @param {Object} options
							 | 
						|
								 * @return {String} upload id
							 | 
						|
								 */
							 | 
						|
								proto.initMultipartUpload = async function initMultipartUpload(name, options) {
							 | 
						|
								  options = options || {};
							 | 
						|
								  const opt = {};
							 | 
						|
								  copy(options).to(opt);
							 | 
						|
								  opt.headers = opt.headers || {};
							 | 
						|
								  this._convertMetaToHeaders(options.meta, opt.headers);
							 | 
						|
								
							 | 
						|
								  opt.subres = 'uploads';
							 | 
						|
								  const params = this._objectRequestParams('POST', name, opt);
							 | 
						|
								  params.mime = options.mime;
							 | 
						|
								  params.xmlResponse = true;
							 | 
						|
								  params.successStatuses = [200];
							 | 
						|
								
							 | 
						|
								  const result = await this.request(params);
							 | 
						|
								
							 | 
						|
								  return {
							 | 
						|
								    res: result.res,
							 | 
						|
								    bucket: result.data.Bucket,
							 | 
						|
								    name: result.data.Key,
							 | 
						|
								    uploadId: result.data.UploadId
							 | 
						|
								  };
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Upload a part in a multipart upload transaction
							 | 
						|
								 * @param {String} name the object name
							 | 
						|
								 * @param {String} uploadId the upload id
							 | 
						|
								 * @param {Integer} partNo the part number
							 | 
						|
								 * @param {File} file upload File, whole File
							 | 
						|
								 * @param {Integer} start  part start bytes  e.g: 102400
							 | 
						|
								 * @param {Integer} end  part end bytes  e.g: 204800
							 | 
						|
								 * @param {Object} options
							 | 
						|
								 */
							 | 
						|
								proto.uploadPart = async function uploadPart(name, uploadId, partNo, file, start, end, options) {
							 | 
						|
								  const data = {
							 | 
						|
								    size: end - start
							 | 
						|
								  };
							 | 
						|
								  const isBrowserEnv = process && process.browser;
							 | 
						|
								  isBrowserEnv
							 | 
						|
								    ? (data.content = await this._createBuffer(file, start, end))
							 | 
						|
								    : (data.stream = await this._createStream(file, start, end));
							 | 
						|
								  return await this._uploadPart(name, uploadId, partNo, data, options);
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Complete a multipart upload transaction
							 | 
						|
								 * @param {String} name the object name
							 | 
						|
								 * @param {String} uploadId the upload id
							 | 
						|
								 * @param {Array} parts the uploaded parts, each in the structure:
							 | 
						|
								 *        {Integer} number partNo
							 | 
						|
								 *        {String} etag  part etag  uploadPartCopy result.res.header.etag
							 | 
						|
								 * @param {Object} options
							 | 
						|
								 *         {Object} [options.callback] The callback parameter is composed of a JSON string encoded in Base64
							 | 
						|
								 *         {String} options.callback.url  the OSS sends a callback request to this URL
							 | 
						|
								 *         {String} [options.callback.host]  The host header value for initiating callback requests
							 | 
						|
								 *         {String} options.callback.body  The value of the request body when a callback is initiated
							 | 
						|
								 *         {String} [options.callback.contentType]  The Content-Type of the callback requests initiated
							 | 
						|
								 *         {Boolean} [options.callback.callbackSNI] Whether OSS sends SNI to the origin address specified by callbackUrl when a callback request is initiated from the client
							 | 
						|
								 *         {Object} [options.callback.customValue]  Custom parameters are a map of key-values, e.g:
							 | 
						|
								 *                   customValue = {
							 | 
						|
								 *                     key1: 'value1',
							 | 
						|
								 *                     key2: 'value2'
							 | 
						|
								 *                   }
							 | 
						|
								 */
							 | 
						|
								proto.completeMultipartUpload = async function completeMultipartUpload(name, uploadId, parts, options) {
							 | 
						|
								  const completeParts = parts
							 | 
						|
								    .concat()
							 | 
						|
								    .sort((a, b) => a.number - b.number)
							 | 
						|
								    .filter((item, index, arr) => !index || item.number !== arr[index - 1].number);
							 | 
						|
								  let xml = '<?xml version="1.0" encoding="UTF-8"?>\n<CompleteMultipartUpload>\n';
							 | 
						|
								  for (let i = 0; i < completeParts.length; i++) {
							 | 
						|
								    const p = completeParts[i];
							 | 
						|
								    xml += '<Part>\n';
							 | 
						|
								    xml += `<PartNumber>${p.number}</PartNumber>\n`;
							 | 
						|
								    xml += `<ETag>${p.etag}</ETag>\n`;
							 | 
						|
								    xml += '</Part>\n';
							 | 
						|
								  }
							 | 
						|
								  xml += '</CompleteMultipartUpload>';
							 | 
						|
								
							 | 
						|
								  options = options || {};
							 | 
						|
								  let opt = {};
							 | 
						|
								  opt = deepCopyWith(options, _ => {
							 | 
						|
								    if (isBuffer(_)) return null;
							 | 
						|
								  });
							 | 
						|
								  opt.subres = { uploadId };
							 | 
						|
								  opt.headers = omit(opt.headers, ['x-oss-server-side-encryption', 'x-oss-storage-class']);
							 | 
						|
								
							 | 
						|
								  const params = this._objectRequestParams('POST', name, opt);
							 | 
						|
								  callback.encodeCallback(params, opt);
							 | 
						|
								  params.mime = 'xml';
							 | 
						|
								  params.content = xml;
							 | 
						|
								
							 | 
						|
								  if (!(params.headers && params.headers['x-oss-callback'])) {
							 | 
						|
								    params.xmlResponse = true;
							 | 
						|
								  }
							 | 
						|
								  params.successStatuses = [200];
							 | 
						|
								  const result = await this.request(params);
							 | 
						|
								
							 | 
						|
								  if (options.progress) {
							 | 
						|
								    await options.progress(1, null, result.res);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  const ret = {
							 | 
						|
								    res: result.res,
							 | 
						|
								    bucket: params.bucket,
							 | 
						|
								    name,
							 | 
						|
								    etag: result.res.headers.etag
							 | 
						|
								  };
							 | 
						|
								
							 | 
						|
								  if (params.headers && params.headers['x-oss-callback']) {
							 | 
						|
								    ret.data = JSON.parse(result.data.toString());
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  return ret;
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * Upload a part in a multipart upload transaction
							 | 
						|
								 * @param {String} name the object name
							 | 
						|
								 * @param {String} uploadId the upload id
							 | 
						|
								 * @param {Integer} partNo the part number
							 | 
						|
								 * @param {Object} data the body data
							 | 
						|
								 * @param {Object} options
							 | 
						|
								 */
							 | 
						|
								proto._uploadPart = async function _uploadPart(name, uploadId, partNo, data, options) {
							 | 
						|
								  options = options || {};
							 | 
						|
								  const opt = {};
							 | 
						|
								  copy(options).to(opt);
							 | 
						|
								  opt.headers = opt.headers || {};
							 | 
						|
								  opt.headers['Content-Length'] = data.size;
							 | 
						|
								
							 | 
						|
								  // Uploading shards does not require x-oss headers.
							 | 
						|
								  opt.headers = omit(opt.headers, ['x-oss-server-side-encryption', 'x-oss-storage-class']);
							 | 
						|
								  opt.subres = {
							 | 
						|
								    partNumber: partNo,
							 | 
						|
								    uploadId
							 | 
						|
								  };
							 | 
						|
								
							 | 
						|
								  const params = this._objectRequestParams('PUT', name, opt);
							 | 
						|
								  params.mime = opt.mime;
							 | 
						|
								  const isBrowserEnv = process && process.browser;
							 | 
						|
								  isBrowserEnv ? (params.content = data.content) : (params.stream = data.stream);
							 | 
						|
								  params.successStatuses = [200];
							 | 
						|
								  params.disabledMD5 = options.disabledMD5;
							 | 
						|
								
							 | 
						|
								  const result = await this.request(params);
							 | 
						|
								
							 | 
						|
								  if (!result.res.headers.etag) {
							 | 
						|
								    throw new Error(
							 | 
						|
								      'Please set the etag of expose-headers in OSS \n https://help.aliyun.com/document_detail/32069.html'
							 | 
						|
								    );
							 | 
						|
								  }
							 | 
						|
								  if (data.stream) {
							 | 
						|
								    data.stream = null;
							 | 
						|
								    params.stream = null;
							 | 
						|
								  }
							 | 
						|
								  return {
							 | 
						|
								    name,
							 | 
						|
								    etag: result.res.headers.etag,
							 | 
						|
								    res: result.res
							 | 
						|
								  };
							 | 
						|
								};
							 |