123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- 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 initiatiated
- * {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 server side encryption
- opt.headers = omit(opt.headers, ['x-oss-server-side-encryption']);
- 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
- };
- };
|