UNPKG

ks3-js-sdk

Version:

js sdk for ks3

1,224 lines (1,189 loc) 60.8 kB
var utils = require('./utils.js'); var generalRequest = require('./request.js'); var async = require('async'); /** * 获取bucket下的objects * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.region region名称,非必须 * @params {String} params.delimiter 分隔符,用于对一组参数进行分割的字符,非必须 * @params {String} params['encoding-type'] 前缀匹配,用来规定返回的文件前缀地址,非必须 * @params {String} params.marker 指定列举指定空间中对象的起始位置。KS3按照字母排序方式返回结果,将从给定的 marker 开始返回列表。如果相应内容中IsTruncated为true,则可以使用返回的Contents中的最后一个key作为下次list的marker参数,非必须 * @params {String} params['max-keys'] 设置响应体中返回的最大记录数(最后实际返回可能小于该值)。默认为1000。如果你想要的结果在1000条以后,你可以设定 marker 的值来调整起始位置,非必须 * @params {String} params.prefix 限定响应结果列表使用的前缀,非必须 * @params {Object} params.headers 自定义header信息,非必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 */ async function listObjects(params){ var headers = params.headers || {}; var urlParams = { delimiter: params['delimiter'], 'encoding-type': params['encoding-type'], marker: params['marker'], 'max-keys': params['max-keys'], prefix: params['prefix'] }; var bucket = params.bucket || this.config.bucket; var region = params.region || this.config.region; var url = getUrl.bind(this)({ bucket, region }) var reqParams = { method: 'GET', bucket, url, qs: urlParams, headers: headers } if(!reqParams.headers['x-kss-date']) { reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString(); } reqParams.date = reqParams.headers['x-kss-date']; var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, '', '', reqParams.method, reqParams.headers, reqParams.date); reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`; return await generalRequest.bind(this)(reqParams); } /** * 获取object的元数据 * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.key object key,必须 * @params {String} params.region region名称,非必须 * @params {Object} params.headers 自定义header信息,非必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 */ async function headObject(params){ if (params.key === null || params.key === undefined) { throw Error('require the params of key!'); } var headers = params.headers || {}; var bucket = params.bucket || this.config.bucket; var region = params.region || this.config.region; var url = getUrl.bind(this)({ bucket, region, key: params.key }) var reqParams = { method: 'HEAD', bucket, url, qs: {}, headers: headers } if(!reqParams.headers['x-kss-date']) { reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString(); } reqParams.date = reqParams.headers['x-kss-date']; var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, '', reqParams.method, reqParams.headers, reqParams.date); reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`; return await generalRequest.bind(this)(reqParams); } /** * 获取指定object * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.key object key,必须 * @params {String} params.region region名称,非必须 * @params {String} params.range range(用于请求资源的部分内容,单位是byte),非必须 * @params {Object} params.headers 自定义header信息,非必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 */ async function getObject(params){ if (params.key === null || params.key === undefined) { throw Error('require the params of key!'); } if(!params.bucket && !this.config.bucket){ throw Error('require the params of bucket or this.config of bucket!'); } if(!params.region && !this.config.region){ throw Error('require the params of region or this.config of region!'); } var headers = params.headers || {}; if(params.range){ headers['Range'] = params.range; } var bucket = params.bucket || this.config.bucket; var region = params.region || this.config.region; var url = getUrl.bind(this)({ bucket, region, key: params.key }) var reqParams = { method: 'GET', bucket, url, qs: {}, headers: headers, responseType: 'blob', } if(!reqParams.headers['x-kss-date']) { reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString(); } reqParams.date = reqParams.headers['x-kss-date']; var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, '',reqParams.method, reqParams.headers, reqParams.date); reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`; return await generalRequest.bind(this)(reqParams); } /** * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.key object key,必须 * @params {String} params.region region名称,非必须 * @params {String} params.method 请求方法,PUT/GET/POST/DELETE,非必须 * @params {String} params.expires 签名几秒后失效,默认900秒,非必须 * @params {Object} params.headers 自定义header信息,非必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 */ function getObjectUrl(params){ if (params.key === null || params.key === undefined) { throw Error('require the params of key!'); } if(!params.bucket && !this.config.bucket){ throw Error('require the params of bucket or this.config of bucket!'); } if(!params.region && !this.config.region){ throw Error('require the params of region or this.config of region!'); } var headers = params.headers || {}; var bucket = params.bucket || this.config.bucket; var region = params.region || this.config.region; var url = getUrl.bind(this)({ bucket, region, key: params.key }) var expires = params.expires || 15*60; // 时间戳精确到秒 var expirationTime = (new Date().getTime() + expires * 1000).toString().substr(0,10); var reqParams = { method: params.method || 'GET', bucket, url, qs: {}, headers: headers } var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, '', reqParams.method, reqParams.headers, expirationTime); url = `${url}?KSSAccessKeyId=${this.config.AK}&Expires=${expirationTime}&Signature=${encodeURIComponent(signature)}` var promise = new Promise((resolve) => { resolve(url) }); return promise; } /** * 删除指定object * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.key object key,必须 * @params {String} params.region region名称,非必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 * @params {Object} params.headers 自定义header信息,非必须 */ async function delObject(params){ if (params.key === null || params.key === undefined) { throw Error('require the params of key!'); } if(!params.bucket && !this.config.bucket){ throw Error('require the params of bucket or this.config of bucket!'); } if(!params.region && !this.config.region){ throw Error('require the params of region or this.config of region!'); } var headers = params.headers || {}; var bucket = params.bucket || this.config.bucket; var region = params.region || this.config.region; var url = getUrl.bind(this)({ bucket, region, key: params.key }) var reqParams = { method: 'DELETE', bucket, url, qs: {}, headers: headers } if(!reqParams.headers['x-kss-date']) { reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString(); } reqParams.date = reqParams.headers['x-kss-date']; var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, '', reqParams.method, reqParams.headers, reqParams.date); reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`; return await generalRequest.bind(this)(reqParams); } /** * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.key object key,必须 * @params {String} params.region region名称,非必须 * @params {String} params.acl 文件预设ACL(private | public-read),默认值private,非必须 * @params {String} params.file 上传的文件,非必须 * @params {Boolean} params.encryption 是否加密文件,非必须 * @params {String} params.storageClass 对象的存储类型,非必须,如果Bucket是归档类型,当不指定storageClass时,Object自动为归档类型,如果Bucket是非归档类型,Object自动为标准类型 * @params {Function} params.progress 上传进度监听函数,非必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 * @params {String} params.headers 自定义header信息,非必须 */ async function putObject(params){ if (params.key === null || params.key === undefined) { throw Error('require the params of key!'); } // if (params.file === null || params.file === undefined) { // throw Error('require the params of file!'); // return; // } if(!params.bucket && !this.config.bucket){ throw Error('require the params of bucket or defaultConfig of bucket!'); } if(!params.region && !this.config.region){ throw Error('require the params of region or defaultConfig of region!'); } var headers = params.headers || {}; if (!headers['Content-Type'] && !headers['content-type']) { headers['Content-Type'] = (params.file && params.file.type) ? params.file.type : ''; } if(params.acl){ if(['private','public-read'].indexOf(params.acl)==-1){ throw Error('The value of acl can only be private or public-read!'); } headers['x-kss-acl'] = params.acl; } if(params.encryption){ headers['x-kss-server-side-encryption'] = 'AES256'; } if(params.storageClass){ headers['x-kss-storage-class'] = params.storageClass; } var onProgress = utils.throttleOnProgress.call(this, 0, params.progress); var bucket = params.bucket || this.config.bucket; var region = params.region || this.config.region; var url = getUrl.bind(this)({ bucket, region, key: params.key }) var reqParams = { method: 'PUT', bucket, url, qs: {}, headers: headers, body: params.file, onProgress } if(!reqParams.headers['x-kss-date']) { reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString(); } reqParams.date = reqParams.headers['x-kss-date']; var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, '', reqParams.method, reqParams.headers, reqParams.date); reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`; if (params.authorization) { reqParams.headers['Authorization'] = params.authorization; } return await generalRequest.bind(this)(reqParams); } /** * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.key object key,必须 * @params {String} params.region region名称,非必须 * @params {String} params.acl 文件预设ACL(private | public-read),默认值private,非必须 * @params {String} params.file 上传的文件,非必须 * @params {Boolean} params.encryption 是否加密文件,非必须 * @params {String} params.storageClass 对象的存储类型,非必须,如果Bucket是归档类型,当不指定storageClass时,Object自动为归档类型,如果Bucket是非归档类型,Object自动为标准类型 * @params {Function} params.progress 上传进度监听函数,非必须 * @params {String} params.signature 请求签名,非必须 * @params {String} params.headers 自定义header信息,非必须 */ async function appendObject(params){ if (params.key === null || params.key === undefined) { throw Error('require the params of key!'); } if(!params.bucket && !this.config.bucket){ throw Error('require the params of bucket or defaultConfig of bucket!'); } if(!params.region && !this.config.region){ throw Error('require the params of region or defaultConfig of region!'); } var headers = params.headers || {}; if (!headers['Content-Type'] && !headers['content-type']) { headers['Content-Type'] = (params.file && params.file.type) ? params.file.type : ''; } if(params.acl){ if(['private','public-read'].indexOf(params.acl)==-1){ throw Error('The value of acl can only be private or public-read!'); } headers['x-kss-acl'] = params.acl; } if(params.encryption){ headers['x-kss-server-side-encryption'] = 'AES256'; } if(params.storageClass){ headers['x-kss-storage-class'] = params.storageClass; } if(params.position === null || params.position === undefined || Number(params.position)< 0){ throw Error('require the params of position!'); } var onProgress = utils.throttleOnProgress.call(this, 0, params.progress); var bucket = params.bucket || this.config.bucket; var region = params.region || this.config.region; var resource = `?append&position=${params.position}`; var url = getUrl.bind(this)({ bucket, region, key: params.key, resource }) var reqParams = { method: 'POST', bucket, url, qs: {}, headers: headers, body: params.file, onProgress } if(!reqParams.headers['x-kss-date']) { reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString(); } reqParams.date = reqParams.headers['x-kss-date']; var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, resource, reqParams.method, reqParams.headers, reqParams.date); reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`; if (params.authorization) { reqParams.headers['Authorization'] = params.authorization; } return await generalRequest.bind(this)(reqParams); } /** * 解冻指定object * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.key object key,必须 * @params {String} params.region region名称,非必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 * @params {Object} params.headers 自定义header信息,非必须 */ async function restoreObject(params){ if (params.key === null || params.key === undefined) { throw Error('require the params of key!'); } if(!params.bucket && !this.config.bucket){ throw Error('require the params of bucket or this.config of bucket!'); } if(!params.region && !this.config.region){ throw Error('require the params of region or this.config of region!'); } var resource = '?restore'; var bucket = params.bucket || this.config.bucket; var region = params.region || this.config.region; var url = getUrl.bind(this)({ bucket, region, key: params.key, resource }) var headers = params.headers || {}; var reqParams = { method: 'POST', bucket, url, qs: {}, headers: headers } if(!reqParams.headers['x-kss-date']) { reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString(); } reqParams.date = reqParams.headers['x-kss-date']; var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, resource, reqParams.method, reqParams.headers, reqParams.date); reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`; return await generalRequest.bind(this)(reqParams); } /** * 获取object ACL * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.key object key,必须 * @params {String} params.region region名称,非必须 * @params {Object} params.headers 自定义header信息,非必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 */ async function getObjectAcl(params){ if (params.key === null || params.key === undefined) { throw Error('require the params of key!'); } if(!params.bucket && !this.config.bucket){ throw Error('require the params of bucket or this.config of bucket!'); } if(!params.region && !this.config.region){ throw Error('require the params of region or this.config of region!'); } var resource = '?acl'; var bucket = params.bucket || this.config.bucket; var region = params.region || this.config.region; var url = getUrl.bind(this)({ bucket, region, key: params.key, resource }) var headers = params.headers || {}; var reqParams = { method: 'GET', bucket, url, qs: {}, headers: headers } if(!reqParams.headers['x-kss-date']) { reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString(); } reqParams.date = reqParams.headers['x-kss-date']; var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, resource, reqParams.method, reqParams.headers, reqParams.date); reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`; return await generalRequest.bind(this)(reqParams); } /** * 设置object ACL * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.key object key,必须 * @params {String} params.region region名称,非必须 * @params {String} params.acl acl,有效值(private, public-read),必须 * @params {Object} params.headers 自定义header信息,非必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 */ async function putObjectAcl(params){ if (params.key === null || params.key === undefined) { throw Error('require the params of key!'); } if(!params.bucket && !this.config.bucket){ throw Error('require the params of bucket or this.config of bucket!'); } if(!params.region && !this.config.region){ throw Error('require the params of region or this.config of region!'); } if(params.acl !== 'private' && params.acl !== 'public-read'){ throw Error('The value of acl can only be private or public-read!'); } var headers = params.headers || {}; var resource = `?acl`; var bucket = params.bucket || this.config.bucket; var region = params.region || this.config.region; var url = getUrl.bind(this)({ bucket, region, key: params.key, resource }) if(params.acl){ headers['x-kss-acl'] = params.acl; } var reqParams = { method: 'PUT', bucket, url, qs: {}, headers } if(!reqParams.headers['x-kss-date']) { reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString(); } reqParams.date = reqParams.headers['x-kss-date']; var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, resource, reqParams.method, reqParams.headers, reqParams.date); reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`; return await generalRequest.bind(this)(reqParams); } /** * 大文件拷贝 * * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.key 目标文件URL绝对路径,必须 * @params {String} params.sourceBucket 源文件URL绝对路径,例如:test-bucket/test.jpeg,必须 * @params {String} params.sourceKey 源bucket名称,必须 * @params {Function} params.progress 上传进度监听函数,非必须 * @params {Boolean} params.encryption 是否加密文件,非必须 * @params {Object} params.headers 自定义header信息,非必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 * * @params {*} cb * @return {Object} res 请求结果 */ async function uploadPartCopy (params, cb) { if(!params.bucket && !this.config.bucket){ throw Error('require the params of bucket or defaultConfig of bucket!'); } if(!params.sourceKey){ throw Error('require the params of sourceKey!'); } if(!params.sourceBucket){ throw Error('require the params of sourceBucket!'); } if(!params.key){ throw Error('require the params of key!'); } let self = this; return await headObject.bind(self)({ 'key': params.sourceKey, 'bucket': params.sourceBucket, }).then(res => { if(res.statusCode === 200){ var size = 0; size = Number(res.headers['content-length'] ? res.headers['content-length'] : 0); params.uploadType = 'copyPart'; params.file = {size}; self.uploadMultiPart(params, cb); }else{ throw Error('This key does not exist !'); } }) } /** * 复制小文件 * * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.key 目标文件URL绝对路径,必须 * @params {String} params.sourceBucket 源文件URL绝对路径,例如:test-bucket/test.jpeg,必须 * @params {String} params.sourceKey 源bucket名称,必须 * @params {String} params.storageClass 对象的存储类型,非必须,如果Bucket是归档类型,当不指定storageClass时,Object自动为归档类型,如果Bucket是非归档类型,Object自动为标准类型 * @params {Boolean} params.encryption 是否加密文件,非必须 (如果源文件进行过加密,copy时目标文件也要进行加密) * @params {Object} params.headers 自定义header信息,非必须 * @params {Function}params.progress 上传进度监听函数,非必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 * */ async function putObjectCopy(params) { if(!params.bucket && !this.config.bucket){ throw Error('require the params of bucket or defaultConfig of bucket!'); } if(!params.sourceKey){ throw Error('require the params of sourceKey!'); } if(!params.sourceBucket){ throw Error('require the params of sourceBucket!'); } if(!params.key) { throw Error('require the params of key!'); } var headers = {}; var bucket = params.bucket || this.config.bucket; var region = params.region || this.config.region; var contentType = params['content-type'] || ''; headers['x-kss-metadata-directive'] = 'COPY'; headers['x-kss-copy-source'] = '/' + params.sourceBucket + '/' + encodeURIComponent(params.sourceKey); if(params.storageClass){ headers['x-kss-storage-class'] = params.storageClass; } if(params.encryption){ headers['x-kss-server-side-encryption'] = 'AES256'; } headers = Object.assign(headers, params.headers); var url = getUrl.bind(this)({ bucket, region, key: params.key }) var reqParams = { method: 'PUT', bucket, url, qs: {}, headers } if(!reqParams.headers['x-kss-date']) { reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString(); } reqParams.date = reqParams.headers['x-kss-date']; var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, '', reqParams.method, reqParams.headers, reqParams.date); reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`; return await generalRequest.bind(this)(reqParams); } /** * post方式上传文件 * @params {Object} params 参数对象,必须 * @params {FormData} params.formData * @params {String} key object的key,必须 * @params {String} file 上传的文件,必须 * @params {String} acl acl,有效值(private, public-read),非必须 * @params {String} KSSAccessKeyId AK,非必须 * @params {String} signature 请求签名,非必须 * @params {String} policy policy,非必须 * @params {Object} params.headers 自定义header信息,非必须 * @params {String} params.bucket bucket名称,非必须 * - formData: { KSSAccessKeyId, key, Policy, signature, file, ... } * - KSSAccessKeyId, key, signature, file必填 */ async function postObject (params) { if(!params.bucket && !this.config.bucket){ throw Error('require the params of bucket or defaultConfig of bucket!'); } if(!params.region && !this.config.region){ throw Error('require the params of region or defaultConfig of region!'); } if(!params.formData) { throw Error('require the params of formData!'); } var formData = params.formData; var bucket = params.bucket || this.config.bucket; var region = params.region || this.config.region; var headers = params.headers || {}; var url = getUrl.bind(this)({ bucket, region }) if (formData.get('policy')) { var policy = JSON.parse(formData.get('policy')) formData.set('policy', utils.getStrBase64(policy)); formData.set('signature', formData.get('signature') || utils.getPostSignature(this.config.SK, policy)); formData.set('KSSAccessKeyId', formData.get('KSSAccessKeyId') || this.config.AK) } //表单上传时,file必须为表单的最后一项 if (formData.get('file')) { var file = formData.get('file'); formData.delete('file'); formData.append('file', file); } var reqParams = { method: 'POST', bucket, url, headers: headers, body: formData } if(!reqParams.headers['x-kss-date']) { reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString(); } reqParams.date = reqParams.headers['x-kss-date']; if (!formData.get('policy')) { var signature = utils.getAuth(this.config.SK, reqParams.bucket, formData.get('key'), '', reqParams.method, reqParams.headers, reqParams.date); reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`; } return await generalRequest.bind(this)(reqParams); } /** * 分块上传相关---全流程 * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.key object key,必须 * @params {String} params.region region名称,非必须 * @params {String} params.acl 文件预设ACL(private | public-read),默认值private,非必须 * @params {String} params.file 上传的文件,必须 * @params {Function}params.progress 上传进度监听函数,非必须 * @params {String} params.parallelLimit 分块请求的最大并发数,默认为10,非必须 * @params {String} params.retries 分块请求失败重试次数,默认为2,非必须 * @params {Boolean} params.encryption 是否使用服务端加密,仅支持"AES256"加密,非必须 * @params {String} params.uploadType 'upload'大文件上传 / 'copyPart'大文件复制,默认upload,非必须 * @params {Object} params.headers 自定义header信息,非必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 * @params {*} cb * @return {Object} res 请求结果 */ function uploadMultiPart(params, cb){ if ((params.file === null || params.file === undefined) && params.uploadType !== 'copyPart') { throw Error('require the params of file!'); } let self = this; // 每个块的上传进度数组 let uploadArr = []; let timer = null; async.auto({ // 初始化分块上传 uploadId: function (callback) { self.initiateMultipartUpload({ bucket: params.bucket, file: params.file, encryption: params.encryption, key: params.key, acl: params.acl, headers: params.headers }).then(res => { if(res && res.statusCode === 200){ if (res.body && res.body.InitiateMultipartUploadResult) { var uploadId = res.body.InitiateMultipartUploadResult.UploadId; callback(null, uploadId); } }else{ callback(res.error ? res : ''); } }); }, sliceList: ['uploadId', function(results, callback){ // 获取文件大小 var totalSize = params.file.size; // 控制分块大小 var chunkSize = self.config.chunkSize; var chunkNum = Math.ceil(totalSize/chunkSize); // 存放分片后的数据 var sliceList = []; // 初始化进度数组 uploadArr = new Array(chunkNum).fill(0); // 总进度 let uploadSize = 0; // 进度参数存在 if (params.progress) { // 设置定时器 timer = setInterval(() => { // 计算已上传的文件大小 uploadSize = uploadArr.reduce((pre, cur) => pre + cur, 0); // 最终进度 params.progress({ percent: (uploadSize / totalSize).toFixed(2), uploadId: results.uploadId }); }, self.config.progressInterval); } // 上传的分片数据 for(let i = 1; i <= chunkNum; i++){ // 给文件分块 var endSize = i == chunkNum ? totalSize : chunkSize * i; if(params.uploadType === 'copyPart'){ //大文件拷贝 sliceList.push({ key: params.key, partNumber: i, uploadId: results.uploadId, range: 'bytes=' + chunkSize * (i - 1)+ '-' + endSize, uploadType: 'copyPart', sourceKey: params.sourceKey, sourceBucket: params.sourceBucket, bucket: params.bucket, progress: (e) => { uploadArr[i - 1] = e.loaded; } }) if(sliceList.length === chunkNum){ console.log('sliceList:', sliceList); callback(null, sliceList); } }else{ //大文件上传 sliceList.push({ key: params.key, partNumber: i, uploadId: results.uploadId, uploadType: 'upload', bucket: params.bucket, progress: (e) => { uploadArr[i - 1] = e.loaded; }, start:chunkSize*(i-1), end: endSize }) if(sliceList.length === chunkNum){ console.log('sliceList:', sliceList); callback(null, sliceList); } } }; }], uploadPartList: ['sliceList', function (results, callback) { var uploadPartList = []; // 上传控制并发数 var limit = params.parallelLimit || self.config.parallelLimit; // 失败重试次数 var retryTimes = params.retryTimes || self.config.retryTimes; // 上传分块 async.eachLimit(results.sliceList, limit, function(sliceItem, callback){ async.retry(retryTimes, function (tryCallback) { if(params.uploadType === 'copyPart') { self.uploadPart(sliceItem).then(res => { console.log(res) console.log('正在上传第'+ sliceItem.partNumber +'块!'); if(!res.error){ uploadPartList.push({ partNumber: sliceItem.partNumber, etag: res.headers.etag }); } tryCallback(res.error ? res : '', res); }) } else { utils.fileSlice(params.file, sliceItem.start, sliceItem.end, function(result) { let item = { key: sliceItem.key, partNumber: sliceItem.partNumber, body: result, uploadId: sliceItem.uploadId, uploadType: sliceItem.uploadType, bucket: sliceItem.bucket, progress: sliceItem.progress, } self.uploadPart(item).then(res => { console.log(res) console.log('正在上传第'+ item.partNumber +'块!'); if(!res.error){ uploadPartList.push({ partNumber: item.partNumber, etag: res.headers.etag }); } tryCallback(res.error ? res : '', res); }) }) } }, function (err, res) { console.log('retry result:',err, res); callback(err, res) }); }, function(err){ console.log('迭代器结束或出现一个err:', err); clearInterval(timer); if(err){ callback(err); }else{ callback(null, uploadPartList); } }) }], complete: ['uploadPartList', function (results, callback) { // 清除定时器 clearInterval(timer); console.log('results:', results); var partList = results.uploadPartList; // 合并上传的分块 self.completeMultipart({ key: params.key, parts: partList, uploadId: results.uploadId, uploadType: params.uploadType === 'copyPart' ? 'copyPart' : 'upload' }).then(res => { callback(res.error ? res : '',res); }) }] }, function(err, res) { var result = {}; if(err){ result = err; }else{ result = res.complete; } cb(result); }); } /** * 分块上传相关---初始化分块上传 * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.key object key,必须 * @params {String} params.region region名称,非必须 * @params {String} params.acl 文件预设ACL(private | public-read),默认值private,非必须 * @params {String} params.storageClass 存储类型,非必须,如果Bucket是归档类型,当不指定storageClass时,Object自动为归档类型,如果Bucket是非归档类型,Object自动为标准类型 * @params {Boolean} params.encryption 是否使用服务端加密,仅支持"AES256"加密,非必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 * @params {Object} params.headers 自定义header信息,非必须 */ async function initiateMultipartUpload(params){ var headers = {}; if (params.key === null || params.key === undefined) { throw Error('require the params of key!'); } if(!params.bucket && !this.config.bucket){ throw Error('require the params of bucket or defaultConfig of bucket!'); } if(!params.region && !this.config.region){ throw Error('require the params of region or defaultConfig of region!'); } if(params.acl){ if(['private','public-read'].indexOf(params.acl)===-1){ throw Error('The value of acl can only be private or public-read!'); } headers['x-kss-acl'] = params.acl; } if(params.encryption){ headers['x-kss-server-side-encryption'] = 'AES256'; } if(params.storageClass){ headers['x-kss-storage-class'] = params.storageClass; } headers = Object.assign(headers, params.headers); var resource = '?uploads' var bucket = params.bucket || this.config.bucket; var region = params.region || this.config.region; var url = getUrl.bind(this)({ bucket, region, key: params.key, resource }) var reqParams = { method: 'POST', bucket, url, qs: {}, headers: headers } if(!reqParams.headers['x-kss-date']) { reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString(); } reqParams.date = reqParams.headers['x-kss-date']; var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, resource, reqParams.method, reqParams.headers, reqParams.date); reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`; return await generalRequest.bind(this)(reqParams); } /** * 分块上传相关---上传文件块 * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.key object key,必须 * @params {String} params.region region名称,非必须 * @params {File || Blob || String} params.body 分块数据,上传文件对象或字符串,必须 * @params {String} params.partNumber 分块的序号,必须 * @params {String} params.uploadId 初始化分块上传时获取的上传id,必须 * @params {Function} params.progress 上传进度监听函数,非必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 * @params {Object} params.headers 自定义header信息,非必须 */ async function uploadPart(params){ if (params.key === null || params.key === undefined) { throw Error('require the params of key!'); } if(!params.bucket && !this.config.bucket){ throw Error('require the params of bucket or defaultConfig of bucket!'); } if(!params.region && !this.config.region){ throw Error('require the params of region or defaultConfig of region!'); } if(!params.partNumber){ throw Error('require the params of partNumber!'); } if(!params.uploadId){ throw Error('require the params of uploadId!'); } var headers = {}; if(params.uploadType === 'copyPart'){ headers['x-kss-copy-source'] = '/' + params.sourceBucket + '/' + utils.encodeKey(params.sourceKey); headers['x-kss-copy-source-range'] = params.range; } headers = Object.assign(headers, params.headers); var resource = `?partNumber=${params.partNumber}&uploadId=${params.uploadId}`; var bucket = params.bucket || this.config.bucket; var region = params.region || this.config.region; var url = getUrl.bind(this)({ bucket, region, key: params.key, resource }) var onProgress = utils.throttleOnProgress.call(this, 0, params.progress); var reqParams = { method: 'PUT', bucket, url, qs: {}, headers: headers, onProgress } if(params.uploadType === 'upload'){ reqParams.body = params.body } if(!reqParams.headers['x-kss-date']) { reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString(); } reqParams.date = reqParams.headers['x-kss-date']; var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key , resource, reqParams.method, reqParams.headers, reqParams.date); reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`; return await generalRequest.bind(this)(reqParams); } /** * 分块上传相关---完成分块上传后,合并分块 * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.key object key,必须 * @params {String} params.region region名称,非必须 * @params {Array} params.parts 分块信息列表,必须 * @params {String} params.parts[i].partNumber 块编号,必须 * @params {String} params.parts[i].etag 分块的 sha1 校验值,必须 * @params {String} params.uploadId 初始化分块上传时获取的上传id,必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 * @params {Object} params.headers 自定义header信息,非必须 */ async function completeMultipart(params){ if (params.key === null || params.key === undefined) { throw Error('require the params of key!'); } if(!params.bucket && !this.config.bucket){ throw Error('require the params of bucket or defaultConfig of bucket!'); } if(!params.region && !this.config.region){ throw Error('require the params of region or defaultConfig of region!'); } if(!params.uploadId){ throw Error('require the params of uploadId!'); } if(!params.parts || !params.parts.length){ throw Error('require the params of parts!'); } var headers = {}; headers = Object.assign({ 'content-type': 'text/plain;charset=UTF-8' }, params.headers); var resource = `?uploadId=${params.uploadId}`; var body = utils.generateCompleteXML(params.parts) var region = params.region || this.config.region; var bucket = params.bucket || this.config.bucket; var url = getUrl.bind(this)({ bucket, region, key: params.key, resource }) var reqParams = { method: 'POST', bucket, url, qs: {}, headers: headers, body } if(!reqParams.headers['x-kss-date']) { reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString(); } reqParams.date = reqParams.headers['x-kss-date']; var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, resource, reqParams.method, reqParams.headers, reqParams.date); reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`; return await generalRequest.bind(this)(reqParams); } /** * 列出指定上传任务中所有已上传的块 * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.key object key,必须 * @params {String} params.region region名称,非必须 * @params {String} params.uploadId 初始化分块上传时获取的上传id,必须 * @params {String} params.max-parts 设置响应体中块的最大数量(默认值: 1000),非必须 * @params {String} params.part-number-marker 指定应该从哪个块开始列举(只有比设定值大的块才会被列举),非必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 * @params {Object} params.headers 自定义header信息,非必须 */ async function listParts(params){ if (params.key === null || params.key === undefined) { throw Error('require the params of key!'); } if(!params.bucket && !this.config.bucket){ throw Error('require the params of bucket or defaultConfig of bucket!'); } if(!params.region && !this.config.region){ throw Error('require the params of region or defaultConfig of region!'); } if(!params.uploadId){ throw Error('require the params of uploadId!'); } var headers = params.headers || {}; var resource = `?uploadId=${params.uploadId}`; var bucket = params.bucket || this.config.bucket; var region = params.region || this.config.region; var url = getUrl.bind(this)({ bucket, region, key: params.key, resource }) var qs = {}; if(params['max-parts']){ qs['max-parts'] = params['max-parts']; } if(params['part-number-marker']){ qs['part-number-marker'] = params['part-number-marker']; } if(params['encoding-type']){ qs['encoding-type'] = params['encoding-type']; } var reqParams = { method: 'GET', bucket, url, qs, headers: headers, body: {} } if(!reqParams.headers['x-kss-date']) { reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString(); } reqParams.date = reqParams.headers['x-kss-date']; var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, resource, reqParams.method, reqParams.headers, reqParams.date); reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`; return await generalRequest.bind(this)(reqParams); } /** * 取消已上传的块 * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.key object key,必须 * @params {String} params.region region名称,非必须 * @params {String} params.uploadId 初始化分块上传时获取的上传id,必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 * @params {Object} params.headers 自定义header信息,非必须 */ async function abortMultipartUpload(params){ if (params.key === null || params.key === undefined) { throw Error('require the params of key!'); } if(!params.bucket && !this.config.bucket){ throw Error('require the params of bucket or defaultConfig of bucket!'); } if(!params.region && !this.config.region){ throw Error('require the params of region or defaultConfig of region!'); } if(!params.uploadId){ throw Error('require the params of uploadId!'); } var headers = params.headers || {}; var resource = `?uploadId=${params.uploadId}`; var bucket = params.bucket || this.config.bucket; var region = params.region || this.config.region; var url = getUrl.bind(this)({ bucket, region, key: params.key, resource }) var reqParams = { method: 'DELETE', bucket, url, qs: {}, headers: headers, body: params.body } if(!reqParams.headers['x-kss-date']) { reqParams.headers['x-kss-date'] = params.date ? params.date : new Date().toUTCString(); } reqParams.date = reqParams.headers['x-kss-date']; var signature = params.signature || utils.getAuth(this.config.SK, reqParams.bucket, params.key, resource, reqParams.method, reqParams.headers, reqParams.date); reqParams.headers['Authorization'] = `KSS ${this.config.AK}:${signature}`; return await generalRequest.bind(this)(reqParams); } /** * 查看正在进行的分块上传任务 * @params {Object} params 参数对象,必须 * @params {String} params.bucket bucket名称,非必须 * @params {String} params.region region名称,非必须 * @params {Integer} params['max-uploads'] 限定要列出正在进行任务的上限值([1,1000]),默认1000,非必须 * @params {String} params['upload-id-marker'] 与key-marker配合使用,指定列举目标空间中正在进行分块上传任务的起始位置,非必须 * @params {String} params['key-marker'] 与upload-id-marker配合使用,指定列举目标空间中正在进行分块上传任务的起始位置,非必须 * @params {String} params['encoding-type'] 指明请求KS3与KS3响应使用的编码方式。object key 可以包含任意Unicode字符,非必须 * @params {String} params.prefix 限定响应结果列表使用的前缀,正如你在电脑中使用的文件夹一样,非必须 * @params {String} params.signature 请求签名(从服务端获取),非必须 * @params {Object} params.headers 自定义header信息,非必须 */ async function listMultipartUploads(params){ if(!params.bucket && !this.config.bucket){ throw Error('require the params of bucket or defaultConfig of bucket!'); } if(!params.region && !this.config.region){ throw Error('require the params of region or defaultConfig of region!'); } var headers = params.headers || {}; var qs = {}; if(params['max-uploads']){ qs['max-uploads'] = params['max-uploads']; } if(params['upload-id-marker']){ qs['upload-id-marker'] = params['upload-id-marker']; } if(params['key-marker']){