ks3-js-sdk
Version:
js sdk for ks3
1,224 lines (1,189 loc) • 60.8 kB
JavaScript
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']){