diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..bb94764 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "printWidth": 120, + "tabWidth": 2, + "useTabs": false, + "semi": true, + "singleQuote": true, + "jsxSingleQuote": true, + "jsxBracketSameLine": true, + "trailingComma": "all" +} diff --git a/demo/demo.js b/demo/demo.js index d68a641..5762ba5 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -7,821 +7,1019 @@ var pathLib = require('path'); var config = require('./config'); var json2xml = require('../sdk/util').json2xml; - var cos = new COS({ - // 必选参数 - SecretId: config.SecretId, - SecretKey: config.SecretKey, - // 可选参数 - FileParallelLimit: 3, // 控制文件上传并发数 - ChunkParallelLimit: 8, // 控制单个文件下分片上传并发数,在同园区上传可以设置较大的并发数 - ChunkSize: 1024 * 1024 * 8, // 控制分片大小,单位 B,在同园区上传可以设置较大的分片大小 - Proxy: '', - Protocol: 'https:', - FollowRedirect: false, + // 必选参数 + SecretId: config.SecretId, + SecretKey: config.SecretKey, + // 可选参数 + FileParallelLimit: 3, // 控制文件上传并发数 + ChunkParallelLimit: 8, // 控制单个文件下分片上传并发数,在同园区上传可以设置较大的并发数 + ChunkSize: 1024 * 1024 * 8, // 控制分片大小,单位 B,在同园区上传可以设置较大的分片大小 + Proxy: '', + Protocol: 'https:', + FollowRedirect: false, }); var TaskId; function camSafeUrlEncode(str) { - return encodeURIComponent(str) - .replace(/!/g, '%21') - .replace(/'/g, '%27') - .replace(/\(/g, '%28') - .replace(/\)/g, '%29') - .replace(/\*/g, '%2A'); + return encodeURIComponent(str) + .replace(/!/g, '%21') + .replace(/'/g, '%27') + .replace(/\(/g, '%28') + .replace(/\)/g, '%29') + .replace(/\*/g, '%2A'); } function getAuth() { - var key = '1mb.zip'; - var auth = cos.getAuth({ - Method: 'get', - Key: key, - Expires: 60, - }); - // 注意:这里的 Bucket 格式是 test-1250000000 - console.log('http://' + config.Bucket + '.cos.' + config.Region + '.myqcloud.com' + '/' + camSafeUrlEncode(key).replace(/%2F/g, '/') + '?sign=' + encodeURIComponent(auth)); + var key = '1mb.zip'; + var auth = cos.getAuth({ + Method: 'get', + Key: key, + Expires: 60, + }); + // 注意:这里的 Bucket 格式是 test-1250000000 + console.log( + 'http://' + + config.Bucket + + '.cos.' + + config.Region + + '.myqcloud.com' + + '/' + + camSafeUrlEncode(key).replace(/%2F/g, '/') + + '?sign=' + + encodeURIComponent(auth), + ); } function getV4Auth() { - console.log(); - var key = '中文.txt'; - var auth = cos.getV4Auth({ - Bucket: config.Bucket, - Key: key, - Expires: 60, - }); - // 注意:这里的 Bucket 格式是 test-1250000000 - console.log('http://' + config.Bucket + '.cos.' + config.Region + '.myqcloud.com' + '/' + camSafeUrlEncode(key).replace(/%2F/g, '/') + '?sign=' + encodeURIComponent(auth)); + console.log(); + var key = '中文.txt'; + var auth = cos.getV4Auth({ + Bucket: config.Bucket, + Key: key, + Expires: 60, + }); + // 注意:这里的 Bucket 格式是 test-1250000000 + console.log( + 'http://' + + config.Bucket + + '.cos.' + + config.Region + + '.myqcloud.com' + + '/' + + camSafeUrlEncode(key).replace(/%2F/g, '/') + + '?sign=' + + encodeURIComponent(auth), + ); } function getObjectUrl() { - var url = cos.getObjectUrl({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1mb.zip', - Expires: 60, - Sign: true, - }, function (err, data) { - console.log(err || data); - }); - console.log(url); + var url = cos.getObjectUrl( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1mb.zip', + Expires: 60, + Sign: true, + }, + function (err, data) { + console.log(err || data); + }, + ); + console.log(url); } function getService() { - cos.getService({ + cos.getService( + { Region: 'ap-guangzhou', - },function (err, data) { - console.log(err || data); - }); + }, + function (err, data) { + console.log(err || data); + }, + ); } function putBucket() { - cos.putBucket({ - Bucket: 'testnew-' + config.Bucket.substr(config.Bucket.lastIndexOf('-') + 1), - Region: 'ap-guangzhou', - // BucketAZConfig: 'MAZ', - // BucketArchConfig: 'OFS', - }, function (err, data) { - console.log(err || data); - }); + cos.putBucket( + { + Bucket: 'testnew-' + config.Bucket.substr(config.Bucket.lastIndexOf('-') + 1), + Region: 'ap-guangzhou', + // BucketAZConfig: 'MAZ', + // BucketArchConfig: 'OFS', + }, + function (err, data) { + console.log(err || data); + }, + ); } function getBucket() { - cos.getBucket({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - console.log(err || data); - }); + cos.getBucket( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function headBucket() { - cos.headBucket({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - console.log(err || data); - }); + cos.headBucket( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function deleteBucket() { - cos.deleteBucket({ - Bucket: 'testnew-' + config.Bucket.substr(config.Bucket.lastIndexOf('-') + 1), - Region: 'ap-guangzhou' - }, function (err, data) { - console.log(err || data); - }); + cos.deleteBucket( + { + Bucket: 'testnew-' + config.Bucket.substr(config.Bucket.lastIndexOf('-') + 1), + Region: 'ap-guangzhou', + }, + function (err, data) { + console.log(err || data); + }, + ); } function putBucketAcl() { - cos.putBucketAcl({ - Bucket: config.Bucket, - Region: config.Region, - // GrantFullControl: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', - // GrantWrite: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', - // GrantRead: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', - // GrantReadAcp: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', - // GrantWriteAcp: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', - // ACL: 'public-read-write', - // ACL: 'public-read', - ACL: 'private', - AccessControlPolicy: { - "Owner": { // AccessControlPolicy 里必须有 owner - "ID": 'qcs::cam::uin/10001:uin/10001' // 10001 是 Bucket 所属用户的 QQ 号 - }, - "Grants": [ - { - "Grantee": { - "URI": "http://cam.qcloud.com/groups/global/AllUsers", // 允许匿名用户组访问 - }, - "Permission": "READ" + cos.putBucketAcl( + { + Bucket: config.Bucket, + Region: config.Region, + // GrantFullControl: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', + // GrantWrite: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', + // GrantRead: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', + // GrantReadAcp: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', + // GrantWriteAcp: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', + // ACL: 'public-read-write', + // ACL: 'public-read', + ACL: 'private', + AccessControlPolicy: { + Owner: { + // AccessControlPolicy 里必须有 owner + ID: 'qcs::cam::uin/10001:uin/10001', // 10001 是 Bucket 所属用户的 QQ 号 + }, + Grants: [ + { + Grantee: { + URI: 'http://cam.qcloud.com/groups/global/AllUsers', // 允许匿名用户组访问 }, - { - "Grantee": { - "ID": "qcs::cam::uin/1001:uin/1001", // 10002 是 QQ 号 - }, - "Permission": "WRITE" - }, { - "Grantee": { - "ID": "qcs::cam::uin/10002:uin/10002", // 10002 是 QQ 号 - }, - "Permission": "READ_ACP" - }, { - "Grantee": { - "ID": "qcs::cam::uin/10002:uin/10002", // 10002 是 QQ 号 - }, - "Permission": "WRITE_ACP" - }] - } - }, function (err, data) { - console.log(err || data); - }); + Permission: 'READ', + }, + { + Grantee: { + ID: 'qcs::cam::uin/1001:uin/1001', // 10002 是 QQ 号 + }, + Permission: 'WRITE', + }, + { + Grantee: { + ID: 'qcs::cam::uin/10002:uin/10002', // 10002 是 QQ 号 + }, + Permission: 'READ_ACP', + }, + { + Grantee: { + ID: 'qcs::cam::uin/10002:uin/10002', // 10002 是 QQ 号 + }, + Permission: 'WRITE_ACP', + }, + ], + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } function getBucketAcl() { - cos.getBucketAcl({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - console.log(err || data); - }); + cos.getBucketAcl( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function putBucketCors() { - cos.putBucketCors({ - Bucket: config.Bucket, - Region: config.Region, - ResponseVary: "true", - CORSRules: [{ - "AllowedOrigin": ["*"], - "AllowedMethod": ["GET", "POST", "PUT", "DELETE", "HEAD"], - "AllowedHeader": ["*"], - "ExposeHeader": ["ETag", "Date", "Content-Length", "x-cos-acl", "x-cos-version-id", "x-cos-request-id", "x-cos-delete-marker", "x-cos-server-side-encryption"], - "MaxAgeSeconds": 5 - }] - }, function (err, data) { - console.log(err || data); - }); + cos.putBucketCors( + { + Bucket: config.Bucket, + Region: config.Region, + ResponseVary: 'true', + CORSRules: [ + { + AllowedOrigin: ['*'], + AllowedMethod: ['GET', 'POST', 'PUT', 'DELETE', 'HEAD'], + AllowedHeader: ['*'], + ExposeHeader: [ + 'ETag', + 'Date', + 'Content-Length', + 'x-cos-acl', + 'x-cos-version-id', + 'x-cos-request-id', + 'x-cos-delete-marker', + 'x-cos-server-side-encryption', + ], + MaxAgeSeconds: 5, + }, + ], + }, + function (err, data) { + console.log(err || data); + }, + ); } function getBucketCors() { - cos.getBucketCors({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - console.log(err || data); - }); + cos.getBucketCors( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function deleteBucketCors() { - cos.deleteBucketCors({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - console.log(err || data); - }); + cos.deleteBucketCors( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function putBucketPolicy() { - var AppId = config.Bucket.substr(config.Bucket.lastIndexOf('-') + 1); - cos.putBucketPolicy({ - Policy: { - "version": "2.0", - "statement": [{ - "effect": "allow", - "principal": {"qcs": ["qcs::cam::uin/10001:uin/10001"]}, // 这里的 10001 是 QQ 号 - "action": [ - // 这里可以从临时密钥的权限上控制前端允许的操作 - // 'name/cos:*', // 这样写可以包含下面所有权限 - - // // 列出所有允许的操作 - // // ACL 读写 - // 'name/cos:GetBucketACL', - // 'name/cos:PutBucketACL', - // 'name/cos:GetObjectACL', - // 'name/cos:PutObjectACL', - // // 简单 Bucket 操作 - // 'name/cos:PutBucket', - // 'name/cos:HeadBucket', - // 'name/cos:GetBucket', - // 'name/cos:DeleteBucket', - // 'name/cos:GetBucketLocation', - // // Versioning - // 'name/cos:PutBucketVersioning', - // 'name/cos:GetBucketVersioning', - // // CORS - // 'name/cos:PutBucketCORS', - // 'name/cos:GetBucketCORS', - // 'name/cos:DeleteBucketCORS', - // // Lifecycle - // 'name/cos:PutBucketLifecycle', - // 'name/cos:GetBucketLifecycle', - // 'name/cos:DeleteBucketLifecycle', - // // Replication - // 'name/cos:PutBucketReplication', - // 'name/cos:GetBucketReplication', - // 'name/cos:DeleteBucketReplication', - // // 删除文件 - // 'name/cos:DeleteMultipleObject', - // 'name/cos:DeleteObject', - // 简单文件操作 - 'name/cos:PutObject', - 'name/cos:AppendObject', - 'name/cos:GetObject', - 'name/cos:HeadObject', - 'name/cos:OptionsObject', - 'name/cos:PutObjectCopy', - 'name/cos:PostObjectRestore', - // 分片上传操作 - 'name/cos:InitiateMultipartUpload', - 'name/cos:ListMultipartUploads', - 'name/cos:ListParts', - 'name/cos:UploadPart', - 'name/cos:CompleteMultipartUpload', - 'name/cos:AbortMultipartUpload', - ], - // "resource": ["qcs::cos:ap-guangzhou:uid/1250000000:test-1250000000/*"] // 1250000000 是 appid - "resource": ["qcs::cos:" + config.Region + ":uid/" + AppId + ":" + config.Bucket + "/*"] // 1250000000 是 appid - }] - }, - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - console.log(err || data); - }); + var AppId = config.Bucket.substr(config.Bucket.lastIndexOf('-') + 1); + cos.putBucketPolicy( + { + Policy: { + version: '2.0', + statement: [ + { + effect: 'allow', + principal: { qcs: ['qcs::cam::uin/10001:uin/10001'] }, // 这里的 10001 是 QQ 号 + action: [ + // 这里可以从临时密钥的权限上控制前端允许的操作 + // 'name/cos:*', // 这样写可以包含下面所有权限 + + // // 列出所有允许的操作 + // // ACL 读写 + // 'name/cos:GetBucketACL', + // 'name/cos:PutBucketACL', + // 'name/cos:GetObjectACL', + // 'name/cos:PutObjectACL', + // // 简单 Bucket 操作 + // 'name/cos:PutBucket', + // 'name/cos:HeadBucket', + // 'name/cos:GetBucket', + // 'name/cos:DeleteBucket', + // 'name/cos:GetBucketLocation', + // // Versioning + // 'name/cos:PutBucketVersioning', + // 'name/cos:GetBucketVersioning', + // // CORS + // 'name/cos:PutBucketCORS', + // 'name/cos:GetBucketCORS', + // 'name/cos:DeleteBucketCORS', + // // Lifecycle + // 'name/cos:PutBucketLifecycle', + // 'name/cos:GetBucketLifecycle', + // 'name/cos:DeleteBucketLifecycle', + // // Replication + // 'name/cos:PutBucketReplication', + // 'name/cos:GetBucketReplication', + // 'name/cos:DeleteBucketReplication', + // // 删除文件 + // 'name/cos:DeleteMultipleObject', + // 'name/cos:DeleteObject', + // 简单文件操作 + 'name/cos:PutObject', + 'name/cos:AppendObject', + 'name/cos:GetObject', + 'name/cos:HeadObject', + 'name/cos:OptionsObject', + 'name/cos:PutObjectCopy', + 'name/cos:PostObjectRestore', + // 分片上传操作 + 'name/cos:InitiateMultipartUpload', + 'name/cos:ListMultipartUploads', + 'name/cos:ListParts', + 'name/cos:UploadPart', + 'name/cos:CompleteMultipartUpload', + 'name/cos:AbortMultipartUpload', + ], + // "resource": ["qcs::cos:ap-guangzhou:uid/1250000000:test-1250000000/*"] // 1250000000 是 appid + resource: ['qcs::cos:' + config.Region + ':uid/' + AppId + ':' + config.Bucket + '/*'], // 1250000000 是 appid + }, + ], + }, + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function getBucketPolicy() { - cos.getBucketPolicy({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - console.log(err || data); - }); + cos.getBucketPolicy( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function deleteBucketPolicy() { - cos.deleteBucketPolicy({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - console.log(err || data); - }); + cos.deleteBucketPolicy( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function getBucketLocation() { - cos.getBucketLocation({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - console.log(err || data); - }); + cos.getBucketLocation( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function putBucketTagging() { - cos.putBucketTagging({ - Bucket: config.Bucket, - Region: config.Region, - Tags: [ - {"Key": "k1", "Value": "v1"}, - {"Key": "k2", "Value": "v2"} - ] - }, function (err, data) { - console.log(err || data); - }); + cos.putBucketTagging( + { + Bucket: config.Bucket, + Region: config.Region, + Tags: [ + { Key: 'k1', Value: 'v1' }, + { Key: 'k2', Value: 'v2' }, + ], + }, + function (err, data) { + console.log(err || data); + }, + ); } function getBucketTagging() { - cos.getBucketTagging({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - console.log(err || data); - }); + cos.getBucketTagging( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function deleteBucketTagging() { - cos.deleteBucketTagging({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - console.log(err || data); - }); + cos.deleteBucketTagging( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function putBucketLifecycle() { - cos.putBucketLifecycle({ - Bucket: config.Bucket, - Region: config.Region, - Rules: [{ - "ID": "1", - "Status": "Enabled", - "Filter": {}, - "Transition": { - "Days": "30", - "StorageClass": "STANDARD_IA" - } - }, { - "ID": "2", - "Status": "Enabled", - "Filter": { - "Prefix": "dir/" - }, - "Transition": { - "Days": "180", - "StorageClass": "ARCHIVE" - } - }, { - "ID": "3", - "Status": "Enabled", - "Filter": {}, - "Expiration": { - "Days": "180" - } - }, { - "ID": "4", - "Status": "Enabled", - "Filter": {}, - "AbortIncompleteMultipartUpload": { - "DaysAfterInitiation": "30" - } - }], - }, function (err, data) { - console.log(err || data); - }); + cos.putBucketLifecycle( + { + Bucket: config.Bucket, + Region: config.Region, + Rules: [ + { + ID: '1', + Status: 'Enabled', + Filter: {}, + Transition: { + Days: '30', + StorageClass: 'STANDARD_IA', + }, + }, + { + ID: '2', + Status: 'Enabled', + Filter: { + Prefix: 'dir/', + }, + Transition: { + Days: '180', + StorageClass: 'ARCHIVE', + }, + }, + { + ID: '3', + Status: 'Enabled', + Filter: {}, + Expiration: { + Days: '180', + }, + }, + { + ID: '4', + Status: 'Enabled', + Filter: {}, + AbortIncompleteMultipartUpload: { + DaysAfterInitiation: '30', + }, + }, + ], + }, + function (err, data) { + console.log(err || data); + }, + ); } function getBucketLifecycle() { - cos.getBucketLifecycle({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - console.log(err || data); - }); + cos.getBucketLifecycle( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function deleteBucketLifecycle() { - cos.deleteBucketLifecycle({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - console.log(err || data); - }); + cos.deleteBucketLifecycle( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function putBucketVersioning() { - cos.putBucketVersioning({ - Bucket: config.Bucket, - Region: config.Region, - VersioningConfiguration: { - Status: "Enabled" - } - }, function (err, data) { - console.log(err || data); - }); + cos.putBucketVersioning( + { + Bucket: config.Bucket, + Region: config.Region, + VersioningConfiguration: { + Status: 'Enabled', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } function getBucketVersioning() { - cos.getBucketVersioning({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - console.log(err || data); - }); + cos.getBucketVersioning( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function putBucketReplication() { - var AppId = config.Bucket.substr(config.Bucket.lastIndexOf('-') + 1); - cos.putBucketReplication({ - Bucket: config.Bucket, - Region: config.Region, - ReplicationConfiguration: { - Role: "qcs::cam::uin/10001:uin/10001", - Rules: [{ - ID: "1", - Status: "Enabled", - Prefix: "sync/", - Destination: { - Bucket: "qcs:id/0:cos:ap-chengdu:appid/" + AppId + ":backup", - // StorageClass: "Standard", - } - }] - } - }, function (err, data) { - console.log(err || data); - }); + var AppId = config.Bucket.substr(config.Bucket.lastIndexOf('-') + 1); + cos.putBucketReplication( + { + Bucket: config.Bucket, + Region: config.Region, + ReplicationConfiguration: { + Role: 'qcs::cam::uin/10001:uin/10001', + Rules: [ + { + ID: '1', + Status: 'Enabled', + Prefix: 'sync/', + Destination: { + Bucket: 'qcs:id/0:cos:ap-chengdu:appid/' + AppId + ':backup', + // StorageClass: "Standard", + }, + }, + ], + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } function getBucketReplication() { - cos.getBucketReplication({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - console.log(err || data); - }); + cos.getBucketReplication( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function deleteBucketReplication() { - cos.deleteBucketReplication({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - console.log(err || data); - }); + cos.deleteBucketReplication( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function putBucketWebsite() { - cos.putBucketWebsite({ - Bucket: config.Bucket, - Region: config.Region, - WebsiteConfiguration: { - IndexDocument: { - Suffix: "index.html" // 必选 - }, - RedirectAllRequestsTo: { - Protocol: "https" - }, - // ErrorDocument: { - // Key: "error.html" - // }, - // RoutingRules: [{ - // Condition: { - // HttpErrorCodeReturnedEquals: "404" - // }, - // Redirect: { - // Protocol: "https", - // ReplaceKeyWith: "404.html" - // } - // }, { - // Condition: { - // KeyPrefixEquals: "docs/" - // }, - // Redirect: { - // Protocol: "https", - // ReplaceKeyPrefixWith: "documents/" - // } - // }, { - // Condition: { - // KeyPrefixEquals: "img/" - // }, - // Redirect: { - // Protocol: "https", - // ReplaceKeyWith: "picture.jpg" - // } - // }] - } - }, function (err, data) { - console.log(err || data); - }); + cos.putBucketWebsite( + { + Bucket: config.Bucket, + Region: config.Region, + WebsiteConfiguration: { + IndexDocument: { + Suffix: 'index.html', // 必选 + }, + RedirectAllRequestsTo: { + Protocol: 'https', + }, + // ErrorDocument: { + // Key: "error.html" + // }, + // RoutingRules: [{ + // Condition: { + // HttpErrorCodeReturnedEquals: "404" + // }, + // Redirect: { + // Protocol: "https", + // ReplaceKeyWith: "404.html" + // } + // }, { + // Condition: { + // KeyPrefixEquals: "docs/" + // }, + // Redirect: { + // Protocol: "https", + // ReplaceKeyPrefixWith: "documents/" + // } + // }, { + // Condition: { + // KeyPrefixEquals: "img/" + // }, + // Redirect: { + // Protocol: "https", + // ReplaceKeyWith: "picture.jpg" + // } + // }] + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } function getBucketWebsite() { - cos.getBucketWebsite({ - Bucket: config.Bucket, - Region: config.Region - },function(err, data){ - console.log(err || data); - }); + cos.getBucketWebsite( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function deleteBucketWebsite() { - cos.deleteBucketWebsite({ - Bucket: config.Bucket, - Region: config.Region - },function(err, data){ - console.log(err || data); - }); + cos.deleteBucketWebsite( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function putBucketReferer() { - cos.putBucketReferer({ - Bucket: config.Bucket, - Region: config.Region, - RefererConfiguration: { - Status: 'Enabled', - RefererType: 'White-List', - DomainList: { - Domains: [ - '*.qq.com', - '*.qcloud.com', - ] - }, - EmptyReferConfiguration: 'Allow', - } - }, function (err, data) { - console.log(err || data); - }); + cos.putBucketReferer( + { + Bucket: config.Bucket, + Region: config.Region, + RefererConfiguration: { + Status: 'Enabled', + RefererType: 'White-List', + DomainList: { + Domains: ['*.qq.com', '*.qcloud.com'], + }, + EmptyReferConfiguration: 'Allow', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } function getBucketReferer() { - cos.getBucketReferer({ - Bucket: config.Bucket, - Region: config.Region - },function(err, data){ - console.log(err || JSON.stringify(data, null, ' ')); - }); + cos.getBucketReferer( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || JSON.stringify(data, null, ' ')); + }, + ); } function putBucketDomain() { - cos.putBucketDomain({ - Bucket: config.Bucket, - Region: config.Region, - DomainRule:[{ - Status: "DISABLED", - Name: "www.testDomain1.com", - Type: "REST" - }, { - Status: "DISABLED", - Name: "www.testDomain2.com", - Type: "WEBSITE" - }] - },function(err, data){ - console.log(err || data); - }); + cos.putBucketDomain( + { + Bucket: config.Bucket, + Region: config.Region, + DomainRule: [ + { + Status: 'DISABLED', + Name: 'www.testDomain1.com', + Type: 'REST', + }, + { + Status: 'DISABLED', + Name: 'www.testDomain2.com', + Type: 'WEBSITE', + }, + ], + }, + function (err, data) { + console.log(err || data); + }, + ); } function getBucketDomain() { - cos.getBucketDomain({ - Bucket: config.Bucket, - Region: config.Region - },function(err, data){ - console.log(err || data); - }); + cos.getBucketDomain( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function deleteBucketDomain() { - cos.deleteBucketDomain({ - Bucket: config.Bucket, - Region: config.Region - },function(err, data){ - console.log(err || data); - }); + cos.deleteBucketDomain( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function putBucketOrigin() { - cos.putBucketOrigin({ - Bucket: config.Bucket, - Region: config.Region, - OriginRule: [{ - OriginType: 'Mirror', - OriginCondition: {HTTPStatusCode: 404, Prefix: ''}, - OriginParameter: { - Protocol: 'HTTP', - FollowQueryString: 'true', - HttpHeader: { - NewHttpHeader: { - Header: [{ - Key: 'a', - Value: 'a' - }] - } - }, - FollowRedirection: 'true', - HttpRedirectCode: ['301', '302'] + cos.putBucketOrigin( + { + Bucket: config.Bucket, + Region: config.Region, + OriginRule: [ + { + OriginType: 'Mirror', + OriginCondition: { HTTPStatusCode: 404, Prefix: '' }, + OriginParameter: { + Protocol: 'HTTP', + FollowQueryString: 'true', + HttpHeader: { + NewHttpHeader: { + Header: [ + { + Key: 'a', + Value: 'a', + }, + ], + }, }, - OriginInfo: { - HostInfo: {HostName: 'qq.com'}, - FileInfo: { - PrefixConfiguration: {Prefix: '123/'}, - SuffixConfiguration: {Suffix: '.jpg'} - } + FollowRedirection: 'true', + HttpRedirectCode: ['301', '302'], + }, + OriginInfo: { + HostInfo: { HostName: 'qq.com' }, + FileInfo: { + PrefixConfiguration: { Prefix: '123/' }, + SuffixConfiguration: { Suffix: '.jpg' }, }, - RulePriority: 1 - }] - },function(err, data){ - console.log(err || data); - }); + }, + RulePriority: 1, + }, + ], + }, + function (err, data) { + console.log(err || data); + }, + ); } function getBucketOrigin() { - cos.getBucketOrigin({ - Bucket: config.Bucket, - Region: config.Region, - }, function(err, data){ - console.log(err || data); - }); + cos.getBucketOrigin( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function deleteBucketOrigin() { - cos.deleteBucketOrigin({ - Bucket: config.Bucket, - Region: config.Region, - },function(err, data){ - console.log(err || data); - }); + cos.deleteBucketOrigin( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function putBucketLogging() { - var AppId = config.Bucket.substr(config.Bucket.lastIndexOf('-') + 1); - cos.putBucketLogging({ - Bucket: config.Bucket, - Region: config.Region, - BucketLoggingStatus: { - LoggingEnabled: { - TargetBucket: 'bucket-logging-' + AppId, - TargetPrefix: 'logging' - } - } - }, function (err, data) { - console.log(err || data); - }); + var AppId = config.Bucket.substr(config.Bucket.lastIndexOf('-') + 1); + cos.putBucketLogging( + { + Bucket: config.Bucket, + Region: config.Region, + BucketLoggingStatus: { + LoggingEnabled: { + TargetBucket: 'bucket-logging-' + AppId, + TargetPrefix: 'logging', + }, + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } function getBucketLogging() { - cos.getBucketLogging({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - console.log(err || data); - }); + cos.getBucketLogging( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function deleteBucketLogging() { - cos.putBucketLogging({ - Bucket: config.Bucket, - Region: config.Region, - BucketLoggingStatus: { - } - }, function (err, data) { - console.log(err || data); - }); + cos.putBucketLogging( + { + Bucket: config.Bucket, + Region: config.Region, + BucketLoggingStatus: {}, + }, + function (err, data) { + console.log(err || data); + }, + ); } function putBucketInventory() { - var AppId = config.Bucket.substr(config.Bucket.lastIndexOf('-') + 1); - cos.putBucketInventory({ - Bucket: config.Bucket, - Region: config.Region, + var AppId = config.Bucket.substr(config.Bucket.lastIndexOf('-') + 1); + cos.putBucketInventory( + { + Bucket: config.Bucket, + Region: config.Region, + Id: 'inventory_test', + InventoryConfiguration: { Id: 'inventory_test', - InventoryConfiguration: { - Id: 'inventory_test', - IsEnabled: 'true', - Destination: { - COSBucketDestination: { - Format: 'CSV', - AccountId: config.Uin, - Bucket: 'qcs::cos:ap-guangzhou::bucket-logging-' + AppId, - Prefix: 'inventory', - Encryption: { - SSECOS: '' - } - } - }, - Schedule: { - Frequency: 'Daily' + IsEnabled: 'true', + Destination: { + COSBucketDestination: { + Format: 'CSV', + AccountId: config.Uin, + Bucket: 'qcs::cos:ap-guangzhou::bucket-logging-' + AppId, + Prefix: 'inventory', + Encryption: { + SSECOS: '', }, - Filter: { - Prefix: 'myPrefix' - }, - IncludedObjectVersions: 'All', - OptionalFields: [ - 'Size', - 'LastModifiedDate', - 'ETag', - 'StorageClass', - 'IsMultipartUploaded', - 'ReplicationStatus' - ] - } - }, function (err, data) { - console.log(err || data); - }); + }, + }, + Schedule: { + Frequency: 'Daily', + }, + Filter: { + Prefix: 'myPrefix', + }, + IncludedObjectVersions: 'All', + OptionalFields: [ + 'Size', + 'LastModifiedDate', + 'ETag', + 'StorageClass', + 'IsMultipartUploaded', + 'ReplicationStatus', + ], + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } function getBucketInventory() { - cos.getBucketInventory({ - Bucket: config.Bucket, - Region: config.Region, - Id: 'inventory_test' - }, function(err, data) { - console.log(err || JSON.stringify(data)); - }); + cos.getBucketInventory( + { + Bucket: config.Bucket, + Region: config.Region, + Id: 'inventory_test', + }, + function (err, data) { + console.log(err || JSON.stringify(data)); + }, + ); } function deleteBucketInventory() { - cos.deleteBucketInventory({ - Bucket: config.Bucket, - Region: config.Region, - Id: 'inventory_test' - }, function(err, data) { - console.log(err || JSON.stringify(data)); - }); + cos.deleteBucketInventory( + { + Bucket: config.Bucket, + Region: config.Region, + Id: 'inventory_test', + }, + function (err, data) { + console.log(err || JSON.stringify(data)); + }, + ); } function listBucketInventory() { - cos.listBucketInventory({ - Bucket: config.Bucket, - Region: config.Region - }, function(err, data) { - console.log(err || JSON.stringify(data)); - }); + cos.listBucketInventory( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || JSON.stringify(data)); + }, + ); } function putBucketAccelerate() { - cos.putBucketAccelerate({ - Bucket: config.Bucket, - Region: config.Region, - AccelerateConfiguration: { - Status: 'Enabled' - } - }, function (err, data) { - console.log(err || data); - }); + cos.putBucketAccelerate( + { + Bucket: config.Bucket, + Region: config.Region, + AccelerateConfiguration: { + Status: 'Enabled', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } function getBucketAccelerate() { - cos.getBucketAccelerate({ - Bucket: config.Bucket, - Region: config.Region, - }, function(err, data) { - console.log(err || data); - }); + cos.getBucketAccelerate( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || data); + }, + ); } function putBucketEncryption() { - cos.putBucketEncryption({ - Bucket: config.Bucket, - Region: config.Region, - ServerSideEncryptionConfiguration: { - Rule: [{ - ApplySideEncryptionConfiguration: { - SSEAlgorithm: 'AES256', - }, - }], - }, - }, function(err, data) { - console.log(JSON.stringify(err || data, null, 2)); - }); + cos.putBucketEncryption( + { + Bucket: config.Bucket, + Region: config.Region, + ServerSideEncryptionConfiguration: { + Rule: [ + { + ApplySideEncryptionConfiguration: { + SSEAlgorithm: 'AES256', + }, + }, + ], + }, + }, + function (err, data) { + console.log(JSON.stringify(err || data, null, 2)); + }, + ); } function getBucketEncryption() { - cos.getBucketEncryption({ - Bucket: config.Bucket, - Region: config.Region - }, function(err, data) { - console.log(err || JSON.stringify(data)); - }); + cos.getBucketEncryption( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || JSON.stringify(data)); + }, + ); } function deleteBucketEncryption() { - cos.deleteBucketEncryption({ - Bucket: config.Bucket, - Region: config.Region - }, function(err, data) { - console.log(err || JSON.stringify(data)); - }); + cos.deleteBucketEncryption( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(err || JSON.stringify(data)); + }, + ); } function putObject() { - // 创建测试文件 - var filename = '1mb.zip'; - var filepath = path.resolve(__dirname, filename); - util.createFile(filepath, 1024 * 1024, function (err) { - // 调用方法 - cos.putObject({ - Bucket: config.Bucket, /* 必须 */ - Region: config.Region, - Key: filename, /* 必须 */ - onTaskReady: function (tid) { - TaskId = tid; - }, - onProgress: function (progressData) { - console.log(JSON.stringify(progressData)); - }, - // 格式1. 传入文件内容 - // Body: fs.readFileSync(filepath), - // 格式2. 传入文件流,必须需要传文件大小 - Body: fs.createReadStream(filepath), - ContentLength: fs.statSync(filepath).size, - Headers: { - // 万象持久化接口,上传时持久化 - // 'Pic-Operations': '{"is_pic_info": 1, "rules": [{"fileid": "test.jpg", "rule": "imageMogr2/thumbnail/!50p"}]}' - }, - }, function (err, data) { - console.log(err || data); - fs.unlinkSync(filepath); - }); + // 创建测试文件 + var filename = '1mb.zip'; + var filepath = path.resolve(__dirname, filename); + util.createFile(filepath, 1024 * 1024, function (err) { + // 调用方法 + cos.putObject( + { + Bucket: config.Bucket /* 必须 */, + Region: config.Region, + Key: filename /* 必须 */, + onTaskReady: function (tid) { + TaskId = tid; + }, + onProgress: function (progressData) { + console.log(JSON.stringify(progressData)); + }, + // 格式1. 传入文件内容 + // Body: fs.readFileSync(filepath), + // 格式2. 传入文件流,必须需要传文件大小 + Body: fs.createReadStream(filepath), + ContentLength: fs.statSync(filepath).size, + Headers: { + // 万象持久化接口,上传时持久化 + // 'Pic-Operations': '{"is_pic_info": 1, "rules": [{"fileid": "test.jpg", "rule": "imageMogr2/thumbnail/!50p"}]}' + }, + }, + function (err, data) { + console.log(err || data); + fs.unlinkSync(filepath); + }, + ); }); } @@ -829,19 +1027,21 @@ function putObject_base64ToBuffer() { // 创建测试文件 var filename = 'test.png'; var filepath = path.resolve(__dirname, filename); - var base64Url = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABRFBMVEUAAAAAo/8Ao/8Ao/8Ao/8ApP8Aov8Ao/8Abv8Abv8AyNwAyNwAo/8Ao/8Ao/8Abv8Ao/8AivgAo/8AyNwAbv8Abv8AydwApf8Abf8Ao/8AbP8Ao/8AyNwAydwAbv8AydwApP8Ao/8AyNwAo/8AyNwAydsAyNwAxd8Aov8AyNwAytsAo/8Abv8AyNwAbv8Av+MAo/8AytsAo/8Abv8AyNwAo/8Abv8AqfkAbv8Aov8Abv8AyNwAov8Abv8Ao/8Abv8Ao/8AydwAo/8Ao/8Ate8Ay9oAvOcAof8AveAAyNwAyNwAo/8AyNwAy9kAo/8AyNwAyNwAo/8AqP8Aaf8AyNwAbv0Abv8Abv8AaP8Ao/8Ao/8Ao/8Ao/8Abv8AyNwAgvcAaP8A0dkAo/8AyNwAav8Abv8Ao/8Abv8AyNwAy9sAvOUAtePdkYxjAAAAZnRSTlMAw/co8uAuJAn8+/Tt29R8DAX77+nZz87Jv6CTh3lxTklAPjouJRsL5tjAuLiyr62roaCakYp0XVtOQTMyLiohICAcGRP49vTv5+PJurawq6mnnJuYl4+OiIB7eXVvX15QSDgqHxNcw3l6AAABe0lEQVQ4y82P11oCQQxGIy5FUJpKk6aAhV6k92LvvXedDfj+92ZkYQHxnnMxu3/OfJMEJo6y++baXf5XVw22GVGcsRmq431mQZRYyIzRGgdXi+HwIv86NDBKisrRAtU1hSj9pkZ9jpo/9YKbRsmNNKCHDXI00BxfMMirKNpMcjQ5Lm4/YZArUXyBYUwg40nsdr5jb3LBe25VWpNeKa1GENsEnq52C80z1uW48estiKjb19G54QdCrScnKAU69U3KJ4jzrsBawDWPuOcBqMyRvlcb1Y+zjMUBVsivAKe4gXgEKiVjSh9wlunGMmwiOqFL3RI0cj+nkgp3jC1BELVFkGiZSuvkp3tZZWZ2sKCuDj185PXqfmwI7AAOUctHkJoOeXg3sxA4ES+l7CVvrYHMEmNp8GtR+wycPG0+1RrwWQUzl4CvgQmPP5Ddofl8tWkJVT7J+BIAaxEktrYZoRAUfXgOGYHfcOqw3WF/EdLccz5cMfvUCPb4QwUmhB8+v12HZPCkbgAAAABJRU5ErkJggg=='; - var body = Buffer.from(base64Url.split(',')[1] , 'base64'); + var base64Url = + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABRFBMVEUAAAAAo/8Ao/8Ao/8Ao/8ApP8Aov8Ao/8Abv8Abv8AyNwAyNwAo/8Ao/8Ao/8Abv8Ao/8AivgAo/8AyNwAbv8Abv8AydwApf8Abf8Ao/8AbP8Ao/8AyNwAydwAbv8AydwApP8Ao/8AyNwAo/8AyNwAydsAyNwAxd8Aov8AyNwAytsAo/8Abv8AyNwAbv8Av+MAo/8AytsAo/8Abv8AyNwAo/8Abv8AqfkAbv8Aov8Abv8AyNwAov8Abv8Ao/8Abv8Ao/8AydwAo/8Ao/8Ate8Ay9oAvOcAof8AveAAyNwAyNwAo/8AyNwAy9kAo/8AyNwAyNwAo/8AqP8Aaf8AyNwAbv0Abv8Abv8AaP8Ao/8Ao/8Ao/8Ao/8Abv8AyNwAgvcAaP8A0dkAo/8AyNwAav8Abv8Ao/8Abv8AyNwAy9sAvOUAtePdkYxjAAAAZnRSTlMAw/co8uAuJAn8+/Tt29R8DAX77+nZz87Jv6CTh3lxTklAPjouJRsL5tjAuLiyr62roaCakYp0XVtOQTMyLiohICAcGRP49vTv5+PJurawq6mnnJuYl4+OiIB7eXVvX15QSDgqHxNcw3l6AAABe0lEQVQ4y82P11oCQQxGIy5FUJpKk6aAhV6k92LvvXedDfj+92ZkYQHxnnMxu3/OfJMEJo6y++baXf5XVw22GVGcsRmq431mQZRYyIzRGgdXi+HwIv86NDBKisrRAtU1hSj9pkZ9jpo/9YKbRsmNNKCHDXI00BxfMMirKNpMcjQ5Lm4/YZArUXyBYUwg40nsdr5jb3LBe25VWpNeKa1GENsEnq52C80z1uW48estiKjb19G54QdCrScnKAU69U3KJ4jzrsBawDWPuOcBqMyRvlcb1Y+zjMUBVsivAKe4gXgEKiVjSh9wlunGMmwiOqFL3RI0cj+nkgp3jC1BELVFkGiZSuvkp3tZZWZ2sKCuDj185PXqfmwI7AAOUctHkJoOeXg3sxA4ES+l7CVvrYHMEmNp8GtR+wycPG0+1RrwWQUzl4CvgQmPP5Ddofl8tWkJVT7J+BIAaxEktrYZoRAUfXgOGYHfcOqw3WF/EdLccz5cMfvUCPb4QwUmhB8+v12HZPCkbgAAAABJRU5ErkJggg=='; + var body = Buffer.from(base64Url.split(',')[1], 'base64'); util.createFile(filepath, 1024 * 1024, function (err) { // 调用方法 - cos.putObject({ - Bucket: config.Bucket, /* 必须 */ + cos.putObject( + { + Bucket: config.Bucket /* 必须 */, Region: config.Region, - Key: filename, /* 必须 */ + Key: filename /* 必须 */, onTaskReady: function (tid) { - TaskId = tid; + TaskId = tid; }, onProgress: function (progressData) { - console.log(JSON.stringify(progressData)); + console.log(JSON.stringify(progressData)); }, // 格式1. 传入文件内容 // Body: fs.readFileSync(filepath), @@ -849,1908 +1049,3312 @@ function putObject_base64ToBuffer() { Body: body, ContentLength: body.length, Headers: { - // 万象持久化接口,上传时持久化 - // 'Pic-Operations': '{"is_pic_info": 1, "rules": [{"fileid": "test.jpg", "rule": "imageMogr2/thumbnail/!50p"}]}' + // 万象持久化接口,上传时持久化 + // 'Pic-Operations': '{"is_pic_info": 1, "rules": [{"fileid": "test.jpg", "rule": "imageMogr2/thumbnail/!50p"}]}' }, - }, function (err, data) { + }, + function (err, data) { console.log(err || data); fs.unlinkSync(filepath); - }); -}); + }, + ); + }); } function putObjectCopy() { - cos.putObjectCopy({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1mb.copy.zip', - CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + camSafeUrlEncode('1mb.zip').replace(/%2F/g, '/'), - }, function (err, data) { - console.log(err || data); - }); + cos.putObjectCopy( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1mb.copy.zip', + CopySource: + config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + camSafeUrlEncode('1mb.zip').replace(/%2F/g, '/'), + }, + function (err, data) { + console.log(err || data); + }, + ); } function getObject() { - var filepath1 = path.resolve(__dirname, '1mb.out1.zip'); - var filepath2 = path.resolve(__dirname, '1mb.out2.zip'); - var filepath3 = path.resolve(__dirname, '1mb.out3.zip'); - - // file1 获取对象字节到内存变量 - cos.getObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1mb.zip', - onProgress: function (progressData) { - console.log(JSON.stringify(progressData)); - } - }, function (err, data) { - if(data){ - fs.writeFileSync(filepath1, data.Body); - } else { - console.log(err); - } - }); + var filepath1 = path.resolve(__dirname, '1mb.out1.zip'); + var filepath2 = path.resolve(__dirname, '1mb.out2.zip'); + var filepath3 = path.resolve(__dirname, '1mb.out3.zip'); + // file1 获取对象字节到内存变量 + cos.getObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1mb.zip', + onProgress: function (progressData) { + console.log(JSON.stringify(progressData)); + }, + }, + function (err, data) { + if (data) { + fs.writeFileSync(filepath1, data.Body); + } else { + console.log(err); + } + }, + ); } function headObject() { - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1mb.zip' - }, function (err, data) { - console.log(err || data); - }); + cos.headObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1mb.zip', + }, + function (err, data) { + console.log(err || data); + }, + ); } function listObjectVersions() { - cos.listObjectVersions({ - Bucket: config.Bucket, - Region: config.Region, - // Prefix: "", - // Delimiter: '/' - }, function (err, data) { - console.log(err || JSON.stringify(data, null, ' ')); - }); + cos.listObjectVersions( + { + Bucket: config.Bucket, + Region: config.Region, + // Prefix: "", + // Delimiter: '/' + }, + function (err, data) { + console.log(err || JSON.stringify(data, null, ' ')); + }, + ); } function putObjectAcl() { - cos.putObjectAcl({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1mb.zip', - // GrantFullControl: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', - // GrantWriteAcp: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', - // GrantReadAcp: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', - // GrantRead: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', - // ACL: 'public-read-write', - // ACL: 'public-read', - // ACL: 'private', - ACL: 'default', // 继承上一级目录权限 - // AccessControlPolicy: { - // "Owner": { // AccessControlPolicy 里必须有 owner - // "ID": 'qcs::cam::uin/459000000:uin/459000000' // 459000000 是 Bucket 所属用户的 QQ 号 - // }, - // "Grants": [{ - // "Grantee": { - // "ID": "qcs::cam::uin/10002:uin/10002", // 10002 是 QQ 号 - // }, - // "Permission": "READ" - // }] - // } - }, function (err, data) { - console.log(err || data); - }); + cos.putObjectAcl( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1mb.zip', + // GrantFullControl: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', + // GrantWriteAcp: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', + // GrantReadAcp: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', + // GrantRead: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"', + // ACL: 'public-read-write', + // ACL: 'public-read', + // ACL: 'private', + ACL: 'default', // 继承上一级目录权限 + // AccessControlPolicy: { + // "Owner": { // AccessControlPolicy 里必须有 owner + // "ID": 'qcs::cam::uin/459000000:uin/459000000' // 459000000 是 Bucket 所属用户的 QQ 号 + // }, + // "Grants": [{ + // "Grantee": { + // "ID": "qcs::cam::uin/10002:uin/10002", // 10002 是 QQ 号 + // }, + // "Permission": "READ" + // }] + // } + }, + function (err, data) { + console.log(err || data); + }, + ); } function getObjectAcl() { - cos.getObjectAcl({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1mb.zip' - }, function (err, data) { - console.log(err || data); - }); + cos.getObjectAcl( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1mb.zip', + }, + function (err, data) { + console.log(err || data); + }, + ); } function deleteObject() { - cos.deleteObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1mb.zip' - }, function (err, data) { - console.log(err || data); - }); + cos.deleteObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1mb.zip', + }, + function (err, data) { + console.log(err || data); + }, + ); } function deleteMultipleObject() { - cos.deleteMultipleObject({ - Bucket: config.Bucket, - Region: config.Region, - Objects: [ - {Key: '中文/中文.txt'}, - {Key: '中文/中文.zip',VersionId: 'MTg0NDY3NDI1MzM4NzM0ODA2MTI'}, - ] - }, function (err, data) { - console.log(err || data); - }); + cos.deleteMultipleObject( + { + Bucket: config.Bucket, + Region: config.Region, + Objects: [{ Key: '中文/中文.txt' }, { Key: '中文/中文.zip', VersionId: 'MTg0NDY3NDI1MzM4NzM0ODA2MTI' }], + }, + function (err, data) { + console.log(err || data); + }, + ); } function restoreObject() { - cos.restoreObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.txt', - RestoreRequest: { - Days: 1, - CASJobParameters: { - Tier: 'Expedited' - } - } - }, function (err, data) { - console.log(err || data); - }); + cos.restoreObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1.txt', + RestoreRequest: { + Days: 1, + CASJobParameters: { + Tier: 'Expedited', + }, + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } var selectCsvOpt = { - Bucket: config.Bucket, - Region: config.Region, - Key: '1.csv', - SelectType: 2, - SelectRequest: { - // Expression: "select * from cosobject s limit 100", - Expression: "Select * from COSObject", - ExpressionType: "SQL", - InputSerialization: { - CSV: { - FileHeaderInfo: "IGNORE", - RecordDelimiter: "\\n", - FieldDelimiter: ",", - QuoteCharacter: "\"", - QuoteEscapeCharacter: "\"", - Comments: "#", - AllowQuotedRecordDelimiter: "FALSE" - } - }, - OutputSerialization: { - CSV: { - QuoteFields: "ASNEEDED", - RecordDelimiter: "\\n", - FieldDelimiter: ",", - QuoteCharacter: "\"", - QuoteEscapeCharacter: "\"" - } - }, - RequestProgress: {Enabled: "FALSE"} + Bucket: config.Bucket, + Region: config.Region, + Key: '1.csv', + SelectType: 2, + SelectRequest: { + // Expression: "select * from cosobject s limit 100", + Expression: 'Select * from COSObject', + ExpressionType: 'SQL', + InputSerialization: { + CSV: { + FileHeaderInfo: 'IGNORE', + RecordDelimiter: '\\n', + FieldDelimiter: ',', + QuoteCharacter: '"', + QuoteEscapeCharacter: '"', + Comments: '#', + AllowQuotedRecordDelimiter: 'FALSE', + }, + }, + OutputSerialization: { + CSV: { + QuoteFields: 'ASNEEDED', + RecordDelimiter: '\\n', + FieldDelimiter: ',', + QuoteCharacter: '"', + QuoteEscapeCharacter: '"', + }, }, + RequestProgress: { Enabled: 'FALSE' }, + }, }; var selectJsonOpt = { - Bucket: config.Bucket, - Region: config.Region, - Key: '1.json', - SelectType: 2, - SelectRequest: { - Expression: "Select * from COSObject", - ExpressionType: "SQL", - InputSerialization: {JSON: {Type: "DOCUMENT"}}, - OutputSerialization: {JSON: {RecordDelimiter: "\n"}}, - RequestProgress: {Enabled: "FALSE"} - }, + Bucket: config.Bucket, + Region: config.Region, + Key: '1.json', + SelectType: 2, + SelectRequest: { + Expression: 'Select * from COSObject', + ExpressionType: 'SQL', + InputSerialization: { JSON: { Type: 'DOCUMENT' } }, + OutputSerialization: { JSON: { RecordDelimiter: '\n' } }, + RequestProgress: { Enabled: 'FALSE' }, + }, }; function selectObjectContentStream() { - // 查询 JSON - var opt = Object.assign({ - // DataType: 'raw', - }, selectJsonOpt); - var selectStream = cos.selectObjectContentStream(opt, function (err, data) { - console.log(err || data); - }); - var outFile = './result.txt'; - selectStream.pipe(fs.createWriteStream(outFile)); - selectStream.on('end', () => console.log(fs.readFileSync(outFile).toString())) + // 查询 JSON + var opt = Object.assign( + { + // DataType: 'raw', + }, + selectJsonOpt, + ); + var selectStream = cos.selectObjectContentStream(opt, function (err, data) { + console.log(err || data); + }); + var outFile = './result.txt'; + selectStream.pipe(fs.createWriteStream(outFile)); + selectStream.on('end', () => console.log(fs.readFileSync(outFile).toString())); } function selectObjectContent() { - // // 如果返回结果很大,可以用 selectObjectContentStream 处理 - // // 查询 CSV - // cos.selectObjectContent(selectCsvOpt, function (err, data) { - // console.log(err || data); - // }); - - // 查询 JSON - cos.selectObjectContent(selectJsonOpt, function (err, data) { - console.log(err || data); - }); + // // 如果返回结果很大,可以用 selectObjectContentStream 处理 + // // 查询 CSV + // cos.selectObjectContent(selectCsvOpt, function (err, data) { + // console.log(err || data); + // }); + + // 查询 JSON + cos.selectObjectContent(selectJsonOpt, function (err, data) { + console.log(err || data); + }); } function multipartList() { - cos.multipartList({ - Bucket: config.Bucket, - Region: config.Region, - Prefix: '', - MaxUploads: 1, - Delimiter: '/' - }, function (err, data) { - console.log(err || JSON.stringify(data, null, 2)); - }); + cos.multipartList( + { + Bucket: config.Bucket, + Region: config.Region, + Prefix: '', + MaxUploads: 1, + Delimiter: '/', + }, + function (err, data) { + console.log(err || JSON.stringify(data, null, 2)); + }, + ); } function multipartListPart() { - cos.multipartListPart({ - Bucket: config.Bucket, - Region: config.Region, - Key: "10mb.zip", - MaxParts: 1, - UploadId: 'xxx', - }, function (err, data) { - console.log(err || JSON.stringify(data, null, 2)); - }); + cos.multipartListPart( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '10mb.zip', + MaxParts: 1, + UploadId: 'xxx', + }, + function (err, data) { + console.log(err || JSON.stringify(data, null, 2)); + }, + ); } function multipartInit() { - cos.multipartInit({ - Bucket: config.Bucket, - Region: config.Region, - Key: "10mb.zip", - }, function (err, data) { - console.log(err || JSON.stringify(data, null, 2)); - }); + cos.multipartInit( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '10mb.zip', + }, + function (err, data) { + console.log(err || JSON.stringify(data, null, 2)); + }, + ); } function multipartUpload() { - cos.multipartUpload({ - Bucket: config.Bucket, - Region: config.Region, - Key: "10mb.zip", - UploadId: 'xxx', - PartNumber: 1, - Body: '123', - }, function (err, data) { - console.log(err || JSON.stringify(data, null, 2)); - }); + cos.multipartUpload( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '10mb.zip', + UploadId: 'xxx', + PartNumber: 1, + Body: '123', + }, + function (err, data) { + console.log(err || JSON.stringify(data, null, 2)); + }, + ); } function multipartCom() { - cos.multipartComplete({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.zip', - UploadId: 'xxx', - Parts: [{ - PartNumber: 1, - ETag: 'xxx', - }], - }, function (err, data) { - console.log(err || JSON.stringify(data, null, 2)); - }); + cos.multipartComplete( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1.zip', + UploadId: 'xxx', + Parts: [ + { + PartNumber: 1, + ETag: 'xxx', + }, + ], + }, + function (err, data) { + console.log(err || JSON.stringify(data, null, 2)); + }, + ); } function multipartAbort() { - cos.multipartAbort({ - Bucket: config.Bucket, - Region: config.Region, - Key: "10mb.zip", - UploadId: 'xxx', - }, function (err, data) { - console.log(err || JSON.stringify(data, null, 2)); - }); + cos.multipartAbort( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '10mb.zip', + UploadId: 'xxx', + }, + function (err, data) { + console.log(err || JSON.stringify(data, null, 2)); + }, + ); } function abortUploadTask() { - cos.abortUploadTask({ - Bucket: config.Bucket, /* 必须 */ - Region: config.Region, /* 必须 */ - // 格式1,删除单个上传任务 - // Level: 'task', - // Key: '10mb.zip', - // UploadId: '14985543913e4e2642e31db217b9a1a3d9b3cd6cf62abfda23372c8d36ffa38585492681e3', - // 格式2,删除单个文件所有未完成上传任务 - Level: 'file', - Key: '10mb.zip', - // 格式3,删除 Bucket 下所有未完成上传任务 - // Level: 'bucket', - }, function (err, data) { - console.log(err || data); - }); + cos.abortUploadTask( + { + Bucket: config.Bucket /* 必须 */, + Region: config.Region /* 必须 */, + // 格式1,删除单个上传任务 + // Level: 'task', + // Key: '10mb.zip', + // UploadId: '14985543913e4e2642e31db217b9a1a3d9b3cd6cf62abfda23372c8d36ffa38585492681e3', + // 格式2,删除单个文件所有未完成上传任务 + Level: 'file', + Key: '10mb.zip', + // 格式3,删除 Bucket 下所有未完成上传任务 + // Level: 'bucket', + }, + function (err, data) { + console.log(err || data); + }, + ); } function sliceUploadFile() { - // 创建测试文件 - var filename = '10mb.zip'; - var filepath = path.resolve(__dirname, filename); - util.createFile(filepath, 1024 * 1024 * 10, function (err) { - // 调用方法 - cos.sliceUploadFile({ - Bucket: config.Bucket, /* 必须 */ - Region: config.Region, - Key: filename, /* 必须 */ - FilePath: filepath, /* 必须 */ - onTaskReady: function (tid) { - TaskId = tid; - }, - onHashProgress: function (progressData) { - console.log(JSON.stringify(progressData)); - }, - onProgress: function (progressData) { - console.log(JSON.stringify(progressData)); - }, - Headers: { - // 万象持久化接口,上传时持久化 - // 'Pic-Operations': '{"is_pic_info": 1, "rules": [{"fileid": "test.jpg", "rule": "imageMogr2/thumbnail/!50p"}]}' - }, - }, function (err, data) { - console.log(err || data); - fs.unlinkSync(filepath); - }); - }); + // 创建测试文件 + var filename = '10mb.zip'; + var filepath = path.resolve(__dirname, filename); + util.createFile(filepath, 1024 * 1024 * 10, function (err) { + // 调用方法 + cos.sliceUploadFile( + { + Bucket: config.Bucket /* 必须 */, + Region: config.Region, + Key: filename /* 必须 */, + FilePath: filepath /* 必须 */, + onTaskReady: function (tid) { + TaskId = tid; + }, + onHashProgress: function (progressData) { + console.log(JSON.stringify(progressData)); + }, + onProgress: function (progressData) { + console.log(JSON.stringify(progressData)); + }, + Headers: { + // 万象持久化接口,上传时持久化 + // 'Pic-Operations': '{"is_pic_info": 1, "rules": [{"fileid": "test.jpg", "rule": "imageMogr2/thumbnail/!50p"}]}' + }, + }, + function (err, data) { + console.log(err || data); + fs.unlinkSync(filepath); + }, + ); + }); } function cancelTask() { - cos.cancelTask(TaskId); - console.log('canceled'); + cos.cancelTask(TaskId); + console.log('canceled'); } function pauseTask() { - cos.pauseTask(TaskId); - console.log('paused'); + cos.pauseTask(TaskId); + console.log('paused'); } function restartTask() { - cos.restartTask(TaskId); - console.log('restart'); + cos.restartTask(TaskId); + console.log('restart'); } function uploadFile() { var filename = '3mb.zip'; var filepath = path.resolve(__dirname, filename); util.createFile(filepath, 1024 * 1024 * 3, function (err) { - cos.uploadFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - FilePath: filepath, - SliceSize: 1024 * 1024 * 5, // 大于5mb才进行分块上传 - onProgress: function (info) { - var percent = Math.floor(info.percent * 10000) / 100; - var speed = Math.floor(info.speed / 1024 / 1024 * 100) / 100; - console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;'); - }, - }, function (err, data) { - console.log('上传' + (err ? '失败' : '完成')); - console.log(err || data); - fs.unlinkSync(filepath); - }); + cos.uploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + FilePath: filepath, + SliceSize: 1024 * 1024 * 5, // 大于5mb才进行分块上传 + onProgress: function (info) { + var percent = Math.floor(info.percent * 10000) / 100; + var speed = Math.floor((info.speed / 1024 / 1024) * 100) / 100; + console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;'); + }, + }, + function (err, data) { + console.log('上传' + (err ? '失败' : '完成')); + console.log(err || data); + fs.unlinkSync(filepath); + }, + ); }); } function uploadFiles() { - var filepath = path.resolve(__dirname, '1mb.zip'); - util.createFile(filepath, 1024 * 1024 * 10, function (err) { - var filename = 'mb.zip'; - cos.uploadFiles({ - files: [{ - Bucket: config.Bucket, - Region: config.Region, - Key: '1' + filename, - FilePath: filepath, - }, { - Bucket: config.Bucket, - Region: config.Region, - Key: '2' + filename, - FilePath: filepath, + var filepath = path.resolve(__dirname, '1mb.zip'); + util.createFile(filepath, 1024 * 1024 * 10, function (err) { + var filename = 'mb.zip'; + cos.uploadFiles( + { + files: [ + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1' + filename, + FilePath: filepath, + }, + { + Bucket: config.Bucket, + Region: config.Region, + Key: '2' + filename, + FilePath: filepath, // }, { // Bucket: config.Bucket, // Region: config.Region, // Key: '3' + filename, // FilePath: filepath, - }], - SliceSize: 1024 * 1024, - onProgress: function (info) { - var percent = Math.floor(info.percent * 10000) / 100; - var speed = Math.floor(info.speed / 1024 / 1024 * 100) / 100; - console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;'); - }, - onFileFinish: function (err, data, options) { - console.log(options.Key + ' 上传' + (err ? '失败' : '完成')); - }, - }, function (err, data) { - console.log(err || data); - fs.unlinkSync(filepath); - }); - }); + }, + ], + SliceSize: 1024 * 1024, + onProgress: function (info) { + var percent = Math.floor(info.percent * 10000) / 100; + var speed = Math.floor((info.speed / 1024 / 1024) * 100) / 100; + console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;'); + }, + onFileFinish: function (err, data, options) { + console.log(options.Key + ' 上传' + (err ? '失败' : '完成')); + }, + }, + function (err, data) { + console.log(err || data); + fs.unlinkSync(filepath); + }, + ); + }); } function sliceCopyFile() { - // 创建测试文件 - var sourceName = '3mb.zip'; - var Key = '3mb.copy.zip'; + // 创建测试文件 + var sourceName = '3mb.zip'; + var Key = '3mb.copy.zip'; - var sourcePath = config.Bucket + '.cos.' + config.Region + '.myqcloud.com/'+ camSafeUrlEncode(sourceName).replace(/%2F/g, '/'); + var sourcePath = + config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + camSafeUrlEncode(sourceName).replace(/%2F/g, '/'); - cos.sliceCopyFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: Key, - CopySource: sourcePath, - CopySliceSize: 2 * 1024 * 1024, // 大于2M的文件用分片复制,小于则用单片复制 - onProgress: function (info) { - var percent = Math.floor(info.percent * 10000) / 100; - var speed = Math.floor(info.speed / 1024 / 1024 * 100) / 100; - console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;'); - } - },function (err,data) { - if (err) { - console.log(err); - } else { - console.log(data); - } - }); + cos.sliceCopyFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + CopySource: sourcePath, + CopySliceSize: 2 * 1024 * 1024, // 大于2M的文件用分片复制,小于则用单片复制 + onProgress: function (info) { + var percent = Math.floor(info.percent * 10000) / 100; + var speed = Math.floor((info.speed / 1024 / 1024) * 100) / 100; + console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;'); + }, + }, + function (err, data) { + if (err) { + console.log(err); + } else { + console.log(data); + } + }, + ); } function putObjectTagging() { - cos.putObjectTagging({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1mb.zip', - Tags: [ - {Key: 'k1', Value: 'v1'}, - {Key: 'k2', Value: 'v2'}, - ], - }, function (err, data) { - console.log(err || data); - }); + cos.putObjectTagging( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1mb.zip', + Tags: [ + { Key: 'k1', Value: 'v1' }, + { Key: 'k2', Value: 'v2' }, + ], + }, + function (err, data) { + console.log(err || data); + }, + ); } function getObjectTagging() { - cos.getObjectTagging({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1mb.zip', - }, function (err, data) { - console.log(err || data); - }); + cos.getObjectTagging( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1mb.zip', + }, + function (err, data) { + console.log(err || data); + }, + ); } function deleteObjectTagging() { - cos.getObjectTagging({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1mb.zip', - }, function (err, data) { - console.log(err || data); - }); + cos.getObjectTagging( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1mb.zip', + }, + function (err, data) { + console.log(err || data); + }, + ); } /* 移动对象*/ function moveObject() { - // COS 没有对象重命名或移动的接口,移动对象可以通过复制/删除对象实现 - var source = 'source.txt'; - var target = 'target.txt'; - var copySource = config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + camSafeUrlEncode(source).replace(/%2F/g, '/'); - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: source, - Body: 'hello!', - }, function (err, data) { - if (err) return console.log(err); - cos.putObjectCopy({ - Bucket: config.Bucket, - Region: config.Region, - Key: target, - CopySource: copySource, - }, function (err, data) { - if (err) return console.log(err); - cos.deleteObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: source, - }, function (err, data) { - console.log(err || data); - }); - }); - }); + // COS 没有对象重命名或移动的接口,移动对象可以通过复制/删除对象实现 + var source = 'source.txt'; + var target = 'target.txt'; + var copySource = + config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + camSafeUrlEncode(source).replace(/%2F/g, '/'); + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: source, + Body: 'hello!', + }, + function (err, data) { + if (err) return console.log(err); + cos.putObjectCopy( + { + Bucket: config.Bucket, + Region: config.Region, + Key: target, + CopySource: copySource, + }, + function (err, data) { + if (err) return console.log(err); + cos.deleteObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: source, + }, + function (err, data) { + console.log(err || data); + }, + ); + }, + ); + }, + ); } /* 上传本地文件夹 */ function uploadFolder() { - var localFolder = '../test/'; - var remotePrefix = 'folder/'; - util.fastListFolder(localFolder, function (err, list) { - if (err) return console.error(err); - var files = list.map(function (file) { - var filename = pathLib.relative(localFolder, file.path).replace(/\\/g, '/'); - if (filename && file.isDir && !filename.endsWith('/')) - filename += '/'; - var Key = remotePrefix + filename; - return { - Bucket: config.Bucket, - Region: config.Region, - Key: Key, - FilePath: file.path, - }; - }); - cos.uploadFiles({ - files: files, - SliceSize: 1024 * 1024, - onProgress: function (info) { - var percent = Math.floor(info.percent * 10000) / 100; - var speed = Math.floor(info.speed / 1024 / 1024 * 100) / 100; - console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;'); - }, - onFileFinish: function (err, data, options) { - console.log(options.Key + ' 上传' + (err ? '失败' : '完成')); - }, - }, function (err, data) { - console.log(err || data); - }); + var localFolder = '../test/'; + var remotePrefix = 'folder/'; + util.fastListFolder(localFolder, function (err, list) { + if (err) return console.error(err); + var files = list.map(function (file) { + var filename = pathLib.relative(localFolder, file.path).replace(/\\/g, '/'); + if (filename && file.isDir && !filename.endsWith('/')) filename += '/'; + var Key = remotePrefix + filename; + return { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + FilePath: file.path, + }; }); + cos.uploadFiles( + { + files: files, + SliceSize: 1024 * 1024, + onProgress: function (info) { + var percent = Math.floor(info.percent * 10000) / 100; + var speed = Math.floor((info.speed / 1024 / 1024) * 100) / 100; + console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;'); + }, + onFileFinish: function (err, data, options) { + console.log(options.Key + ' 上传' + (err ? '失败' : '完成')); + }, + }, + function (err, data) { + console.log(err || data); + }, + ); + }); } /* 创建文件夹 */ function createFolder() { - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: 'folder/', // 对象存储没有实际的文件夹,可以创建一个路径以 / 结尾的空对象表示,能在部分场景中满足文件夹使用需要 - Body: '', - }, function(err, data) { - console.log(err || data); - }); + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: 'folder/', // 对象存储没有实际的文件夹,可以创建一个路径以 / 结尾的空对象表示,能在部分场景中满足文件夹使用需要 + Body: '', + }, + function (err, data) { + console.log(err || data); + }, + ); } /* 列出文件夹下的文件 */ function listFolder() { - var _listFolder = function(params, callback) { - var Contents = []; - var CommonPrefixes = []; - var marker; - var next = function() { - params.Marker = marker; - cos.getBucket(params, function(err, data) { - if (err) return callback(err); - data && data.CommonPrefixes && data.CommonPrefixes.forEach(function (item) { - CommonPrefixes.push(item); - }); - data && data.Contents && data.Contents.forEach(function (item) { - Contents.push(item); - }); - if (data.IsTruncated === 'true') { - marker = data.NextMarker; - next(); - } else { - callback(null, { - CommonPrefixes: CommonPrefixes, - Contents: Contents, - }); - } - }); - }; - next(); + var _listFolder = function (params, callback) { + var Contents = []; + var CommonPrefixes = []; + var marker; + var next = function () { + params.Marker = marker; + cos.getBucket(params, function (err, data) { + if (err) return callback(err); + data && + data.CommonPrefixes && + data.CommonPrefixes.forEach(function (item) { + CommonPrefixes.push(item); + }); + data && + data.Contents && + data.Contents.forEach(function (item) { + Contents.push(item); + }); + if (data.IsTruncated === 'true') { + marker = data.NextMarker; + next(); + } else { + callback(null, { + CommonPrefixes: CommonPrefixes, + Contents: Contents, + }); + } + }); }; - _listFolder({ - Bucket: config.Bucket, - Region: config.Region, - Delimiter: '/', // 如果按目录列出文件传入该分隔符,如果要深度列出文件不传改参数 - Prefix: 'folder/', // 要列出的目录前缀 - }, function (err, data) { - console.log(err || data); - }); + next(); + }; + _listFolder( + { + Bucket: config.Bucket, + Region: config.Region, + Delimiter: '/', // 如果按目录列出文件传入该分隔符,如果要深度列出文件不传改参数 + Prefix: 'folder/', // 要列出的目录前缀 + }, + function (err, data) { + console.log(err || data); + }, + ); } /* 删除指定文件夹下的所有对象(删除存储桶里指定前缀所有对象) */ function deleteFolder() { - var _deleteFolder = function(params, callback) { - var deletedList = []; - var errorList = []; - var marker; - var next = function() { - params.Marker = marker; - cos.getBucket(params, function(err, data) { - if (err) return callback(err); - var Objects = []; - if (data && data.Contents && data.Contents.length) { - data.Contents.forEach(function (item) { - Objects.push({Key: item.Key}); - }); - } - var afterDeleted = function () { - if (data.IsTruncated === 'true') { - marker = data.NextMarker; - next(); - } else { - callback(null, { Deleted: deletedList, Error: errorList }); - } - }; - if (Objects.length) { - cos.deleteMultipleObject({ - Bucket: params.Bucket, - Region: params.Region, - Objects: Objects, - }, function (err, data) { - data.Deleted && data.Deleted.forEach(function (item) { - deletedList.push(item); - }); - data.Error && data.Error.forEach(function (item) { - errorList.push(item); - }); - afterDeleted(); - }); - } else { - afterDeleted(); - } - }); + var _deleteFolder = function (params, callback) { + var deletedList = []; + var errorList = []; + var marker; + var next = function () { + params.Marker = marker; + cos.getBucket(params, function (err, data) { + if (err) return callback(err); + var Objects = []; + if (data && data.Contents && data.Contents.length) { + data.Contents.forEach(function (item) { + Objects.push({ Key: item.Key }); + }); + } + var afterDeleted = function () { + if (data.IsTruncated === 'true') { + marker = data.NextMarker; + next(); + } else { + callback(null, { Deleted: deletedList, Error: errorList }); + } }; - next(); + if (Objects.length) { + cos.deleteMultipleObject( + { + Bucket: params.Bucket, + Region: params.Region, + Objects: Objects, + }, + function (err, data) { + data.Deleted && + data.Deleted.forEach(function (item) { + deletedList.push(item); + }); + data.Error && + data.Error.forEach(function (item) { + errorList.push(item); + }); + afterDeleted(); + }, + ); + } else { + afterDeleted(); + } + }); }; - _deleteFolder({ - Bucket: config.Bucket, - Region: config.Region, - Prefix: 'folder/', // 要列出的目录前缀 - }, function (err, data) { - console.log(err || data); - }); + next(); + }; + _deleteFolder( + { + Bucket: config.Bucket, + Region: config.Region, + Prefix: 'folder/', // 要列出的目录前缀 + }, + function (err, data) { + console.log(err || data); + }, + ); } /* 分片下载文件 */ function downloadFile() { - // 单文件分片并发下载 - var Key = 'windows_7_ultimate_x64.iso'; - cos.downloadFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: Key, - FilePath: './' + Key, - ChunkSize: 1024 * 1024 * 8, // 文件大于 8MB 用分片下载 - ParallelLimit: 5, // 分片并发数 - RetryTimes: 3, // 分片失败重试次数 - TaskId: '123', - onProgress: function (progressData) { - console.log(JSON.stringify(progressData)); - }, - }, function (err, data) { - console.log(err || data); - }); - - // 取消下载任务 - // cos.emit('inner-kill-task', {TaskId: '123'}); -} - + // 单文件分片并发下载 + var Key = 'windows_7_ultimate_x64.iso'; + cos.downloadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + FilePath: './' + Key, + ChunkSize: 1024 * 1024 * 8, // 文件大于 8MB 用分片下载 + ParallelLimit: 5, // 分片并发数 + RetryTimes: 3, // 分片失败重试次数 + TaskId: '123', + onProgress: function (progressData) { + console.log(JSON.stringify(progressData)); + }, + }, + function (err, data) { + console.log(err || data); + }, + ); + + // 取消下载任务 + // cos.emit('inner-kill-task', {TaskId: '123'}); +} + // 追加上传 function appendObject() { - cos.appendObject({ + cos.appendObject( + { Bucket: config.Bucket, // Bucket 格式:test-1250000000 Region: config.Region, - Key: 'append1.txt', /* 必须 */ + Key: 'append1.txt' /* 必须 */, Body: '12345', Position: 0, - }, - function(err, data) { + }, + function (err, data) { console.log(err || data); - }) + }, + ); } // 继续追加上传 function appendObject_continue() { - cos.headObject({ + cos.headObject( + { Bucket: config.Bucket, // Bucket 格式:test-1250000000 Region: config.Region, - Key: 'append1.txt', /* 必须 */ - }, function(err, data) { + Key: 'append1.txt' /* 必须 */, + }, + function (err, data) { if (err) return console.log(err); // 首先取到要追加的文件当前长度,即需要上送的Position var position = data.headers && data.headers['content-length']; - cos.appendObject({ + cos.appendObject( + { Bucket: config.Bucket, // Bucket 格式:test-1250000000 Region: config.Region, - Key: 'append1.txt', /* 必须 */ + Key: 'append1.txt' /* 必须 */, Body: '66666', Position: position, - }, - function(err, data) { + }, + function (err, data) { // 也可以取到下一次上传的position继续追加上传 var nextPosition = data.headers && data.headers['x-cos-next-append-position']; console.log(err || data); - }) - }); + }, + ); + }, + ); } - - function request() { - // 对云上数据进行图片处理 - var filename = 'example_photo.png'; - cos.request({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - Method: 'POST', - Action: 'image_process', - Headers: { - // 万象持久化接口,上传时持久化 - 'Pic-Operations': '{"is_pic_info": 1, "rules": [{"fileid": "example_photo_ci_result.png", "rule": "imageMogr2/thumbnail/200x/"}]}' - }, - }, function (err, data) { - console.log(err || data); - }); + // 对云上数据进行图片处理 + var filename = 'example_photo.png'; + cos.request( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + Method: 'POST', + Action: 'image_process', + Headers: { + // 万象持久化接口,上传时持久化 + 'Pic-Operations': + '{"is_pic_info": 1, "rules": [{"fileid": "example_photo_ci_result.png", "rule": "imageMogr2/thumbnail/200x/"}]}', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } /** * function CIExample1 * @description 上传时使用图片处理 */ -function CIExample1(){ - var filename = 'example_photo.png' - var filepath = path.resolve(__dirname, filename); - cos.putObject({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Key: filename, - Body: fs.readFileSync(filepath), - Headers: { - // 通过 imageMogr2 接口使用图片缩放功能:指定图片宽度为 100,宽度等比压缩 - 'Pic-Operations': - '{"is_pic_info": 1, "rules": [{"fileid": "example_photo_ci_result.png", "rule": "imageMogr2/thumbnail/200x/"}]}', - }, - onTaskReady: function (tid) { - TaskId = tid; - }, - onProgress: function (progressData) { - console.log(JSON.stringify(progressData)); - }, - }, function (err, data) { - console.log(err || data); - }); +function CIExample1() { + var filename = 'example_photo.png'; + var filepath = path.resolve(__dirname, filename); + cos.putObject( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: filename, + Body: fs.readFileSync(filepath), + Headers: { + // 通过 imageMogr2 接口使用图片缩放功能:指定图片宽度为 100,宽度等比压缩 + 'Pic-Operations': + '{"is_pic_info": 1, "rules": [{"fileid": "example_photo_ci_result.png", "rule": "imageMogr2/thumbnail/200x/"}]}', + }, + onTaskReady: function (tid) { + TaskId = tid; + }, + onProgress: function (progressData) { + console.log(JSON.stringify(progressData)); + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } /** * function CIExample2 * @description 对云上数据进行图片处理 */ -function CIExample2(){ - var filename = 'example_photo.png'; - cos.request({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - Method: 'POST', - Action: 'image_process', - Headers: { - // 通过 imageMogr2 接口使用图片缩放功能:指定图片宽度为 200,宽度等比压缩 - 'Pic-Operations': '{"is_pic_info": 1, "rules": [{"fileid": "example_photo_ci_result.png", "rule": "imageMogr2/thumbnail/200x/"}]}' - }, - }, function (err, data) { - console.log(err || data); - }); +function CIExample2() { + var filename = 'example_photo.png'; + cos.request( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + Method: 'POST', + Action: 'image_process', + Headers: { + // 通过 imageMogr2 接口使用图片缩放功能:指定图片宽度为 200,宽度等比压缩 + 'Pic-Operations': + '{"is_pic_info": 1, "rules": [{"fileid": "example_photo_ci_result.png", "rule": "imageMogr2/thumbnail/200x/"}]}', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } /** * function CIExample3 * @description 下载时使用图片处理 */ -function CIExample3(){ - var filepath = path.resolve(__dirname, 'example_photo_ci_result.png'); - cos.getObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: 'example_photo.png', - QueryString: 'imageMogr2/thumbnail/200x/', - }, - function (err, data) { - if(data){ - fs.writeFileSync(filepath, data.Body); - } else { - console.log(err); - } - }, - ); +function CIExample3() { + var filepath = path.resolve(__dirname, 'example_photo_ci_result.png'); + cos.getObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: 'example_photo.png', + QueryString: 'imageMogr2/thumbnail/200x/', + }, + function (err, data) { + if (data) { + fs.writeFileSync(filepath, data.Body); + } else { + console.log(err); + } + }, + ); } /** * function CIExample4 * @description 生成带图片处理参数的签名 URL */ -function CIExample4(){ - - // 生成带图片处理参数的文件签名URL,过期时间设置为 30 分钟。 - cos.getObjectUrl({ - Bucket: config.Bucket, - Region: config.Region, - Key: 'photo.png', - QueryString: 'imageMogr2/thumbnail/200x/', - Expires: 1800, - Sign: true, - }, - function (err, data) { - console.log(err || data); - }, - ); +function CIExample4() { + // 生成带图片处理参数的文件签名URL,过期时间设置为 30 分钟。 + cos.getObjectUrl( + { + Bucket: config.Bucket, + Region: config.Region, + Key: 'photo.png', + QueryString: 'imageMogr2/thumbnail/200x/', + Expires: 1800, + Sign: true, + }, + function (err, data) { + console.log(err || data); + }, + ); - // 生成带图片处理参数的文件URL,不带签名。 - cos.getObjectUrl({ - Bucket: config.Bucket, - Region: config.Region, - Key: 'photo.png', - QueryString: 'imageMogr2/thumbnail/200x/', - Sign: false, - }, - function (err, data) { - console.log(err || data); - }, - ); + // 生成带图片处理参数的文件URL,不带签名。 + cos.getObjectUrl( + { + Bucket: config.Bucket, + Region: config.Region, + Key: 'photo.png', + QueryString: 'imageMogr2/thumbnail/200x/', + Sign: false, + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 查询已经开通数据万象功能的存储桶 */ function DescribeCIBuckets() { - var host = 'ci.' + config.Region + '.myqcloud.com'; - var url = 'https://' + host + '/mediabucket'; - cos.request({ - Bucket: config.Bucket, - Region: config.Region, - Method: 'GET', - Key: 'mediabucket', /** 固定值,必须 */ - Url: url, - Query: { - pageNumber: '1', /** 第几页,非必须 */ - pageSize: '10', /** 每页个数,非必须 */ - // regions: 'ap-chengdu', /** 地域信息,例如'ap-beijing',支持多个值用逗号分隔如'ap-shanghai,ap-beijing',非必须 */ - // bucketNames: 'test-1250000000', /** 存储桶名称,精确搜索,例如'test-1250000000',支持多个值用逗号分隔如'test1-1250000000,test2-1250000000',非必须 */ - // bucketName: 'test', /** 存储桶名称前缀,前缀搜索,例如'test',支持多个值用逗号分隔如'test1,test2',非必须 */ - } + var host = 'ci.' + config.Region + '.myqcloud.com'; + var url = 'https://' + host + '/mediabucket'; + cos.request( + { + Bucket: config.Bucket, + Region: config.Region, + Method: 'GET', + Key: 'mediabucket' /** 固定值,必须 */, + Url: url, + Query: { + pageNumber: '1' /** 第几页,非必须 */, + pageSize: '10' /** 每页个数,非必须 */, + // regions: 'ap-chengdu', /** 地域信息,例如'ap-beijing',支持多个值用逗号分隔如'ap-shanghai,ap-beijing',非必须 */ + // bucketNames: 'test-1250000000', /** 存储桶名称,精确搜索,例如'test-1250000000',支持多个值用逗号分隔如'test1-1250000000,test2-1250000000',非必须 */ + // bucketName: 'test', /** 存储桶名称前缀,前缀搜索,例如'test',支持多个值用逗号分隔如'test1,test2',非必须 */ + }, }, - function(err, data){ - // var CIStatus = data.CIStatus; - console.log(err || data); - }); + function (err, data) { + // var CIStatus = data.CIStatus; + console.log(err || data); + }, + ); } - /** -* 获取媒体文件信息 -*/ + * 获取媒体文件信息 + */ function GetMediaInfo() { - cos.request({ + cos.request( + { Bucket: config.Bucket, Region: config.Region, Method: 'GET', Key: 'test.mp4', Query: { - 'ci-process': 'videoinfo' /** 固定值,必须 */ - } + 'ci-process': 'videoinfo' /** 固定值,必须 */, + }, }, function (err, data) { - console.log(err || data); - }); + console.log(err || data); + }, + ); } /** * 获取媒体文件某个时间的截图 */ function GetSnapshot() { - cos.request({ - Bucket: config.Bucket, - Region: config.Region, - Method: 'GET', - Key: 'test.mp4', - Query: { - 'ci-process': 'snapshot', /** 固定值,必须 */ - time: 1, /** 截图的时间点,单位为秒,必须 */ - // width: 0, /** 截图的宽,非必须 */ - // height: 0, /** 截图的高,非必须 */ - // format: 'jpg', /** 截图的格式,支持 jpg 和 png,默认 jpg,非必须 */ - // rotate: 'auto', /** 图片旋转方式,默认为'auto',非必须 */ - // mode: 'exactframe', /** 截帧方式,默认为'exactframe',非必须 */ - }, - RawBody: true, + cos.request( + { + Bucket: config.Bucket, + Region: config.Region, + Method: 'GET', + Key: 'test.mp4', + Query: { + 'ci-process': 'snapshot' /** 固定值,必须 */, + time: 1 /** 截图的时间点,单位为秒,必须 */, + // width: 0, /** 截图的宽,非必须 */ + // height: 0, /** 截图的高,非必须 */ + // format: 'jpg', /** 截图的格式,支持 jpg 和 png,默认 jpg,非必须 */ + // rotate: 'auto', /** 图片旋转方式,默认为'auto',非必须 */ + // mode: 'exactframe', /** 截帧方式,默认为'exactframe',非必须 */ + }, + RawBody: true, }, function (err, data) { // var Body = data.Body; console.log(err || data); - }); + }, + ); } - /** * 对多种文件类型生成图片格式或html格式预览 */ function GetDocProcess() { - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'GET', - Key: 'test.pptx', - Query: { - 'ci-process': 'doc-preview', - 'page': '1', - 'dstType': 'jpg', - 'ImageParams': 'imageMogr2/thumbnail/!50p|watermark/2/text/5pWw5o2u5LiH6LGh/fill/I0ZGRkZGRg==/fontsize/30/dx/20/dy/20' - } - }, function (err, data) { - console.log(err || data); - }); + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'GET', + Key: 'test.pptx', + Query: { + 'ci-process': 'doc-preview', + page: '1', + dstType: 'jpg', + ImageParams: + 'imageMogr2/thumbnail/!50p|watermark/2/text/5pWw5o2u5LiH6LGh/fill/I0ZGRkZGRg==/fontsize/30/dx/20/dy/20', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 查询文档转码队列 */ function DescribeDocProcessQueues() { - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/docqueue' - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'GET', - Key: 'docqueue', - Url: url, - Query: { - state: 'Active' - } - }, function (err, data) { - console.log(err || data); - }); + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/docqueue'; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'GET', + Key: 'docqueue', + Url: url, + Query: { + state: 'Active', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 更新文档转码队列 */ function UpdateDocProcessQueue() { // 任务所在的队列 ID,请使用查询队列(https://cloud.tencent.com/document/product/460/46946)获取或前往万象控制台(https://cloud.tencent.com/document/product/460/46487)在存储桶中查询 - let queueId = 'p31299c0b3f4742dda2fc1be3ea40xxxx' // 需要更新的队列ID - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/docqueue/' + queueId; - let body = { // 填上队列修改参数 - Request: { - Name: '1', - QueueID: queueId, - State: 'Active', - NotifyConfig: { - Url: 'http://your.callkback.address/index.php', - Type: 'Url', - State: 'On', - Event: 'TaskFinish' - } - } - } - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'PUT', - Key: 'docqueue/' + queueId, - Url: url, - Headers: { - 'content-type': 'application/xml' - }, - Body: json2xml(body) - }, function (err, data) { - console.log(err || data); - }); + let queueId = 'p31299c0b3f4742dda2fc1be3ea40xxxx'; // 需要更新的队列ID + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/docqueue/' + queueId; + let body = { + // 填上队列修改参数 + Request: { + Name: '1', + QueueID: queueId, + State: 'Active', + NotifyConfig: { + Url: 'http://your.callkback.address/index.php', + Type: 'Url', + State: 'On', + Event: 'TaskFinish', + }, + }, + }; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'PUT', + Key: 'docqueue/' + queueId, + Url: url, + Headers: { + 'content-type': 'application/xml', + }, + Body: json2xml(body), + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 创建文档转码任务 */ function CreateDocProcessJobs() { - let queueId = 'p31299c0b3f4742dda2fc1be3ea40xxxx' // 队列ID - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/doc_jobs'; - let body = { // 填上任务参数 - Request: { - Tag: 'DocProcess', - Input: { - Object: 'test.pptx' - }, - QueueId: queueId, - Operation: { - DocProcess: { - StartPage: 3, - EndPage: 4, - TgtType: 'png' - }, - Output: { - Region: config.Region, - Bucket: config.Bucket, - Object: 'doc_${Page}.png' - } - } - } - } - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'POST', - Key: 'doc_jobs', - Url: url, - Headers: { - 'content-type': 'application/xml' + let queueId = 'p31299c0b3f4742dda2fc1be3ea40xxxx'; // 队列ID + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/doc_jobs'; + let body = { + // 填上任务参数 + Request: { + Tag: 'DocProcess', + Input: { + Object: 'test.pptx', + }, + QueueId: queueId, + Operation: { + DocProcess: { + StartPage: 3, + EndPage: 4, + TgtType: 'png', }, - Body: json2xml(body) - }, function (err, data) { - console.log(err || data); - }); + Output: { + Region: config.Region, + Bucket: config.Bucket, + Object: 'doc_${Page}.png', + }, + }, + }, + }; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'POST', + Key: 'doc_jobs', + Url: url, + Headers: { + 'content-type': 'application/xml', + }, + Body: json2xml(body), + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 查询文档转码任务 */ function DescribeDocProcessJob() { - let jobId = 'd2c6c620a415811ecb31b51515222xxxx' - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/doc_jobs/' + jobId; - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'GET', - Key: 'doc_jobs/' + jobId, - Url: url - }, function (err, data) { - console.log(err || data); - }); + let jobId = 'd2c6c620a415811ecb31b51515222xxxx'; + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/doc_jobs/' + jobId; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'GET', + Key: 'doc_jobs/' + jobId, + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 文档转码任务列表 */ function DescribeDocProcessJobs() { - let queueId = 'p31299c0b3f4742dda2fc1be3ea40xxxx' - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/doc_jobs'; - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'GET', - Key: 'doc_jobs', - Url: url, - Query: { - tag: 'DocProcess', - queueId: queueId, - states: 'Failed' - } - }, function (err, data) { - console.log(err || data); - }); + let queueId = 'p31299c0b3f4742dda2fc1be3ea40xxxx'; + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/doc_jobs'; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'GET', + Key: 'doc_jobs', + Url: url, + Query: { + tag: 'DocProcess', + queueId: queueId, + states: 'Failed', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } - - /** * 查询已经开通媒体处理功能的存储桶 */ function DescribeMediaBuckets() { - let host = 'ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/mediabucket' - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'GET', - Key: 'mediabucket', - Url: url, - Query: { - pageNumber: '1', - pageSize: '10' - } - }, function (err, data) { - console.log(err || data); - }); + let host = 'ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/mediabucket'; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'GET', + Key: 'mediabucket', + Url: url, + Query: { + pageNumber: '1', + pageSize: '10', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 查询存储桶的媒体处理队列 */ function DescribeMediaQueues() { - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/queue' - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'GET', - Key: 'queue', - Url: url - }, function (err, data) { - console.log(err || data); - }); + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/queue'; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'GET', + Key: 'queue', + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 更新媒体处理队列 */ function UpdateMediaQueue() { - let queueId = 'p5ad1499214024af2bfaa4401d529xxxx' // 需要更新的队列ID - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/queue/' + queueId; - let body = { // 填上队列修改参数 - Request: { - Name: '1', - QueueID: queueId, - State: 'Active', - NotifyConfig: { - Url: 'http://your.callkback.address/index.php', - Type: 'Url', - Event: 'TaskFinish', - State: 'On' - } - } - } - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'PUT', - Key: 'queue/' + queueId, - Url: url, - Headers: { - 'content-type': 'application/xml' - }, - Body: json2xml(body) - }, function (err, data) { - console.log(err || data); - }); + let queueId = 'p5ad1499214024af2bfaa4401d529xxxx'; // 需要更新的队列ID + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/queue/' + queueId; + let body = { + // 填上队列修改参数 + Request: { + Name: '1', + QueueID: queueId, + State: 'Active', + NotifyConfig: { + Url: 'http://your.callkback.address/index.php', + Type: 'Url', + Event: 'TaskFinish', + State: 'On', + }, + }, + }; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'PUT', + Key: 'queue/' + queueId, + Url: url, + Headers: { + 'content-type': 'application/xml', + }, + Body: json2xml(body), + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 创建媒体处理的各种模版(以截帧模版为例) */ function CreateMediaTemplate() { - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/template'; - let body = { // 填上模板参数 - Request: { - Tag: 'Snapshot', - Name: 'test-template', - Snapshot: { - Mode: 'Interval', - Start: '1', - TimeInterval: '5', - Count: '3', - Width: '1280' - } - } - } - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'POST', - Key: 'template', - Url: url, - Headers: { - 'content-type': 'application/xml' - }, - Body: json2xml(body) - }, function (err, data) { - console.log(err || data); - }); + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/template'; + let body = { + // 填上模板参数 + Request: { + Tag: 'Snapshot', + Name: 'test-template', + Snapshot: { + Mode: 'Interval', + Start: '1', + TimeInterval: '5', + Count: '3', + Width: '1280', + }, + }, + }; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'POST', + Key: 'template', + Url: url, + Headers: { + 'content-type': 'application/xml', + }, + Body: json2xml(body), + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 删除模版 */ function DeleteMediaTemplate() { - let templateId = 't1b11b39d3a91949d6804c08399186xxxx'; // 待删除的模版ID - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/template/' + templateId; - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'DELETE', - Key: 'template/' + templateId, - Url: url, - Headers: { - 'content-type': 'application/xml' - } - }, function (err, data) { - console.log(err || data); - }); + let templateId = 't1b11b39d3a91949d6804c08399186xxxx'; // 待删除的模版ID + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/template/' + templateId; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'DELETE', + Key: 'template/' + templateId, + Url: url, + Headers: { + 'content-type': 'application/xml', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 查看模版详情 */ function DescribeMediaTemplates() { - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/template'; - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'GET', - Key: 'template', - Url: url, - Headers: { - 'content-type': 'application/xml' - }, - Query: { - tag: 'Snapshot', - name: 'test' - } - }, function (err, data) { - console.log(err || data); - }); + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/template'; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'GET', + Key: 'template', + Url: url, + Headers: { + 'content-type': 'application/xml', + }, + Query: { + tag: 'Snapshot', + name: 'test', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 更新模版信息 */ function UpdateMediaTemplate() { - let templateId = 't12cf1cde8d8a845eebc0a5c6047bfxxxx' // 需要更新的模版ID - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/template/' + templateId; - let body = { // 填上模版修改参数 - Request: { - Tag: 'Snapshot', - Name: 'test-new', - Snapshot: { - Mode: 'Average', - Start: '0', - Count: '3', - Height: '1280' - } - } - } - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'PUT', - Key: 'template/' + templateId, - Url: url, - Headers: { - 'content-type': 'application/xml' - }, - Body: json2xml(body) - }, function (err, data) { - console.log(err || data); - }); + let templateId = 't12cf1cde8d8a845eebc0a5c6047bfxxxx'; // 需要更新的模版ID + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/template/' + templateId; + let body = { + // 填上模版修改参数 + Request: { + Tag: 'Snapshot', + Name: 'test-new', + Snapshot: { + Mode: 'Average', + Start: '0', + Count: '3', + Height: '1280', + }, + }, + }; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'PUT', + Key: 'template/' + templateId, + Url: url, + Headers: { + 'content-type': 'application/xml', + }, + Body: json2xml(body), + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 提交媒体处理任务 */ function CreateMediaJobs() { - let templateId = 't12cf1cde8d8a845eebc0a5c6047bfxxxx' // 模版ID - let queueId = 'p5ad1499214024af2bfaa4401d529xxxx' // 队列ID - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/jobs'; - let body = { // 填上任务参数 - Request: { - Tag: 'Snapshot', - Input: { - Object: 'test-input.mp4' - }, - QueueId: queueId, - Operation: { - TemplateId: templateId, - Output: { - Region: config.Region, - Bucket: config.Bucket, - Object: 'test-output${Number}' - } - }, - CallBack: 'http://your.task.callkback.address/index.php' - } - } - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'POST', - Key: 'jobs', - Url: url, - Headers: { - 'content-type': 'application/xml' + let templateId = 't12cf1cde8d8a845eebc0a5c6047bfxxxx'; // 模版ID + let queueId = 'p5ad1499214024af2bfaa4401d529xxxx'; // 队列ID + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/jobs'; + let body = { + // 填上任务参数 + Request: { + Tag: 'Snapshot', + Input: { + Object: 'test-input.mp4', + }, + QueueId: queueId, + Operation: { + TemplateId: templateId, + Output: { + Region: config.Region, + Bucket: config.Bucket, + Object: 'test-output${Number}', }, - Body: json2xml(body) - }, function (err, data) { - console.log(err || data); - }); + }, + CallBack: 'http://your.task.callkback.address/index.php', + }, + }; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'POST', + Key: 'jobs', + Url: url, + Headers: { + 'content-type': 'application/xml', + }, + Body: json2xml(body), + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 取消媒体处理任务 */ function CancelMediaJob() { - let jobId = 'j14596fda409c11eca160977fff35xxxx'; // 待取消的任务ID - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/jobs/' + jobId; - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'PUT', - Key: 'jobs/' + jobId, - Url: url - }, function (err, data) { - console.log(err || data); - }); + let jobId = 'j14596fda409c11eca160977fff35xxxx'; // 待取消的任务ID + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/jobs/' + jobId; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'PUT', + Key: 'jobs/' + jobId, + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 查看媒体处理任务 */ function DescribeMediaJob() { - let jobId = 'j14596fda409c11eca160977fff35xxxx'; // 任务ID - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/jobs/' + jobId; - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'GET', - Key: 'jobs/' + jobId, - Url: url - }, function (err, data) { - console.log(err || data); - }); + let jobId = 'j14596fda409c11eca160977fff35xxxx'; // 任务ID + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/jobs/' + jobId; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'GET', + Key: 'jobs/' + jobId, + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 媒体处理任务列表 */ function DescribeMediaJobs() { - let queueId = 'p5ad1499214024af2bfaa4401d529xxxx' // 队列ID - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/jobs'; - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'GET', - Key: 'jobs', - Url: url, - Query: { - queueId: queueId, - tag: 'Snapshot', - states: 'Failed' - } - }, function (err, data) { - console.log(err || data); - }); + let queueId = 'p5ad1499214024af2bfaa4401d529xxxx'; // 队列ID + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/jobs'; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'GET', + Key: 'jobs', + Url: url, + Query: { + queueId: queueId, + tag: 'Snapshot', + states: 'Failed', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 创建工作流 */ function CreateWorkflow() { - let queueId = 'p5ad1499214024af2bfaa4401d529xxxx'; - let callbackUrl = 'http://your.callback.com/index.php'; - let snapshotTemplate = 't0a60a2bc71a4b40c7b3d7f7e8a277xxxx'; - let transcodeTemplate = 't04e1ab86554984f1aa17c062fbf6cxxxx'; - let animationTemplate = 't0341b0ab2b8a340ff826e9cb4f3a7xxxx'; - let concatTemplate = 't19e96c43b0c05444f9b2facc9dcf5xxxx'; - let voiceSeparateTemplate = 't1c101e2bc074c4506837714edc99axxxx'; - let videoMontageTemplate = 't1ec0b3871d5e340da84536688b810xxxx'; - let watermarkTemplate = 't1ea62f7810d0142c195313330bdd4xxxx'; - let videoProcessTemplate = 't1d945b6de362f4d4db9bd8659bc5exxxx'; - let superResolutionTemplate = 't1d9d5ae4450824427bccc495ed0b0xxxx'; - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/workflow'; - let body = { - Request: { - MediaWorkflow: { - Name: 'demo', - State: 'Active', // 创建并开启工作流 - Topology: { - Dependencies: { - Start: 'Snapshot_1581665960536,Transcode_1581665960537,Animation_1581665960538,Concat_1581665960539,VoiceSeparate_1581665960551,VideoMontage_1581665960551,SDRtoHDR_1581665960553,VideoProcess_1581665960554,SuperResolution_1581665960583,Segment_1581665960667', - 'Snapshot_1581665960536': 'End', - 'Transcode_1581665960537': 'End', - 'Animation_1581665960538': 'End', - 'Concat_1581665960539': 'End', - 'VideoMontage_1581665960551': 'End', - 'SDRtoHDR_1581665960553': 'End', - 'VideoProcess_1581665960554': 'End', - 'SuperResolution_1581665960583': 'End', - 'Segment_1581665960667': 'End', - 'VoiceSeparate_1581665960551': 'End' - }, - Nodes: { - Start: { - Type: 'Start', - Input: { - QueueId: queueId, - ObjectPrefix: 'test-', - NotifyConfig: { - Type: 'Url', - Url:callbackUrl, - Event: 'TaskFinish,WorkflowFinish' - }, - ExtFilter: { - State: 'On', - Audio: 'true', - Custom: 'true', - CustomExts: 'mp4/mp3', - AllFile: 'false' - } - } - }, - 'Snapshot_1581665960536': { - Type: 'Snapshot', - Operation: { - TemplateId: snapshotTemplate, - Output: { - Region: config.Region, - Bucket: config.Bucket, - Object: 'worlflow-test/${RunId}/snapshot-${number}.${Ext}', - SpriteObject: 'worlflow-test/${RunId}/snapshot-sprite-${number}.jpg' - } - } - }, - 'Transcode_1581665960537': { - Type: 'Transcode', - Operation: { - TemplateId: transcodeTemplate, - Output: { - Region: config.Region, - Bucket: config.Bucket, - Object: 'worlflow-test/${RunId}/trans.mp4' - } - } - }, - 'Animation_1581665960538': { - Type: 'Animation', - Operation: { - TemplateId: animationTemplate, - Output: { - Region: config.Region, - Bucket: config.Bucket, - Object: 'worlflow-test/${RunId}/bcd.gif' - } - } - }, - 'Concat_1581665960539': { - Type: 'Concat', - Operation: { - TemplateId: concatTemplate, - Output: { - Region: config.Region, - Bucket: config.Bucket, - Object: 'worlflow-test/${RunId}/abc.${ext}' - } - } - }, - 'VoiceSeparate_1581665960551': { - Type: 'VoiceSeparate', - Operation: { - TemplateId: voiceSeparateTemplate, - Output: { - Region: config.Region, - Bucket: config.Bucket, - Object: 'worlflow-test/${RunId}/background.mp3', - AuObject: 'worlflow-test/${RunId}/audio.mp3' - } - } - }, - 'VideoMontage_1581665960551': { - Type: 'VideoMontage', - Operation: { - TemplateId: videoMontageTemplate, - Output: { - Region: config.Region, - Bucket: config.Bucket, - Object: 'worlflow-test/${RunId}/montage.mp4' - } - } - }, - 'SDRtoHDR_1581665960553': { - Type: 'SDRtoHDR', - Operation: { - SDRtoHDR: { - HdrMode: 'HLG' - }, - TranscodeTemplateId: transcodeTemplate, - WatermarkTemplateId: watermarkTemplate, - Output: { - Region: config.Region, - Bucket: config.Bucket, - Object: 'worlflow-test/${RunId}/SDRtoHDR.mp4' - } - } - }, - 'VideoProcess_1581665960554': { - Type: 'VideoProcess', - Operation: { - TemplateId: videoProcessTemplate, - TranscodeTemplateId: transcodeTemplate, - WatermarkTemplateId: watermarkTemplate, - Output: { - Region: config.Region, - Bucket: config.Bucket, - Object: 'worlflow-test/${RunId}/videoProcess.mp4' - } - } - }, - 'SuperResolution_1581665960583': { - Type: 'SuperResolution', - Operation: { - TemplateId: superResolutionTemplate, - TranscodeTemplateId: transcodeTemplate, - WatermarkTemplateId: watermarkTemplate, - Output: { - Region: config.Region, - Bucket: config.Bucket, - Object: 'worlflow-test/${RunId}/SuperResolution.mkv' - } - } - }, - 'Segment_1581665960667': { - Type: 'Segment', - Operation: { - Segment: { - Format: 'mp4', - Duration: '5' - }, - Output: { - Region: config.Region, - Bucket: config.Bucket, - Object: 'worlflow-test/${RunId}/segment-trans${Number}' - } - } - } - } - } - } - } - } - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'POST', - Key: 'workflow', - Url: url, - Headers: { - 'content-type': 'application/xml' + let queueId = 'p5ad1499214024af2bfaa4401d529xxxx'; + let callbackUrl = 'http://your.callback.com/index.php'; + let snapshotTemplate = 't0a60a2bc71a4b40c7b3d7f7e8a277xxxx'; + let transcodeTemplate = 't04e1ab86554984f1aa17c062fbf6cxxxx'; + let animationTemplate = 't0341b0ab2b8a340ff826e9cb4f3a7xxxx'; + let concatTemplate = 't19e96c43b0c05444f9b2facc9dcf5xxxx'; + let voiceSeparateTemplate = 't1c101e2bc074c4506837714edc99axxxx'; + let videoMontageTemplate = 't1ec0b3871d5e340da84536688b810xxxx'; + let watermarkTemplate = 't1ea62f7810d0142c195313330bdd4xxxx'; + let videoProcessTemplate = 't1d945b6de362f4d4db9bd8659bc5exxxx'; + let superResolutionTemplate = 't1d9d5ae4450824427bccc495ed0b0xxxx'; + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/workflow'; + let body = { + Request: { + MediaWorkflow: { + Name: 'demo', + State: 'Active', // 创建并开启工作流 + Topology: { + Dependencies: { + Start: + 'Snapshot_1581665960536,Transcode_1581665960537,Animation_1581665960538,Concat_1581665960539,VoiceSeparate_1581665960551,VideoMontage_1581665960551,SDRtoHDR_1581665960553,VideoProcess_1581665960554,SuperResolution_1581665960583,Segment_1581665960667', + Snapshot_1581665960536: 'End', + Transcode_1581665960537: 'End', + Animation_1581665960538: 'End', + Concat_1581665960539: 'End', + VideoMontage_1581665960551: 'End', + SDRtoHDR_1581665960553: 'End', + VideoProcess_1581665960554: 'End', + SuperResolution_1581665960583: 'End', + Segment_1581665960667: 'End', + VoiceSeparate_1581665960551: 'End', + }, + Nodes: { + Start: { + Type: 'Start', + Input: { + QueueId: queueId, + ObjectPrefix: 'test-', + NotifyConfig: { + Type: 'Url', + Url: callbackUrl, + Event: 'TaskFinish,WorkflowFinish', + }, + ExtFilter: { + State: 'On', + Audio: 'true', + Custom: 'true', + CustomExts: 'mp4/mp3', + AllFile: 'false', + }, + }, + }, + Snapshot_1581665960536: { + Type: 'Snapshot', + Operation: { + TemplateId: snapshotTemplate, + Output: { + Region: config.Region, + Bucket: config.Bucket, + Object: 'worlflow-test/${RunId}/snapshot-${number}.${Ext}', + SpriteObject: 'worlflow-test/${RunId}/snapshot-sprite-${number}.jpg', + }, + }, + }, + Transcode_1581665960537: { + Type: 'Transcode', + Operation: { + TemplateId: transcodeTemplate, + Output: { + Region: config.Region, + Bucket: config.Bucket, + Object: 'worlflow-test/${RunId}/trans.mp4', + }, + }, + }, + Animation_1581665960538: { + Type: 'Animation', + Operation: { + TemplateId: animationTemplate, + Output: { + Region: config.Region, + Bucket: config.Bucket, + Object: 'worlflow-test/${RunId}/bcd.gif', + }, + }, + }, + Concat_1581665960539: { + Type: 'Concat', + Operation: { + TemplateId: concatTemplate, + Output: { + Region: config.Region, + Bucket: config.Bucket, + Object: 'worlflow-test/${RunId}/abc.${ext}', + }, + }, + }, + VoiceSeparate_1581665960551: { + Type: 'VoiceSeparate', + Operation: { + TemplateId: voiceSeparateTemplate, + Output: { + Region: config.Region, + Bucket: config.Bucket, + Object: 'worlflow-test/${RunId}/background.mp3', + AuObject: 'worlflow-test/${RunId}/audio.mp3', + }, + }, + }, + VideoMontage_1581665960551: { + Type: 'VideoMontage', + Operation: { + TemplateId: videoMontageTemplate, + Output: { + Region: config.Region, + Bucket: config.Bucket, + Object: 'worlflow-test/${RunId}/montage.mp4', + }, + }, + }, + SDRtoHDR_1581665960553: { + Type: 'SDRtoHDR', + Operation: { + SDRtoHDR: { + HdrMode: 'HLG', + }, + TranscodeTemplateId: transcodeTemplate, + WatermarkTemplateId: watermarkTemplate, + Output: { + Region: config.Region, + Bucket: config.Bucket, + Object: 'worlflow-test/${RunId}/SDRtoHDR.mp4', + }, + }, + }, + VideoProcess_1581665960554: { + Type: 'VideoProcess', + Operation: { + TemplateId: videoProcessTemplate, + TranscodeTemplateId: transcodeTemplate, + WatermarkTemplateId: watermarkTemplate, + Output: { + Region: config.Region, + Bucket: config.Bucket, + Object: 'worlflow-test/${RunId}/videoProcess.mp4', + }, + }, + }, + SuperResolution_1581665960583: { + Type: 'SuperResolution', + Operation: { + TemplateId: superResolutionTemplate, + TranscodeTemplateId: transcodeTemplate, + WatermarkTemplateId: watermarkTemplate, + Output: { + Region: config.Region, + Bucket: config.Bucket, + Object: 'worlflow-test/${RunId}/SuperResolution.mkv', + }, + }, + }, + Segment_1581665960667: { + Type: 'Segment', + Operation: { + Segment: { + Format: 'mp4', + Duration: '5', + }, + Output: { + Region: config.Region, + Bucket: config.Bucket, + Object: 'worlflow-test/${RunId}/segment-trans${Number}', + }, + }, + }, + }, }, - Body: json2xml(body) - }, function (err, data) { - console.log(err || data); - }); + }, + }, + }; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'POST', + Key: 'workflow', + Url: url, + Headers: { + 'content-type': 'application/xml', + }, + Body: json2xml(body), + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 删除工作流 */ function DeleteWorkflow() { - let workflowId = 'wad8a9e26e1864a3793446fd9a686xxxx'; // 待删除的工作流ID - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/workflow/' + workflowId; - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'DELETE', - Key: 'workflow/' + workflowId, - Url: url, - Headers: { - 'content-type': 'application/xml' - } - }, function (err, data) { - console.log(err || data); - }); + let workflowId = 'wad8a9e26e1864a3793446fd9a686xxxx'; // 待删除的工作流ID + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/workflow/' + workflowId; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'DELETE', + Key: 'workflow/' + workflowId, + Url: url, + Headers: { + 'content-type': 'application/xml', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 工作流列表 */ function DescribeWorkflow() { - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/workflow'; - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'GET', - Key: 'workflow', - Url: url, - Query: { - ids: '' - } - }, function (err, data) { - console.log(err || data); - }); + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/workflow'; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'GET', + Key: 'workflow', + Url: url, + Query: { + ids: '', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 执行实例详情 */ function DescribeWorkflowExecution() { - let runId = 'ieed8aec4413a11ec913f52540003xxxx'; - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/workflowexecution/' + runId; - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'GET', - Key: 'workflowexecution/' + runId, - Url: url - }, function (err, data) { - console.log(err || data); - }); + let runId = 'ieed8aec4413a11ec913f52540003xxxx'; + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/workflowexecution/' + runId; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'GET', + Key: 'workflowexecution/' + runId, + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); } - /** * 执行实例列表 */ function DescribeWorkflowExecutions() { - let workflowId = 'w093b29cfef824bd0922743a6f0afxxxx'; - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/workflowexecution'; - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'GET', - Key: 'workflowexecution', - Url: url, - Query: { - workflowId: workflowId, - size: '3', - states: 'Failed' - } - }, function (err, data) { - console.log(err || data); - }); + let workflowId = 'w093b29cfef824bd0922743a6f0afxxxx'; + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/workflowexecution'; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'GET', + Key: 'workflowexecution', + Url: url, + Query: { + workflowId: workflowId, + size: '3', + states: 'Failed', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +/** + * 更新工作流配置 + */ +function UpdateWorkflow() { + let workflowId = 'w14404e66c27b4e0aafae6bc96acfxxxx'; + let queueId = 'p5ad1499214024af2bfaa4401d529xxxx'; + let callbackUrl = 'http://your.callback.com/index.php'; + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/workflow/' + workflowId; + let body = { + // 填上模版修改参数 + Request: { + MediaWorkflow: { + Name: 'test1', + State: 'Active', // 创建并开启工作流 + Topology: { + Dependencies: { + Start: 'SmartCover_1581665960539', + SmartCover_1581665960539: 'End', + }, + Nodes: { + Start: { + Type: 'Start', + Input: { + QueueId: queueId, + ObjectPrefix: 'test/', + NotifyConfig: { + Type: 'Url', + Url: callbackUrl, + Event: 'TaskFinish,WorkflowFinish', + }, + ExtFilter: { + State: 'On', + Video: 'true', + Custom: 'true', + CustomExts: 'mp4/mp3', + AllFile: 'false', + }, + }, + }, + SmartCover_1581665960539: { + Type: 'SmartCover', + Operation: { + Output: { + Region: config.Region, + Bucket: config.Bucket, + Object: 'worlflow-test/${RunId}/cover-${Number}.jpg', + }, + SmartCover: { + Format: 'png', + Width: '128', + Height: '128', + Count: '3', + DeleteDuplicates: 'false', + }, + }, + }, + }, + }, + }, + }, + }; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'PUT', + Key: 'workflow/' + workflowId, + Url: url, + Headers: { + 'content-type': 'application/xml', + }, + Body: json2xml(body), + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +/** + * 触发工作流 + */ +function TriggerWorkflow() { + let workflowId = 'w093b29cfef824bd0922743a6f0afxxxx'; + let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + let url = 'https://' + host + '/triggerworkflow'; + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'POST', + Key: 'triggerworkflow', + Url: url, + Headers: { + 'content-type': 'application/xml', + }, + Query: { + workflowId: workflowId, + object: 'test.mp4', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 同步审核存储桶里的图片对象 +function SyncAuditImageObject() { + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: 'audit/1.jpg', + Method: 'GET', + Query: { + 'ci-process': 'sensitive-content-recognition', + // 'detect-url': '', + 'biz-type': '', // 审核策略 id + // 'interval': 5, // gif截取间隔帧数 + // 'max-frames': 5, // gif最大截帧数 + }, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +/** + * 获取私有 M3U8 ts 资源的下载授权 + */ +function GetPrivateM3U8() { + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'GET', + Key: 'test.m3u8', + Query: { + 'ci-process': 'pm3u8', + expires: '3600', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 同步审核任意图片 Url +function SyncAuditImageUrl() { + cos.request( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Method: 'GET', + Query: { + 'ci-process': 'sensitive-content-recognition', + 'detect-url': 'https://ftp.bmp.ovh/imgs/2021/09/ee4e63607465ed8d.jpg', + // 'biz-type': '', // 审核策略 id + // 'interval': 5, // gif截取间隔帧数 + // 'max-frames': 5, // gif最大截帧数 + }, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 批量同步审核任意图片 Url +function SyncAuditImageUrls() { + cos.request( + { + Url: `https://${config.Bucket}.ci.${config.Region}.myqcloud.com/image/auditing`, + Method: 'POST', + Headers: { + 'content-type': 'application/xml', + }, + Body: json2xml({ + Request: { + Input: [ + { + Object: 'audit/1.jpg', + // DataId: '1', // 审核序号 + // Url: '', + // Interval: 5, + // MaxFrames: 5, + }, + { + Object: 'audit/2.jpg', + }, + ], + Conf: { + // Callback: '', // 回调地址 + BizType: '', // 审核策略 + }, + }, + }), + }, + function (err, data) { + console.log(err || data.Response.JobsDetail); + }, + ); +} + +// 审核文本内容 +function SyncAuditTextContent() { + cos.request( + { + Url: `https://${config.Bucket}.ci.${config.Region}.myqcloud.com/text/auditing`, + Method: 'POST', + Headers: { + 'content-type': 'application/xml', + }, + Body: json2xml({ + Request: { + Input: { + Content: Buffer.from('高潮').toString('base64'), + }, + Conf: { + // Callback: '', // 回调地址 + BizType: '', // 审核策略 + }, + }, + }), + }, + function (err, data) { + console.log(err || data.Response.JobsDetail); + }, + ); +} + +// 提交图片审核任务 +function CreateAuditJob() { + var objectKey = 'audit/1.jpg'; + var objectType = 'image'; // image/audio/video/text/document + cos.request( + { + Url: `https://${config.Bucket}.ci.${config.Region}.myqcloud.com/${objectType}/auditing`, + Method: 'POST', + Headers: { + 'content-type': 'application/xml', + }, + Body: json2xml({ + Request: { + Input: { + Object: objectKey, + }, + Conf: { + // Callback: '', // 回调地址 + BizType: '', // 审核策略 + }, + }, + }), + }, + function (err, data) { + console.log(err || data.Response.JobsDetail); + }, + ); +} + +// 查询审核任务结果 +function DescribeAuditJob() { + var jobId = 'st3bb560af647911ec919652540024deb5'; + cos.request( + { + Url: `https://${config.Bucket}.ci.${config.Region}.myqcloud.com/text/auditing/${jobId}`, + Method: 'GET', + }, + function (err, data) { + console.log(err || data.Response.JobsDetail); + }, + ); +} + +// 提交直播审核任务 +function postLiveAuditing() { + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + var url = 'https://' + host + '/video/auditing'; + var body = COS.util.json2xml({ + Request: { + Type: 'live_video', + Input: { + Url: 'rtmp://example.com/live/123', // 需要审核的直播流播放地址 + // DataId: '', + // UserInfo: {}, + }, + Conf: { + BizType: '766d07a7af937c26216c51db29793ea6', + // Callback: 'https://callback.com', // 回调地址,非必须 + // CallbackType: 1, // 回调片段类型,非必须 + }, + }, + }); + cos.request( + { + Bucket: config.Bucket, + Region: config.Region, + Method: 'POST', + Url: url, + Key: '/video/auditing', + ContentType: 'application/xml', + Body: body, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 查询直播审核任务结果 +function getLiveAuditingResult() { + var jobId = 'av99005f3ebd8911edb05a52540084c07b'; // jobId可以通过提交直播审核任务返回 + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; + var url = 'https://' + host + '/video/auditing/' + jobId; + cos.request( + { + Bucket: config.Bucket, + Region: config.Region, + Method: 'GET', + Key: '/video/auditing/' + jobId, + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 提交病毒检测任务 +function postVirusDetect() { + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/virus/detect'; + var url = 'https://' + host; + var body = COS.util.json2xml({ + Request: { + Input: { + Object: 'test/1.png', // 文件名,取值为文件在当前存储桶中的完整名称,与Url参数二选一 + // Url: 'http://examplebucket-1250000000.cos.ap-shanghai.myqcloud.com/virus.doc', // 病毒文件的链接地址,与Object参数二选一 + }, + Conf: { + DetectType: 'Virus', // 检测的病毒类型,当前固定为:Virus + // CallBack: 'http://callback.demo.com', // 任务回调的地址 + }, + }, + }); + cos.request( + { + Method: 'POST', + Key: 'virus/detect', + Url: url, + Body: body, + ContentType: 'application/xml', + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 查询病毒检测任务结果 +function getVirusDetectResult() { + var jobId = 'ssc6df8d13bd8911ed904c525400941127'; // 提交病毒检测任务后会返回当前任务的jobId + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/virus/detect/' + jobId; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Key: 'virus/detect/' + jobId, + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 提交音频降噪任务 +function postNoiseReduction() { + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/jobs'; + var url = 'https://' + host; + var body = COS.util.json2xml({ + Request: { + Tag: 'NoiseReduction', + Input: { + Object: 'ci/music.mp3', // 文件名,取值为文件在当前存储桶中的完整名称 + }, + Operation: { + Output: { + Bucket: config.Bucket, // 输出的存储桶 + Region: config.Region, // 输出的存储桶的地域 + Object: 'ci/out.mp3', // 输出的文件Key + }, + }, + // QueueId: '', // 任务所在的队列 ID,非必须 + // CallBackFormat: '', // 任务回调格式,JSON 或 XML,默认 XML,优先级高于队列的回调格式,非必须 + // CallBackType: '', // 任务回调类型,Url 或 TDMQ,默认 Url,优先级高于队列的回调类型,非必须 + // CallBack: '', // 任务回调地址,优先级高于队列的回调地址。设置为 no 时,表示队列的回调地址不产生回调,非必须 + // CallBackMqConfig: '', // 任务回调 TDMQ 配置,当 CallBackType 为 TDMQ 时必填,非必须 + }, + }); + cos.request( + { + Method: 'POST', + Key: 'jobs', + Url: url, + Body: body, + ContentType: 'application/xml', + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 提交人声分离任务 +function postVoiceSeparate() { + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/jobs'; + var url = 'https://' + host; + var body = COS.util.json2xml({ + Request: { + Tag: 'VoiceSeparate', + Input: { + Object: 'ci/music.mp3', // 文件名,取值为文件在当前存储桶中的完整名称 + }, + Operation: { + // VoiceSeparate: {}, // 指定转码模板参数,非必须 + TemplateId: 't13fca82ad97e84878a22cd81bd2e5652c', // 指定的模板 ID,必须 + // JobLevel: 0, // 任务优先级,级别限制:0 、1 、2。级别越大任务优先级越高,默认为0,非必须 + Output: { + Bucket: config.Bucket, // 输出的存储桶 + Region: config.Region, // 输出的存储桶的地域 + Object: 'ci/out/background.mp3', // 输出的文件Key,背景音结果文件名,不能与 AuObject 同时为空 + AuObject: 'ci/out/audio.mp3', + }, + }, + // QueueId: '', // 任务所在的队列 ID,非必须 + // CallBackFormat: '', // 任务回调格式,JSON 或 XML,默认 XML,优先级高于队列的回调格式,非必须 + // CallBackType: '', // 任务回调类型,Url 或 TDMQ,默认 Url,优先级高于队列的回调类型,非必须 + // CallBack: '', // 任务回调地址,优先级高于队列的回调地址。设置为 no 时,表示队列的回调地址不产生回调,非必须 + // CallBackMqConfig: '', // 任务回调 TDMQ 配置,当 CallBackType 为 TDMQ 时必填,非必须 + }, + }); + cos.request( + { + Method: 'POST', + Key: 'jobs', + Url: url, + Body: body, + ContentType: 'application/xml', + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 提交语音合成任务 +function postTts() { + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/jobs'; + var url = 'https://' + host; + var body = COS.util.json2xml({ + Request: { + Tag: 'Tts', + Operation: { + // VoiceSeparate: {}, // 指定转码模板参数,非必须 + TemplateId: 't192931b3564084168a3f50ebfea59acb3', // 指定的模板 ID,必须 + // JobLevel: 0, // 任务优先级,级别限制:0 、1 、2。级别越大任务优先级越高,默认为0,非必须 + TtsConfig: { + InputType: 'Text', + Input: '床前明月光,疑是地上霜', + }, + Output: { + Bucket: config.Bucket, // 输出的存储桶 + Region: config.Region, // 输出的存储桶的地域 + Object: 'ci/out/tts.mp3', // 输出的文件Key + }, + }, + // QueueId: '', // 任务所在的队列 ID,非必须 + // CallBackFormat: '', // 任务回调格式,JSON 或 XML,默认 XML,优先级高于队列的回调格式,非必须 + // CallBackType: '', // 任务回调类型,Url 或 TDMQ,默认 Url,优先级高于队列的回调类型,非必须 + // CallBack: '', // 任务回调地址,优先级高于队列的回调地址。设置为 no 时,表示队列的回调地址不产生回调,非必须 + // CallBackMqConfig: '', // 任务回调 TDMQ 配置,当 CallBackType 为 TDMQ 时必填,非必须 + }, + }); + cos.request( + { + Method: 'POST', + Key: 'jobs', + Url: url, + Body: body, + ContentType: 'application/xml', + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 提交语音识别任务 +function postSpeechRecognition() { + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/asr_jobs'; + var url = 'https://' + host; + var body = COS.util.json2xml({ + Request: { + Tag: 'SpeechRecognition', + Input: { + Object: 'ci/music.mp3', // 文件名,取值为文件在当前存储桶中的完整名称,与Url参数二选一 + // Url: 'http://examplebucket-1250000000.cos.ap-shanghai.myqcloud.com/music.mp3', // 病毒文件的链接地址,与Object参数二选一 + }, + Operation: { + SpeechRecognition: { + EngineModelType: '16k_zh_video', // 引擎模型类型 + ChannelNum: 1, // 语音声道数 + ResTextFormat: 0, // 识别结果返回形式 + FilterDirty: 1, // 是否过滤脏词(目前支持中文普通话引擎) + FilterModal: 1, // 是否过语气词(目前支持中文普通话引擎) + ConvertNumMode: 0, // 是否进行阿拉伯数字智能转换(目前支持中文普通话引擎) + }, + Output: { + Bucket: config.Bucket, // 输出的存储桶 + Region: config.Region, // 输出的存储桶的地域 + Object: 'ci/out/SpeechRecognition.mp3', // 输出的文件Key + }, + }, + // QueueId: '', // 任务所在的队列 ID,非必须 + // CallBackFormat: '', // 任务回调格式,JSON 或 XML,默认 XML,优先级高于队列的回调格式,非必须 + // CallBackType: '', // 任务回调类型,Url 或 TDMQ,默认 Url,优先级高于队列的回调类型,非必须 + // CallBack: '', // 任务回调地址,优先级高于队列的回调地址。设置为 no 时,表示队列的回调地址不产生回调,非必须 + // CallBackMqConfig: '', // 任务回调 TDMQ 配置,当 CallBackType 为 TDMQ 时必填,非必须 + }, + }); + cos.request( + { + Method: 'POST', + Key: 'asr_jobs', + Url: url, + Body: body, + ContentType: 'application/xml', + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 查询语音识别队列 +function getAsrQueue() { + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/asrqueue'; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Key: 'asrqueue', + Url: url, + Query: { + // queueIds: '', /* 非必须,队列 ID,以“,”符号分割字符串 */ + // state: '', /* 非必须,1=Active,2=Paused */ + // pageNumber: 1, /* 非必须,第几页 */ + // pageSize: 2, /* 非必须,每页个数 */ + }, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 更新语音识别队列 +function putAsrQueue() { + // 任务所在的队列 ID,请使用查询队列(https://cloud.tencent.com/document/product/460/46946)获取或前往万象控制台(https://cloud.tencent.com/document/product/460/46487)在存储桶中查询 + var queueId = 'pcc77499e85c311edb9865254008618d9'; + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/asrqueue/' + queueId; + var url = 'https://' + host; + var body = COS.util.json2xml({ + Request: { + Name: 'queue-doc-process-1', + QueueID: queueId, + State: 'Paused', + NotifyConfig: { + // Url: '', + // Type: 'Url', + // Event: '', + State: 'Off', + }, + }, + }); + cos.request( + { + Method: 'PUT', + Key: 'asrqueue/' + queueId, + Url: url, + Body: body, + ContentType: 'application/xml', + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 查询语音识别开通状态 +function getAsrBucket() { + var host = 'ci.' + config.Region + '.myqcloud.com/asrbucket'; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Key: 'asrbucket', + Url: url, + Query: { + // regions: '', /* 非必须,地域信息,以“,”分隔字符串,支持 All、ap-shanghai、ap-beijing */ + // bucketNames: '', /* 非必须,存储桶名称,以“,”分隔,支持多个存储桶,精确搜索 */ + // bucketName: '', /* 非必须,存储桶名称前缀,前缀搜索 */ + // pageNumber: 1, /* 非必须,第几页 */ + // pageSize: 10, /* 非必须,每页个数 */ + }, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 设置防盗链 +function setRefer() { + var host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?hotlink'; + var url = 'https://' + host; + var body = COS.util.json2xml({ + Hotlink: { + Url: 'https://www.example.com', // 必须,域名地址 + Type: 'white', // 必须,防盗链类型,white 为白名单,black 为黑名单,off 为关闭。 + }, + }); + cos.request( + { + Method: 'PUT', + Url: url, + Body: body, + ContentType: 'application/xml', + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 查询防盗链 +function describeRefer() { + var host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?hotlink'; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 开通原图保护 +function openOriginProtect() { + var host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?origin-protect'; + var url = 'https://' + host; + cos.request( + { + Method: 'PUT', + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 查询原图保护状态 +function describeOriginProtect() { + var host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?origin-protect'; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 关闭原图保护 +function closeOriginProtect() { + var host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?origin-protect'; + var url = 'https://' + host; + cos.request( + { + Method: 'DELETE', + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 图片样式 - 增加样式 +function addImageStyle() { + var host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?style'; + var url = 'https://' + host; + var body = COS.util.json2xml({ + AddStyle: { + StyleName: 'style_name1', // 必须,样式名称 + StyleBody: 'imageMogr2/thumbnail/!50px', // 必须,样式详情 + }, + }); + cos.request( + { + Method: 'PUT', + Url: url, + Body: body, + ContentType: 'application/xml', + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 图片样式 - 查询样式 +function describeImageStyles() { + var host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?style'; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Url: url, + Query: { + // "style-name": 'style_name', // 非必填,样式名称 + }, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 图片样式 - 删除样式 +function deleteImageStyle() { + var host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?style'; + var url = 'https://' + host; + var body = COS.util.json2xml({ + DeleteStyle: { + StyleName: 'style_name1', // 必须,样式名称 + }, + }); + cos.request( + { + Method: 'DELETE', + Url: url, + Body: body, + ContentType: 'application/xml', + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 开通 Guetzli 压缩 +function openImageGuetzli() { + var host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?guetzli'; + var url = 'https://' + host; + cos.request( + { + Method: 'PUT', + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 查询 Guetzli 状态 +function describeImageGuetzli() { + var host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?guetzli'; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 关闭 Guetzli 压缩 +function closeImageGuetzli() { + var host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?guetzli'; + var url = 'https://' + host; + cos.request( + { + Method: 'DELETE', + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 上传时使用图片压缩 +function advanceCompressExample1() { + var filename = 'example_photo.png'; + var filepath = path.resolve(__dirname, filename); + cos.putObject( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: filename, + Body: fs.readFileSync(filepath), + Headers: { + // 通过 imageMogr2 接口进行 avif 压缩,可以根据需要压缩的类型填入不同的压缩格式:webp/heif/tpg/avif/svgc + 'Pic-Operations': + '{"is_pic_info": 1, "rules": [{"fileid": "desample_photo.avif", "rule": "imageMogr2/format/webp"}]}', + }, + onTaskReady: function (tid) { + TaskId = tid; + }, + onProgress: function (progressData) { + console.log(JSON.stringify(progressData)); + }, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 对云上数据进行图片压缩 +function advanceCompressExample2() { + var filename = 'example_photo.png'; + cos.request( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + Method: 'POST', + Action: 'image_process', + Headers: { + // 通过 imageMogr2 接口进行 avif 压缩,可以根据需要压缩的类型填入不同的压缩格式:webp/heif/tpg/avif/svgc + 'Pic-Operations': + '{"is_pic_info": 1, "rules": [{"fileid": "desample_photo.avif", "rule": "imageMogr2/format/avif"}]}', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 下载时使用图片压缩 +function advanceCompressExample3() { + var filepath = path.resolve(__dirname, 'example_photo_ci_result.avif'); + cos.getObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: 'example_photo.png', + QueryString: `imageMogr2/format/avif`, // 可以根据需要压缩的类型填入不同的压缩格式:webp/heif/tpg/avif/svgc + }, + function (err, data) { + if (data) { + fs.writeFileSync(filepath, data.Body); + } else { + console.log(err); + } + }, + ); +} + +// 异常图片检测 +function createImageInspectJob() { + var key = '1.png'; + var host = config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + key; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Key: key, + Url: url, + RawBody: true, + Query: { + 'ci-process': 'ImageInspect' /* 必须,操作类型,异常图片检测固定为:ImageInspect */, + }, + }, + function (err, data) { + // 从响应数据中解析出异常图片检测结果 + let body = {}; + if (data && data.Body) { + body = JSON.parse(data.Body) || {}; + if (body) { + data.body = body; + } + } + console.log(err || data); + }, + ); +} + +// 更新图片处理队列 +function updatePicProcessQueue() { + // 任务所在的队列 ID,请使用查询队列(https://cloud.tencent.com/document/product/460/46946)获取或前往万象控制台(https://cloud.tencent.com/document/product/460/46487)在存储桶中查询 + var queueId = 'p36e92002ff5b418497076f31d33d4xxx'; + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/picqueue/' + queueId; + var url = 'https://' + host; + var body = COS.util.json2xml({ + Request: { + Name: 'My-Queue-Pic', // 必须,队列名称,长度不超过128 + State: 'Active', // 必须,Active 表示队列内的作业会被调度执行。Paused 表示队列暂停,作业不再会被调度执行,队列内的所有作业状态维持在暂停状态,已经执行中的任务不受影响。 + NotifyConfig: { + // 必须,回调配置 + State: 'On', // 必须,回调开关,Off/On,默认Off + Event: 'TaskFinish', // 回调事件,当 State=On时, 必选。任务完成:TaskFinish;工作流完成:WorkflowFinish + ResultFormat: 'XML', // 非必选,回调格式,JSON/XML + Type: 'Url', // 回调类型,当 State=On时, 必选,Url 或 TDMQ + Url: 'https://www.example.com', // 回调地址,当 State=On, 且Type=Url时, 必选 + // MqMode: 'Off', // TDMQ 使用模式,当 State=On, 且Type=TDMQ时, 必选 + // MqRegion: 'Off', // TDMQ 所属地域,当 State=On, 且Type=TDMQ时, 必选 + // MqName: 'Off', // TDMQ 主题名称,当 State=On, 且Type=TDMQ时, 必选 + }, + }, + }); + cos.request( + { + Method: 'POST', + Key: 'picqueue/' + queueId, + Url: url, + Body: body, + ContentType: 'application/xml', + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 查询图片处理队列 +function describePicProcessQueues() { + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/picqueue'; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Key: 'picqueue', + Url: url, + Query: { + // queueIds: '', /* 非必须,队列 ID,以“,”符号分割字符串 */ + state: + 'Active' /* 非必须,1. Active 表示队列内的作业会被媒体处理服务调度执行。2. Paused 表示队列暂停,作业不再会被媒体处理调度执行,队列内的所有作业状态维持在暂停状态,已经执行中的任务不受影响。 */, + pageNumber: 1 /* 非必须,第几页,默认值1 */, + pageSize: 10 /* 非必须,每页个数,默认值10 */, + }, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 查询已经开通文档预览的存储桶 +function describeDocProcessBuckets() { + var host = 'ci.' + config.Region + '.myqcloud.com/docbucket'; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Key: 'docbucket', + Url: url, + Query: { + // regions: '', /* 非必须,地域信息,以“,”分隔字符串,支持 All、ap-shanghai、ap-beijing */ + // bucketNames: '', /* 非必须,存储桶名称,以“,”分隔,支持多个存储桶,精确搜索 */ + // bucketName: '', /* 非必须,存储桶名称前缀,前缀搜索 */ + // pageNumber: 1, /* 非必须,第几页 */ + // pageSize: 10, /* 非必须,每页个数 */ + }, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 文档预览功能同步请求 +function previewDocumentAsync() { + var key = 'test.docx'; + var host = config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + key; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Key: key, + Url: url, + Query: { + ObjectKey: key /* 对象文件名 */, + 'ci-process': 'doc-preview' /* 必须,数据万象处理能力,文档预览固定为 doc-preview */, + }, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 提交文档转码任务 +function createDocProcessJobs() { + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/doc_jobs'; + var url = 'https://' + host; + var body = COS.util.json2xml({ + Request: { + Tag: 'DocProcess', + Input: { + Object: 'test.docx', // 存在cos里的路径 + }, + Operation: { + DocProcess: { + TgtType: 'jpg', + }, + Output: { + Bucket: config.Bucket, + Region: config.Region, + Object: '1/文档转码_${Number}.jpg', // 转码后存到cos的路径 + }, + }, + }, + }); + cos.request( + { + Method: 'POST', + Key: 'doc_jobs', + Url: url, + Body: body, + ContentType: 'application/xml', + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 查询指定的文档预览任务 +function describeDocProcessJob() { + var jobId = 'd622ab912ebdb11ed9baf0316d5139xxx'; // 替换成自己的jogId + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/doc_jobs/' + jobId; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Key: 'doc_jobs/' + jobId, + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 拉取符合条件的文档预览任务 +function describeDocProcessJobs() { + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/doc_jobs'; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Key: 'doc_jobs', + Url: url, + Query: { + tag: 'DocProcess', + }, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 更新文档预览队列 +function updateDocProcessQueue() { + // 任务所在的队列 ID,请使用查询队列(https://cloud.tencent.com/document/product/460/46946)获取或前往万象控制台(https://cloud.tencent.com/document/product/460/46487)在存储桶中查询 + var queueId = 'p58639252a2cf45aba7a7f3335ffe3xxx'; // 替换成自己的队列id + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/docqueue/' + queueId; + var url = 'https://' + host; + var body = COS.util.json2xml({ + Request: { + Name: 'queue-doc-process-1', // 替换成自己的队列name + QueueID: queueId, + State: 'Active', + NotifyConfig: { + State: 'Off', + }, + }, + }); + cos.request( + { + Method: 'PUT', + Key: 'docqueue/' + queueId, + Url: url, + Body: body, + ContentType: 'application/xml', + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 查询文档转码队列 +function describeDocProcessQueues() { + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/docqueue'; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Key: 'docqueue', + Url: url, + Query: { + // queueIds: '', /* 非必须,队列 ID,以“,”符号分割字符串 */ + // state: '', /* 非必须,1=Active,2=Paused */ + // pageNumber: 1, /* 非必须,第几页 */ + // pageSize: 2, /* 非必须,每页个数 */ + }, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 文档转 HTML +function getDocHtmlUrl() { + cos.getObjectUrl( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: 'test.docx', + Query: { + 'ci-process': 'doc-preview' /* 必须,数据万象处理能力,文档预览固定为 doc-preview */, + // srcType: '', /* 非必须,源数据的后缀类型,当前文档转换根据 COS 对象的后缀名来确定源数据类型。当 COS 对象没有后缀名时,可以设置该值 */ + // page: '', /* 非必须,需转换的文档页码,默认从1开始计数;表格文件中 page 表示转换的第 X 个 sheet 的第 X 张图 */ + dstType: 'html' /* 非必须,转换输出目标文件类型 */, + }, + }, + function (err, data) { + if (err) { + console.log(err); + } else { + // 使用浏览器打开url即可预览 + var url = data.Url; + console.log(url); + } + }, + ); } - -/** - * 更新工作流配置 - */ -function UpdateWorkflow() { - let workflowId = 'w14404e66c27b4e0aafae6bc96acfxxxx'; - let queueId = 'p5ad1499214024af2bfaa4401d529xxxx'; - let callbackUrl = 'http://your.callback.com/index.php'; - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/workflow/' + workflowId; - let body = { // 填上模版修改参数 - Request: { - MediaWorkflow: { - Name: 'test1', - State: 'Active', // 创建并开启工作流 - Topology: { - Dependencies: { - Start: 'SmartCover_1581665960539', - 'SmartCover_1581665960539': 'End' - }, - Nodes: { - Start: { - Type: 'Start', - Input: { - QueueId: queueId, - ObjectPrefix: 'test/', - NotifyConfig: { - Type: 'Url', - Url: callbackUrl, - Event: 'TaskFinish,WorkflowFinish' - }, - ExtFilter: { - State: 'On', - Video: 'true', - Custom: 'true', - CustomExts: 'mp4/mp3', - AllFile: 'false' - } - } - }, - 'SmartCover_1581665960539': { - Type: 'SmartCover', - Operation: { - Output: { - Region: config.Region, - Bucket: config.Bucket, - Object: 'worlflow-test/${RunId}/cover-${Number}.jpg' - }, - SmartCover: { - Format: 'png', - Width: '128', - Height: '128', - Count: '3', - DeleteDuplicates: 'false' - } - } - } - } - } - } - } - } - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'PUT', - Key: 'workflow/' + workflowId, - Url: url, - Headers: { - 'content-type': 'application/xml' - }, - Body: json2xml(body) - }, function (err, data) { - console.log(err || data); - }); +// 获取在线文档预览地址 +function getDocHtmlPreviewUrl() { + var key = 'test.docx'; + var host = config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + key; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Key: key, + Url: url, + RawBody: true, + Query: { + 'ci-process': 'doc-preview' /* 必须,预览固定参数,值为 doc-preview */, + dstType: 'html' /* 必须,预览类型,如需预览生成类型为 html 则填入 html */, + weboffice_url: 1 /* 非必须,是否获取预览链接。填入值为1会返回预览链接和Token信息;填入值为2只返回Token信息;不传会直接预览 */, + }, + }, + function (err, data) { + // 从响应数据中解析出在线文档预览地址 + let body = {}; + if (data && data.Body) { + body = JSON.parse(data.Body) || {}; + } + if (body && body.PreviewUrl) { + data.PreviewUrl = body.PreviewUrl; + } + console.log(err || data); + }, + ); } +// 开通文件处理服务 +function createFileProcessBucket() { + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_bucket'; + var url = 'https://' + host; + cos.request( + { + Method: 'POST', + Key: 'file_bucket', + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); +} -/** - * 触发工作流 - */ -function TriggerWorkflow() { - let workflowId = 'w093b29cfef824bd0922743a6f0afxxxx'; - let host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com'; - let url = 'https://' + host + '/triggerworkflow'; - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'POST', - Key: 'triggerworkflow', - Url: url, - Headers: { - 'content-type': 'application/xml' - }, - Query: { - workflowId: workflowId, - object: 'test.mp4' - } - }, function (err, data) { - console.log(err || data); - }); +// 更新文件处理队列 +function updateFileProcessQueue() { + // 任务所在的队列 ID,请使用查询队列(https://cloud.tencent.com/document/product/460/46946)获取或前往万象控制台(https://cloud.tencent.com/document/product/460/46487)在存储桶中查询 + var queueId = 'p5d0dc85debe149febdd6fd9b208aaxxx'; + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_queue/' + queueId; + var url = 'https://' + host; + var body = COS.util.json2xml({ + Request: { + Name: 'My-Queue-file', // 必须,队列名称,长度不超过128 + State: 'Active', // 必须,Active 表示队列内的作业会被调度执行。Paused 表示队列暂停,作业不再会被调度执行,队列内的所有作业状态维持在暂停状态,已经执行中的任务不受影响。 + NotifyConfig: { + // 必须,回调配置 + State: 'On', // 必须,回调开关,Off/On,默认Off + Event: 'TaskFinish', // 回调事件,当 State=On时, 必选。任务完成:TaskFinish;工作流完成:WorkflowFinish + ResultFormat: 'XML', // 非必选,回调格式,JSON/XML + Type: 'Url', // 回调类型,当 State=On时, 必选,Url 或 TDMQ + Url: 'https://www.example.com', // 回调地址,当 State=On, 且Type=Url时, 必选 + // MqMode: 'Off', // TDMQ 使用模式,当 State=On, 且Type=TDMQ时, 必选 + // MqRegion: 'Off', // TDMQ 所属地域,当 State=On, 且Type=TDMQ时, 必选 + // MqName: 'Off', // TDMQ 主题名称,当 State=On, 且Type=TDMQ时, 必选 + }, + }, + }); + cos.request( + { + Method: 'POST', + Key: 'file_queue/' + queueId, + Url: url, + Body: body, + ContentType: 'application/xml', + }, + function (err, data) { + console.log(err || data); + }, + ); } -// 同步审核存储桶里的图片对象 -function SyncAuditImageObject() { - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Key: 'audit/1.jpg', - Method: 'GET', - Query: { - 'ci-process': 'sensitive-content-recognition', - // 'detect-url': '', - 'biz-type': '', // 审核策略 id - // 'interval': 5, // gif截取间隔帧数 - // 'max-frames': 5, // gif最大截帧数 - } - }, function (err, data) { - console.log(err || data); - }); +// 查询文件处理队列 +function describeFileProcessQueues() { + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_queue'; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Key: 'file_queue', + Url: url, + Query: { + // queueIds: '', /* 非必须,队列 ID,以“,”符号分割字符串 */ + state: + 'Active' /* 非必须,Active 表示队列内的作业会被调度执行。Paused 表示队列暂停,作业不再会被调度执行,队列内的所有作业状态维持在暂停状态,已经执行中的任务不受影响。 */, + pageNumber: 1 /* 第几页,默认值1 */, + pageSize: 10 /* 非必须,每页个数,默认值10 */, + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } -/** - * 获取私有 M3U8 ts 资源的下载授权 - */ -function GetPrivateM3U8() { - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'GET', - Key: 'test.m3u8', - Query: { - 'ci-process': 'pm3u8', - expires: '3600' - } - }, function (err, data) { - console.log(err || data); - }); +// 哈希值计算同步请求 +function generateFileHash() { + var key = 'test.docx'; + var host = config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + key; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Key: key, + Url: url, + Query: { + 'ci-process': 'filehash' /* 必须,操作类型,哈希值计算固定为:filehash */, + type: 'md5' /* 必须,支持的哈希算法类型,有效值:md5、sha1、sha256 */, + // 'addtoheader': false, /* 非必须,是否将计算得到的哈希值,自动添加至文件的自定义header,格式为:x-cos-meta-md5/sha1/sha256;有效值:true、false,不填则默认为false。 */ + }, + }, + function (err, data) { + console.log(err || data); + }, + ); } -// 同步审核任意图片 Url -function SyncAuditImageUrl() { - cos.request({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Method: 'GET', - Query: { - 'ci-process': 'sensitive-content-recognition', - 'detect-url': 'https://ftp.bmp.ovh/imgs/2021/09/ee4e63607465ed8d.jpg', - // 'biz-type': '', // 审核策略 id - // 'interval': 5, // gif截取间隔帧数 - // 'max-frames': 5, // gif最大截帧数 - } - }, function (err, data) { - console.log(err || data); - }); +// 提交哈希值计算任务 +function postFileHashTask() { + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_jobs'; + var url = 'https://' + host; + var body = COS.util.json2xml({ + Request: { + Tag: 'FileHashCode', // 必须 + Input: { + Object: 'test.docx', // 文件名,取值为文件在当前存储桶中的完整名称 + }, + Operation: { + FileHashCodeConfig: { + Type: 'MD5', // 哈希值的算法类型,有效值:MD5、SHA1、SHA256 + AddToHeader: 'false', // 是否将计算得到的哈希值添加至文件自定义header, 有效值:true、false,默认值为 false。 + }, + // UserData: '', // 透传用户信息, 可打印的 ASCII 码, 长度不超过1024 + }, + // QueueId: '', // 任务所在的队列 ID + // CallBack: 'http://callback.demo.com', // 任务回调的地址 + // CallBackFormat: 'JSON', // 任务回调格式 + // CallBackType: 'Url', // 任务回调类型,Url 或 TDMQ,默认 Url + }, + }); + cos.request( + { + Method: 'POST', + Key: 'file_jobs', + Url: url, + Body: body, + ContentType: 'application/xml', + }, + function (err, data) { + console.log(err || data); + }, + ); } -// 批量同步审核任意图片 Url -function SyncAuditImageUrls() { - cos.request({ - Url: `https://${config.Bucket}.ci.${config.Region}.myqcloud.com/image/auditing`, - Method: 'POST', - Headers: { - 'content-type': 'application/xml' - }, - Body: json2xml({ - Request: { - Input: [{ - Object: 'audit/1.jpg', - // DataId: '1', // 审核序号 - // Url: '', - // Interval: 5, - // MaxFrames: 5, - }, { - Object: 'audit/2.jpg', - }], - Conf: { - // Callback: '', // 回调地址 - BizType: '', // 审核策略 - }, - }, - }), - }, function (err, data) { - console.log(err || data.Response.JobsDetail); - }); +// 查询哈希值计算任务结果 +function getFileHashTask() { + var jobId = 'f99ca3336ebde11ed96313ffa040a7xxx'; // 提交文件哈希值计算任务后会返回当前任务的jobId + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_jobs/' + jobId; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Key: 'file_jobs/' + jobId, + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); } -// 审核文本内容 -function SyncAuditTextContent() { - cos.request({ - Url: `https://${config.Bucket}.ci.${config.Region}.myqcloud.com/text/auditing`, - Method: 'POST', - Headers: { - 'content-type': 'application/xml' +// 提交文件解压任务 +function postFileUnCompressTask() { + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_jobs'; + var url = 'https://' + host; + var body = COS.util.json2xml({ + Request: { + Tag: 'FileUncompress', // 必须 + Input: { + Object: 'testCompress/compressed.zip', // 文件名,取值为文件在当前存储桶中的完整名称 + }, + Operation: { + FileUncompressConfig: { + Prefix: 'testCompress', // 指定解压后输出文件的前缀,不填则默认保存在存储桶根路径 + PrefixReplaced: '0', // 指定解压后的文件路径是否需要替换前缀,默认0 }, - Body: json2xml({ - Request: { - Input: { - Content: Buffer.from('高潮').toString('base64'), - }, - Conf: { - // Callback: '', // 回调地址 - BizType: '', // 审核策略 - }, - }, - }), - }, function (err, data) { - console.log(err || data.Response.JobsDetail); - }); + Output: { + Bucket: config.Bucket, // 保存解压后文件的存储桶 + Region: config.Region, // 保存解压后文件的存储桶地域 + }, + }, + // QueueId: '', // 任务所在的队列 ID + // CallBack: 'http://callback.demo.com', // 任务回调的地址 + // CallBackFormat: 'JSON', // 任务回调格式 + // CallBackType: 'Url', // 任务回调类型,Url 或 TDMQ,默认 Url + }, + }); + cos.request( + { + Method: 'POST', + Key: 'file_jobs', + Url: url, + Body: body, + ContentType: 'application/xml', + }, + function (err, data) { + console.log(err || data); + }, + ); } -// 提交图片审核任务 -function CreateAuditJob() { - var objectKey = 'audit/1.jpg'; - var objectType = 'image'; // image/audio/video/text/document - cos.request({ - Url: `https://${config.Bucket}.ci.${config.Region}.myqcloud.com/${objectType}/auditing`, - Method: 'POST', - Headers: { - 'content-type': 'application/xml' +// 查询文件解压任务结果 +function getFileUnCompressTask() { + var jobId = 'f52028b26ebe211edae4c1b36c787axxx'; // 提交文件解压任务后会返回当前任务的jobId + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_jobs/' + jobId; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Key: 'file_jobs/' + jobId, + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); +} + +// 提交文件压缩任务 +function postFileCompressTask() { + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_jobs'; + var url = 'https://' + host; + var body = COS.util.json2xml({ + Request: { + Tag: 'FileCompress', // 必须 + Operation: { + FileCompressConfig: { + Flatten: '0', // 文件打包时,是否需要去除源文件已有的目录结构.0:不需要;1:需要 + Format: 'zip', // 打包压缩的类型,有效值:zip、tar、tar.gz + // UrlList、Prefix、Key 三者仅能选择一个,不能都为空,也不会同时生效 + // UrlList: '', // 索引文件的对象地址 + Prefix: '/', // 目录前缀 + Key: [''], // 支持对存储桶中的多个文件进行打包,个数不能超过 1000, 总大小不超过50G,否则会导致任务失败 }, - Body: json2xml({ - Request: { - Input: { - Object: objectKey, - }, - Conf: { - // Callback: '', // 回调地址 - BizType: '', // 审核策略 - }, - }, - }), - }, function (err, data) { - console.log(err || data.Response.JobsDetail); - }); + Output: { + Bucket: config.Bucket, // 保存压缩后文件的存储桶 + Region: config.Region, // 保存压缩后文件的存储桶地域 + Object: 'testCompress/compressed.zip', // 压缩后文件的文件名 + }, + UserData: '', + }, + // QueueId: '', // 任务所在的队列 ID + // CallBack: 'http://callback.demo.com', // 任务回调的地址 + // CallBackFormat: 'JSON', // 任务回调格式 + // CallBackType: 'Url', // 任务回调类型,Url 或 TDMQ,默认 Url + }, + }); + cos.request( + { + Method: 'POST', + Key: 'file_jobs', + Url: url, + Body: body, + ContentType: 'application/xml', + }, + function (err, data) { + console.log(err || data); + }, + ); } -// 查询审核任务结果 -function DescribeAuditJob() { - var jobId = 'st3bb560af647911ec919652540024deb5'; - cos.request({ - Url: `https://${config.Bucket}.ci.${config.Region}.myqcloud.com/text/auditing/${jobId}`, - Method: 'GET', - }, function (err, data) { - console.log(err || data.Response.JobsDetail); - }); +// 查询文件压缩任务结果 +function getFileCompressTask() { + var jobId = 'fc3c90292ebdf11eda4be2be811d77xxx'; // 提交文件压缩任务后会返回当前任务的jobId + var host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_jobs/' + jobId; + var url = 'https://' + host; + cos.request( + { + Method: 'GET', + Key: 'file_jobs/' + jobId, + Url: url, + }, + function (err, data) { + console.log(err || data); + }, + ); } // 提交直播审核任务 @@ -3901,7 +5505,6 @@ function getFileCompressTask() { // deleteBucketEncryption(); // deleteBucket(); - // 对象操作 // putObjectCopy(); // getObjectStream(); @@ -3944,7 +5547,6 @@ function getFileCompressTask() { // GetMediaInfo(); // GetSnapshot(); - //DescribeDocProcessBuckets(); //GetDocProcess() //DescribeDocProcessQueues() @@ -3982,7 +5584,6 @@ function getFileCompressTask() { // postLiveAuditing(); // getLiveAuditingResult(); - // postVirusDetect(); // getVirusDetectResult(); @@ -3994,7 +5595,6 @@ function getFileCompressTask() { // putAsrQueue(); // getAsrBucket(); - // setRefer(); // describeRefer(); // openOriginProtect(); diff --git a/index.d.ts b/index.d.ts index 4bfbb44..3fe512f 100644 --- a/index.d.ts +++ b/index.d.ts @@ -7,7 +7,6 @@ import { Stream } from 'stream'; * 定义 COS 命名空间,方便导出用到的变量类型给外部引用 */ declare namespace COS { - /** 存储桶的名称,命名规则为 BucketName-APPID,例如 examplebucket-1250000000 */ type Bucket = string; /** 存储桶所在地域 @see https://cloud.tencent.com/document/product/436/6224 */ @@ -43,7 +42,15 @@ declare namespace COS { /** 上传的文件内容 */ type UploadBody = Buffer | String | Stream; /** 对象存储类型。枚举值 STANDARD | STANDARD_IA | ARCHIVE | DEEP_ARCHIVE | INTELLIGENT_TIERING | MAZ_STANDARD | MAZ_STANDARD_IA | MAZ_INTELLIGENT_TIERING @see https://cloud.tencent.com/document/product/436/33417 */ - type StorageClass = 'STANDARD' | 'STANDARD_IA' | 'ARCHIVE' | 'DEEP_ARCHIVE' | 'INTELLIGENT_TIERING' | 'MAZ_STANDARD' | 'MAZ_STANDARD_IA' | 'MAZ_INTELLIGENT_TIERING'; + type StorageClass = + | 'STANDARD' + | 'STANDARD_IA' + | 'ARCHIVE' + | 'DEEP_ARCHIVE' + | 'INTELLIGENT_TIERING' + | 'MAZ_STANDARD' + | 'MAZ_STANDARD_IA' + | 'MAZ_INTELLIGENT_TIERING'; /** 请求方法 */ type Method = 'GET' | 'DELETE' | 'POST' | 'PUT' | 'OPTIONS' | 'get' | 'delete' | 'post' | 'put' | 'options'; /** 权限信息,枚举值:READ | WRITE | READ_ACP | WRITE_ACP | FULL_CONTROL 腾讯云对象存储 COS 在资源 ACL 上支持的操作实际上是一系列的操作集合,对于存储桶和对象 ACL 来说分别代表不同的含义。 */ @@ -51,18 +58,24 @@ declare namespace COS { /** 存储桶的预设 ACL @see https://cloud.tencent.com/document/product/436/30752#.E9.A2.84.E8.AE.BE.E7.9A.84-acl */ type BucketACL = 'private' | 'public-read' | 'public-read-write' | 'authenticated-read'; /** 对象的预设 ACL @see https://cloud.tencent.com/document/product/436/30752#.E9.A2.84.E8.AE.BE.E7.9A.84-acl */ - type ObjectACL = 'default' | 'private' | 'public-read' | 'authenticated-read' | 'bucket-owner-read' | 'bucket-owner-full-control'; + type ObjectACL = + | 'default' + | 'private' + | 'public-read' + | 'authenticated-read' + | 'bucket-owner-read' + | 'bucket-owner-full-control'; /** 二进制值的字符串,'true' | 'false' */ type BooleanString = 'true' | 'false'; /** 所有者的信息 */ type Owner = { /** 存储桶持有者的完整 ID,格式为 qcs::cam::uin/[OwnerUin]:uin/[OwnerUin],如 qcs::cam::uin/100000000001:uin/100000000001 */ - ID: string, + ID: string; }; /** 所有者的信息 */ type GroupOwner = { /** 预设用户组,格式为 http://cam.qcloud.com/groups/global/AllUsers (匿名用户组) 或 http://cam.qcloud.com/groups/global/AuthenticatedUsers (认证用户组) 。参见 {@link https://cloud.tencent.com/document/product/436/30752#.E8.BA.AB.E4.BB.BD-grantee| ACL 概述} */ - URI: string, + URI: string; }; /** 上传发起者的信息 */ type Initiator = Owner; @@ -71,45 +84,45 @@ declare namespace COS { /** 被授权者信息与权限信息 */ interface Grants { /** 所有者的信息 */ - Grantee: Owner | GroupOwner, + Grantee: Owner | GroupOwner; /** 权限信息,枚举值:READ | WRITE | READ_ACP | WRITE_ACP | FULL_CONTROL 腾讯云对象存储 COS 在资源 ACL 上支持的操作实际上是一系列的操作集合,对于存储桶和对象 ACL 来说分别代表不同的含义。 */ - Permission: Permission, + Permission: Permission; } /** 存储桶/对象标签信息 */ interface Tag { /** 标签的 Key,长度不超过128字节, 支持英文字母、数字、空格、加号、减号、下划线、等号、点号、冒号、斜线 */ - Key: Key, + Key: Key; /** 标签的 Value,长度不超过256字节, 支持英文字母、数字、空格、加号、减号、下划线、等号、点号、冒号、斜线 */ - Value: string, + Value: string; } /** 用来说明本次分块上传中每个块的信息 */ interface Part { /** 标识本次分块上传的编号,范围在1 - 10000 */ - PartNumber: PartNumber, + PartNumber: PartNumber; /** 使用 Upload Part 请求上传分块成功后返回的 ETag 响应头部的值 */ - ETag: ETag, + ETag: ETag; } /** 当前需要用凭证的请求,需要的最小权限 */ type Scope = { /** 需要的权限 */ - action: string, + action: string; /** 操作的存储桶的名称,命名规则为 BucketName-APPID,例如 examplebucket-1250000000 */ - bucket: Bucket, + bucket: Bucket; /** 存储桶所在地域 @see https://cloud.tencent.com/document/product/436/6224 */ - region: Region, + region: Region; /** 前缀匹配,用来规定返回的文件前缀地址,支持 * 结尾 */ - prefix: Prefix + prefix: Prefix; }[]; /** onProgress 回调的进度信息 */ interface ProgressInfo { /** 已上传/下载的字节数,单位 B(字节) */ - loaded: number, + loaded: number; /** 要上传/下载的文件的大小,单位 B(字节) */ - total: number, + total: number; /** 速度,单位 B/s */ - speed: number, + speed: number; /** 进度百分比,范围是 0-1,保留两位小数 */ - percent: number, + percent: number; } /** 上传/下载的进度回调方法 */ type onProgress = (params: ProgressInfo) => any; @@ -117,83 +130,83 @@ declare namespace COS { // 实例参数 interface COSOptions { /** 固定密钥的 SecretId,可从{@link https://console.cloud.tencent.com/cam/capi|API密钥管理}获取 */ - SecretId?: string, + SecretId?: string; /** 固定密钥的 SecretKey,可从{@link https://console.cloud.tencent.com/cam/capi|API密钥管理}获取 */ - SecretKey?: string, + SecretKey?: string; /** 如果传入 SecretId、SecretKey 是临时密钥,需要再传入一个临时密钥的 sessionToken */ - SecurityToken?: string, + SecurityToken?: string; /** 同 SecurityToken,推荐用 SecurityToken */ - XCosSecurityToken?: string, + XCosSecurityToken?: string; /** 分块上传及分块复制时,出错重试次数,默认值3(加第一次,请求共4次) */ - ChunkRetryTimes?: number, + ChunkRetryTimes?: number; /** 同一个实例下上传的文件并发数,默认值3 */ - FileParallelLimit?: number, + FileParallelLimit?: number; /** 同一个上传文件的分块并发数,默认值3 */ - ChunkParallelLimit?: number, + ChunkParallelLimit?: number; /** 分块上传时,每片的字节数大小,默认值1048576(1MB) */ - ChunkSize?: number, + ChunkSize?: number; /** 使用 uploadFiles 批量上传时,文件大小大于该数值将使用按分块上传,否则将调用简单上传,单位 Byte,默认值1048576(1MB) */ - SliceSize?: number, + SliceSize?: number; /** 进行分块复制操作中复制分块上传的并发数,默认值20 */ - CopyChunkParallelLimit?: number, + CopyChunkParallelLimit?: number; /** 使用 sliceCopyFile 分块复制文件时,每片的大小字节数,默认值10485760(10MB) */ - CopyChunkSize?: number, + CopyChunkSize?: number; /** 使用 sliceCopyFile 分块复制文件时,文件大小大于该数值将使用分块复制 ,否则将调用简单复制,默认值10485760(10MB) */ - CopySliceSize?: number, + CopySliceSize?: number; /** 最大分片数,默认 1000,最大 10000,分片上传超大文件时,会根据文件大小和该最大分片数计算合适的的分片大小 */ - MaxPartNumber?: number, + MaxPartNumber?: number; /** 上传进度的回调方法 onProgress 的回调频率,单位 ms ,默认值1000 */ - ProgressInterval?: number, + ProgressInterval?: number; /** 上传队列最长大小,超出的任务如果状态不是 waiting、checking、uploading 会被清理,默认10000 */ - UploadQueueSize?: number, + UploadQueueSize?: number; /** 调用操作存储桶和对象的 API 时自定义请求域名。可以使用模板,如"{Bucket}.cos.{Region}.myqcloud.com",即在调用 API 时会使用参数中传入的 Bucket 和 Region 进行替换。 */ - Domain?: string, + Domain?: string; /** getService方法可以使用的自定义域名 */ - ServiceDomain?: string, + ServiceDomain?: string; /** 强制使用后缀式模式发请求。后缀式模式中 Bucket 会放在域名后的 pathname 里,并且 Bucket 会加入签名 pathname 计算,默认 false */ - Protocol?: string, + Protocol?: string; /** 设置代理,格式如 http://127.0.0.1:8888 */ - Proxy?: string, + Proxy?: string; /** 透传给request */ - Tunnel?: boolean, + Tunnel?: boolean; /** 开启兼容模式,默认 false 不开启,兼容模式下不校验 Region 是否格式有误,在用于私有化 COS 时使用 */ - CompatibilityMode?: boolean, + CompatibilityMode?: boolean; /** 强制使用后缀式模式发请求。后缀式模式中 Bucket 会放在域名后的 pathname 里,并且 Bucket 会加入签名 pathname 计算,默认 false */ - ForcePathStyle?: boolean, + ForcePathStyle?: boolean; /** 是否原样保留 Key 字段的 / 前缀,默认 false 不保留,这时如果 Key 是 / 开头,强制去掉第一个 / */ - UseRawKey?: boolean, + UseRawKey?: boolean; /** 请求超时时间,单位 ms(毫秒),透传给 request 或 ajax 或小程序请求库 */ - Timeout?: number, + Timeout?: number; /** 客户端时间是否不准确,默认 false,在第一次请求 COS API 返回时会判断是否偏差大于 30s,如果是会把该值设置为 true,开发者也可以预先判断并设置该参数 */ - CorrectClockSkew?: boolean, + CorrectClockSkew?: boolean; /** 校正时间的偏移值,单位 ms(毫秒),计算签名时会用设备当前时间戳加上该偏移值,在设备时间有误时可用于校正签名用的时间参数,在第一次请求 COS API 返回时会判断是否偏差大于 30s,如果是会把该值设置为 true,开发者也可以预先判断并设置该参数。 */ - SystemClockOffset?: number, + SystemClockOffset?: number; /** 上传文件时校验 Content-MD5,默认 false。如果开启,上传文件时会对文件内容计算 MD5,大文件耗时较长 */ - UploadCheckContentMd5?: boolean, + UploadCheckContentMd5?: boolean; /** 上传文件时计算文件内容 md5 并设置为文件 x-cos-meta-md5 元数据 Header 字段 */ - UploadAddMetaMd5?: boolean, + UploadAddMetaMd5?: boolean; /** 分片上传缓存的 UploadId 列表大小限制,nodejs-sdk 默认 500 个,js-sdk、小程序 SDK 默认 50 */ - UploadIdCacheLimit?: number, + UploadIdCacheLimit?: number; /** 分片上传缓存的 UploadId 列表时,保存的本地缓存文件目录路径,nodejs-sdk 默认 500 个,js-sdk 默认 50 */ - ConfCwd?: string, + ConfCwd?: string; /** 301/302 回源跟随配置。 */ - FollowRedirect?: boolean, + FollowRedirect?: boolean; /** 是否使用全球加速域名。开启该配置后仅以下接口支持操作:putObject、getObject、headObject、optionsObject、multipartInit、multipartListPart、multipartUpload、multipartAbort、multipartComplete、multipartList、sliceUploadFile、uploadFiles */ - UseAccelerate?: boolean, + UseAccelerate?: boolean; /** 是否开启长链接,默认开启 */ - KeepAlive?: boolean, - Ip?: string, + KeepAlive?: boolean; + Ip?: string; /** 默认将host加入签名计算,关闭后可能导致越权风险,建议保持为true */ - ForceSignHost?: boolean, + ForceSignHost?: boolean; /** 获取签名的回调方法,如果没有 SecretId、SecretKey 时,必选 */ getAuthorization?: ( options: GetAuthorizationOptions, /** callback 获取完签名或临时密钥后,回传给 SDK 的方法 */ callback: ( /** params 回传给 SDK 的签名或获取临时密钥 */ - params: GetAuthorizationCallbackParams - ) => void - ) => void, + params: GetAuthorizationCallbackParams, + ) => void, + ) => void; /** 支持动态Credentials */ Credentials?: { secretId?: string; @@ -203,77 +216,78 @@ declare namespace COS { type StringOrBuffer = Buffer | String; interface Util { - md5: (str: StringOrBuffer, encoding?: string) => string, - xml2json: (bodyStr: string) => any, - json2xml: (json: any) => string, + md5: (str: StringOrBuffer, encoding?: string) => string; + xml2json: (bodyStr: string) => any; + json2xml: (json: any) => string; + encodeBase64: (str: string, safe?: boolean) => string; } interface StaticGetAuthorizationOptions { /** 计算签名用的密钥 SecretId,必选 */ - SecretId: string, + SecretId: string; /** 计算签名用的密钥 SecretKey,必选 */ - SecretKey: string, + SecretKey: string; /** 请求的存储桶,如果传入了 Bucket、Region,签名会默认加上 Host 字段,可选 */ - Bucket?: Bucket, + Bucket?: Bucket; /** 请求的地域,如果传入了 Bucket、Region,签名会默认加上 Host 字段,可选 */ - Region?: Region, + Region?: Region; /** 请求方法,可选 */ - Method?: Method, + Method?: Method; /** 请求路径,最前面带 /,例如 /images/1.jpg,可选 */ - Pathname?: Pathname, + Pathname?: Pathname; /** 请求的对象键,最前面不带 /,例如 images/1.jpg,可选 */ - Key?: Key, + Key?: Key; /** 要参与签名计算的 Url Query 参数,可选 */ - Query?: Query, + Query?: Query; /** 要参与签名计算的 Header 参数,可选 */ - Headers?: Headers, + Headers?: Headers; /** 签名几秒后失效,默认为900秒,如果传入了 KeyTime,以 KeyTime 为准,可选 */ - Expires?: number, + Expires?: number; /** 签名有效时间戳区间,如果传入了该参数,会赋值给在签名里的 q-key-time 和 q-sign-time 字段,格式如:1611915436;1611916336 */ - KeyTime?: string, + KeyTime?: string; /** 校正时间的偏移值,单位 ms(毫秒),计算签名时会用设备当前时间戳加上该偏移值,在设备时间有误时可用于校正签名用的时间参数。 */ - SystemClockOffset?: number, + SystemClockOffset?: number; } /** 计算签名或获取临时密钥可能需要的参数列表 */ interface GetAuthorizationOptions { /** 存储桶的名称,格式为,例如examplebucket-1250000000 */ - Bucket: Bucket, + Bucket: Bucket; /** 存储桶所在地域 @see https://cloud.tencent.com/document/product/436/6224 */ - Region: Region, + Region: Region; /** 请求方法 */ - Method: Method, + Method: Method; /** 请求路径,最前面带 /,例如 /images/1.jpg,Pathname 和 Key 二选一 */ - Pathname: Pathname, + Pathname: Pathname; /** 请求的对象键,最前面不带 /,例如 images/1.jpg,如果是存储桶接口,传入空字符串,Key 和 Pathname 二选一,推荐使用 Pathname 参数 */ - Key: Key, + Key: Key; /** 请求里的 Url Query 参数,可选 */ - Query: Query, + Query: Query; /** 请求里的 Header 参数,可选 */ - Headers: Headers, + Headers: Headers; /** 当前需要用凭证的请求,需要的最小权限 */ - Scope: Scope, + Scope: Scope; /** 校正时间的偏移值,单位 ms(毫秒),计算签名时会用设备当前时间戳加上该偏移值,在设备时间有误时可用于校正签名用的时间参数。 */ - SystemClockOffset: number, + SystemClockOffset: number; } /** 请求凭证,包含临时密钥信息 */ interface Credentials { /** 临时密钥 tmpSecretId */ - TmpSecretId: string, + TmpSecretId: string; /** 临时密钥 tmpSecretKey */ - TmpSecretKey: string, + TmpSecretKey: string; /** 临时密钥 sessonToken */ - SecurityToken?: string, + SecurityToken?: string; /** 同 SecurityToken,推荐用 SecurityToken */ - XCosSecurityToken?: string, + XCosSecurityToken?: string; /** 获取临时密钥时,服务端的时间,该时间用于计算签名,可以避免设备时间有偏差导致请求错误 */ - StartTime: number, + StartTime: number; /** 获取临时密钥的过期时间戳 */ - ExpiredTime: number, + ExpiredTime: number; /** 该临时密钥是否仅用于相同 Scope 权限范围的请求 */ - ScopeLimit?: boolean, + ScopeLimit?: boolean; /** 签名 */ - Authorization?: string, + Authorization?: string; } /** 用于发请求的签名字符串,会放在请求 Header 里的 Authorization 字段 */ @@ -283,90 +297,90 @@ declare namespace COS { /** 一般接口的返回结果 */ interface GeneralResult { /** 请求返回的 HTTP 状态码 */ - statusCode?: number, + statusCode?: number; /** 请求返回的 header 字段 */ - headers?: Headers, + headers?: Headers; /** 请求的唯一标识 */ - RequestId?: string, + RequestId?: string; } /** SDK 的错误格式,其中服务端返回错误码可查看 @see https://cloud.tencent.com/document/product/436/7730 */ interface CosSdkError extends GeneralResult { /** 错误码 */ - code: string, + code: string; /** 错误信息 */ - message: string, + message: string; /** 兼容老的错误信息字段,不建议使用,可能是参数错误、客户端出错、或服务端返回的错误 */ - error: string | Error | { Code: string, Message: string }, + error: string | Error | { Code: string; Message: string }; } /** 回调的错误格式,其中服务端返回错误码可查看 @see https://cloud.tencent.com/document/product/436/7730 */ type CosError = null | CosSdkError; /** 存储桶操作接口的公共参数 */ interface BucketParams { /** 存储桶的名称,格式为,例如examplebucket-1250000000 */ - Bucket: Bucket, + Bucket: Bucket; /** 存储桶所在地域 @see https://cloud.tencent.com/document/product/436/6224 */ - Region: Region, + Region: Region; /** 请求时带上的 Header 字段 */ - Headers?: Headers, + Headers?: Headers; } /** 对象操作接口的公共参数 */ interface ObjectParams { /** 存储桶的名称,格式为,例如examplebucket-1250000000 */ - Bucket: Bucket, + Bucket: Bucket; /** 存储桶所在地域,如果有传入只返回该地域的存储桶列表 */ - Region: Region, + Region: Region; /** 请求的对象键,最前面不带 / */ - Key: Key, + Key: Key; /** 发请求时带上的 Header 字段 */ - Headers?: Headers, + Headers?: Headers; } // 所有接口的入参和出参 // getService interface GetServiceParams { /** 存储桶所在地域,如果传入只返回该地域的存储桶 */ - Region?: Region, + Region?: Region; /** 发请求时带上的 Header 字段 */ - Headers?: Headers, + Headers?: Headers; } /** getService 接口返回值 */ interface GetServiceResult extends GeneralResult { Buckets: { /** 存储桶的名称,格式为,例如examplebucket-1250000000 */ - Name: Bucket, + Name: Bucket; /** 存储桶所在地域 */ - Location: Region, + Location: Region; /** 存储桶创建时间 */ - CreationDate: IsoDateTime, - }[], + CreationDate: IsoDateTime; + }[]; /** 所有者的信息 */ - Owner: Owner, + Owner: Owner; } // putBucket /** putBucket 接口参数 */ interface PutBucketParams extends BucketParams { /** 允许用户自定义存储桶权限,有效值:private | public-read | public-read-write,可选 */ - ACL?: BucketACL, + ACL?: BucketACL; /** 赋予被授权者读取对象的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantRead?: Grant, + GrantRead?: Grant; /** 赋予被授权者写取对象的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantWrite?: Grant, + GrantWrite?: Grant; /** 赋予被授权者读取对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantReadAcp?: Grant, + GrantReadAcp?: Grant; /** 赋予被授权者写入对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantWriteAcp?: Grant, + GrantWriteAcp?: Grant; /** 赋予被授权者操作对象的所有权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantFullControl?: Grant, + GrantFullControl?: Grant; /** 要创建存储桶的AZ类型,创建多AZ存储桶,传入 'MAZ' */ - BucketAZConfig?: 'MAZ' | string, + BucketAZConfig?: 'MAZ' | string; /** 如果创建索引多活存储桶,传入 'OFS' */ - BucketArchConfig?: 'OFS' | string, + BucketArchConfig?: 'OFS' | string; } /** putBucket 接口返回值 */ interface PutBucketResult extends GeneralResult { /** 创建的存储桶访问地址,不带 https:// 前缀,例如 examplebucket-1250000000.cos.ap-guangzhou.myqcloud.com/ */ - Location: Location + Location: Location; } // headBucket @@ -379,113 +393,113 @@ declare namespace COS { /** getBucket 接口参数 */ interface GetBucketParams extends BucketParams { /** 前缀匹配,用来规定返回的文件前缀地址,可选 */ - Prefix?: Prefix, + Prefix?: Prefix; /** 一个字符的分隔符,常用 / 字符,用于对对象键进行分组。所有对象键中从 prefix 或从头(如未指定 prefix)到首个 delimiter 之间相同的部分将作为 CommonPrefixes 下的一个 Prefix 节点。被分组的对象键不再出现在后续对象列表中,可选 */ - Delimiter?: Delimiter, + Delimiter?: Delimiter; /** 默认以UTF-8二进制顺序列出条目,所有列出条目从marker开始,可选 */ - Marker?: Key, + Marker?: Key; /** 单次返回最大的条目数量,默认值为1000,最大为1000,注意:该参数会限制每一次 List 操作返回的最大条目数,COS 在每次 List 操作中将返回不超过 max-keys 所设定数值的条目(即 CommonPrefixes 和 Contents 的总和),如果单次响应中未列出所有对象,COS 会返回 NextMarker 节点,其值作为您下次 List 请求的 marker 参数,以便您列出后续对象,可选 */ - MaxKeys?: number, + MaxKeys?: number; /** 规定返回值的编码方式,可选值:url,代表返回的对象键为 URL 编码(百分号编码)后的值,例如“腾讯云”将被编码为%E8%85%BE%E8%AE%AF%E4%BA%91 */ - EncodingType?: EncodingType, + EncodingType?: EncodingType; } /** 对象信息 */ interface CosObject { /** 对象键 */ - Key: Key, + Key: Key; /** 当前版本的最后修改时间,为 ISO8601 格式,例如2019-05-24T10:56:40Z */ - LastModified: IsoDateTime, + LastModified: IsoDateTime; /** 对象的实体标签(Entity Tag),是对象被创建时标识对象内容的信息标签,可用于检查对象的内容是否发生变化,例如“8e0b617ca298a564c3331da28dcb50df”,此头部并不一定返回对象的 MD5 值,而是根据对象上传和加密方式而有所不同 */ - ETag: ETag, + ETag: ETag; /** 对象大小,单位为 Byte */ - Size: string, + Size: string; /** 对象存储类型。枚举值 STANDARD | STANDARD_IA | ARCHIVE | DEEP_ARCHIVE | INTELLIGENT_TIERING | MAZ_STANDARD | MAZ_STANDARD_IA | MAZ_INTELLIGENT_TIERING @see https://cloud.tencent.com/document/product/436/33417 */ - StorageClass: StorageClass, + StorageClass: StorageClass; /** 当对象存储类型为智能分层存储时,指示对象当前所处的存储层,枚举值:FREQUENT(标准层),INFREQUENT(低频层)。仅当 StorageClass 为 INTELLIGENT_TIERING(智能分层)时才会返回该节点 */ - StorageTier?: string, + StorageTier?: string; /** 对象持有者信息 */ - Owner: Owner, + Owner: Owner; } /** getBucket 接口返回值 */ interface GetBucketResult extends GeneralResult { /** 对象条目 */ - Contents: CosObject[] + Contents: CosObject[]; /** 从 prefix 或从头(如未指定 prefix)到首个 delimiter 之间相同的部分,定义为 Common Prefix。仅当请求中指定了 delimiter 参数才有可能返回该节点 */ CommonPrefixes: { /** 前缀匹配,用来规定返回的文件前缀地址 */ - Prefix: Prefix, - }[], + Prefix: Prefix; + }[]; /** 响应条目是否被截断,布尔值,例如 true 或 false,可用于判断是否还需要继续列出文件 */ - IsTruncated: BooleanString, + IsTruncated: BooleanString; /** 仅当响应条目有截断(IsTruncated 为 true)才会返回该节点,该节点的值为当前响应条目中的最后一个对象键,当需要继续请求后续条目时,将该节点的值作为下一次请求的 marker 参数传入 */ - NextMarker?: string, + NextMarker?: string; } // listObjectVersions /** listObjectVersions 接口参数 */ interface ListObjectVersionsParams extends BucketParams { /** 前缀匹配,用来规定返回的文件前缀地址,可选 */ - Prefix?: Prefix, + Prefix?: Prefix; /** 一个字符的分隔符,常用 / 字符,用于对对象键进行分组。所有对象键中从 prefix 或从头(如未指定 prefix)到首个 delimiter 之间相同的部分将作为 CommonPrefixes 下的一个 Prefix 节点。被分组的对象键不再出现在后续对象列表中,可选 */ - Delimiter?: Delimiter, + Delimiter?: Delimiter; /** 默认以UTF-8二进制顺序列出条目,所有列出条目从marker开始,可选 */ - Marker?: string, + Marker?: string; /** 单次返回最大的条目数量,默认值为1000,最大为1000,注意:该参数会限制每一次 List 操作返回的最大条目数,COS 在每次 List 操作中将返回不超过 max-keys 所设定数值的条目(即 CommonPrefixes 和 Contents 的总和),如果单次响应中未列出所有对象,COS 会返回 NextMarker 节点,其值作为您下次 List 请求的 marker 参数,以便您列出后续对象,可选 */ - MaxKeys?: string, + MaxKeys?: string; /** 起始版本 ID 标记,从该标记之后(不含)返回对象版本条目,对应请求中的 url 参数 version-id-marker */ - VersionIdMarker?: string, + VersionIdMarker?: string; /** 规定返回值的编码方式,可选值:url,代表返回的对象键为 URL 编码(百分号编码)后的值,例如“腾讯云”将被编码为%E8%85%BE%E8%AE%AF%E4%BA%91 */ - EncodingType?: EncodingType, + EncodingType?: EncodingType; } /** 对象删除标记条目 */ interface DeleteMarker { /** 对象键 */ - Key: Key, + Key: Key; /** 对象的版本 ID;当未启用版本控制时,该节点的值为空字符串;当启用版本控制时,启用版本控制之前的对象,其版本 ID 为 null;当暂停版本控制时,新上传的对象其版本 ID 为 null,且同一个对象最多只存在一个版本 ID 为 null 的对象版本 */ - VersionId: VersionId, + VersionId: VersionId; /** 当前版本是否为该对象的最新版本 */ - IsLatest: string, + IsLatest: string; /** 当前版本的最后修改时间,为 ISO8601 格式,例如2019-05-24T10:56:40Z */ - LastModified: IsoDateTime, - Owner: Owner, + LastModified: IsoDateTime; + Owner: Owner; } interface ObjectVersion { /** 对象键 */ - Key: Key, + Key: Key; /** 对象的删除标记的版本 ID */ - VersionId: VersionId, + VersionId: VersionId; /** 当前版本是否为该对象的最新版本 */ - IsLatest: BooleanString, + IsLatest: BooleanString; /** 当前版本的最后修改时间,为 ISO8601 格式,例如2019-05-24T10:56:40Z */ - LastModified: IsoDateTime, + LastModified: IsoDateTime; /** 对象的实体标签(Entity Tag),是对象被创建时标识对象内容的信息标签,可用于检查对象的内容是否发生变化,例如"8e0b617ca298a564c3331da28dcb50df"。此头部并不一定返回对象的 MD5 值,而是根据对象上传和加密方式而有所不同 */ - ETag: ETag, + ETag: ETag; /** 对象大小,单位为 Byte */ - Size: string, + Size: string; /** 对象大小,单位为 Byte */ - Owner: Owner, + Owner: Owner; /** 对象存储类型。枚举值 STANDARD | STANDARD_IA | ARCHIVE | DEEP_ARCHIVE | INTELLIGENT_TIERING | MAZ_STANDARD | MAZ_STANDARD_IA | MAZ_INTELLIGENT_TIERING @see https://cloud.tencent.com/document/product/436/33417 */ - StorageClass: StorageClass, + StorageClass: StorageClass; /** 当对象存储类型为智能分层存储时,指示对象当前所处的存储层,枚举值:FREQUENT(标准层),INFREQUENT(低频层)。仅当 StorageClass 为 INTELLIGENT_TIERING(智能分层)时才会返回该节点 */ - StorageTier?: string, + StorageTier?: string; } /** listObjectVersions 接口返回值 */ interface ListObjectVersionsResult extends GeneralResult { /** 从 prefix 或从头(如未指定 prefix)到首个 delimiter 之间相同的部分,定义为 Common Prefix。仅当请求中指定了 delimiter 参数才有可能返回该节点 */ CommonPrefixes: { /** 前缀匹配,用来规定返回的文件前缀地址 */ - Prefix: Prefix, - }[], + Prefix: Prefix; + }[]; /** 对象版本条目 */ - Versions: ObjectVersion[], + Versions: ObjectVersion[]; /** 对象删除标记条目 */ - DeleteMarkers: DeleteMarker[], + DeleteMarkers: DeleteMarker[]; /** 响应条目是否被截断,布尔值,例如 true 或 false,可用于判断是否还需要继续列出文件 */ - IsTruncated: BooleanString, + IsTruncated: BooleanString; /** 仅当响应条目有截断(IsTruncated 为 true)才会返回该节点,该节点的值为当前响应条目中的最后一个对象键,当需要继续请求后续条目时,将该节点的值作为下一次请求的 marker 参数传入 */ - NextMarker?: string, + NextMarker?: string; /** 仅当响应条目有截断(IsTruncated 为 true)才会返回该节点,该节点的值为当前响应条目中的最后一个对象的版本 ID,当需要继续请求后续条目时,将该节点的值作为下一次请求的 version-id-marker 参数传入。该节点的值可能为空,此时下一次请求的 version-id-marker 参数也需要指定为空。 */ - NextVersionIdMarker?: string, + NextVersionIdMarker?: string; } // deleteBucket @@ -498,24 +512,24 @@ declare namespace COS { /** putBucketAcl 接口参数 */ interface PutBucketAclParams extends BucketParams { /** 允许用户自定义存储桶权限,有效值:private | public-read | public-read-write,可选 */ - ACL?: BucketACL, + ACL?: BucketACL; /** 赋予被授权者读取对象的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantRead?: Grant, + GrantRead?: Grant; /** 赋予被授权者写取对象的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantWrite?: Grant, + GrantWrite?: Grant; /** 赋予被授权者读取对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantReadAcp?: Grant, + GrantReadAcp?: Grant; /** 赋予被授权者写入对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantWriteAcp?: Grant, + GrantWriteAcp?: Grant; /** 赋予被授权者操作对象的所有权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantFullControl?: Grant, + GrantFullControl?: Grant; /** 放在 XML Body 的授权参数 */ AccessControlPolicy?: { /** 所有者的信息 */ - Owner: Owner, + Owner: Owner; /** 被授权者信息与权限信息 */ - Grants: Grants[] - } + Grants: Grants[]; + }; } /** putBucketAcl 接口返回值 */ interface PutBucketAclResult extends GeneralResult {} @@ -526,21 +540,21 @@ declare namespace COS { /** getBucketAcl 接口返回值 */ interface GetBucketAclResult extends GeneralResult { /** 允许用户自定义存储桶权限,有效值:private | public-read | public-read-write */ - ACL: BucketACL, + ACL: BucketACL; /** 赋予被授权者读取对象的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者 */ - GrantRead: Grant, + GrantRead: Grant; /** 赋予被授权者写取对象的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者 */ - GrantWrite: Grant, + GrantWrite: Grant; /** 赋予被授权者读取对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者 */ - GrantReadAcp: Grant, + GrantReadAcp: Grant; /** 赋予被授权者写入对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者 */ - GrantWriteAcp: Grant, + GrantWriteAcp: Grant; /** 赋予被授权者操作对象的所有权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者 */ - GrantFullControl: Grant, + GrantFullControl: Grant; /** 存储桶持有者信息 */ - Owner: Owner, + Owner: Owner; /** 被授权者信息与权限信息 */ - Grants: Grants[], + Grants: Grants[]; } // putBucketCors @@ -550,27 +564,27 @@ declare namespace COS { 支持单个具体域名,例如 http://www.example.com。 支持 * 通配符,通配符可出现在任何位置,包括协议、域名和端口,可匹配0个或多个字符,但是只能有一个 *。请谨慎使用通配符,因为可能意外匹配到非预期的来源 注意不要遗漏协议名 http 或 https,若端口不是默认的80(http)或443(https),还需要带上端口,例如 https://example.com:8443。 */ - AllowedOrigin: string[], + AllowedOrigin: string[]; /** 允许的 HTTP 操作方法(Method),对应 CORS 请求响应中的 Access-Control-Allow-Methods 头部,单条 CORSRule 可以配置多个 AllowedMethod。枚举值:PUT、GET、POST、DELETE、HEAD。 */ - AllowedMethod: string[], + AllowedMethod: string[]; /** 在发送预检(OPTIONS)请求时,浏览器会告知服务端接下来的正式请求将使用的自定义 HTTP 请求头部,此配置用于指定允许浏览器发送 CORS 请求时携带的自定义 HTTP 请求头部,不区分英文大小写,单条 CORSRule 可以配置多个 AllowedHeader。 可以配置*,代表允许所有头部,为了避免遗漏,推荐配置为*。 如果不配置为*,那么在预检(OPTIONS)请求中 Access-Control-Request-Headers 头部出现的每个 Header,都必须在 AllowedHeader 中有对应项。 */ - AllowedHeader?: string[], + AllowedHeader?: string[]; /** 允许浏览器获取的 CORS 请求响应中的头部,不区分大小写,单条 CORSRule 可以配置多个 ExposeHeader。 默认情况下浏览器只能访问简单响应头部:Cache-Control、Content-Type、Expires、Last-Modified,如果需要访问其他响应头部,需要添加 ExposeHeader 配置。 不支持配置为 *,必须明确配置具体的 Header。 根据浏览器的实际需求确定,默认推荐填写 ETag,可参考各 API 文档的响应头部分及 公共响应头部 文档。@see https://cloud.tencent.com/document/product/436/7729 */ - ExposeHeader?: string[], + ExposeHeader?: string[]; /** 跨域资源共享配置的有效时间,单位为秒,在有效时间内,浏览器无须为同一请求再次发起预检(OPTIONS)请求,对应 CORS 请求响应中的 Access-Control-Max-Age 头部,单条 CORSRule 只能配置一个 MaxAgeSeconds。 */ - MaxAgeSeconds?: number, + MaxAgeSeconds?: number; }; /** putBucketCors 接口参数 */ interface PutBucketCorsParams extends BucketParams { /** 存储桶跨域资源共享(CORS)访问控制规则 */ - CORSRules: CORSRule[], + CORSRules: CORSRule[]; /** 是否允许同一个 url 有多份缓存,如果设置为 true 浏览器在 img 标签加载和 ajax 加载同一个对象 url 将会使用不同缓存 */ - ResponseVary?: BooleanString, + ResponseVary?: BooleanString; } /** putBucketCors 接口返回值 */ interface PutBucketCorsResult extends GeneralResult {} @@ -581,9 +595,9 @@ declare namespace COS { /** getBucketCors 接口返回值 */ interface GetBucketCorsResult extends GeneralResult { /** 存储桶跨域资源共享(CORS)访问控制规则 */ - CORSRules: Record, + CORSRules: Record; /** 是否允许同一个 url 有多份缓存,如果设置为 true 浏览器在 img 标签加载和 ajax 加载同一个对象 url 将会使用不同缓存 */ - ResponseVary?: BooleanString, + ResponseVary?: BooleanString; } // deleteBucketCors @@ -595,7 +609,7 @@ declare namespace COS { // getBucketLocation interface GetBucketLocationResult { /** 存储桶所在地域 */ - LocationConstraint: Region, + LocationConstraint: Region; } /** getBucketLocation 接口参数 */ interface GetBucketLocationParams extends BucketParams {} @@ -604,7 +618,7 @@ declare namespace COS { /** putBucketPolicy 接口参数 */ interface PutBucketPolicyParams extends BucketParams { /** 存储桶的权限策略 @see https://cloud.tencent.com/document/product/436/31923 */ - Policy: Record, + Policy: Record; } /** putBucketPolicy 接口返回值 */ interface PutBucketPolicyResult extends GeneralResult {} @@ -615,7 +629,7 @@ declare namespace COS { /** getBucketPolicy 接口返回值 */ interface GetBucketPolicyResult extends GeneralResult { /** 存储桶的权限策略 @see https://cloud.tencent.com/document/product/436/31923 */ - Policy: Record + Policy: Record; } // deleteBucketPolicy @@ -628,7 +642,7 @@ declare namespace COS { /** putBucketTagging 接口参数 */ interface PutBucketTaggingParams extends BucketParams { /** 标签集合,最多支持10个标签 */ - Tags: Tag[], + Tags: Tag[]; } /** putBucketTagging 接口返回值 */ interface PutBucketTaggingResult extends GeneralResult {} @@ -639,7 +653,7 @@ declare namespace COS { /** getBucketTagging 接口返回值 */ interface GetBucketTaggingResult extends GeneralResult { /** 标签集合,最多支持10个标签 */ - Tags: Tag[] + Tags: Tag[]; } // deleteBucketTagging @@ -652,26 +666,26 @@ declare namespace COS { /** 生命周期配置规则 */ type LifecycleRule = { /** 用于唯一地标识规则,长度不能超过255个字符,可选 */ - ID: string, + ID: string; /** 指明规则是否启用,枚举值:Enabled,Disabled,必选 */ - Status: 'Enabled' | 'Disabled', + Status: 'Enabled' | 'Disabled'; /** Filter 用于描述规则影响的 Object 集合,必选 */ - Filter?: Record, + Filter?: Record; /** 规则转换属性,对象何时转换为 Standard_IA 或 Archive 等存储类型 */ - Transition?: Record, + Transition?: Record; /** 规则过期属性 */ - Expiration?: Record, + Expiration?: Record; /** 设置允许分片上传保持运行的最长时间 */ - AbortIncompleteMultipartUpload?: Record, + AbortIncompleteMultipartUpload?: Record; /** 指明非当前版本对象何时过期 */ - NoncurrentVersionExpiration?: Record, + NoncurrentVersionExpiration?: Record; /** 指明非当前版本对象何时转换为 STANDARD_IA 或 ARCHIVE 等存储类型 */ - NoncurrentVersionTransition?: Record, + NoncurrentVersionTransition?: Record; }; /** putBucketLifecycle 接口参数 */ interface PutBucketLifecycleParams extends BucketParams { /** 生命周期配置规则列表 */ - Rules: LifecycleRule[], + Rules: LifecycleRule[]; } /** putBucketLifecycle 接口返回值 */ interface PutBucketLifecycleResult extends GeneralResult {} @@ -682,7 +696,7 @@ declare namespace COS { /** getBucketLifecycle 接口返回值 */ interface GetBucketLifecycleResult extends GeneralResult { /** 生命周期配置规则列表 */ - Rules: LifecycleRule[] + Rules: LifecycleRule[]; } // deleteBucketLifecycle @@ -695,12 +709,12 @@ declare namespace COS { /** 存储桶版本控制开关信息 */ interface VersioningConfiguration { /** 说明版本是否开启,枚举值:Suspended、Enabled */ - Status: 'Enabled' | 'Suspended', + Status: 'Enabled' | 'Suspended'; } /** putBucketVersioning 接口参数 */ interface PutBucketVersioningParams extends BucketParams { /** 存储桶版本控制开关信息 */ - VersioningConfiguration: VersioningConfiguration, + VersioningConfiguration: VersioningConfiguration; } /** putBucketVersioning 接口返回值 */ interface PutBucketVersioningResult extends GeneralResult {} @@ -711,36 +725,36 @@ declare namespace COS { /** getBucketVersioning 接口返回值 */ interface GetBucketVersioningResult extends GeneralResult { /** 存储桶版本控制开关信息 */ - VersioningConfiguration: VersioningConfiguration, + VersioningConfiguration: VersioningConfiguration; } // putBucketReplication interface ReplicationRule { /** 用来标注具体 Rule 的名称 */ - ID?: string, + ID?: string; /** 标识 Rule 是否生效,枚举值:Enabled, Disabled */ - Status: 'Enabled' | 'Disabled', + Status: 'Enabled' | 'Disabled'; /** 前缀匹配,用来规定返回的文件前缀地址 */ - Prefix: Prefix, + Prefix: Prefix; /** 目标存储桶信息 */ Destination: { /** 资源标识符:qcs::cos::: */ - Bucket: string, + Bucket: string; /** 存储类型,枚举值:STANDARD,INTELLIGENT_TIERING,STANDARD_IA 等。默认值:原存储类型 */ - StorageClass?: StorageClass, - } + StorageClass?: StorageClass; + }; } /** 说明所有复制配置信息 */ interface ReplicationConfiguration { /** 发起者身份标示:qcs::cam::uin/<OwnerUin>:uin/<SubUin> */ - Role: string, + Role: string; /** 具体配置信息,最多支持1000个,所有策略只能指向一个目标存储桶 */ - Rules: ReplicationRule[] + Rules: ReplicationRule[]; } /** putBucketReplication 接口参数 */ interface PutBucketReplicationParams extends BucketParams { /** 说明所有复制配置信息 */ - ReplicationConfiguration: ReplicationConfiguration, + ReplicationConfiguration: ReplicationConfiguration; } /** putBucketReplication 接口返回值 */ interface PutBucketReplicationResult extends GeneralResult {} @@ -751,7 +765,7 @@ declare namespace COS { /** getBucketReplication 接口返回值 */ interface GetBucketReplicationResult extends GeneralResult { /** 说明所有复制配置信息 */ - ReplicationConfiguration: ReplicationConfiguration, + ReplicationConfiguration: ReplicationConfiguration; } // deleteBucketReplication @@ -766,49 +780,49 @@ declare namespace COS { /** 索引文档配置 */ IndexDocument: { /** 指定索引文档的对象键后缀。例如指定为index.html,那么当访问到存储桶的根目录时,会自动返回 index.html 的内容,或者当访问到article/目录时,会自动返回 article/index.html的内容 */ - Suffix: string, - }, + Suffix: string; + }; /** 重定向所有请求配置 */ RedirectAllRequestsTo?: { /** 指定重定向所有请求的目标协议,只能设置为 https */ - Protocol: "https" | string - }, + Protocol: 'https' | string; + }; /** 用于配置是否忽略扩展名 */ AutoAddressing?: { /** 用于配置是否忽略 HTML 拓展名,可选值为 Enabled 或 Disabled,默认为 Disabled */ - Status: 'Disabled' | 'Enabled' - }, + Status: 'Disabled' | 'Enabled'; + }; /** 错误文档配置 */ ErrorDocument?: { /** 指定通用错误文档的对象键,当发生错误且未命中重定向规则中的错误码重定向时,将返回该对象键的内容 */ - Key: Key, + Key: Key; /** 用于配置命中错误文档的 HTTP 状态码,可选值为 Enabled 或 Disabled,默认为 Enabled */ - OriginalHttpStatus?: 'Enabled' | 'Disabled' - }, + OriginalHttpStatus?: 'Enabled' | 'Disabled'; + }; /** 重定向规则配置,最多设置100条 RoutingRule */ RoutingRules?: { /** 重定向规则的条件配置 */ Condition: { /** 指定重定向规则的错误码匹配条件,只支持配置4XX返回码,例如403或404,HttpErrorCodeReturnedEquals 与 KeyPrefixEquals 必选其一 */ - HttpErrorCodeReturnedEquals?: string | number, + HttpErrorCodeReturnedEquals?: string | number; /** 指定重定向规则的对象键前缀匹配条件,HttpErrorCodeReturnedEquals 与 KeyPrefixEquals 必选其一 */ - KeyPrefixEquals?: 'Enabled' | 'Disabled', - }, + KeyPrefixEquals?: 'Enabled' | 'Disabled'; + }; /** 重定向规则的具体重定向目标配置 */ Redirect: { /** 指定重定向规则的目标协议,只能设置为 https */ - Protocol?: 'https' | string, + Protocol?: 'https' | string; /** 指定重定向规则的具体重定向目标的对象键,替换方式为替换整个原始请求的对象键,ReplaceKeyWith 与 ReplaceKeyPrefixWith 必选其一 */ - ReplaceKeyWith?: string, + ReplaceKeyWith?: string; /** 指定重定向规则的具体重定向目标的对象键,替换方式为替换原始请求中所匹配到的前缀部分,仅可在 Condition 为 KeyPrefixEquals 时设置,ReplaceKeyWith 与 ReplaceKeyPrefixWith 必选其一 */ - ReplaceKeyPrefixWith?: string, - }, - }[], + ReplaceKeyPrefixWith?: string; + }; + }[]; } /** putBucketWebsite 接口参数 */ interface PutBucketWebsiteParams extends BucketParams { /** 存储桶配置静态网站配置信息 */ - WebsiteConfiguration: WebsiteConfiguration, + WebsiteConfiguration: WebsiteConfiguration; } /** putBucketWebsite 接口返回值 */ interface PutBucketWebsiteResult extends GeneralResult {} @@ -819,7 +833,7 @@ declare namespace COS { /** getBucketWebsite 接口返回值 */ interface GetBucketWebsiteResult extends GeneralResult { /** 存储桶配置静态网站配置信息 */ - WebsiteConfiguration: WebsiteConfiguration + WebsiteConfiguration: WebsiteConfiguration; } // deleteBucketWebsite @@ -832,21 +846,21 @@ declare namespace COS { /** 防盗链配置信息 */ interface RefererConfiguration { /** 是否开启防盗链,枚举值:Enabled、Disabled */ - Status: 'Enabled' | 'Disabled', + Status: 'Enabled' | 'Disabled'; /** 防盗链类型,枚举值:Black-List、White-List */ - RefererType: 'Black-List' | 'White-List', + RefererType: 'Black-List' | 'White-List'; /** 生效域名列表, 支持多个域名且为前缀匹配, 支持带端口的域名和 IP, 支持通配符*,做二级域名或多级域名的通配 */ DomainList: { /** 生效域名,例如www.qq.com/example,192.168.1.2:8080, *.qq.com */ - Domains: string[] - }, + Domains: string[]; + }; /** 是否允许空 Referer 访问,枚举值:Allow、Deny,默认值为 Deny */ - EmptyReferConfiguration?: 'Allow' | 'Deny', + EmptyReferConfiguration?: 'Allow' | 'Deny'; } /** putBucketReferer 接口参数 */ interface PutBucketRefererParams extends BucketParams { /** 防盗链配置信息 */ - RefererConfiguration: RefererConfiguration, + RefererConfiguration: RefererConfiguration; } /** putBucketReferer 接口返回值 */ interface PutBucketRefererResult extends GeneralResult {} @@ -857,25 +871,25 @@ declare namespace COS { /** getBucketReferer 接口返回值 */ interface GetBucketRefererResult extends GeneralResult { /** 防盗链配置信息 */ - RefererConfiguration: RefererConfiguration, + RefererConfiguration: RefererConfiguration; } // putBucketDomain /** 绑定的域名条目 */ interface DomainRule { /** 是否启用。枚举值:ENABLED:启用,DISABLED:禁用,必选 */ - Status: 'DISABLED' | 'ENABLED', + Status: 'DISABLED' | 'ENABLED'; /** 完整域名,必选 */ - Name: string, + Name: string; /** 源站类型。枚举值:REST:默认源站,WEBSITE:静态源站源站,ACCELERATE:全球加速源站,必选 */ - Type: 'REST' | 'WEBSITE' | 'ACCELERATE', + Type: 'REST' | 'WEBSITE' | 'ACCELERATE'; /** 如果指定域名已经作为其他存储桶的自定义域名,那么可以指定该元素强制将该域名作为当前存储桶的自定义域名。当前只支持 CNAME,代表您需要先将该域名的 CNAME 指向当前存储桶的源站域名(根据 Type 元素的不同对应为默认源站、静态网站源站或全球加速源站)后才能通过该接口设置自定义域名。可选 */ - ForcedReplacement?: string, + ForcedReplacement?: string; } /** putBucketDomain 接口参数 */ interface PutBucketDomainParams extends BucketParams { /** 绑定的域名条目 */ - DomainRule: DomainRule[], + DomainRule: DomainRule[]; } /** putBucketDomain 接口返回值 */ interface PutBucketDomainResult extends GeneralResult {} @@ -886,7 +900,7 @@ declare namespace COS { /** getBucketDomain 接口返回值 */ interface GetBucketDomainResult extends GeneralResult { /** 绑定的域名条目 */ - DomainRule: DomainRule[] + DomainRule: DomainRule[]; } // deleteBucketDomain @@ -899,68 +913,68 @@ declare namespace COS { /** Origin 回源规则配置 */ interface OriginRule { /** 通过优先级区分规则执行先后,必选 */ - RulePriority: 1 + RulePriority: 1; /** 回源类型,支持同步回源(Mirror)和异步回源(Proxy)两种模式。 枚举值:Mirror、Proxy。必选 */ - OriginType: 'Mirror' | 'Proxy', + OriginType: 'Mirror' | 'Proxy'; /** 回源配置,配置用户使用的 HTTP 传输协议等信息。必选 */ OriginCondition: { /** 触发回源的 HTTP 状态码,默认为404。必选 */ - HTTPStatusCode: number, + HTTPStatusCode: number; /** 触发回源的文件前缀,默认为空,任意文件均可触发。可选 */ - Prefix: Prefix, - }, + Prefix: Prefix; + }; /** 回源地址相关信息,必选 */ OriginParameter: { /** 回源使用的协议,枚举值为 HTTP(使用 HTTP 协议),HTTPS(使用 HTTPS 协议)、FOLLOW(跟随用户使用的协议),默认值为 FOLLOW。必选 */ - Protocol: 'HTTP' | 'HTTPS' | 'FOLLOW', + Protocol: 'HTTP' | 'HTTPS' | 'FOLLOW'; /** Proxy 模式下是否需要透传 HTTP 请求串,枚举值:true、false,默认为 true。可选 */ - FollowQueryString?: BooleanString, + FollowQueryString?: BooleanString; /** Proxy 模式下是否需要 Http 头部传输配置。可选 */ HttpHeader?: { /** Proxy 模式下是否传输请求头部,枚举值:true、false,默认为 false。可选 */ - FollowHttpHeader?: BooleanString, + FollowHttpHeader?: BooleanString; /** 设置 Proxy 模式传输的请求头部。可选 */ NewHttpHeader?: { /** 回源到源站时添加新的自定义头部,默认为空。可选 */ Header?: { /** 用户设置的头部名称,默认为空。形式如 x-cos、oss、amz-ContentType、CacheControl、ContentDisposition、ContentEncoding、HttpExpiresDate、UserMetaData。可选 */ - Key?: string, + Key?: string; /** 用户设置的头部值,默认为空。可选 */ - Value?: string - }[] - }, - }, + Value?: string; + }[]; + }; + }; /** Proxy 模式下源站 3XX 响应策略,枚举值:true、false,选择 true 时跟随源站 3xx 重定向请求获取到资源,并将资源保存到 COS 上;选择 false 时透传 3XX 响应,不获取资源),默认为 true。可选 */ - FollowRedirection: BooleanString, + FollowRedirection: BooleanString; /** Proxy 模式下的返回码参数,枚举值:301、302,默认为 302。可选 */ - HttpRedirectCode: ('301' | '302')[] - }, + HttpRedirectCode: ('301' | '302')[]; + }; /** 回源配置,配置用户使用的 HTTP 传输协议等信息。必选 */ OriginInfo: { /** 源站信息。必选 */ HostInfo: { /** 源站域名或者源站 IP。必选 */ - HostName: string - }, + HostName: string; + }; /** 回源文件信息。必选 */ FileInfo: { /** 回源文件前缀配置信息。可选 */ PrefixConfiguration: { /** 回源文件的文件前缀,默认为空。可选 */ - Prefix: Prefix - }, + Prefix: Prefix; + }; /** 回源文件后缀配置信息。可选 */ SuffixConfiguration: { /** 回源文件的文件后缀,默认为空。可选 */ - Suffix: string - } - } - }, + Suffix: string; + }; + }; + }; } /** putBucketOrigin 接口参数 */ interface PutBucketOriginParams extends BucketParams { /** Origin 回源规则配置 */ - OriginRule: OriginRule[], + OriginRule: OriginRule[]; } /** putBucketOrigin 接口返回值 */ interface PutBucketOriginResult extends GeneralResult {} @@ -971,7 +985,7 @@ declare namespace COS { /** getBucketOrigin 接口返回值 */ interface GetBucketOriginResult extends GeneralResult { /** Origin 回源规则配置 */ - OriginRule: OriginRule[], + OriginRule: OriginRule[]; } // deleteBucketOrigin @@ -985,15 +999,15 @@ declare namespace COS { /** 存储桶 logging 设置的具体信息,主要是目标存储桶 */ LoggingEnabled?: { /** 存放日志的目标存储桶,可以是同一个存储桶(但不推荐),或同一账户下、同一地域的存储桶 */ - TargetBucket: Bucket, + TargetBucket: Bucket; /** 日志存放在目标存储桶的指定路径 */ - TargetPrefix: Prefix, - } + TargetPrefix: Prefix; + }; } /** putBucketLogging 接口参数 */ interface PutBucketLoggingParams extends BucketParams { /** 说明日志记录配置的状态,如果无子节点信息则意为关闭日志记录 */ - BucketLoggingStatus: BucketLoggingStatus, + BucketLoggingStatus: BucketLoggingStatus; } /** putBucketLogging 接口返回值 */ interface PutBucketLoggingResult extends GeneralResult {} @@ -1004,55 +1018,55 @@ declare namespace COS { /** getBucketLogging 接口返回值 */ interface GetBucketLoggingResult extends GeneralResult { /** 说明日志记录配置的状态,如果无子节点信息则意为关闭日志记录 */ - BucketLoggingStatus: BucketLoggingStatus, + BucketLoggingStatus: BucketLoggingStatus; } // putBucketInventory /** putBucketInventory 接口参数 */ interface InventoryConfiguration { /** 清单的名称,与请求参数中的 id 对应,可选 */ - Id: string, + Id: string; /** 清单是否启用的标识:如果设置为 true,清单功能将生效,如果设置为 false,将不生成任何清单,必选 */ - IsEnabled: BooleanString, + IsEnabled: BooleanString; /** 是否在清单中包含对象版本:如果设置为 All,清单中将会包含所有对象版本,并在清单中增加 VersionId,IsLatest,DeleteMarker 这几个字段,如果设置为 Current,则清单中不包含对象版本信息,必选 */ - IncludedObjectVersions: 'All' | 'Current', + IncludedObjectVersions: 'All' | 'Current'; /** 筛选待分析对象。清单功能将分析符合 Filter 中设置的前缀的对象,可选 */ Filter?: { /** 筛选待分析对象。清单功能将分析符合 Filter 中设置的前缀的对象,可选 */ - Prefix?: Prefix - }, + Prefix?: Prefix; + }; /** 设置清单结果中应包含的分析项目,可选 */ - OptionalFields?: string[], + OptionalFields?: string[]; /** 配置清单任务周期,必选 */ Schedule: { /** 清单任务周期,可选项为按日或者按周,枚举值:Daily、Weekly,必选 */ - Frequency: 'Daily' | 'Weekly' - }, + Frequency: 'Daily' | 'Weekly'; + }; /** 描述存放清单结果的信息,必选 */ Destination: { /** 清单结果导出后存放的存储桶信息,必选 */ COSBucketDestination: { /** 清单分析结果的存储桶名,如:qcs::cos:ap-guangzhou::bucket-logging-1250000000,必选 */ - Bucket: string, + Bucket: string; /** 清单分析结果的文件形式,可选项为 CSV 格式,必选 */ - Format: 'CSV', + Format: 'CSV'; /** 存储桶的所有者 ID,例如100000000001,可选 */ - AccountId?: string, + AccountId?: string; /** 清单分析结果的前缀,可选 */ - Prefix?: Prefix, + Prefix?: Prefix; /** 为清单结果提供服务端加密的选项,可选 */ Encryption?: { /** COS 托管密钥的加密方式,无需填充,可选 */ - SSECOS?: '' - } - } - } + SSECOS?: ''; + }; + }; + }; } interface PutBucketInventoryParams extends BucketParams { /** 清单的名称,与请求参数中的 id 对应 */ - Id: string, + Id: string; /** 包含清单任务的详细信息 */ - InventoryConfiguration: InventoryConfiguration, + InventoryConfiguration: InventoryConfiguration; } /** putBucketInventory 接口返回值 */ interface PutBucketInventoryResult extends GeneralResult {} @@ -1061,12 +1075,12 @@ declare namespace COS { /** getBucketInventory 接口参数 */ interface GetBucketInventoryParams extends BucketParams { /** 清单的名称,与请求参数中的 id 对应 */ - Id: string, + Id: string; } /** getBucketInventory 接口返回值 */ interface GetBucketInventoryResult extends GeneralResult { /** 包含清单任务的详细信息 */ - InventoryConfiguration: InventoryConfiguration + InventoryConfiguration: InventoryConfiguration; } // listBucketInventory @@ -1075,19 +1089,19 @@ declare namespace COS { /** listBucketInventory 接口返回值 */ interface ListBucketInventoryResult extends GeneralResult { /** 包含清单任务的详细信息 */ - InventoryConfigurations: Record, + InventoryConfigurations: Record; /** 当 COS 响应体中 IsTruncated 为 true,且 NextContinuationToken 节点中存在参数值时,您可以将这个参数作为 continuation-token 参数值,以获取下一页的清单任务信息。缺省值:None */ - ContinuationToken: string, + ContinuationToken: string; /** 是否已列出所有清单任务信息的标识。如果已经展示完则为 false,否则为 true */ - IsTruncated: BooleanString, + IsTruncated: BooleanString; /** 下一页清单列表的标识。如果该参数中有值,则可将该值作为 continuation-token 参数并发起 GET 请求以获取下一页清单任务信息 */ - NextContinuationToken?: string, + NextContinuationToken?: string; } // deleteBucketInventory /** deleteBucketInventory 接口参数 */ interface DeleteBucketInventoryParams extends BucketParams { - Id: string, + Id: string; } /** deleteBucketInventory 接口返回值 */ interface DeleteBucketInventoryResult extends GeneralResult {} @@ -1096,12 +1110,12 @@ declare namespace COS { /** 全球加速的具体信息 */ interface AccelerateConfiguration { /** 说明全球加速功能是否开启,枚举值:Suspended、Enabled */ - Status: 'Enabled' | 'Suspended', + Status: 'Enabled' | 'Suspended'; } /** putBucketAccelerate 接口参数 */ interface PutBucketAccelerateParams extends BucketParams { /** 全球加速的具体信息 */ - AccelerateConfiguration: AccelerateConfiguration, + AccelerateConfiguration: AccelerateConfiguration; } /** putBucketAccelerate 接口返回值 */ interface PutBucketAccelerateResult extends GeneralResult {} @@ -1112,7 +1126,7 @@ declare namespace COS { /** getBucketAccelerate 接口返回值 */ interface GetBucketAccelerateResult extends GeneralResult { /** 全球加速的具体信息 */ - InventoryConfiguration: AccelerateConfiguration, + InventoryConfiguration: AccelerateConfiguration; } // putBucketEncryption @@ -1121,18 +1135,18 @@ declare namespace COS { /** 服务端加密的默认配置信息 */ ApplySideEncryptionConfiguration: { /** 要使用的服务端加密算法,枚举值:AES256 */ - SSEAlgorithm: 'AES256' - }, + SSEAlgorithm: 'AES256'; + }; } /** 包含默认加密的配置参数 */ interface ServerSideEncryptionConfiguration { /** 默认的服务端加密配置规则 */ - Rule: EncryptionRule[], + Rule: EncryptionRule[]; } /** putBucketEncryption 接口参数 */ interface PutBucketEncryptionParams extends BucketParams { /** 包含默认加密的配置参数 */ - ServerSideEncryptionConfiguration: ServerSideEncryptionConfiguration, + ServerSideEncryptionConfiguration: ServerSideEncryptionConfiguration; } /** putBucketEncryption 接口返回值 */ interface PutBucketEncryptionResult extends GeneralResult {} @@ -1143,7 +1157,7 @@ declare namespace COS { /** getBucketEncryption 接口返回值 */ interface GetBucketEncryptionResult extends GeneralResult { /** 默认加密的配置参数 */ - ServerSideEncryptionConfiguration: ServerSideEncryptionConfiguration, + ServerSideEncryptionConfiguration: ServerSideEncryptionConfiguration; } // deleteBucketEncryption @@ -1158,9 +1172,9 @@ declare namespace COS { /** headObject 接口返回值 */ interface HeadObjectResult extends GeneralResult { /** 对象的实体标签(Entity Tag),是对象被创建时标识对象内容的信息标签,可用于检查对象的内容是否发生变化,例如"8e0b617ca298a564c3331da28dcb50df"。此头部并不一定返回对象的 MD5 值,而是根据对象上传和加密方式而有所不同 */ - ETag: ETag, + ETag: ETag; /** 对象的版本 ID */ - VersionId?: string, + VersionId?: string; } // getObject @@ -1170,99 +1184,99 @@ declare namespace COS { // nodejs getObject 不支持传参BodyType // BodyType?: 'text' | 'blob' | 'arraybuffer', /** 写入流,可以传本地文件写入流 */ - Output?: Stream, + Output?: Stream; /** 请求里的 Url Query 参数,传入该值中的 key/value 将会被 URLEncode */ - Query?: Query, + Query?: Query; /** 请求里的 Url Query 参数。传入该值将直接拼接在 Url 上,不会对其进行 URLEncode */ - QueryString?: string, + QueryString?: string; /** 当对象在指定时间后被修改,则返回对象,否则返回 HTTP 状态码为304(Not Modified) */ - IfModifiedSince?: string, + IfModifiedSince?: string; /** 当对象在指定时间后未被修改,则返回对象,否则返回 HTTP 状态码为412(Precondition Failed) */ - IfUnmodifiedSince?: string, + IfUnmodifiedSince?: string; /** 当对象的 ETag 与指定的值一致,则返回对象,否则返回 HTTP 状态码为412(Precondition Failed) */ - IfMatch?: string, + IfMatch?: string; /** 当对象的 ETag 与指定的值不一致,则返回对象,否则返回 HTTP 状态码为304(Not Modified) */ - IfNoneMatch?: string, + IfNoneMatch?: string; /** 针对本次下载进行流量控制的限速值,必须为数字,单位默认为 bit/s。限速值设置范围为819200 - 838860800,即100KB/s - 100MB/s,如果超出该范围将返回400错误 */ - TrafficLimit?: number, + TrafficLimit?: number; /** 设置响应中的 Cache-Control 头部的值 */ - ResponseCacheControl?: string, + ResponseCacheControl?: string; /** 设置响应中的 Content-Disposition 头部的值 */ - ResponseContentDisposition?: string, + ResponseContentDisposition?: string; /** 设置响应中的 Content-Encoding 头部的值 */ - ResponseContentEncoding?: string, + ResponseContentEncoding?: string; /** 设置响应中的 Content-Language 头部的值 */ - ResponseContentLanguage?: string, + ResponseContentLanguage?: string; /** 设置响应中的 Content-Type 头部的值 */ - ResponseExpires?: string, + ResponseExpires?: string; /** 设置响应中的 Expires 头部的值 */ - ResponseContentType?: string, + ResponseContentType?: string; /** RFC 2616 中定义的字节范围,范围值必须使用 bytes=first-last 格式,first 和 last 都是基于0开始的偏移量。例如 bytes=0-9 表示下载对象的开头10个字节的数据 ,如果不指定,则表示下载整个对象 */ - Range?: string, + Range?: string; /** 当启用版本控制时,指定要下载的版本 ID,如不指定则下载对象的最新版本 */ - VersionId?: string, + VersionId?: string; /** 下载的进度回调方法 */ - onProgress?: onProgress, + onProgress?: onProgress; } /** getObject 接口返回值 */ interface GetObjectResult extends GeneralResult { /** 对象内容 */ - Body: Buffer, + Body: Buffer; /** 对象的实体标签(Entity Tag),是对象被创建时标识对象内容的信息标签,可用于检查对象的内容是否发生变化,例如"8e0b617ca298a564c3331da28dcb50df"。此头部并不一定返回对象的 MD5 值,而是根据对象上传和加密方式而有所不同 */ - ETag: ETag, + ETag: ETag; /** 对象的版本 ID */ - VersionId?: string, + VersionId?: string; } // putObject /** putObject 接口参数 */ interface PutObjectParams extends ObjectParams { /** 要上传对象内容 */ - Body: UploadBody, + Body: UploadBody; /** 上传的文件大小,单位 Byte 字节,如果不传且 Body 是流,会走服务端流式上传 */ - ContentLength?: number, + ContentLength?: number; /** 请求里的 Url Query 参数 */ - Query?: string, + Query?: string; /** RFC 2616 中定义的缓存指令,将作为对象元数据保存 */ - CacheControl?: string, + CacheControl?: string; /** RFC 2616 中定义的文件名称,将作为对象元数据保存 */ - ContentDisposition?: string, + ContentDisposition?: string; /** RFC 2616 中定义的编码格式,将作为对象元数据保存 */ - ContentEncoding?: string, + ContentEncoding?: string; /** RFC 2616 中定义的 HTTP 请求内容类型(MIME),此头部用于描述待上传对象的内容类型,将作为对象元数据保存。例如text/html或image/jpeg */ - ContentType?: string, + ContentType?: string; /** RFC 2616 中定义的缓存失效时间,将作为对象元数据保存 */ - Expires?: string, + Expires?: string; /** RFC 2616 中定义的缓存失效时间,将作为对象元数据保存 */ - Expect?: string, + Expect?: string; /** 允许用户自定义存储桶权限,有效值:private | public-read | public-read-write,可选 */ - ACL?: ObjectACL, + ACL?: ObjectACL; /** 赋予被授权者读取对象的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantRead?: Grant, + GrantRead?: Grant; /** 赋予被授权者读取对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantReadAcp?: Grant, + GrantReadAcp?: Grant; /** 赋予被授权者写入对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantWriteAcp?: Grant, + GrantWriteAcp?: Grant; /** 赋予被授权者操作对象的所有权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantFullControl?: Grant, + GrantFullControl?: Grant; /** 对象存储类型。例如 STANDARD | STANDARD_IA | ARCHIVE | DEEP_ARCHIVE | INTELLIGENT_TIERING | MAZ_STANDARD | MAZ_STANDARD_IA | MAZ_INTELLIGENT_TIERING。默认值:STANDARD */ - StorageClass?: StorageClass, + StorageClass?: StorageClass; /** 包括用户自定义元数据头部后缀和用户自定义元数据信息,将作为对象元数据保存,大小限制为2KB,注意:用户自定义元数据信息支持下划线(_),但用户自定义元数据头部后缀不支持下划线,仅支持减号(-) */ - 'x-cos-meta-*'?: string, + 'x-cos-meta-*'?: string; /** 任务开始上传的回调方法 */ - onTaskReady?: (TaskId: COS.TaskId) => void, - onTaskStart?: (TaskInfo: COS.Task) => void, + onTaskReady?: (TaskId: COS.TaskId) => void; + onTaskStart?: (TaskInfo: COS.Task) => void; /** 上传的进度回调方法 */ - onProgress?: onProgress, + onProgress?: onProgress; } /** putObject 接口返回值 */ interface PutObjectResult extends GeneralResult { /** 对象的实体标签(Entity Tag),是对象被创建时标识对象内容的信息标签,可用于检查对象的内容是否发生变化,例如"8e0b617ca298a564c3331da28dcb50df"。此头部并不一定返回对象的 MD5 值,而是根据对象上传和加密方式而有所不同 */ - ETag: ETag, + ETag: ETag; /** 创建的存储桶访问地址,不带 https:// 前缀,例如 examplebucket-1250000000.cos.ap-guangzhou.myqcloud.com/images/1.jpg */ - Location: string, + Location: string; /** 对象的版本 ID */ - VersionId?: VersionId, + VersionId?: VersionId; } /** appendObject 接口参数 */ @@ -1283,73 +1297,73 @@ declare namespace COS { /** 要删除的对象列表 */ Objects: { /** 要删除的对象键 */ - Key: Key, + Key: Key; /** 要删除的对象版本 ID */ - VersionId?: string - }[], + VersionId?: string; + }[]; /** 是否启动 Quiet 模式 */ - Quiet?: boolean, + Quiet?: boolean; } /** deleteMultipleObject 接口返回值 */ interface DeleteMultipleObjectResult extends GeneralResult { Deleted: { /** 删除成功的对象的对象键 */ - Key: Key, + Key: Key; /** 删除成功的版本 ID,仅当请求中指定了要删除对象的版本 ID 时才返回该元素 */ - VersionId?: VersionId, + VersionId?: VersionId; /** 仅当对该对象的删除创建了一个删除标记,或删除的是该对象的一个删除标记时才返回该元素,布尔值,固定为 true */ - DeleteMarker?: BooleanString, + DeleteMarker?: BooleanString; /** 仅当对该对象的删除创建了一个删除标记,或删除的是该对象的一个删除标记时才返回该元素,值为创建或删除的删除标记的版本 ID */ - DeleteMarkerVersionId?: VersionId, - }[], + DeleteMarkerVersionId?: VersionId; + }[]; Error: { /** 删除失败的对象的对象键 */ - Key: Key, + Key: Key; /** 删除失败的版本 ID,仅当请求中指定了要删除对象的版本 ID 时才返回该元素 */ - VersionId?: string, + VersionId?: string; /** 删除失败的错误码,用来定位唯一的错误条件和确定错误场景 */ - Code?: string, + Code?: string; /** 删除失败的具体错误信息 */ - Message?: string, - }[], + Message?: string; + }[]; } // getObjectAcl /** getObjectAcl 接口参数 */ interface GetObjectAclParams extends ObjectParams { - VersionId?: VersionId, + VersionId?: VersionId; } /** getObjectAcl 接口返回值 */ interface GetObjectAclResult extends GeneralResult { /** 允许用户自定义存储桶权限,有效值:private | public-read | public-read-write */ - ACL: ObjectACL, + ACL: ObjectACL; /** 赋予被授权者读取对象的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者 */ - GrantRead: Grant, + GrantRead: Grant; /** 赋予被授权者读取对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者 */ - GrantReadAcp: Grant, + GrantReadAcp: Grant; /** 赋予被授权者写入对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者 */ - GrantWriteAcp: Grant, + GrantWriteAcp: Grant; /** 赋予被授权者操作对象的所有权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者 */ - GrantFullControl: Grant, + GrantFullControl: Grant; /** 存储桶持有者信息 */ - Owner: Owner, + Owner: Owner; /** 被授权者信息与权限信息 */ - Grants: Grants[], + Grants: Grants[]; } // putObjectAcl /** putObjectAcl 接口参数 */ interface PutObjectAclParams extends ObjectParams { /** 允许用户自定义存储桶权限,有效值:private | public-read | public-read-write,可选 */ - ACL?: ObjectACL, + ACL?: ObjectACL; /** 赋予被授权者读取对象的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantRead?: Grant, + GrantRead?: Grant; /** 赋予被授权者读取对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantReadAcp?: Grant, + GrantReadAcp?: Grant; /** 赋予被授权者写入对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantWriteAcp?: Grant, + GrantWriteAcp?: Grant; /** 赋予被授权者操作对象的所有权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantFullControl?: Grant, + GrantFullControl?: Grant; } /** putObjectAcl 接口返回值 */ interface PutObjectAclResult extends GeneralResult {} @@ -1358,35 +1372,35 @@ declare namespace COS { /** optionsObject 接口参数 */ interface OptionsObjectParams extends ObjectParams { /** 发起 CORS 请求所在的页面域名(Origin) */ - Origin: string, + Origin: string; /** 发起 CORS 请求所用的方法(Method) */ - AccessControlRequestMethod: Method, + AccessControlRequestMethod: Method; /** 发起 CORS 请求时使用的 HTTP 请求头部,不区分英文大小写,可使用英文逗号(,)分隔多个头部 */ - AccessControlRequestHeaders: string, + AccessControlRequestHeaders: string; } /** optionsObject 接口返回值 */ interface OptionsObjectResult extends GeneralResult { /** 允许发起 CORS 的域名,可能的值有以下两种: *:代表允许所有域名 请求头 Origin 中指定的域名:代表允许指定域名 */ - AccessControlAllowOrigin: string, + AccessControlAllowOrigin: string; /** 允许发起 CORS 请求所使用的方法(Method),可使用英文逗号(,)分隔多个方法 */ - AccessControlAllowMethods: string, + AccessControlAllowMethods: string; /** 允许发起 CORS 请求带的 HTTP 头部,不区分英文大小写,可使用英文逗号(,)分隔多个头部 */ - AccessControlAllowHeaders: string, + AccessControlAllowHeaders: string; /** 允许浏览器获取的 CORS 请求中的 HTTP 响应头部,不区分英文大小写,可使用英文逗号(,)分隔多个头部 */ - AccessControlExposeHeaders: string, + AccessControlExposeHeaders: string; /** CORS 配置的有效时间,单位为秒,在有效时间内,浏览器无须为同一请求再次发起预检请求 */ - AccessControlMaxAge: string + AccessControlMaxAge: string; } // restoreObject interface RestoreRequest { /** 指定恢复出的临时副本的有效时长,单位为“天” */ - Days: number | string, + Days: number | string; /** 恢复工作参数 */ CASJobParameters: { - /** 恢复时,Tier 可以指定为支持的恢复模式。 + /** 恢复时,Tier 可以指定为支持的恢复模式。 对于恢复归档存储类型数据,有三种恢复模式,分别为: Expedited:极速模式,恢复任务在1 - 5分钟内可完成。 Standard:标准模式,恢复任务在3 - 5小时内完成 @@ -1394,15 +1408,15 @@ Bulk:批量模式,恢复任务在5 - 12小时内完成。 对于恢复深度归档存储类型数据,有两种恢复模式,分别为: Standard:标准模式,恢复时间为12 - 24小时。 Bulk:批量模式,恢复时间为24 - 48小时。 */ - Tier: 'Expedited' | 'Standard' | 'Bulk' - } + Tier: 'Expedited' | 'Standard' | 'Bulk'; + }; } /** restoreObject 接口参数 */ interface RestoreObjectParams extends ObjectParams { /** 包含 POST Object restore 操作的所有请求信息 */ - RestoreRequest: RestoreRequest, + RestoreRequest: RestoreRequest; /** 当启用版本控制时,指定要恢复的版本 ID,如不指定则恢复对象的最新版本 */ - VersionId?: VersionId, + VersionId?: VersionId; } /** restoreObject 接口返回值 */ interface RestoreObjectResult extends GeneralResult {} @@ -1412,66 +1426,66 @@ Bulk:批量模式,恢复时间为24 - 48小时。 */ /** selectObjectContent 接口参数 */ interface SelectObjectContentParams extends ObjectParams { /** 接口的版本信息,当前最新版本是 2 */ - SelectType: number, + SelectType: number; /** 检索参数,当前版本支持检索 JSON、CSV 文件内容 */ - SelectRequest: Record, + SelectRequest: Record; /** 当启用版本控制时,指定要检索的版本 ID,如不指定则检索对象的最新版本 */ - VersionId?: VersionId, + VersionId?: VersionId; } /** selectObjectContent 接口返回值 */ interface SelectObjectContentResult extends GeneralResult { /** 查询过程统计信息 */ Stats: { /** 如果文件是压缩文件,该数值代表文件解压前的字节大小;如果文件不是压缩文件,该数值即文件的字节大小 */ - BytesScanned: number, + BytesScanned: number; /** 如果文件是压缩文件,该数值代表文件解压后的字节大小;如果文件不是压缩文件,该数值即文件的字节大小 */ - BytesProcessed: number, + BytesProcessed: number; /** COS Select 在本次查询中返回的检索结果字节大小 */ - BytesReturned: number, - }, + BytesReturned: number; + }; /** 查询的结果内容 */ - Payload?: Buffer, + Payload?: Buffer; } // putObjectCopy /** putObjectCopy 接口参数 */ interface PutObjectCopyParams extends ObjectParams { /** 源对象的 URL,其中对象键需经过 URLEncode,可以通过 versionId 参数指定源对象的版本,例如: sourcebucket-1250000001.cos.ap-shanghai.myqcloud.com/example-%E8%85%BE%E8%AE%AF%E4%BA%91.jpg 或 sourcebucket-1250000001.cos.ap-shanghai.myqcloud.com/example-%E8%85%BE%E8%AE%AF%E4%BA%91.jpg?versionId=MTg0NDUxNzYzMDc0NDMzNDExOTc */ - CopySource: string, + CopySource: string; /** 是否复制源对象的元数据信息,枚举值:Copy,Replaced,默认为 Copy。如果标记为 Copy,则复制源对象的元数据信息;如果标记为 Replaced,则按本次请求的请求头中的元数据信息作为目标对象的元数据信息;当目标对象和源对象为同一对象时,即用户试图修改元数据时,则标记必须为 Replaced */ - MetadataDirective?: 'Copy' | 'Replaced', + MetadataDirective?: 'Copy' | 'Replaced'; /** 允许用户自定义存储桶权限,有效值:private | public-read | public-read-write,可选 */ - ACL?: ObjectACL, + ACL?: ObjectACL; /** 赋予被授权者读取对象的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantRead?: Grant, + GrantRead?: Grant; /** 赋予被授权者读取对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantReadAcp?: Grant, + GrantReadAcp?: Grant; /** 赋予被授权者写入对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantWriteAcp?: Grant, + GrantWriteAcp?: Grant; /** 赋予被授权者操作对象的所有权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantFullControl?: Grant, + GrantFullControl?: Grant; /** 当对象在指定时间后被修改,则执行复制操作,否则返回 HTTP 状态码为412(Precondition Failed) */ - CopySourceIfModifiedSince?: string, + CopySourceIfModifiedSince?: string; /** 当对象在指定时间后未被修改,则执行复制操作,否则返回 HTTP 状态码为412(Precondition Failed) */ - CopySourceIfUnmodifiedSince?: string, + CopySourceIfUnmodifiedSince?: string; /** 当对象的 ETag 与指定的值一致,则执行复制操作,否则返回 HTTP 状态码为412(Precondition Failed) */ - CopySourceIfMatch?: string, + CopySourceIfMatch?: string; /** 当对象的 ETag 与指定的值不一致,则执行复制操作,否则返回 HTTP 状态码为412(Precondition Failed) */ - CopySourceIfNoneMatch?: string, + CopySourceIfNoneMatch?: string; /** 对象存储类型。例如 STANDARD | STANDARD_IA | ARCHIVE | DEEP_ARCHIVE | INTELLIGENT_TIERING | MAZ_STANDARD | MAZ_STANDARD_IA | MAZ_INTELLIGENT_TIERING。默认值:STANDARD */ - StorageClass?: StorageClass, + StorageClass?: StorageClass; /** RFC 2616 中定义的缓存指令,将作为目标对象元数据保存 */ - CacheControl?: string, + CacheControl?: string; /** RFC 2616 中定义的文件名称,将作为目标对象元数据保存 */ - ContentDisposition?: string, + ContentDisposition?: string; /** RFC 2616 中定义的编码格式,将作为目标对象元数据保存 */ - ContentEncoding?: string, + ContentEncoding?: string; /** RFC 2616 中定义的 HTTP 请求内容类型(MIME),此头部用于描述目标对象的内容类型,将作为目标对象元数据保存。例如 text/html 或 image/jpeg。 */ - ContentType?: string, + ContentType?: string; /** RFC 2616 中定义的缓存失效时间,将作为目标对象元数据保存 */ - Expires?: string, + Expires?: string; /** 包括用户自定义元数据头部后缀和用户自定义元数据信息,将作为目标对象元数据保存,大小限制为2KB。注意:用户自定义元数据信息支持下划线(_),但用户自定义元数据头部后缀不支持下划线,仅支持减号(-) */ - 'x-cos-meta-*'?: string + 'x-cos-meta-*'?: string; } /** putObjectCopy 接口返回值 */ interface PutObjectCopyResult extends GeneralResult { @@ -1486,9 +1500,9 @@ Bulk:批量模式,恢复时间为24 - 48小时。 */ /** putObjectTagging 接口参数 */ interface PutObjectTaggingParams extends ObjectParams { /** 标签集合,最多支持10个标签 */ - Tags: Tag[], + Tags: Tag[]; /** 对象的版本 ID;当未启用版本控制时,该节点的值为空字符串;当启用版本控制时,启用版本控制之前的对象,其版本 ID 为 null;当暂停版本控制时,新上传的对象其版本 ID 为 null,且同一个对象最多只存在一个版本 ID 为 null 的对象版本 */ - VersionId?: VersionId, + VersionId?: VersionId; } /** putObjectTagging 接口返回值 */ interface PutObjectTaggingResult extends GeneralResult {} @@ -1499,7 +1513,7 @@ Bulk:批量模式,恢复时间为24 - 48小时。 */ /** getObjectTagging 接口返回值 */ interface GetObjectTaggingResult extends GeneralResult { /** 标签集合,最多支持10个标签 */ - Tags: Tag[], + Tags: Tag[]; } // deleteObjectTagging @@ -1512,185 +1526,185 @@ Bulk:批量模式,恢复时间为24 - 48小时。 */ /** multipartInit 接口参数 */ interface MultipartInitParams extends ObjectParams { /** RFC 2616 中定义的缓存指令,将作为对象元数据保存 */ - CacheControl?: string, + CacheControl?: string; /** RFC 2616 中定义的文件名称,将作为对象元数据保存 */ - ContentDisposition?: string, + ContentDisposition?: string; /** RFC 2616 中定义的编码格式,将作为对象元数据保存 */ - ContentEncoding?: string, + ContentEncoding?: string; /** RFC 2616 中定义的 HTTP 请求内容类型(MIME),此头部用于描述待上传对象的内容类型,将作为对象元数据保存。例如text/html或 image/jpeg */ - ContentType?: string, + ContentType?: string; /** RFC 2616 中定义的缓存失效时间,将作为对象元数据保存 */ - Expires?: string, + Expires?: string; /** 允许用户自定义存储桶权限,有效值:private | public-read | public-read-write,可选 */ - ACL?: ObjectACL, + ACL?: ObjectACL; /** 赋予被授权者读取对象的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantRead?: Grant, + GrantRead?: Grant; /** 赋予被授权者读取对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantReadAcp?: Grant, + GrantReadAcp?: Grant; /** 赋予被授权者写入对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantWriteAcp?: Grant, + GrantWriteAcp?: Grant; /** 赋予被授权者操作对象的所有权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantFullControl?: Grant, + GrantFullControl?: Grant; /** 请求里的 Url Query 参数 */ - Query?: Query, + Query?: Query; /** 对象存储类型。例如 STANDARD | STANDARD_IA | ARCHIVE | DEEP_ARCHIVE | INTELLIGENT_TIERING | MAZ_STANDARD | MAZ_STANDARD_IA | MAZ_INTELLIGENT_TIERING。默认值:STANDARD */ - StorageClass?: StorageClass, + StorageClass?: StorageClass; /** 包括用户自定义元数据头部后缀和用户自定义元数据信息,将作为对象元数据保存,大小限制为2KB。注意:用户自定义元数据信息支持下划线(_),但用户自定义元数据头部后缀不支持下划线,仅支持减号(-) */ - 'x-cos-meta-*'?: string, + 'x-cos-meta-*'?: string; } /** multipartInit 接口返回值 */ interface MultipartInitResult extends GeneralResult { - UploadId: string, + UploadId: string; } // multipartUpload /** multipartUpload 接口参数 */ interface MultipartUploadParams extends ObjectParams { /** 分块上传的任务 ID */ - UploadId: UploadId, + UploadId: UploadId; /** 标识本次分块上传的编号,范围在1 - 10000 */ - PartNumber: PartNumber, + PartNumber: PartNumber; /** 要上传分片内容 */ - Body: UploadBody, + Body: UploadBody; /** 要上传分片内容大小 */ - ContentLength?: number, + ContentLength?: number; /** 服务端加密算法 */ - ServerSideEncryption?: string, + ServerSideEncryption?: string; } /** multipartUpload 接口返回值 */ interface MultipartUploadResult extends GeneralResult { /** 返回对象的 MD5 算法校验值,ETag 的值可以用于检查分块的内容是否发生变化 */ - ETag: ETag + ETag: ETag; } // uploadPartCopy /** uploadPartCopy 接口参数 */ interface UploadPartCopyParams extends ObjectParams { /** 源对象 URL 路径,可以通过 versionid 子资源指定历史版本 */ - CopySource: string, + CopySource: string; /** 分块上传的任务 ID */ - UploadId: UploadId, + UploadId: UploadId; /** 标识本次分块上传的编号,范围在1 - 10000 */ - PartNumber: PartNumber, + PartNumber: PartNumber; /** 源对象的字节范围,范围值必须使用 bytes=first-last 格式,first 和 last 都是基于 0 开始的偏移量。例如 bytes=0-9 表示您希望拷贝源对象的开头10个字节的数据,如果不指定,则表示拷贝整个对象 */ - CopySourceRange?: string, + CopySourceRange?: string; /** 当 Object 在指定时间后被修改,则执行操作,否则返回412,可与 x-cos-copy-source-If-None-Match 一起使用,与其他条件联合使用返回冲突 */ - CopySourceIfModifiedSince?: string, + CopySourceIfModifiedSince?: string; /** 当 Object 在指定时间后未被修改,则执行操作,否则返回412,可与 x-cos-copy-source-If-Match 一起使用,与其他条件联合使用返回冲突 */ - CopySourceIfUnmodifiedSince?: string, + CopySourceIfUnmodifiedSince?: string; /** 当 Object 的 Etag 和给定一致时,则执行操作,否则返回412,可与 x-cos-copy-source-If-Unmodified-Since 一起使用,与其他条件联合使用返回冲突 */ - CopySourceIfMatch?: string, + CopySourceIfMatch?: string; /** 当 Object 的 Etag 和给定不一致时,则执行操作,否则返回412,可与 x-cos-copy-source-If-Modified-Since 一起使用,与其他条件联合使用返回冲突 */ - CopySourceIfNoneMatch?: string, + CopySourceIfNoneMatch?: string; } /** uploadPartCopy 接口返回值 */ interface UploadPartCopyResult extends GeneralResult { /** 返回对象的 MD5 算法校验值,ETag 的值可以用于检查分块的内容是否发生变化 */ - ETag: ETag + ETag: ETag; } // multipartComplete /** multipartComplete 接口参数 */ interface MultipartCompleteParams extends ObjectParams { /** 分块上传的任务 ID */ - UploadId: UploadId, + UploadId: UploadId; /** 用来说明本次分块上传中每个块的信息 */ - Parts: Part[], + Parts: Part[]; } /** multipartComplete 接口返回值 */ interface MultipartCompleteResult extends GeneralResult { /** 使用 Upload Part 请求上传分块成功后返回的 ETag 响应头部的值 */ - ETag: ETag, + ETag: ETag; /** 创建的存储桶访问地址,不带 https:// 前缀,例如 examplebucket-1250000000.cos.ap-guangzhou.myqcloud.com/images/1.jpg */ - Location: Location, + Location: Location; /** 对象的版本 ID;当未启用版本控制时,该节点的值为空字符串;当启用版本控制时,启用版本控制之前的对象,其版本 ID 为 null;当暂停版本控制时,新上传的对象其版本 ID 为 null,且同一个对象最多只存在一个版本 ID 为 null 的对象版本 */ - VersionId?: VersionId, + VersionId?: VersionId; } // multipartList /** multipartList 接口参数 */ interface MultipartListParams extends BucketParams { /** 限定返回的 Object key 必须以 Prefix 作为前缀。注意使用 prefix 查询时,返回的 key 中仍会包含 Prefix。 */ - Prefix: Prefix, + Prefix: Prefix; /** 一个字符的分隔符,常用 / 字符,用于对对象键进行分组。所有对象键中从 prefix 或从头(如未指定 prefix)到首个 delimiter 之间相同的部分将作为 CommonPrefixes 下的一个 Prefix 节点。被分组的对象键不再出现在后续对象列表中 */ - Delimiter: Delimiter + Delimiter: Delimiter; /** 设置最大返回的 multipart 数量,合法取值从1到1000,默认1000 */ - MaxUploads?: number, + MaxUploads?: number; /** 与 upload-id-marker 一起使用:当 upload-id-marker 未被指定时,ObjectName 字母顺序大于 key-marker 的条目将被列出。当 upload-id-marker 被指定时,ObjectName 字母顺序大于 key-marker 的条目被列出,ObjectName 字母顺序等于 key-marker 同时 UploadId 大于 upload-id-marker 的条目将被列出。 */ - KeyMarker?: Key, + KeyMarker?: Key; /** 与 key-marker 一起使用:当 key-marker 未被指定时,upload-id-marker 将被忽略。当 key-marker 被指定时,ObjectName字母顺序大于 key-marker 的条目被列出,ObjectName 字母顺序等于 key-marker 同时 UploadId 大于 upload-id-marker 的条目将被列出。 */ - UploadIdMarker?: UploadId, + UploadIdMarker?: UploadId; /** 规定返回值的编码方式,可选值:url,代表返回的对象键为 URL 编码(百分号编码)后的值,例如“腾讯云”将被编码为%E8%85%BE%E8%AE%AF%E4%BA%91 */ - EncodingType?: EncodingType, + EncodingType?: EncodingType; } /** multipartList 接口返回值 */ interface MultipartListResult extends GeneralResult { /** 每个上传任务的信息 */ Upload: { /** 对象键 */ - Key: Key, + Key: Key; /** 分块上传的任务 ID */ - UploadId: UploadId, + UploadId: UploadId; /** 上传任务发起者的信息 */ - Initiator: Initiator, + Initiator: Initiator; /** 上传任务所有者的信息 */ - Owner: Owner, + Owner: Owner; /** 对象存储类型。枚举值 STANDARD | STANDARD_IA | ARCHIVE | DEEP_ARCHIVE | INTELLIGENT_TIERING | MAZ_STANDARD | MAZ_STANDARD_IA | MAZ_INTELLIGENT_TIERING @see https://cloud.tencent.com/document/product/436/33417 */ - StorageClass: StorageClass, + StorageClass: StorageClass; /** UploadId 的创建时间,为 ISO8601 格式,例如2019-05-24T10:56:40Z */ - Initiated: IsoDateTime - }[], + Initiated: IsoDateTime; + }[]; /** 仅当响应条目有截断(IsTruncated 为 true)才会返回该节点,该节点的值为当前响应条目中的最后一个对象键,当需要继续请求后续条目时,将该节点的值作为下一次请求的 marker 参数传入 */ - IsTruncated: BooleanString, + IsTruncated: BooleanString; /** 假如返回条目被截断,则返回的 NextKeyMarker 就是下一个条目的起点。 */ - NextKeyMarker: Key, + NextKeyMarker: Key; /** 假如返回条目被截断,则返回的 UploadId 就是下一个条目的起点。 */ - NextUploadIdMarker: UploadId, + NextUploadIdMarker: UploadId; } // multipartListPart /** multipartListPart 接口参数 */ interface MultipartListPartParams extends ObjectParams { /** 请求的对象键,最前面不带 /,例如 images/1.jpg */ - Key: Key, + Key: Key; /** 标识本次分块上传的 ID,使用 Initiate Multipart Upload 接口初始化分块上传时得到的 UploadId */ - UploadId: UploadId, + UploadId: UploadId; /** 单次返回最大的条目数量,默认1000 */ - MaxParts?: number, + MaxParts?: number; /** 默认以 UTF-8 二进制顺序列出条目,所有列出条目从 marker 开始 */ - PartNumberMarker?: string, + PartNumberMarker?: string; /** 规定返回值的编码方式,可选值:url,代表返回的对象键为 URL 编码(百分号编码)后的值,例如“腾讯云”将被编码为%E8%85%BE%E8%AE%AF%E4%BA%91 */ - EncodingType?: EncodingType, + EncodingType?: EncodingType; } /** multipartListPart 接口返回值 */ interface MultipartListPartResult extends GeneralResult { /** 用来说明本次分块上传中每个块的信息 */ Part: { /** 块的编号 */ - PartNumber: PartNumber, + PartNumber: PartNumber; /** 说明块最后被修改时间 */ - LastModified: IsoDateTime, + LastModified: IsoDateTime; /** 块的 MD5 算法校验值 */ - ETag: ETag, + ETag: ETag; /** 说明块大小,单位是 Byte */ - Size: number, - }[], + Size: number; + }[]; /** 上传任务所有者的信息 */ - Owner: Owner, + Owner: Owner; /** 上传任务发起者的信息 */ - Initiator: Initiator + Initiator: Initiator; /** 假如返回条目被截断,则返回 NextMarker 就是下一个条目的起点 */ - NextPartNumberMarker: number, + NextPartNumberMarker: number; /** 对象存储类型。枚举值 STANDARD | STANDARD_IA | ARCHIVE | DEEP_ARCHIVE | INTELLIGENT_TIERING | MAZ_STANDARD | MAZ_STANDARD_IA | MAZ_INTELLIGENT_TIERING @see https://cloud.tencent.com/document/product/436/33417 */ - StorageClass: StorageClass, + StorageClass: StorageClass; /** 仅当响应条目有截断(IsTruncated 为 true)才会返回该节点,该节点的值为当前响应条目中的最后一个对象键,当需要继续请求后续条目时,将该节点的值作为下一次请求的 marker 参数传入 */ - IsTruncated: BooleanString, + IsTruncated: BooleanString; } // multipartAbort /** multipartAbort 接口参数 */ interface MultipartAbortParams extends ObjectParams { - UploadId: string, + UploadId: string; } /** multipartAbort 接口返回值 */ interface MultipartAbortResult extends GeneralResult {} @@ -1699,64 +1713,64 @@ Bulk:批量模式,恢复时间为24 - 48小时。 */ /** sliceUploadFile 接口参数 */ interface SliceUploadFileParams extends ObjectParams { /** 要上传的本地文件路径 */ - FilePath: string, + FilePath: string; /** 分块上传时,每片的字节数大小,默认值1048576(1MB) */ - ChunkSize?: number, + ChunkSize?: number; /** 分块上传时,每片的字节数大小,默认值1048576(1MB) */ - SliceSize?: number, + SliceSize?: number; /** 请求里的 Url Query 参数 */ - Query?: string, + Query?: string; /** RFC 2616 中定义的缓存指令,将作为对象元数据保存 */ - CacheControl?: string, + CacheControl?: string; /** RFC 2616 中定义的文件名称,将作为对象元数据保存 */ - ContentDisposition?: string, + ContentDisposition?: string; /** RFC 2616 中定义的编码格式,将作为对象元数据保存 */ - ContentEncoding?: string, + ContentEncoding?: string; /** RFC 2616 中定义的 HTTP 请求内容类型(MIME),此头部用于描述待上传对象的内容类型,将作为对象元数据保存。例如text/html或image/jpeg */ - ContentType?: string, + ContentType?: string; /** RFC 2616 中定义的缓存失效时间,将作为对象元数据保存 */ - Expires?: string, + Expires?: string; /** RFC 2616 中定义的缓存失效时间,将作为对象元数据保存 */ - Expect?: string, + Expect?: string; /** 允许用户自定义存储桶权限,有效值:private | public-read | public-read-write,可选 */ - ACL?: ObjectACL, + ACL?: ObjectACL; /** 赋予被授权者读取对象的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantRead?: Grant, + GrantRead?: Grant; /** 赋予被授权者读取对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantReadAcp?: Grant, + GrantReadAcp?: Grant; /** 赋予被授权者写入对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantWriteAcp?: Grant, + GrantWriteAcp?: Grant; /** 赋予被授权者操作对象的所有权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,可选 */ - GrantFullControl?: Grant, + GrantFullControl?: Grant; /** 对象存储类型。枚举值 STANDARD | STANDARD_IA | ARCHIVE | DEEP_ARCHIVE | INTELLIGENT_TIERING | MAZ_STANDARD | MAZ_STANDARD_IA | MAZ_INTELLIGENT_TIERING @see https://cloud.tencent.com/document/product/436/33417 */ - StorageClass?: StorageClass, + StorageClass?: StorageClass; /** 包括用户自定义元数据头部后缀和用户自定义元数据信息,将作为对象元数据保存,大小限制为2KB,注意:用户自定义元数据信息支持下划线(_),但用户自定义元数据头部后缀不支持下划线,仅支持减号(-) */ - 'x-cos-meta-*'?: string, + 'x-cos-meta-*'?: string; /** 任务开始上传的回调方法 */ - onTaskReady?: (TaskId: COS.TaskId) => void, - onTaskStart?: (TaskInfo: COS.Task) => void, + onTaskReady?: (TaskId: COS.TaskId) => void; + onTaskStart?: (TaskInfo: COS.Task) => void; /** 上传的进度回调方法 */ - onProgress?: onProgress, + onProgress?: onProgress; /** 续传校验的进度回调方法 */ - onHashProgress?: onProgress, + onHashProgress?: onProgress; } /** sliceUploadFile 接口返回值 */ interface SliceUploadFileResult extends GeneralResult { /** 对象的实体标签(Entity Tag),是对象被创建时标识对象内容的信息标签,可用于检查对象的内容是否发生变化,例如"8e0b617ca298a564c3331da28dcb50df"。此头部并不一定返回对象的 MD5 值,而是根据对象上传和加密方式而有所不同 */ - ETag: ETag, + ETag: ETag; /** 创建的存储桶访问地址,不带 https:// 前缀,例如 examplebucket-1250000000.cos.ap-guangzhou.myqcloud.com/images/1.jpg */ - Location: string, + Location: string; /** 对象的版本 ID */ - VersionId?: VersionId, + VersionId?: VersionId; } // abortUploadTask /** abortUploadTask 接口参数 */ interface AbortUploadTaskParams extends ObjectParams { /** 清理上传任务的级别,枚举值 'task' | 'file' | 'bucket',默认 task */ - Level?: 'task' | 'file' | 'bucket', + Level?: 'task' | 'file' | 'bucket'; /** 要清理的 UploadId,Level 为 task 时必选 */ - UploadId?: UploadId, + UploadId?: UploadId; } /** abortUploadTask 接口返回值 */ interface AbortUploadTaskResult extends GeneralResult {} @@ -1764,42 +1778,42 @@ Bulk:批量模式,恢复时间为24 - 48小时。 */ // uploadFiles type UploadFileItemParams = (PutObjectParams | SliceUploadFileParams) & { /** 要上传的本地文件路径 */ - FilePath: string, + FilePath: string; /** 上传的进度回调方法 */ - onProgress?: onProgress, + onProgress?: onProgress; /** 上传完成回调方法 */ - onFileFinish?: (err: Error, data?: Record) => void, - } + onFileFinish?: (err: Error, data?: Record) => void; + }; /** 要上传的单个文件参数 */ interface UploadFileItemResult extends GeneralResult { /** 对象的实体标签(Entity Tag),是对象被创建时标识对象内容的信息标签,可用于检查对象的内容是否发生变化,例如"8e0b617ca298a564c3331da28dcb50df"。此头部并不一定返回对象的 MD5 值,而是根据对象上传和加密方式而有所不同 */ - ETag: ETag, + ETag: ETag; /** 创建的存储桶访问地址,不带 https:// 前缀,例如 examplebucket-1250000000.cos.ap-guangzhou.myqcloud.com/images/1.jpg */ - Location: string, + Location: string; /** 对象的版本 ID */ - VersionId?: VersionId, + VersionId?: VersionId; } interface UploadFilesParams { /** 要上传的文件参数列表 */ - files: UploadFileItemParams[], + files: UploadFileItemParams[]; /** 使用 uploadFiles 批量上传时,文件大小大于该数值将使用按分块上传,否则将调用简单上传,单位 Byte,默认值1048576(1MB) */ - SliceSize?: number, + SliceSize?: number; /** 所有文件整体上传进度回调方法 */ - onProgress?: onProgress, + onProgress?: onProgress; /** 所有文件上传完成回调方法 */ - onFileFinish?: (err: CosError, data?: Record) => void, + onFileFinish?: (err: CosError, data?: Record) => void; } /** uploadFiles 接口返回值 */ interface UploadFilesResult extends GeneralResult { /** 文件列表上传结果 */ files: { /** 单个文件上传参数 */ - options: UploadFileItemParams, + options: UploadFileItemParams; /** 单个文件上传错误信息 */ - error: Error, + error: Error; /** 单个文件上传成功信息 */ - data: UploadFileItemResult, - }[], + data: UploadFileItemResult; + }[]; } // uploadFile 高级上传 @@ -1812,70 +1826,70 @@ Bulk:批量模式,恢复时间为24 - 48小时。 */ type UploadFileParams = (PutObjectParams | SliceUploadFileParams) & { /** 要上传的本地文件路径 */ - FilePath: string, + FilePath: string; /** 使用 uploadFile 高级上传时,文件大小大于该数值将使用按分块上传,否则将调用简单上传,单位 Byte,默认值1048576(1MB) */ - SliceSize?: number, + SliceSize?: number; /** 上传的进度回调方法 */ - onProgress?: onProgress, + onProgress?: onProgress; /** 上传完成回调方法 */ - onFileFinish?: onFileFinish, + onFileFinish?: onFileFinish; }; /** uploadFiles 接口返回值 */ interface UploadFileResult extends GeneralResult { /** 对象的实体标签(Entity Tag),是对象被创建时标识对象内容的信息标签,可用于检查对象的内容是否发生变化,例如"8e0b617ca298a564c3331da28dcb50df"。此头部并不一定返回对象的 MD5 值,而是根据对象上传和加密方式而有所不同 */ - ETag: ETag, + ETag: ETag; /** 创建的存储桶访问地址,不带 https:// 前缀,例如 examplebucket-1250000000.cos.ap-guangzhou.myqcloud.com/images/1.jpg */ - Location: string, + Location: string; /** 对象的版本 ID */ - VersionId?: VersionId, + VersionId?: VersionId; } // sliceCopyFile /** sliceCopyFile 接口参数 */ interface SliceCopyFileParams extends ObjectParams { /** 源对象的 URL,其中对象键需经过 URLEncode,可以通过 versionId 参数指定源对象的版本,例如: sourcebucket-1250000001.cos.ap-shanghai.myqcloud.com/example-%E8%85%BE%E8%AE%AF%E4%BA%91.jpg 或 sourcebucket-1250000001.cos.ap-shanghai.myqcloud.com/example-%E8%85%BE%E8%AE%AF%E4%BA%91.jpg?versionId=MTg0NDUxNzYzMDc0NDMzNDExOTc */ - CopySource: string, + CopySource: string; /** 使用 sliceCopyFile 分块复制文件时,文件大小大于该数值将使用分块复制 ,否则将调用简单复制,默认值10485760(10MB) */ - CopySliceSize?: number, + CopySliceSize?: number; /** 使用 sliceCopyFile 分块复制文件时,每片的大小字节数,默认值10485760(10MB) */ - CopyChunkSize?: number, + CopyChunkSize?: number; /** 分片复制进度回调方法 */ - onProgress: onProgress + onProgress: onProgress; } /** sliceCopyFile 接口返回值 */ interface SliceCopyFileResult extends GeneralResult {} // getTaskList - type TaskId = string + type TaskId = string; type Task = { /** 上传任务 ID */ - id: TaskId, + id: TaskId; /** 存储桶的名称,格式为,例如examplebucket-1250000000 */ - Bucket: Bucket, + Bucket: Bucket; /** 存储桶所在地域 @see https://cloud.tencent.com/document/product/436/6224 */ - Region: Region, + Region: Region; /** 请求的对象键,最前面不带 /,例如 images/1.jpg */ - Key: Key, + Key: Key; /** 要上传的本地文件路径 */ - FilePath: string, + FilePath: string; /** 上传状态 */ - state: 'waiting' | 'checking' | 'uploading' | 'error' | 'paused' | 'success' | 'canceled', + state: 'waiting' | 'checking' | 'uploading' | 'error' | 'paused' | 'success' | 'canceled'; /** 上传错误信息 */ - error: string | Error | { Code: string, Message: string }, + error: string | Error | { Code: string; Message: string }; /** 已上传内容大小,单位 B(字节) */ - loaded: number, + loaded: number; /** 上传文件大小,单位 B(字节) */ - size: number, + size: number; /** 上传速递,单位 B/s */ - speed: number, + speed: number; /** 上传进度,范围 0-1,保留两位小数 */ - percent: number, + percent: number; /** 续传校验进度,范围 0-1,保留两位小数 */ - hashPercent: number, - } + hashPercent: number; + }; /** 上传任务列表 */ - type TaskList = Task[] + type TaskList = Task[]; // request /** request 接口参数 */ @@ -1883,66 +1897,73 @@ Bulk:批量模式,恢复时间为24 - 48小时。 */ Bucket?: Bucket; Region?: Region; /** 操作方法,如 get,post,delete, head 等 HTTP 方法 */ - Method: string, + Method: string; /** 请求的对象键,最前面不带 / */ - Key?: Key, + Key?: Key; /** 请求里的 Url Query 参数 */ - Query?: Query, + Query?: Query; /** 请求里的 Body 参数 */ - Body?: UploadBody, + Body?: UploadBody; /** 请求的 API 动作接口(可理解为不带 = 的 Query 参数),如 acl、tagging、image_process 等 */ - Action?: Action, + Action?: Action; /** 请求url */ - Url?: string, + Url?: string; /** 返回值body是否不需要解析 */ - RawBody?: boolean, - ContentType?: string, + RawBody?: boolean; + ContentType?: string; /** 请求时带上的 Header 字段 */ - Headers?: Headers, + Headers?: Headers; } /** Request 接口返回值 */ interface RequestResult extends GeneralResult { - Body?: Buffer, - Response?: any, + Body?: Buffer; + Response?: any; } // getObjectUrl /** getObjectUrl 接口参数 */ interface GetObjectUrlParams extends ObjectParams { /** 获取的 Url 是否计算签名 */ - Sign?: boolean, + Sign?: boolean; /** 请求方法 */ - Method?: Method, + Method?: Method; /** 请求里的 Url Query 参数,传入该值中的 key/value 将会被 URLEncode */ - Query?: Query, + Query?: Query; /** 请求里的 Url Query 参数。传入该值将直接拼接在 Url 上,不会对其进行 URLEncode */ - QueryString?: string, + QueryString?: string; /** 签名几秒后失效,默认为900秒 */ - Expires?: number, + Expires?: number; /** 是否使用全球加速 */ - UseAccelerate?: boolean, + UseAccelerate?: boolean; /** 调用操作存储桶和对象的 API 时自定义请求域名。可以使用模板,如"{Bucket}.cos.{Region}.myqcloud.com",即在调用 API 时会使用参数中传入的 Bucket 和 Region 进行替换。 */ - Domain?: string, + Domain?: string; /** http协议,枚举值'http:','https:' */ - Protocol?: string, + Protocol?: string; } /** getObjectUrl 接口返回值 */ interface GetObjectUrlResult { /** 返回对象 Url */ - Url: string + Url: string; } interface DownloadFileParams { - Bucket: Bucket, - Region: Region, - Key: Key, - FilePath: string, - ChunkSize?: number, - ParallelLimit?: number, - RetryTimes?: number, - TaskId?: string, - onTaskReady?: (TaskId: COS.TaskId) => void, - onProgress?: onProgress, + Bucket: Bucket; + Region: Region; + Key: Key; + FilePath: string; + ChunkSize?: number; + ParallelLimit?: number; + RetryTimes?: number; + TaskId?: string; + onTaskReady?: (TaskId: COS.TaskId) => void; + onProgress?: onProgress; + } + + interface DownloadFileResult extends GeneralResult { + /** 对象的实体标签(Entity Tag),是对象被创建时标识对象内容的信息标签,可用于检查对象的内容是否发生变化,例如"8e0b617ca298a564c3331da28dcb50df"。此头部并不一定返回对象的 MD5 值,而是根据对象上传和加密方式而有所不同 */ + ETag: ETag; + /** 对象的版本 ID */ + VersionId?: string; } interface DownloadFileResult extends GeneralResult { @@ -1955,41 +1976,40 @@ Bulk:批量模式,恢复时间为24 - 48小时。 */ // getV4Auth interface GetV4AuthParams { /** 计算签名用的密钥 SecretId,如果不传会用实例本身的凭证,可选 */ - SecretId?: string, + SecretId?: string; /** 计算签名用的密钥 SecretKey,如果不传会用实例本身的凭证,可选 */ - SecretKey?: string, + SecretKey?: string; /** 存储桶的名称,命名规则为 BucketName-APPID,例如 examplebucket-1250000000 */ - Bucket?: Bucket, + Bucket?: Bucket; /** 请求的对象键,最前面不带 /,例如 images/1.jpg */ - Key?: Key, + Key?: Key; /** 签名几秒后失效,默认为900秒 */ - Expires?: number, + Expires?: number; } // getAuth interface GetAuthParams { /** 计算签名用的密钥 SecretId,如果不传会用实例本身的凭证,可选 */ - SecretId?: string, + SecretId?: string; /** 计算签名用的密钥 SecretKey,如果不传会用实例本身的凭证,可选 */ - SecretKey?: string, + SecretKey?: string; /** 请求的存储桶,如果传入了 Bucket、Region,签名会默认加上 Host 字段,可选 */ - Bucket?: Bucket, + Bucket?: Bucket; /** 请求的地域,如果传入了 Bucket、Region,签名会默认加上 Host 字段,可选 */ - Region?: Region, + Region?: Region; /** 请求方法 */ - Method?: Method, + Method?: Method; /** 请求的对象键,最前面不带 /,例如 images/1.jpg */ - Key?: Key, + Key?: Key; /** 签名几秒后失效,默认为900秒 */ - Expires?: number, + Expires?: number; /** 请求里的 Url Query 参数 */ - Query?: Query, + Query?: Query; /** 请求里的 Header 参数 */ - Headers?: Headers, + Headers?: Headers; /** 默认将host加入签名计算,关闭后可能导致越权风险,建议保持为true */ - ForceSignHost?: boolean, + ForceSignHost?: boolean; } - } /** @@ -1997,7 +2017,6 @@ Bulk:批量模式,恢复时间为24 - 48小时。 */ * @see https://cloud.tencent.com/document/product/436/7751 */ declare class COS { - // 构造方法 constructor(options: COS.COSOptions); @@ -2030,180 +2049,311 @@ declare class COS { getBucket(params: COS.GetBucketParams): Promise; /** 获取 Bucket 下的 Object 版本列表 @see https://cloud.tencent.com/document/product/436/35521 */ - listObjectVersions(params: COS.ListObjectVersionsParams, callback: (err: COS.CosError, data: COS.ListObjectVersionsResult) => void): void; + listObjectVersions( + params: COS.ListObjectVersionsParams, + callback: (err: COS.CosError, data: COS.ListObjectVersionsResult) => void, + ): void; listObjectVersions(params: COS.ListObjectVersionsParams): Promise; /** 删除 Bucket @see https://cloud.tencent.com/document/product/436/7732 */ - deleteBucket(params: COS.DeleteBucketParams, callback: (err: COS.CosError, data: COS.DeleteBucketResult) => void): void; + deleteBucket( + params: COS.DeleteBucketParams, + callback: (err: COS.CosError, data: COS.DeleteBucketResult) => void, + ): void; deleteBucket(params: COS.DeleteBucketParams): Promise; /** 设置 Bucket 的 权限列表 @see https://cloud.tencent.com/document/product/436/7737 */ - putBucketAcl(params: COS.PutBucketAclParams, callback: (err: COS.CosError, data: COS.PutBucketAclResult) => void): void; + putBucketAcl( + params: COS.PutBucketAclParams, + callback: (err: COS.CosError, data: COS.PutBucketAclResult) => void, + ): void; putBucketAcl(params: COS.PutBucketAclParams): Promise; /** 获取 Bucket 的 权限列表 @see https://cloud.tencent.com/document/product/436/7733 */ - getBucketAcl(params: COS.GetBucketAclParams, callback: (err: COS.CosError, data: COS.GetBucketAclResult) => void): void; + getBucketAcl( + params: COS.GetBucketAclParams, + callback: (err: COS.CosError, data: COS.GetBucketAclResult) => void, + ): void; getBucketAcl(params: COS.GetBucketAclParams): Promise; /** 设置 Bucket 的 跨域设置 @see https://cloud.tencent.com/document/product/436/8279 */ - putBucketCors(params: COS.PutBucketCorsParams, callback: (err: COS.CosError, data: COS.PutBucketCorsResult) => void): void; + putBucketCors( + params: COS.PutBucketCorsParams, + callback: (err: COS.CosError, data: COS.PutBucketCorsResult) => void, + ): void; putBucketCors(params: COS.PutBucketCorsParams): Promise; /** 获取 Bucket 的 跨域设置 @see https://cloud.tencent.com/document/product/436/8274 */ - getBucketCors(params: COS.GetBucketCorsParams, callback: (err: COS.CosError, data: COS.GetBucketCorsResult) => void): void; + getBucketCors( + params: COS.GetBucketCorsParams, + callback: (err: COS.CosError, data: COS.GetBucketCorsResult) => void, + ): void; getBucketCors(params: COS.GetBucketCorsParams): Promise; /** 删除 Bucket 的 跨域设置 @see https://cloud.tencent.com/document/product/436/8283 */ - deleteBucketCors(params: COS.DeleteBucketCorsParams, callback: (err: COS.CosError, data: COS.DeleteBucketCorsResult) => void): void; + deleteBucketCors( + params: COS.DeleteBucketCorsParams, + callback: (err: COS.CosError, data: COS.DeleteBucketCorsResult) => void, + ): void; deleteBucketCors(params: COS.DeleteBucketCorsParams): Promise; /** 获取 Bucket 的 地域信息 */ - getBucketLocation(params: COS.GetBucketLocationParams, callback: (err: COS.CosError, data: COS.GetBucketLocationResult) => void): void; + getBucketLocation( + params: COS.GetBucketLocationParams, + callback: (err: COS.CosError, data: COS.GetBucketLocationResult) => void, + ): void; getBucketLocation(params: COS.GetBucketLocationParams): Promise; /** 获取 Bucket 的读取权限策略 @see https://cloud.tencent.com/document/product/436/8282 */ - putBucketPolicy(params: COS.PutBucketPolicyParams, callback: (err: COS.CosError, data: COS.PutBucketPolicyResult) => void): void; + putBucketPolicy( + params: COS.PutBucketPolicyParams, + callback: (err: COS.CosError, data: COS.PutBucketPolicyResult) => void, + ): void; putBucketPolicy(params: COS.PutBucketPolicyParams): Promise; /** 获取 Bucket 的读取权限策略 @see https://cloud.tencent.com/document/product/436/8276 */ - getBucketPolicy(params: COS.GetBucketPolicyParams, callback: (err: COS.CosError, data: COS.GetBucketPolicyResult) => void): void; + getBucketPolicy( + params: COS.GetBucketPolicyParams, + callback: (err: COS.CosError, data: COS.GetBucketPolicyResult) => void, + ): void; getBucketPolicy(params: COS.GetBucketPolicyParams): Promise; /** 删除 Bucket 的 跨域设置 @see https://cloud.tencent.com/document/product/436/8285 */ - deleteBucketPolicy(params: COS.DeleteBucketPolicyParams, callback: (err: COS.CosError, data: COS.DeleteBucketPolicyResult) => void): void; + deleteBucketPolicy( + params: COS.DeleteBucketPolicyParams, + callback: (err: COS.CosError, data: COS.DeleteBucketPolicyResult) => void, + ): void; deleteBucketPolicy(params: COS.DeleteBucketPolicyParams): Promise; /** 设置 Bucket 的标签 @see https://cloud.tencent.com/document/product/436/34838 */ - putBucketTagging(params: COS.PutBucketTaggingParams, callback: (err: COS.CosError, data: COS.PutBucketTaggingResult) => void): void; + putBucketTagging( + params: COS.PutBucketTaggingParams, + callback: (err: COS.CosError, data: COS.PutBucketTaggingResult) => void, + ): void; putBucketTagging(params: COS.PutBucketTaggingParams): Promise; /** 获取 Bucket 的标签设置 @see https://cloud.tencent.com/document/product/436/34837 */ - getBucketTagging(params: COS.GetBucketTaggingParams, callback: (err: COS.CosError, data: COS.GetBucketTaggingResult) => void): void; + getBucketTagging( + params: COS.GetBucketTaggingParams, + callback: (err: COS.CosError, data: COS.GetBucketTaggingResult) => void, + ): void; getBucketTagging(params: COS.GetBucketTaggingParams): Promise; /** 删除 Bucket 的 标签设置 @see https://cloud.tencent.com/document/product/436/34836 */ - deleteBucketTagging(params: COS.DeleteBucketTaggingParams, callback: (err: COS.CosError, data: COS.DeleteBucketTaggingResult) => void): void; + deleteBucketTagging( + params: COS.DeleteBucketTaggingParams, + callback: (err: COS.CosError, data: COS.DeleteBucketTaggingResult) => void, + ): void; deleteBucketTagging(params: COS.DeleteBucketTaggingParams): Promise; - /** 设置 Bucket 生命周期 @see https://cloud.tencent.com/document/product/436/8280 */ - putBucketLifecycle(params: COS.PutBucketLifecycleParams, callback: (err: COS.CosError, data: COS.PutBucketLifecycleResult) => void): void; + putBucketLifecycle( + params: COS.PutBucketLifecycleParams, + callback: (err: COS.CosError, data: COS.PutBucketLifecycleResult) => void, + ): void; putBucketLifecycle(params: COS.PutBucketLifecycleParams): Promise; /** 获取 Bucket 生命周期 @see https://cloud.tencent.com/document/product/436/8280 */ - getBucketLifecycle(params: COS.GetBucketLifecycleParams, callback: (err: COS.CosError, data: COS.GetBucketLifecycleResult) => void): void; + getBucketLifecycle( + params: COS.GetBucketLifecycleParams, + callback: (err: COS.CosError, data: COS.GetBucketLifecycleResult) => void, + ): void; getBucketLifecycle(params: COS.GetBucketLifecycleParams): Promise; /** 删除 Bucket 生命周期 @see https://cloud.tencent.com/document/product/436/8278 */ - deleteBucketLifecycle(params: COS.DeleteBucketLifecycleParams, callback: (err: COS.CosError, data: COS.DeleteBucketLifecycleResult) => void): void; + deleteBucketLifecycle( + params: COS.DeleteBucketLifecycleParams, + callback: (err: COS.CosError, data: COS.DeleteBucketLifecycleResult) => void, + ): void; deleteBucketLifecycle(params: COS.DeleteBucketLifecycleParams): Promise; /** 设置 Bucket 版本 @see https://cloud.tencent.com/document/product/436/19889 */ - putBucketVersioning(params: COS.PutBucketVersioningParams, callback: (err: COS.CosError, data: COS.PutBucketVersioningResult) => void): void; + putBucketVersioning( + params: COS.PutBucketVersioningParams, + callback: (err: COS.CosError, data: COS.PutBucketVersioningResult) => void, + ): void; putBucketVersioning(params: COS.PutBucketVersioningParams): Promise; /** 获取 Bucket 版本 @see https://cloud.tencent.com/document/product/436/19888 */ - getBucketVersioning(params: COS.GetBucketVersioningParams, callback: (err: COS.CosError, data: COS.GetBucketVersioningResult) => void): void; + getBucketVersioning( + params: COS.GetBucketVersioningParams, + callback: (err: COS.CosError, data: COS.GetBucketVersioningResult) => void, + ): void; getBucketVersioning(params: COS.GetBucketVersioningParams): Promise; /** 设置 Bucket 副本 @see https://cloud.tencent.com/document/product/436/19223 */ - putBucketReplication(params: COS.PutBucketReplicationParams, callback: (err: COS.CosError, data: COS.PutBucketReplicationResult) => void): void; + putBucketReplication( + params: COS.PutBucketReplicationParams, + callback: (err: COS.CosError, data: COS.PutBucketReplicationResult) => void, + ): void; putBucketReplication(params: COS.PutBucketReplicationParams): Promise; /** 获取 Bucket 副本 @see https://cloud.tencent.com/document/product/436/19222 */ - getBucketReplication(params: COS.GetBucketReplicationParams, callback: (err: COS.CosError, data: COS.GetBucketReplicationResult) => void): void; + getBucketReplication( + params: COS.GetBucketReplicationParams, + callback: (err: COS.CosError, data: COS.GetBucketReplicationResult) => void, + ): void; getBucketReplication(params: COS.GetBucketReplicationParams): Promise; /** 删除 Bucket 副本 @see https://cloud.tencent.com/document/product/436/19221 */ - deleteBucketReplication(params: COS.DeleteBucketReplicationParams, callback: (err: COS.CosError, data: COS.DeleteBucketReplicationResult) => void): void; + deleteBucketReplication( + params: COS.DeleteBucketReplicationParams, + callback: (err: COS.CosError, data: COS.DeleteBucketReplicationResult) => void, + ): void; deleteBucketReplication(params: COS.DeleteBucketReplicationParams): Promise; /** 设置 Bucket 静态网站配置信息 @see https://cloud.tencent.com/document/product/436/31930 */ - putBucketWebsite(params: COS.PutBucketWebsiteParams, callback: (err: COS.CosError, data: COS.PutBucketWebsiteResult) => void): void; + putBucketWebsite( + params: COS.PutBucketWebsiteParams, + callback: (err: COS.CosError, data: COS.PutBucketWebsiteResult) => void, + ): void; putBucketWebsite(params: COS.PutBucketWebsiteParams): Promise; /** 获取 Bucket 的静态网站配置信息 @see https://cloud.tencent.com/document/product/436/31929 */ - getBucketWebsite(params: COS.GetBucketWebsiteParams, callback: (err: COS.CosError, data: COS.GetBucketWebsiteResult) => void): void; + getBucketWebsite( + params: COS.GetBucketWebsiteParams, + callback: (err: COS.CosError, data: COS.GetBucketWebsiteResult) => void, + ): void; getBucketWebsite(params: COS.GetBucketWebsiteParams): Promise; /** 删除 Bucket 的静态网站配置 @see https://cloud.tencent.com/document/product/436/31928 */ - deleteBucketWebsite(params: COS.DeleteBucketWebsiteParams, callback: (err: COS.CosError, data: COS.DeleteBucketWebsiteResult) => void): void; + deleteBucketWebsite( + params: COS.DeleteBucketWebsiteParams, + callback: (err: COS.CosError, data: COS.DeleteBucketWebsiteResult) => void, + ): void; deleteBucketWebsite(params: COS.DeleteBucketWebsiteParams): Promise; /** 设置 Bucket 的防盗链白名单或者黑名单 @see https://cloud.tencent.com/document/product/436/32492 */ - putBucketReferer(params: COS.PutBucketRefererParams, callback: (err: COS.CosError, data: COS.PutBucketRefererResult) => void): void; + putBucketReferer( + params: COS.PutBucketRefererParams, + callback: (err: COS.CosError, data: COS.PutBucketRefererResult) => void, + ): void; putBucketReferer(params: COS.PutBucketRefererParams): Promise; /** 获取 Bucket 的防盗链白名单或者黑名单 @see https://cloud.tencent.com/document/product/436/32493 */ - getBucketReferer(params: COS.GetBucketRefererParams, callback: (err: COS.CosError, data: COS.GetBucketRefererResult) => void): void; + getBucketReferer( + params: COS.GetBucketRefererParams, + callback: (err: COS.CosError, data: COS.GetBucketRefererResult) => void, + ): void; getBucketReferer(params: COS.GetBucketRefererParams): Promise; /** 设置 Bucket 自定义域名 */ - putBucketDomain(params: COS.PutBucketDomainParams, callback: (err: COS.CosError, data: COS.PutBucketDomainResult) => void): void; + putBucketDomain( + params: COS.PutBucketDomainParams, + callback: (err: COS.CosError, data: COS.PutBucketDomainResult) => void, + ): void; putBucketDomain(params: COS.PutBucketDomainParams): Promise; /** 获取 Bucket 的自定义域名 */ - getBucketDomain(params: COS.GetBucketDomainParams, callback: (err: COS.CosError, data: COS.GetBucketDomainResult) => void): void; + getBucketDomain( + params: COS.GetBucketDomainParams, + callback: (err: COS.CosError, data: COS.GetBucketDomainResult) => void, + ): void; getBucketDomain(params: COS.GetBucketDomainParams): Promise; /** 删除 Bucket 自定义域名 */ - deleteBucketDomain(params: COS.DeleteBucketDomainParams, callback: (err: COS.CosError, data: COS.DeleteBucketDomainResult) => void): void; + deleteBucketDomain( + params: COS.DeleteBucketDomainParams, + callback: (err: COS.CosError, data: COS.DeleteBucketDomainResult) => void, + ): void; deleteBucketDomain(params: COS.DeleteBucketDomainParams): Promise; /** 设置 Bucket 的回源 */ - putBucketOrigin(params: COS.PutBucketOriginParams, callback: (err: COS.CosError, data: COS.PutBucketOriginResult) => void): void; + putBucketOrigin( + params: COS.PutBucketOriginParams, + callback: (err: COS.CosError, data: COS.PutBucketOriginResult) => void, + ): void; putBucketOrigin(params: COS.PutBucketOriginParams): Promise; /** 获取 Bucket 的回源 */ - getBucketOrigin(params: COS.GetBucketOriginParams, callback: (err: COS.CosError, data: COS.GetBucketOriginResult) => void): void; + getBucketOrigin( + params: COS.GetBucketOriginParams, + callback: (err: COS.CosError, data: COS.GetBucketOriginResult) => void, + ): void; getBucketOrigin(params: COS.GetBucketOriginParams): Promise; /** 删除 Bucket 的回源 */ - deleteBucketOrigin(params: COS.DeleteBucketOriginParams, callback: (err: COS.CosError, data: COS.DeleteBucketOriginResult) => void): void; + deleteBucketOrigin( + params: COS.DeleteBucketOriginParams, + callback: (err: COS.CosError, data: COS.DeleteBucketOriginResult) => void, + ): void; deleteBucketOrigin(params: COS.DeleteBucketOriginParams): Promise; /** 设置 Bucket 的日志记录 @see https://cloud.tencent.com/document/product/436/17054 */ - putBucketLogging(params: COS.PutBucketLoggingParams, callback: (err: COS.CosError, data: COS.PutBucketLoggingResult) => void): void; + putBucketLogging( + params: COS.PutBucketLoggingParams, + callback: (err: COS.CosError, data: COS.PutBucketLoggingResult) => void, + ): void; putBucketLogging(params: COS.PutBucketLoggingParams): Promise; /** 获取 Bucket 的日志记录 @see https://cloud.tencent.com/document/product/436/17053 */ - getBucketLogging(params: COS.GetBucketLoggingParams, callback: (err: COS.CosError, data: COS.GetBucketLoggingResult) => void): void; + getBucketLogging( + params: COS.GetBucketLoggingParams, + callback: (err: COS.CosError, data: COS.GetBucketLoggingResult) => void, + ): void; getBucketLogging(params: COS.GetBucketLoggingParams): Promise; /** 创建/编辑 Bucket 的清单任务 @see https://cloud.tencent.com/document/product/436/33707 */ - putBucketInventory(params: COS.PutBucketInventoryParams, callback: (err: COS.CosError, data: COS.PutBucketInventoryResult) => void): void; + putBucketInventory( + params: COS.PutBucketInventoryParams, + callback: (err: COS.CosError, data: COS.PutBucketInventoryResult) => void, + ): void; putBucketInventory(params: COS.PutBucketInventoryParams): Promise; /** 获取 Bucket 的清单任务信息 @see https://cloud.tencent.com/document/product/436/33705 */ - getBucketInventory(params: COS.GetBucketInventoryParams, callback: (err: COS.CosError, data: COS.GetBucketInventoryResult) => void): void; + getBucketInventory( + params: COS.GetBucketInventoryParams, + callback: (err: COS.CosError, data: COS.GetBucketInventoryResult) => void, + ): void; getBucketInventory(params: COS.GetBucketInventoryParams): Promise; /** 获取 Bucket 的清单任务信息 @see https://cloud.tencent.com/document/product/436/33706 */ - listBucketInventory(params: COS.ListBucketInventoryParams, callback: (err: COS.CosError, data: COS.ListBucketInventoryResult) => void): void; + listBucketInventory( + params: COS.ListBucketInventoryParams, + callback: (err: COS.CosError, data: COS.ListBucketInventoryResult) => void, + ): void; listBucketInventory(params: COS.ListBucketInventoryParams): Promise; /** 删除 Bucket 的清单任务 @see https://cloud.tencent.com/document/product/436/33704 */ - deleteBucketInventory(params: COS.DeleteBucketInventoryParams, callback: (err: COS.CosError, data: COS.DeleteBucketInventoryResult) => void): void; + deleteBucketInventory( + params: COS.DeleteBucketInventoryParams, + callback: (err: COS.CosError, data: COS.DeleteBucketInventoryResult) => void, + ): void; deleteBucketInventory(params: COS.DeleteBucketInventoryParams): Promise; /** 启用或者暂停存储桶的全球加速功能 @see https://cloud.tencent.com/document/product/436/38869 */ - putBucketAccelerate(params: COS.PutBucketAccelerateParams, callback: (err: COS.CosError, data: COS.PutBucketAccelerateResult) => void): void; + putBucketAccelerate( + params: COS.PutBucketAccelerateParams, + callback: (err: COS.CosError, data: COS.PutBucketAccelerateResult) => void, + ): void; putBucketAccelerate(params: COS.PutBucketAccelerateParams): Promise; /** 查询存储桶的全球加速功能配置 @see https://cloud.tencent.com/document/product/436/38868 */ - getBucketAccelerate(params: COS.GetBucketAccelerateParams, callback: (err: COS.CosError, data: COS.GetBucketAccelerateResult) => void): void; + getBucketAccelerate( + params: COS.GetBucketAccelerateParams, + callback: (err: COS.CosError, data: COS.GetBucketAccelerateResult) => void, + ): void; getBucketAccelerate(params: COS.GetBucketAccelerateParams): Promise; /** 设置指定存储桶下的默认加密配置 @see https://cloud.tencent.com/document/product/436/40136 */ - putBucketEncryption(params: COS.PutBucketEncryptionParams, callback: (err: COS.CosError, data: COS.PutBucketEncryptionResult) => void): void; + putBucketEncryption( + params: COS.PutBucketEncryptionParams, + callback: (err: COS.CosError, data: COS.PutBucketEncryptionResult) => void, + ): void; putBucketEncryption(params: COS.PutBucketEncryptionParams): Promise; /** 查询指定存储桶下的默认加密配置 @see https://cloud.tencent.com/document/product/436/40137 */ - getBucketEncryption(params: COS.GetBucketEncryptionParams, callback: (err: COS.CosError, data: COS.GetBucketEncryptionResult) => void): void; + getBucketEncryption( + params: COS.GetBucketEncryptionParams, + callback: (err: COS.CosError, data: COS.GetBucketEncryptionResult) => void, + ): void; getBucketEncryption(params: COS.GetBucketEncryptionParams): Promise; /** 删除指定存储桶下的默认加密配置 @see https://cloud.tencent.com/document/product/436/40138 */ - deleteBucketEncryption(params: COS.DeleteBucketEncryptionParams, callback: (err: COS.CosError, data: COS.DeleteBucketEncryptionResult) => void): void; + deleteBucketEncryption( + params: COS.DeleteBucketEncryptionParams, + callback: (err: COS.CosError, data: COS.DeleteBucketEncryptionResult) => void, + ): void; deleteBucketEncryption(params: COS.DeleteBucketEncryptionParams): Promise; /** 取回对应对象(Object)的元数据,Head的权限与Get的权限一致 @see https://cloud.tencent.com/document/product/436/7745 */ @@ -2215,93 +2365,159 @@ declare class COS { getObject(params: COS.GetObjectParams): Promise; /** 下载对象(Object),返回 Stream 对象 @see https://cloud.tencent.com/document/product/436/7753 */ - getObjectStream(params: COS.GetObjectParams, callback?: (err: COS.CosError, data: COS.GetObjectResult) => void): Stream; + getObjectStream( + params: COS.GetObjectParams, + callback?: (err: COS.CosError, data: COS.GetObjectResult) => void, + ): Stream; /** 简单上传对象(Object)至指定存储桶 @see https://cloud.tencent.com/document/product/436/7749 */ putObject(params: COS.PutObjectParams, callback: (err: COS.CosError, data: COS.PutObjectResult) => void): void; putObject(params: COS.PutObjectParams): Promise; /** 删除一个指定的对象(Object) @see https://cloud.tencent.com/document/product/436/7743 */ - deleteObject(params: COS.DeleteObjectParams, callback: (err: COS.CosError, data: COS.DeleteObjectResult) => void): void; + deleteObject( + params: COS.DeleteObjectParams, + callback: (err: COS.CosError, data: COS.DeleteObjectResult) => void, + ): void; deleteObject(params: COS.DeleteObjectParams): Promise; /** 批量删除指定存储桶中的多个对象(Object) @see https://cloud.tencent.com/document/product/436/8289 */ - deleteMultipleObject(params: COS.DeleteMultipleObjectParams, callback: (err: COS.CosError, data: COS.DeleteMultipleObjectResult) => void): void; + deleteMultipleObject( + params: COS.DeleteMultipleObjectParams, + callback: (err: COS.CosError, data: COS.DeleteMultipleObjectResult) => void, + ): void; deleteMultipleObject(params: COS.DeleteMultipleObjectParams): Promise; /** 获取 Object 的权限列表 @see https://cloud.tencent.com/document/product/436/7744 */ - getObjectAcl(params: COS.GetObjectAclParams, callback: (err: COS.CosError, data: COS.GetObjectAclResult) => void): void; + getObjectAcl( + params: COS.GetObjectAclParams, + callback: (err: COS.CosError, data: COS.GetObjectAclResult) => void, + ): void; getObjectAcl(params: COS.GetObjectAclParams): Promise; /** 设置 Object 的权限列表 @see https://cloud.tencent.com/document/product/436/7748 */ - putObjectAcl(params: COS.PutObjectAclParams, callback: (err: COS.CosError, data: COS.PutObjectAclResult) => void): void; + putObjectAcl( + params: COS.PutObjectAclParams, + callback: (err: COS.CosError, data: COS.PutObjectAclResult) => void, + ): void; putObjectAcl(params: COS.PutObjectAclParams): Promise; /** 跨域资源共享(CORS)的预检(Preflight)请求 @see https://cloud.tencent.com/document/product/436/8288 */ - optionsObject(params: COS.OptionsObjectParams, callback: (err: COS.CosError, data: COS.OptionsObjectResult) => void): void; + optionsObject( + params: COS.OptionsObjectParams, + callback: (err: COS.CosError, data: COS.OptionsObjectResult) => void, + ): void; optionsObject(params: COS.OptionsObjectParams): Promise; /** 恢复归档对象 @see https://cloud.tencent.com/document/product/436/12633 */ - restoreObject(params: COS.RestoreObjectParams, callback: (err: COS.CosError, data: COS.RestoreObjectResult) => void): void; + restoreObject( + params: COS.RestoreObjectParams, + callback: (err: COS.CosError, data: COS.RestoreObjectResult) => void, + ): void; restoreObject(params: COS.RestoreObjectParams): Promise; /** 检索对象内容 @see https://cloud.tencent.com/document/product/436/37641 */ - selectObjectContent(params: COS.SelectObjectContentParams, callback: (err: COS.CosError, data: COS.SelectObjectContentResult) => void): void; + selectObjectContent( + params: COS.SelectObjectContentParams, + callback: (err: COS.CosError, data: COS.SelectObjectContentResult) => void, + ): void; selectObjectContent(params: COS.SelectObjectContentParams): Promise; /** 检索对象内容,返回 Stream 对象 @see https://cloud.tencent.com/document/product/436/37641 */ - selectObjectContentStream(params: COS.SelectObjectContentParams, callback?: (err: COS.CosError, data: COS.SelectObjectContentResult) => void): Stream; + selectObjectContentStream( + params: COS.SelectObjectContentParams, + callback?: (err: COS.CosError, data: COS.SelectObjectContentResult) => void, + ): Stream; /** 复制对象 @see https://cloud.tencent.com/document/product/436/10881 */ - putObjectCopy(params: COS.PutObjectCopyParams, callback: (err: COS.CosError, data: COS.PutObjectCopyResult) => void): void; + putObjectCopy( + params: COS.PutObjectCopyParams, + callback: (err: COS.CosError, data: COS.PutObjectCopyResult) => void, + ): void; putObjectCopy(params: COS.PutObjectCopyParams): Promise; /** 设置对象标签 @see https://cloud.tencent.com/document/product/436/42997 */ - putObjectTagging(params: COS.PutObjectTaggingParams, callback: (err: COS.CosError, data: COS.PutObjectTaggingResult) => void): void; + putObjectTagging( + params: COS.PutObjectTaggingParams, + callback: (err: COS.CosError, data: COS.PutObjectTaggingResult) => void, + ): void; putObjectTagging(params: COS.PutObjectTaggingParams): Promise; /** 查询对象标签 @see https://cloud.tencent.com/document/product/436/42998 */ - getObjectTagging(params: COS.GetObjectTaggingParams, callback: (err: COS.CosError, data: COS.GetObjectTaggingResult) => void): void; + getObjectTagging( + params: COS.GetObjectTaggingParams, + callback: (err: COS.CosError, data: COS.GetObjectTaggingResult) => void, + ): void; getObjectTagging(params: COS.GetObjectTaggingParams): Promise; /** 删除对象标签 @see https://cloud.tencent.com/document/product/436/42999 */ - deleteObjectTagging(params: COS.DeleteObjectTaggingParams, callback: (err: COS.CosError, data: COS.DeleteObjectTaggingResult) => void): void; + deleteObjectTagging( + params: COS.DeleteObjectTaggingParams, + callback: (err: COS.CosError, data: COS.DeleteObjectTaggingResult) => void, + ): void; deleteObjectTagging(params: COS.DeleteObjectTaggingParams): Promise; /** 初始化分块上传 @see https://cloud.tencent.com/document/product/436/7746 */ - multipartInit(params: COS.MultipartInitParams, callback: (err: COS.CosError, data: COS.MultipartInitResult) => void): void; + multipartInit( + params: COS.MultipartInitParams, + callback: (err: COS.CosError, data: COS.MultipartInitResult) => void, + ): void; multipartInit(params: COS.MultipartInitParams): Promise; /** 分块上传 @see https://cloud.tencent.com/document/product/436/7750 */ - multipartUpload(params: COS.MultipartUploadParams, callback: (err: COS.CosError, data: COS.MultipartUploadResult) => void): void; + multipartUpload( + params: COS.MultipartUploadParams, + callback: (err: COS.CosError, data: COS.MultipartUploadResult) => void, + ): void; multipartUpload(params: COS.MultipartUploadParams): Promise; /** 分块上传 @see https://cloud.tencent.com/document/product/436/8287 */ - uploadPartCopy(params: COS.UploadPartCopyParams, callback: (err: COS.CosError, data: COS.UploadPartCopyResult) => void): void; + uploadPartCopy( + params: COS.UploadPartCopyParams, + callback: (err: COS.CosError, data: COS.UploadPartCopyResult) => void, + ): void; uploadPartCopy(params: COS.UploadPartCopyParams): Promise; /** 完成分块上传 @see https://cloud.tencent.com/document/product/436/7742 */ - multipartComplete(params: COS.MultipartCompleteParams, callback: (err: COS.CosError, data: COS.MultipartCompleteResult) => void): void; + multipartComplete( + params: COS.MultipartCompleteParams, + callback: (err: COS.CosError, data: COS.MultipartCompleteResult) => void, + ): void; multipartComplete(params: COS.MultipartCompleteParams): Promise; /** 分块上传任务列表查询 @see https://cloud.tencent.com/document/product/436/7736 */ - multipartList(params: COS.MultipartListParams, callback: (err: COS.CosError, data: COS.MultipartListResult) => void): void; + multipartList( + params: COS.MultipartListParams, + callback: (err: COS.CosError, data: COS.MultipartListResult) => void, + ): void; multipartList(params: COS.MultipartListParams): Promise; /** 上传的分块列表查询 @see https://cloud.tencent.com/document/product/436/7747 */ - multipartListPart(params: COS.MultipartListPartParams, callback: (err: COS.CosError, data: COS.MultipartListPartResult) => void): void; + multipartListPart( + params: COS.MultipartListPartParams, + callback: (err: COS.CosError, data: COS.MultipartListPartResult) => void, + ): void; multipartListPart(params: COS.MultipartListPartParams): Promise; /** 抛弃分块上传 @see https://cloud.tencent.com/document/product/436/7740 */ - multipartAbort(params: COS.MultipartAbortParams, callback: (err: COS.CosError, data: COS.MultipartAbortResult) => void): void; + multipartAbort( + params: COS.MultipartAbortParams, + callback: (err: COS.CosError, data: COS.MultipartAbortResult) => void, + ): void; multipartAbort(params: COS.MultipartAbortParams): Promise; /** 分片上传文件,封装好分片上传的多个步骤的上传方法。 */ - sliceUploadFile(params: COS.SliceUploadFileParams, callback: (err: COS.CosError, data: COS.SliceUploadFileResult) => void): void; + sliceUploadFile( + params: COS.SliceUploadFileParams, + callback: (err: COS.CosError, data: COS.SliceUploadFileResult) => void, + ): void; sliceUploadFile(params: COS.SliceUploadFileParams): Promise; /** 清理分片上传 UploadId,封装好的清理单个文件或存储桶所有文件未完成的 UploadId。 */ - abortUploadTask(params: COS.AbortUploadTaskParams, callback: (err: COS.CosError, data: COS.AbortUploadTaskResult) => void): void; + abortUploadTask( + params: COS.AbortUploadTaskParams, + callback: (err: COS.CosError, data: COS.AbortUploadTaskResult) => void, + ): void; abortUploadTask(params: COS.AbortUploadTaskParams): Promise; /** 高级上传文件 */ @@ -2313,7 +2529,10 @@ declare class COS { uploadFiles(params: COS.UploadFilesParams): Promise; /** 分片复制文件 */ - sliceCopyFile(params: COS.SliceCopyFileParams, callback: (err: COS.CosError, data: COS.SliceCopyFileResult) => void): void; + sliceCopyFile( + params: COS.SliceCopyFileParams, + callback: (err: COS.CosError, data: COS.SliceCopyFileResult) => void, + ): void; sliceCopyFile(params: COS.SliceCopyFileParams): Promise; /** 获取上传任务列表 */ @@ -2336,14 +2555,20 @@ declare class COS { request(params: COS.RequestParams): Promise; /** 获取文件下载链接 @see https://cloud.tencent.com/document/product/436/35651 */ - getObjectUrl(params: COS.GetObjectUrlParams, callback: (err: COS.CosError, data: COS.GetObjectUrlResult) => void): string; + getObjectUrl( + params: COS.GetObjectUrlParams, + callback: (err: COS.CosError, data: COS.GetObjectUrlResult) => void, + ): string; /** 追加上传 @see https://cloud.tencent.com/document/product/436/7741 */ appendObject(params: COS.AppendObjectParams, callback: (err: COS.CosError, data: COS.GeneralResult) => void): void; appendObject(params: COS.AppendObjectParams): Promise; /** 分块下载 @see https://cloud.tencent.com/document/product/436/64981#.E5.88.86.E5.9D.97.E4.B8.8B.E8.BD.BD.E5.AF.B9.E8.B1.A1 */ - downloadFile(params: COS.DownloadFileParams, callback: (err: COS.CosError, data: COS.DownloadFileResult) => void): void; + downloadFile( + params: COS.DownloadFileParams, + callback: (err: COS.CosError, data: COS.DownloadFileResult) => void, + ): void; downloadFile(params: COS.DownloadFileParams): Promise; /** 获取 COS JSON API (v4) 签名 @see https://cloud.tencent.com/document/product/436/6054 */ @@ -2355,7 +2580,6 @@ declare class COS { on(action: string, callback: (params?: any) => void): void; off(action: string, callback: (params?: any) => void): void; emit(action: string, data?: any): void; - } export = COS; diff --git a/package.json b/package.json index 4f89986..40bd140 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { "name": "cos-nodejs-sdk-v5", - "version": "2.12.3", + "version": "2.12.4", "description": "cos nodejs sdk v5", "main": "index.js", "types": "index.d.ts", "scripts": { + "prettier": "prettier --write sdk demo/demo.js test/test.js index.d.ts", "demo": "node demo/demo.js", "demo-sts": "node demo/demo-sts.js", "demo-sts-scope": "node demo/demo-sts-scope.js", @@ -42,6 +43,7 @@ "crc64-ecma182.js": "^1.0.0", "mocha": "^4.0.1", "nyc": "^15.1.0", + "prettier": "^3.0.1", "qcloud-cos-sts": "^3.0.0" }, "engines": { diff --git a/sdk/advance.js b/sdk/advance.js index cf8ea44..079985b 100644 --- a/sdk/advance.js +++ b/sdk/advance.js @@ -6,488 +6,526 @@ var util = require('./util'); // 文件分块上传全过程,暴露的分块上传接口 function sliceUploadFile(params, callback) { - var self = this; - var ep = new EventProxy(); - var TaskId = params.TaskId; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var FilePath = params.FilePath; - var ChunkSize = params.ChunkSize || params.SliceSize || self.options.ChunkSize; - var AsyncLimit = params.AsyncLimit; - var StorageClass = params.StorageClass; - var ServerSideEncryption = params.ServerSideEncryption; - var FileSize; - - var onProgress; - var onHashProgress = params.onHashProgress; - - // 上传过程中出现错误,返回错误 - ep.on('error', function (err) { - if (!self._isRunningTask(TaskId)) return; - var _err = { - UploadId: params.UploadData.UploadId || '', - err: err, - }; - return callback(_err); - }); - - // 上传分块完成,开始 uploadSliceComplete 操作 - ep.on('upload_complete', function (UploadCompleteData) { - var _UploadCompleteData = util.extend({ - UploadId: params.UploadData.UploadId || '' - }, UploadCompleteData); - callback(null, _UploadCompleteData); - }); - - // 上传分块完成,开始 uploadSliceComplete 操作 - ep.on('upload_slice_complete', function (UploadData) { - var metaHeaders = {}; - util.each(params.Headers, function (val, k) { - var shortKey = k.toLowerCase(); - if (shortKey.indexOf('x-cos-meta-') === 0 || shortKey === 'pic-operations') metaHeaders[k] = val; - }); - uploadSliceComplete.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - UploadId: UploadData.UploadId, - SliceList: UploadData.SliceList, - Headers: metaHeaders, - }, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - session.removeUsing(UploadData.UploadId); - if (err) { - onProgress(null, true); - return ep.emit('error', err); - } - session.removeUploadId.call(self, UploadData.UploadId); - onProgress({loaded: FileSize, total: FileSize}, true); - ep.emit('upload_complete', data); - }); - }); - - // 获取 UploadId 完成,开始上传每个分片 - ep.on('get_upload_data_finish', function (UploadData) { + var self = this; + var ep = new EventProxy(); + var TaskId = params.TaskId; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var FilePath = params.FilePath; + var ChunkSize = params.ChunkSize || params.SliceSize || self.options.ChunkSize; + var AsyncLimit = params.AsyncLimit; + var StorageClass = params.StorageClass; + var ServerSideEncryption = params.ServerSideEncryption; + var FileSize; + + var onProgress; + var onHashProgress = params.onHashProgress; + + // 上传过程中出现错误,返回错误 + ep.on('error', function (err) { + if (!self._isRunningTask(TaskId)) return; + var _err = { + UploadId: params.UploadData.UploadId || '', + err: err, + }; + return callback(_err); + }); - // 处理 UploadId 缓存 - var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key); - uuid && session.saveUploadId.call(self, uuid, UploadData.UploadId, self.options.UploadIdCacheLimit); // 缓存 UploadId - session.setUsing(UploadData.UploadId); // 标记 UploadId 为正在使用 + // 上传分块完成,开始 uploadSliceComplete 操作 + ep.on('upload_complete', function (UploadCompleteData) { + var _UploadCompleteData = util.extend( + { + UploadId: params.UploadData.UploadId || '', + }, + UploadCompleteData, + ); + callback(null, _UploadCompleteData); + }); - // 获取 UploadId - onProgress(null, true); // 任务状态开始 uploading - uploadSliceList.call(self, { - TaskId: TaskId, - Bucket: Bucket, - Region: Region, - Key: Key, - FilePath: FilePath, - FileSize: FileSize, - SliceSize: ChunkSize, - AsyncLimit: AsyncLimit, - ServerSideEncryption: ServerSideEncryption, - UploadData: UploadData, - Headers: params.Headers, - onProgress: onProgress - }, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - if (err) { - onProgress(null, true); - return ep.emit('error', err); - } - ep.emit('upload_slice_complete', data); - }); + // 上传分块完成,开始 uploadSliceComplete 操作 + ep.on('upload_slice_complete', function (UploadData) { + var metaHeaders = {}; + util.each(params.Headers, function (val, k) { + var shortKey = k.toLowerCase(); + if (shortKey.indexOf('x-cos-meta-') === 0 || shortKey === 'pic-operations') metaHeaders[k] = val; }); - - // 开始获取文件 UploadId,里面会视情况计算 ETag,并比对,保证文件一致性,也优化上传 - ep.on('get_file_size_finish', function () { - - onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); - - if (params.UploadData.UploadId) { - ep.emit('get_upload_data_finish', params.UploadData); - } else { - var _params = util.extend({ - TaskId: TaskId, - Bucket: Bucket, - Region: Region, - Key: Key, - Headers: params.Headers, - StorageClass: StorageClass, - FilePath: FilePath, - FileSize: FileSize, - SliceSize: ChunkSize, - onHashProgress: onHashProgress, - }, params); - getUploadIdAndPartList.call(self, _params, function (err, UploadData) { - if (!self._isRunningTask(TaskId)) return; - if (err) return ep.emit('error', err); - params.UploadData.UploadId = UploadData.UploadId; - params.UploadData.PartList = UploadData.PartList; - ep.emit('get_upload_data_finish', params.UploadData); - }); + uploadSliceComplete.call( + self, + { + Bucket: Bucket, + Region: Region, + Key: Key, + UploadId: UploadData.UploadId, + SliceList: UploadData.SliceList, + Headers: metaHeaders, + }, + function (err, data) { + if (!self._isRunningTask(TaskId)) return; + session.removeUsing(UploadData.UploadId); + if (err) { + onProgress(null, true); + return ep.emit('error', err); } - }); + session.removeUploadId.call(self, UploadData.UploadId); + onProgress({ loaded: FileSize, total: FileSize }, true); + ep.emit('upload_complete', data); + }, + ); + }); - // 获取上传文件大小 - FileSize = params.ContentLength; - delete params.ContentLength; - !params.Headers && (params.Headers = {}); - util.each(params.Headers, function (item, key) { - if (key.toLowerCase() === 'content-length') { - delete params.Headers[key]; + // 获取 UploadId 完成,开始上传每个分片 + ep.on('get_upload_data_finish', function (UploadData) { + // 处理 UploadId 缓存 + var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key); + uuid && session.saveUploadId.call(self, uuid, UploadData.UploadId, self.options.UploadIdCacheLimit); // 缓存 UploadId + session.setUsing(UploadData.UploadId); // 标记 UploadId 为正在使用 + + // 获取 UploadId + onProgress(null, true); // 任务状态开始 uploading + uploadSliceList.call( + self, + { + TaskId: TaskId, + Bucket: Bucket, + Region: Region, + Key: Key, + FilePath: FilePath, + FileSize: FileSize, + SliceSize: ChunkSize, + AsyncLimit: AsyncLimit, + ServerSideEncryption: ServerSideEncryption, + UploadData: UploadData, + Headers: params.Headers, + onProgress: onProgress, + }, + function (err, data) { + if (!self._isRunningTask(TaskId)) return; + if (err) { + onProgress(null, true); + return ep.emit('error', err); } - }); + ep.emit('upload_slice_complete', data); + }, + ); + }); - // 控制分片大小 - (function () { - var SIZE = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 1024 * 2, 1024 * 4, 1024 * 5]; - var AutoChunkSize = 1024 * 1024; - for (var i = 0; i < SIZE.length; i++) { - AutoChunkSize = SIZE[i] * 1024 * 1024; - if (FileSize / AutoChunkSize <= self.options.MaxPartNumber) break; - } - params.ChunkSize = params.SliceSize = ChunkSize = Math.max(ChunkSize, AutoChunkSize); - })(); + // 开始获取文件 UploadId,里面会视情况计算 ETag,并比对,保证文件一致性,也优化上传 + ep.on('get_file_size_finish', function () { + onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); - // 开始上传 - if (FileSize === 0) { - params.Body = ''; - params.ContentLength = 0; - params.SkipTask = true; - self.putObject(params, callback); + if (params.UploadData.UploadId) { + ep.emit('get_upload_data_finish', params.UploadData); } else { - ep.emit('get_file_size_finish'); + var _params = util.extend( + { + TaskId: TaskId, + Bucket: Bucket, + Region: Region, + Key: Key, + Headers: params.Headers, + StorageClass: StorageClass, + FilePath: FilePath, + FileSize: FileSize, + SliceSize: ChunkSize, + onHashProgress: onHashProgress, + }, + params, + ); + getUploadIdAndPartList.call(self, _params, function (err, UploadData) { + if (!self._isRunningTask(TaskId)) return; + if (err) return ep.emit('error', err); + params.UploadData.UploadId = UploadData.UploadId; + params.UploadData.PartList = UploadData.PartList; + ep.emit('get_upload_data_finish', params.UploadData); + }); } + }); + + // 获取上传文件大小 + FileSize = params.ContentLength; + delete params.ContentLength; + !params.Headers && (params.Headers = {}); + util.each(params.Headers, function (item, key) { + if (key.toLowerCase() === 'content-length') { + delete params.Headers[key]; + } + }); + // 控制分片大小 + (function () { + var SIZE = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 1024 * 2, 1024 * 4, 1024 * 5]; + var AutoChunkSize = 1024 * 1024; + for (var i = 0; i < SIZE.length; i++) { + AutoChunkSize = SIZE[i] * 1024 * 1024; + if (FileSize / AutoChunkSize <= self.options.MaxPartNumber) break; + } + params.ChunkSize = params.SliceSize = ChunkSize = Math.max(ChunkSize, AutoChunkSize); + })(); + + // 开始上传 + if (FileSize === 0) { + params.Body = ''; + params.ContentLength = 0; + params.SkipTask = true; + self.putObject(params, callback); + } else { + ep.emit('get_file_size_finish'); + } } // 获取上传任务的 UploadId function getUploadIdAndPartList(params, callback) { - var TaskId = params.TaskId; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var StorageClass = params.StorageClass; - var self = this; - - // 计算 ETag - var ETagMap = {}; - var FileSize = params.FileSize; - var SliceSize = params.SliceSize; - var SliceCount = Math.ceil(FileSize / SliceSize); - var FinishSliceCount = 0; - var FinishSize = 0; - var onHashProgress = util.throttleOnProgress.call(self, FileSize, params.onHashProgress); - var getChunkETag = function (PartNumber, callback) { - var start = SliceSize * (PartNumber - 1); - var end = Math.min(start + SliceSize, FileSize); - var ChunkSize = end - start; - - if (ETagMap[PartNumber]) { - callback(null, { - PartNumber: PartNumber, - ETag: ETagMap[PartNumber], - Size: ChunkSize - }); - } else { - util.fileSlice(params.FilePath, start, end, function (chunkItem) { - util.getFileMd5(chunkItem, function (err, md5) { - if (err) return callback(util.error(err)); - var ETag = '"' + md5 + '"'; - ETagMap[PartNumber] = ETag; - FinishSliceCount += 1; - FinishSize += ChunkSize; - onHashProgress({loaded: FinishSize, total: FileSize}); - callback(null, { - PartNumber: PartNumber, - ETag: ETag, - Size: ChunkSize - }); - }); - }); - } - }; + var TaskId = params.TaskId; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var StorageClass = params.StorageClass; + var self = this; - // 通过和文件的 md5 对比,判断 UploadId 是否可用 - var isAvailableUploadList = function (PartList, callback) { - var PartCount = PartList.length; - // 如果没有分片,通过 - if (PartCount === 0) { - return callback(null, true); - } - // 检查分片数量 - if (PartCount > SliceCount) { - return callback(null, false); - } - // 检查分片大小 - if (PartCount > 1) { - var PartSliceSize = Math.max(PartList[0].Size, PartList[1].Size); - if (PartSliceSize !== SliceSize) { - return callback(null, false); - } - } - // 逐个分片计算并检查 ETag 是否一致 - var next = function (index) { - if (index < PartCount) { - var Part = PartList[index]; - getChunkETag(Part.PartNumber, function (err, chunk) { - if (chunk && chunk.ETag === Part.ETag && chunk.Size === Part.Size) { - next(index + 1); - } else { - callback(null, false); - } - }); - } else { - callback(null, true); - } - }; - next(0); + // 计算 ETag + var ETagMap = {}; + var FileSize = params.FileSize; + var SliceSize = params.SliceSize; + var SliceCount = Math.ceil(FileSize / SliceSize); + var FinishSliceCount = 0; + var FinishSize = 0; + var onHashProgress = util.throttleOnProgress.call(self, FileSize, params.onHashProgress); + var getChunkETag = function (PartNumber, callback) { + var start = SliceSize * (PartNumber - 1); + var end = Math.min(start + SliceSize, FileSize); + var ChunkSize = end - start; + + if (ETagMap[PartNumber]) { + callback(null, { + PartNumber: PartNumber, + ETag: ETagMap[PartNumber], + Size: ChunkSize, + }); + } else { + util.fileSlice(params.FilePath, start, end, function (chunkItem) { + util.getFileMd5(chunkItem, function (err, md5) { + if (err) return callback(util.error(err)); + var ETag = '"' + md5 + '"'; + ETagMap[PartNumber] = ETag; + FinishSliceCount += 1; + FinishSize += ChunkSize; + onHashProgress({ loaded: FinishSize, total: FileSize }); + callback(null, { + PartNumber: PartNumber, + ETag: ETag, + Size: ChunkSize, + }); + }); + }); + } + }; + + // 通过和文件的 md5 对比,判断 UploadId 是否可用 + var isAvailableUploadList = function (PartList, callback) { + var PartCount = PartList.length; + // 如果没有分片,通过 + if (PartCount === 0) { + return callback(null, true); + } + // 检查分片数量 + if (PartCount > SliceCount) { + return callback(null, false); + } + // 检查分片大小 + if (PartCount > 1) { + var PartSliceSize = Math.max(PartList[0].Size, PartList[1].Size); + if (PartSliceSize !== SliceSize) { + return callback(null, false); + } + } + // 逐个分片计算并检查 ETag 是否一致 + var next = function (index) { + if (index < PartCount) { + var Part = PartList[index]; + getChunkETag(Part.PartNumber, function (err, chunk) { + if (chunk && chunk.ETag === Part.ETag && chunk.Size === Part.Size) { + next(index + 1); + } else { + callback(null, false); + } + }); + } else { + callback(null, true); + } }; + next(0); + }; - var ep = new EventProxy(); - ep.on('error', function (errData) { - if (!self._isRunningTask(TaskId)) return; - return callback(errData); + var ep = new EventProxy(); + ep.on('error', function (errData) { + if (!self._isRunningTask(TaskId)) return; + return callback(errData); + }); + + // 存在 UploadId + ep.on('upload_id_available', function (UploadData) { + // 转换成 map + var map = {}; + var list = []; + util.each(UploadData.PartList, function (item) { + map[item.PartNumber] = item; }); + for (var PartNumber = 1; PartNumber <= SliceCount; PartNumber++) { + var item = map[PartNumber]; + if (item) { + item.PartNumber = PartNumber; + item.Uploaded = true; + } else { + item = { + PartNumber: PartNumber, + ETag: null, + Uploaded: false, + }; + } + list.push(item); + } + UploadData.PartList = list; + callback(null, UploadData); + }); - // 存在 UploadId - ep.on('upload_id_available', function (UploadData) { - // 转换成 map - var map = {}; - var list = []; - util.each(UploadData.PartList, function (item) { - map[item.PartNumber] = item; - }); - for (var PartNumber = 1; PartNumber <= SliceCount; PartNumber++) { - var item = map[PartNumber]; - if (item) { - item.PartNumber = PartNumber; - item.Uploaded = true; - } else { - item = { - PartNumber: PartNumber, - ETag: null, - Uploaded: false - }; - } - list.push(item); - } - UploadData.PartList = list; - callback(null, UploadData); + // 不存在 UploadId, 初始化生成 UploadId + ep.on('no_available_upload_id', function () { + if (!self._isRunningTask(TaskId)) return; + var _params = util.extend( + { + Bucket: Bucket, + Region: Region, + Key: Key, + Headers: util.clone(params.Headers), + Query: util.clone(params.Query), + StorageClass: StorageClass, + }, + params, + ); + self.multipartInit(_params, function (err, data) { + if (!self._isRunningTask(TaskId)) return; + if (err) return ep.emit('error', err); + var UploadId = data.UploadId; + if (!UploadId) { + return callback(util.error(new Error('no such upload id'))); + } + ep.emit('upload_id_available', { UploadId: UploadId, PartList: [] }); }); + }); - // 不存在 UploadId, 初始化生成 UploadId - ep.on('no_available_upload_id', function () { + // 如果已存在 UploadId,找一个可以用的 UploadId + ep.on('has_and_check_upload_id', function (UploadIdList) { + // 串行地,找一个内容一致的 UploadId + UploadIdList = UploadIdList.reverse(); + Async.eachLimit( + UploadIdList, + 1, + function (UploadId, asyncCallback) { if (!self._isRunningTask(TaskId)) return; - var _params = util.extend({ + // 如果正在上传,跳过 + if (session.using[UploadId]) { + asyncCallback(); // 检查下一个 UploadId + return; + } + // 判断 UploadId 是否可用 + wholeMultipartListPart.call( + self, + { Bucket: Bucket, Region: Region, Key: Key, - Headers: util.clone(params.Headers), - Query: util.clone(params.Query), - StorageClass: StorageClass, - }, params); - self.multipartInit(_params, function (err, data) { + UploadId: UploadId, + }, + function (err, PartListData) { if (!self._isRunningTask(TaskId)) return; - if (err) return ep.emit('error', err); - var UploadId = data.UploadId; - if (!UploadId) { - return callback(util.error(new Error('no such upload id'))); + if (err) { + session.removeUsing(UploadId); + return ep.emit('error', err); } - ep.emit('upload_id_available', {UploadId: UploadId, PartList: []}); - }); - }); - - // 如果已存在 UploadId,找一个可以用的 UploadId - ep.on('has_and_check_upload_id', function (UploadIdList) { - // 串行地,找一个内容一致的 UploadId - UploadIdList = UploadIdList.reverse(); - Async.eachLimit(UploadIdList, 1, function (UploadId, asyncCallback) { - if (!self._isRunningTask(TaskId)) return; - // 如果正在上传,跳过 - if (session.using[UploadId]) { + var PartList = PartListData.PartList; + PartList.forEach(function (item) { + item.PartNumber *= 1; + item.Size *= 1; + item.ETag = item.ETag || ''; + }); + isAvailableUploadList(PartList, function (err, isAvailable) { + if (!self._isRunningTask(TaskId)) return; + if (err) return ep.emit('error', err); + if (isAvailable) { + asyncCallback({ + UploadId: UploadId, + PartList: PartList, + }); // 马上结束 + } else { asyncCallback(); // 检查下一个 UploadId - return; - } - // 判断 UploadId 是否可用 - wholeMultipartListPart.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - UploadId: UploadId, - }, function (err, PartListData) { - if (!self._isRunningTask(TaskId)) return; - if (err) { - session.removeUsing(UploadId); - return ep.emit('error', err); - } - var PartList = PartListData.PartList; - PartList.forEach(function (item) { - item.PartNumber *= 1; - item.Size *= 1; - item.ETag = item.ETag || ''; - }); - isAvailableUploadList(PartList, function (err, isAvailable) { - if (!self._isRunningTask(TaskId)) return; - if (err) return ep.emit('error', err); - if (isAvailable) { - asyncCallback({ - UploadId: UploadId, - PartList: PartList - }); // 马上结束 - } else { - asyncCallback(); // 检查下一个 UploadId - } - }); + } }); - }, function (AvailableUploadData) { - if (!self._isRunningTask(TaskId)) return; - onHashProgress(null, true); - if (AvailableUploadData && AvailableUploadData.UploadId) { - ep.emit('upload_id_available', AvailableUploadData); - } else { - ep.emit('no_available_upload_id'); - } - }); - }); - - // 在本地缓存找可用的 UploadId - ep.on('seek_local_avail_upload_id', function (RemoteUploadIdList) { - // 在本地找可用的 UploadId - var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key); - var LocalUploadIdList = session.getUploadIdList.call(self, uuid); - if (!uuid || !LocalUploadIdList) { - ep.emit('has_and_check_upload_id', RemoteUploadIdList); - return; + }, + ); + }, + function (AvailableUploadData) { + if (!self._isRunningTask(TaskId)) return; + onHashProgress(null, true); + if (AvailableUploadData && AvailableUploadData.UploadId) { + ep.emit('upload_id_available', AvailableUploadData); + } else { + ep.emit('no_available_upload_id'); } - var next = function (index) { - // 如果本地找不到可用 UploadId,再一个个遍历校验远端 - if (index >= LocalUploadIdList.length) { - ep.emit('has_and_check_upload_id', RemoteUploadIdList); - return; - } - var UploadId = LocalUploadIdList[index]; - // 如果不在远端 UploadId 列表里,跳过并删除 - if (!util.isInArray(RemoteUploadIdList, UploadId)) { - session.removeUploadId.call(self, UploadId); - next(index + 1); - return; - } - // 如果正在上传,跳过 - if (session.using[UploadId]) { - next(index + 1); - return; - } - // 判断 UploadId 是否存在线上 - wholeMultipartListPart.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - UploadId: UploadId, - }, function (err, PartListData) { - if (!self._isRunningTask(TaskId)) return; - if (err) { - // 如果 UploadId 获取会出错,跳过并删除 - session.removeUploadId.call(self, UploadId); - next(index + 1); - } else { - // 找到可用 UploadId - ep.emit('upload_id_available', { - UploadId: UploadId, - PartList: PartListData.PartList, - }); - } - }); - }; - next(0); - }); + }, + ); + }); - // 获取线上 UploadId 列表 - ep.on('get_remote_upload_id_list', function () { - // 获取符合条件的 UploadId 列表,因为同一个文件可以有多个上传任务。 - wholeMultipartList.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - }, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - if (err) return ep.emit('error', err); - // 整理远端 UploadId 列表 - var RemoteUploadIdList = util.filter(data.UploadList, function (item) { - return item.Key === Key && (!StorageClass || item.StorageClass.toUpperCase() === StorageClass.toUpperCase()); - }).reverse().map(function (item) { - return item.UploadId || item.UploadID; + // 在本地缓存找可用的 UploadId + ep.on('seek_local_avail_upload_id', function (RemoteUploadIdList) { + // 在本地找可用的 UploadId + var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key); + var LocalUploadIdList = session.getUploadIdList.call(self, uuid); + if (!uuid || !LocalUploadIdList) { + ep.emit('has_and_check_upload_id', RemoteUploadIdList); + return; + } + var next = function (index) { + // 如果本地找不到可用 UploadId,再一个个遍历校验远端 + if (index >= LocalUploadIdList.length) { + ep.emit('has_and_check_upload_id', RemoteUploadIdList); + return; + } + var UploadId = LocalUploadIdList[index]; + // 如果不在远端 UploadId 列表里,跳过并删除 + if (!util.isInArray(RemoteUploadIdList, UploadId)) { + session.removeUploadId.call(self, UploadId); + next(index + 1); + return; + } + // 如果正在上传,跳过 + if (session.using[UploadId]) { + next(index + 1); + return; + } + // 判断 UploadId 是否存在线上 + wholeMultipartListPart.call( + self, + { + Bucket: Bucket, + Region: Region, + Key: Key, + UploadId: UploadId, + }, + function (err, PartListData) { + if (!self._isRunningTask(TaskId)) return; + if (err) { + // 如果 UploadId 获取会出错,跳过并删除 + session.removeUploadId.call(self, UploadId); + next(index + 1); + } else { + // 找到可用 UploadId + ep.emit('upload_id_available', { + UploadId: UploadId, + PartList: PartListData.PartList, }); - if (RemoteUploadIdList.length) { - ep.emit('seek_local_avail_upload_id', RemoteUploadIdList); - } else { - // 远端没有 UploadId,清理缓存的 UploadId - var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key), LocalUploadIdList; - if (uuid && (LocalUploadIdList = session.getUploadIdList.call(self, uuid))) { - util.each(LocalUploadIdList, function (UploadId) { - session.removeUploadId.call(self, UploadId); - }); - } - ep.emit('no_available_upload_id'); - } - }); - }); + } + }, + ); + }; + next(0); + }); - // 开始找可用 UploadId - ep.emit('get_remote_upload_id_list'); + // 获取线上 UploadId 列表 + ep.on('get_remote_upload_id_list', function () { + // 获取符合条件的 UploadId 列表,因为同一个文件可以有多个上传任务。 + wholeMultipartList.call( + self, + { + Bucket: Bucket, + Region: Region, + Key: Key, + }, + function (err, data) { + if (!self._isRunningTask(TaskId)) return; + if (err) return ep.emit('error', err); + // 整理远端 UploadId 列表 + var RemoteUploadIdList = util + .filter(data.UploadList, function (item) { + return ( + item.Key === Key && (!StorageClass || item.StorageClass.toUpperCase() === StorageClass.toUpperCase()) + ); + }) + .reverse() + .map(function (item) { + return item.UploadId || item.UploadID; + }); + if (RemoteUploadIdList.length) { + ep.emit('seek_local_avail_upload_id', RemoteUploadIdList); + } else { + // 远端没有 UploadId,清理缓存的 UploadId + var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key), + LocalUploadIdList; + if (uuid && (LocalUploadIdList = session.getUploadIdList.call(self, uuid))) { + util.each(LocalUploadIdList, function (UploadId) { + session.removeUploadId.call(self, UploadId); + }); + } + ep.emit('no_available_upload_id'); + } + }, + ); + }); + // 开始找可用 UploadId + ep.emit('get_remote_upload_id_list'); } // 获取符合条件的全部上传任务 (条件包括 Bucket, Region, Prefix) function wholeMultipartList(params, callback) { - var self = this; - var UploadList = []; - var sendParams = { - Bucket: params.Bucket, - Region: params.Region, - Prefix: params.Key - }; - var next = function () { - self.multipartList(sendParams, function (err, data) { - if (err) return callback(err); - UploadList.push.apply(UploadList, data.Upload || []); - if (data.IsTruncated === 'true') { // 列表不完整 - sendParams.KeyMarker = data.NextKeyMarker; - sendParams.UploadIdMarker = data.NextUploadIdMarker; - next(); - } else { - callback(null, {UploadList: UploadList}); - } - }); - }; - next(); + var self = this; + var UploadList = []; + var sendParams = { + Bucket: params.Bucket, + Region: params.Region, + Prefix: params.Key, + }; + var next = function () { + self.multipartList(sendParams, function (err, data) { + if (err) return callback(err); + UploadList.push.apply(UploadList, data.Upload || []); + if (data.IsTruncated === 'true') { + // 列表不完整 + sendParams.KeyMarker = data.NextKeyMarker; + sendParams.UploadIdMarker = data.NextUploadIdMarker; + next(); + } else { + callback(null, { UploadList: UploadList }); + } + }); + }; + next(); } // 获取指定上传任务的分块列表 function wholeMultipartListPart(params, callback) { - var self = this; - var PartList = []; - var sendParams = { - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - UploadId: params.UploadId - }; - var next = function () { - self.multipartListPart(sendParams, function (err, data) { - if (err) return callback(err); - PartList.push.apply(PartList, data.Part || []); - if (data.IsTruncated === 'true') { // 列表不完整 - sendParams.PartNumberMarker = data.NextPartNumberMarker; - next(); - } else { - callback(null, {PartList: PartList}); - } - }); - }; - next(); + var self = this; + var PartList = []; + var sendParams = { + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + UploadId: params.UploadId, + }; + var next = function () { + self.multipartListPart(sendParams, function (err, data) { + if (err) return callback(err); + PartList.push.apply(PartList, data.Part || []); + if (data.IsTruncated === 'true') { + // 列表不完整 + sendParams.PartNumberMarker = data.NextPartNumberMarker; + next(); + } else { + callback(null, { PartList: PartList }); + } + }); + }; + next(); } // 上传文件分块,包括 @@ -501,170 +539,193 @@ function wholeMultipartListPart(params, callback) { onProgress (上传成功之后的回调函数) */ function uploadSliceList(params, cb) { - var self = this; - var TaskId = params.TaskId; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var UploadData = params.UploadData; - var FileSize = params.FileSize; - var SliceSize = params.SliceSize; - var ChunkParallel = Math.min(params.AsyncLimit || self.options.ChunkParallelLimit || 1, 256); - var FilePath = params.FilePath; - var SliceCount = Math.ceil(FileSize / SliceSize); - var FinishSize = 0; - var ServerSideEncryption = params.ServerSideEncryption; - var needUploadSlices = util.filter(UploadData.PartList, function (SliceItem) { - if (SliceItem['Uploaded']) { - FinishSize += SliceItem['PartNumber'] >= SliceCount ? (FileSize % SliceSize || SliceSize) : SliceSize; - } - return !SliceItem['Uploaded']; - }); - var onProgress = params.onProgress; - - Async.eachLimit(needUploadSlices, ChunkParallel, function (SliceItem, asyncCallback) { - if (!self._isRunningTask(TaskId)) return; - var PartNumber = SliceItem['PartNumber']; - var currentSize = Math.min(FileSize, SliceItem['PartNumber'] * SliceSize) - (SliceItem['PartNumber'] - 1) * SliceSize; - var preAddSize = 0; - uploadSliceItem.call(self, { - TaskId: TaskId, - Bucket: Bucket, - Region: Region, - Key: Key, - SliceSize: SliceSize, - FileSize: FileSize, - PartNumber: PartNumber, - ServerSideEncryption: ServerSideEncryption, - FilePath: FilePath, - UploadData: UploadData, - Headers: params.Headers, - onProgress: function (data) { - FinishSize += data.loaded - preAddSize; - preAddSize = data.loaded; - onProgress({loaded: FinishSize, total: FileSize}); - }, - }, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - if (err) { - FinishSize -= preAddSize; - } else { - FinishSize += currentSize - preAddSize; - SliceItem.ETag = data.ETag; - } - onProgress({loaded: FinishSize, total: FileSize}); - asyncCallback(err || null, data); - }); - }, function (err) { - if (!self._isRunningTask(TaskId)) return; - if (err) return cb(err); - cb(null, { - UploadId: UploadData.UploadId, - SliceList: UploadData.PartList - }); - }); + var self = this; + var TaskId = params.TaskId; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var UploadData = params.UploadData; + var FileSize = params.FileSize; + var SliceSize = params.SliceSize; + var ChunkParallel = Math.min(params.AsyncLimit || self.options.ChunkParallelLimit || 1, 256); + var FilePath = params.FilePath; + var SliceCount = Math.ceil(FileSize / SliceSize); + var FinishSize = 0; + var ServerSideEncryption = params.ServerSideEncryption; + var needUploadSlices = util.filter(UploadData.PartList, function (SliceItem) { + if (SliceItem['Uploaded']) { + FinishSize += SliceItem['PartNumber'] >= SliceCount ? FileSize % SliceSize || SliceSize : SliceSize; + } + return !SliceItem['Uploaded']; + }); + var onProgress = params.onProgress; + + Async.eachLimit( + needUploadSlices, + ChunkParallel, + function (SliceItem, asyncCallback) { + if (!self._isRunningTask(TaskId)) return; + var PartNumber = SliceItem['PartNumber']; + var currentSize = + Math.min(FileSize, SliceItem['PartNumber'] * SliceSize) - (SliceItem['PartNumber'] - 1) * SliceSize; + var preAddSize = 0; + uploadSliceItem.call( + self, + { + TaskId: TaskId, + Bucket: Bucket, + Region: Region, + Key: Key, + SliceSize: SliceSize, + FileSize: FileSize, + PartNumber: PartNumber, + ServerSideEncryption: ServerSideEncryption, + FilePath: FilePath, + UploadData: UploadData, + Headers: params.Headers, + onProgress: function (data) { + FinishSize += data.loaded - preAddSize; + preAddSize = data.loaded; + onProgress({ loaded: FinishSize, total: FileSize }); + }, + }, + function (err, data) { + if (!self._isRunningTask(TaskId)) return; + if (err) { + FinishSize -= preAddSize; + } else { + FinishSize += currentSize - preAddSize; + SliceItem.ETag = data.ETag; + } + onProgress({ loaded: FinishSize, total: FileSize }); + asyncCallback(err || null, data); + }, + ); + }, + function (err) { + if (!self._isRunningTask(TaskId)) return; + if (err) return cb(err); + cb(null, { + UploadId: UploadData.UploadId, + SliceList: UploadData.PartList, + }); + }, + ); } // 上传指定分片 function uploadSliceItem(params, callback) { - var self = this; - var TaskId = params.TaskId; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var FileSize = params.FileSize; - var FilePath = params.FilePath; - var PartNumber = params.PartNumber * 1; - var SliceSize = params.SliceSize; - var ServerSideEncryption = params.ServerSideEncryption; - var UploadData = params.UploadData; - var ChunkRetryTimes = self.options.ChunkRetryTimes + 1; - var Headers = params.Headers || {}; - - var start = SliceSize * (PartNumber - 1); - - var ContentLength = SliceSize; - - var end = start + SliceSize; - - if (end > FileSize) { - end = FileSize; - ContentLength = end - start; + var self = this; + var TaskId = params.TaskId; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var FileSize = params.FileSize; + var FilePath = params.FilePath; + var PartNumber = params.PartNumber * 1; + var SliceSize = params.SliceSize; + var ServerSideEncryption = params.ServerSideEncryption; + var UploadData = params.UploadData; + var ChunkRetryTimes = self.options.ChunkRetryTimes + 1; + var Headers = params.Headers || {}; + + var start = SliceSize * (PartNumber - 1); + + var ContentLength = SliceSize; + + var end = start + SliceSize; + + if (end > FileSize) { + end = FileSize; + ContentLength = end - start; + } + + var headersWhiteList = ['x-cos-traffic-limit', 'x-cos-mime-limit']; + var headers = {}; + util.each(Headers, function (v, k) { + if (headersWhiteList.indexOf(k) > -1) { + headers[k] = v; } + }); - var headersWhiteList = ['x-cos-traffic-limit', 'x-cos-mime-limit']; - var headers = {}; - util.each(Headers, function(v, k) { - if (headersWhiteList.indexOf(k) > -1) { - headers[k] = v; - } - }); - - util.fileSlice(FilePath, start, end, function (md5Body) { - util.getFileMd5(md5Body, function (err, md5) { - var contentMd5 = md5 ? util.binaryBase64(md5) : ''; - var PartItem = UploadData.PartList[PartNumber - 1]; - Async.retry(ChunkRetryTimes, function (tryCallback) { - if (!self._isRunningTask(TaskId)) return; - util.fileSlice(FilePath, start, end, function (Body) { - self.multipartUpload({ - TaskId: TaskId, - Bucket: Bucket, - Region: Region, - Key: Key, - ContentLength: ContentLength, - PartNumber: PartNumber, - UploadId: UploadData.UploadId, - ServerSideEncryption: ServerSideEncryption, - Body: Body, - Headers: headers, - onProgress: params.onProgress, - ContentMD5: contentMd5, - }, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - if (err) return tryCallback(err); - PartItem.Uploaded = true; - return tryCallback(null, data); - }); - }); - }, function (err, data) { + util.fileSlice(FilePath, start, end, function (md5Body) { + util.getFileMd5(md5Body, function (err, md5) { + var contentMd5 = md5 ? util.binaryBase64(md5) : ''; + var PartItem = UploadData.PartList[PartNumber - 1]; + Async.retry( + ChunkRetryTimes, + function (tryCallback) { + if (!self._isRunningTask(TaskId)) return; + util.fileSlice(FilePath, start, end, function (Body) { + self.multipartUpload( + { + TaskId: TaskId, + Bucket: Bucket, + Region: Region, + Key: Key, + ContentLength: ContentLength, + PartNumber: PartNumber, + UploadId: UploadData.UploadId, + ServerSideEncryption: ServerSideEncryption, + Body: Body, + Headers: headers, + onProgress: params.onProgress, + ContentMD5: contentMd5, + }, + function (err, data) { if (!self._isRunningTask(TaskId)) return; - return callback(err, data); - }); - }); + if (err) return tryCallback(err); + PartItem.Uploaded = true; + return tryCallback(null, data); + }, + ); + }); + }, + function (err, data) { + if (!self._isRunningTask(TaskId)) return; + return callback(err, data); + }, + ); }); + }); } - // 完成分块上传 function uploadSliceComplete(params, callback) { - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var UploadId = params.UploadId; - var SliceList = params.SliceList; - var self = this; - var ChunkRetryTimes = this.options.ChunkRetryTimes + 1; - var Headers = params.Headers; - var Parts = SliceList.map(function (item) { - return { - PartNumber: item.PartNumber, - ETag: item.ETag - }; - }); - // 完成上传的请求也做重试 - Async.retry(ChunkRetryTimes, function (tryCallback) { - self.multipartComplete({ - Bucket: Bucket, - Region: Region, - Key: Key, - UploadId: UploadId, - Parts: Parts, - Headers: Headers, - }, tryCallback); - }, function (err, data) { - callback(err, data); - }); + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var UploadId = params.UploadId; + var SliceList = params.SliceList; + var self = this; + var ChunkRetryTimes = this.options.ChunkRetryTimes + 1; + var Headers = params.Headers; + var Parts = SliceList.map(function (item) { + return { + PartNumber: item.PartNumber, + ETag: item.ETag, + }; + }); + // 完成上传的请求也做重试 + Async.retry( + ChunkRetryTimes, + function (tryCallback) { + self.multipartComplete( + { + Bucket: Bucket, + Region: Region, + Key: Key, + UploadId: UploadId, + Parts: Parts, + Headers: Headers, + }, + tryCallback, + ); + }, + function (err, data) { + callback(err, data); + }, + ); } // 抛弃分块上传任务 @@ -674,126 +735,146 @@ function uploadSliceComplete(params, callback) { Level (抛弃分块上传任务的级别,task : 抛弃指定的上传任务,file : 抛弃指定的文件对应的上传任务,其他值 :抛弃指定Bucket 的全部上传任务) */ function abortUploadTask(params, callback) { - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var UploadId = params.UploadId; - var Level = params.Level || 'task'; - var AsyncLimit = params.AsyncLimit; - var self = this; - - var ep = new EventProxy(); - - ep.on('error', function (errData) { - return callback(errData); - }); + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var UploadId = params.UploadId; + var Level = params.Level || 'task'; + var AsyncLimit = params.AsyncLimit; + var self = this; - // 已经获取到需要抛弃的任务列表 - ep.on('get_abort_array', function (AbortArray) { - abortUploadTaskArray.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - Headers: params.Headers, - AsyncLimit: AsyncLimit, - AbortArray: AbortArray - }, callback); - }); + var ep = new EventProxy(); - if (Level === 'bucket') { - // Bucket 级别的任务抛弃,抛弃该 Bucket 下的全部上传任务 - wholeMultipartList.call(self, { - Bucket: Bucket, - Region: Region - }, function (err, data) { - if (err) return callback(err); - ep.emit('get_abort_array', data.UploadList || []); - }); - } else if (Level === 'file') { - // 文件级别的任务抛弃,抛弃该文件的全部上传任务 - if (!Key) return callback(util.error(new Error('abort_upload_task_no_key'))); - wholeMultipartList.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key - }, function (err, data) { - if (err) return callback(err); - ep.emit('get_abort_array', data.UploadList || []); - }); - } else if (Level === 'task') { - // 单个任务级别的任务抛弃,抛弃指定 UploadId 的上传任务 - if (!UploadId) return callback(util.error(new Error('abort_upload_task_no_id'))); - if (!Key) return callback(util.error(new Error('abort_upload_task_no_key'))); - ep.emit('get_abort_array', [{ - Key: Key, - UploadId: UploadId - }]); - } else { - return callback(util.error(new Error('abort_unknown_level'))); - } + ep.on('error', function (errData) { + return callback(errData); + }); + + // 已经获取到需要抛弃的任务列表 + ep.on('get_abort_array', function (AbortArray) { + abortUploadTaskArray.call( + self, + { + Bucket: Bucket, + Region: Region, + Key: Key, + Headers: params.Headers, + AsyncLimit: AsyncLimit, + AbortArray: AbortArray, + }, + callback, + ); + }); + + if (Level === 'bucket') { + // Bucket 级别的任务抛弃,抛弃该 Bucket 下的全部上传任务 + wholeMultipartList.call( + self, + { + Bucket: Bucket, + Region: Region, + }, + function (err, data) { + if (err) return callback(err); + ep.emit('get_abort_array', data.UploadList || []); + }, + ); + } else if (Level === 'file') { + // 文件级别的任务抛弃,抛弃该文件的全部上传任务 + if (!Key) return callback(util.error(new Error('abort_upload_task_no_key'))); + wholeMultipartList.call( + self, + { + Bucket: Bucket, + Region: Region, + Key: Key, + }, + function (err, data) { + if (err) return callback(err); + ep.emit('get_abort_array', data.UploadList || []); + }, + ); + } else if (Level === 'task') { + // 单个任务级别的任务抛弃,抛弃指定 UploadId 的上传任务 + if (!UploadId) return callback(util.error(new Error('abort_upload_task_no_id'))); + if (!Key) return callback(util.error(new Error('abort_upload_task_no_key'))); + ep.emit('get_abort_array', [ + { + Key: Key, + UploadId: UploadId, + }, + ]); + } else { + return callback(util.error(new Error('abort_unknown_level'))); + } } // 批量抛弃分块上传任务 function abortUploadTaskArray(params, callback) { + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var AbortArray = params.AbortArray; + var AsyncLimit = params.AsyncLimit || 1; + var self = this; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var AbortArray = params.AbortArray; - var AsyncLimit = params.AsyncLimit || 1; - var self = this; - - var index = 0; - var resultList = new Array(AbortArray.length); - Async.eachLimit(AbortArray, AsyncLimit, function (AbortItem, nextItem) { - var eachIndex = index; - if (Key && Key !== AbortItem.Key) { - resultList[eachIndex] = {error: {KeyNotMatch: true}}; - nextItem(null); - return; - } - var UploadId = AbortItem.UploadId || AbortItem.UploadID; - - self.multipartAbort({ + var index = 0; + var resultList = new Array(AbortArray.length); + Async.eachLimit( + AbortArray, + AsyncLimit, + function (AbortItem, nextItem) { + var eachIndex = index; + if (Key && Key !== AbortItem.Key) { + resultList[eachIndex] = { error: { KeyNotMatch: true } }; + nextItem(null); + return; + } + var UploadId = AbortItem.UploadId || AbortItem.UploadID; + + self.multipartAbort( + { + Bucket: Bucket, + Region: Region, + Key: AbortItem.Key, + Headers: params.Headers, + UploadId: UploadId, + }, + function (err) { + var task = { Bucket: Bucket, Region: Region, Key: AbortItem.Key, - Headers: params.Headers, - UploadId: UploadId - }, function (err) { - var task = { - Bucket: Bucket, - Region: Region, - Key: AbortItem.Key, - UploadId: UploadId - }; - resultList[eachIndex] = {error: err, task: task}; - nextItem(null); - }); - index++; - - }, function (err) { - if (err) return callback(err); - - var successList = []; - var errorList = []; - - for (var i = 0, len = resultList.length; i < len; i++) { - var item = resultList[i]; - if (item['task']) { - if (item['error']) { - errorList.push(item['task']); - } else { - successList.push(item['task']); - } - } + UploadId: UploadId, + }; + resultList[eachIndex] = { error: err, task: task }; + nextItem(null); + }, + ); + index++; + }, + function (err) { + if (err) return callback(err); + + var successList = []; + var errorList = []; + + for (var i = 0, len = resultList.length; i < len; i++) { + var item = resultList[i]; + if (item['task']) { + if (item['error']) { + errorList.push(item['task']); + } else { + successList.push(item['task']); + } } + } - return callback(null, { - successList: successList, - errorList: errorList - }); - }); + return callback(null, { + successList: successList, + errorList: errorList, + }); + }, + ); } // 高级上传 @@ -807,702 +888,772 @@ function uploadFile(params, callback) { var taskList = []; fs.stat(params.FilePath, function (err, stat) { - if (err) { - return callback(err); + if (err) { + return callback(err); + } + + var isDir = stat.isDirectory(); + var FileSize = (params.ContentLength = stat.size || 0); + var fileInfo = { TaskId: '' }; + + // 整理 option,用于返回给回调 + util.each(params, function (v, k) { + if (typeof v !== 'object' && typeof v !== 'function') { + fileInfo[k] = v; } + }); + + // 处理文件 TaskReady + var _onTaskReady = params.onTaskReady; + var onTaskReady = function (tid) { + fileInfo.TaskId = tid; + _onTaskReady && _onTaskReady(tid); + }; + params.onTaskReady = onTaskReady; + + // 处理文件完成 + var _onFileFinish = params.onFileFinish; + var onFileFinish = function (err, data) { + _onFileFinish && _onFileFinish(err, data, fileInfo); + callback && callback(err, data); + }; - var isDir = stat.isDirectory(); - var FileSize = params.ContentLength = stat.size || 0; - var fileInfo = {TaskId: ''}; + // 添加上传任务 + var api = FileSize <= SliceSize || isDir ? 'putObject' : 'sliceUploadFile'; + if (api === 'putObject') { + params.Body = isDir ? '' : fs.createReadStream(params.FilePath); + params.Body.isSdkCreated = true; + } + taskList.push({ + api: api, + params: params, + callback: onFileFinish, + }); + self._addTasks(taskList); + }); +} + +// 批量上传文件 +function uploadFiles(params, callback) { + var self = this; + + // 判断多大的文件使用分片上传 + var SliceSize = params.SliceSize === undefined ? self.options.SliceSize : params.SliceSize; + + // 汇总返回进度 + var TotalSize = 0; + var TotalFinish = 0; + var onTotalProgress = util.throttleOnProgress.call(self, TotalFinish, params.onProgress); + + // 汇总返回回调 + var unFinishCount = params.files.length; + var _onTotalFileFinish = params.onFileFinish; + var resultList = Array(unFinishCount); + var onTotalFileFinish = function (err, data, options) { + onTotalProgress(null, true); + _onTotalFileFinish && _onTotalFileFinish(err, data, options); + resultList[options.Index] = { + options: options, + error: err, + data: data, + }; + if (--unFinishCount <= 0 && callback) { + callback(null, { files: resultList }); + } + }; + + // 开始处理每个文件 + var taskList = []; + var count = params.files.length; + util.each(params.files, function (fileParams, index) { + fs.stat(fileParams.FilePath, function (err, stat) { + var isDir = stat ? stat.isDirectory() : false; + var FileSize = (fileParams.ContentLength = stat ? stat.size : 0); + var fileInfo = { Index: index, TaskId: '' }; + + // 更新文件总大小 + TotalSize += FileSize; // 整理 option,用于返回给回调 - util.each(params, function (v, k) { - if (typeof v !== 'object' && typeof v !== 'function') { - fileInfo[k] = v; - } + util.each(fileParams, function (v, k) { + if (typeof v !== 'object' && typeof v !== 'function') { + fileInfo[k] = v; + } }); - // 处理文件 TaskReady - var _onTaskReady = params.onTaskReady; + // 处理单个文件 TaskReady + var _onTaskReady = fileParams.onTaskReady; var onTaskReady = function (tid) { - fileInfo.TaskId = tid; - _onTaskReady && _onTaskReady(tid); + fileInfo.TaskId = tid; + _onTaskReady && _onTaskReady(tid); }; - params.onTaskReady = onTaskReady; + fileParams.onTaskReady = onTaskReady; + + // 处理单个文件进度 + var PreAddSize = 0; + var _onProgress = fileParams.onProgress; + var onProgress = function (info) { + TotalFinish = TotalFinish - PreAddSize + info.loaded; + PreAddSize = info.loaded; + _onProgress && _onProgress(info); + onTotalProgress({ loaded: TotalFinish, total: TotalSize }); + }; + fileParams.onProgress = onProgress; - // 处理文件完成 - var _onFileFinish = params.onFileFinish; + // 处理单个文件完成 + var _onFileFinish = fileParams.onFileFinish; var onFileFinish = function (err, data) { - _onFileFinish && _onFileFinish(err, data, fileInfo); - callback && callback(err, data); + _onFileFinish && _onFileFinish(err, data); + onTotalFileFinish && onTotalFileFinish(err, data, fileInfo); }; // 添加上传任务 var api = FileSize <= SliceSize || isDir ? 'putObject' : 'sliceUploadFile'; if (api === 'putObject') { - params.Body = isDir ? '' : fs.createReadStream(params.FilePath); - params.Body.isSdkCreated = true; + fileParams.Body = isDir ? '' : fs.createReadStream(fileParams.FilePath); + fileParams.Body.isSdkCreated = true; } taskList.push({ - api: api, - params: params, - callback: onFileFinish, + api: api, + params: fileParams, + callback: onFileFinish, }); - self._addTasks(taskList); - }); -} - -// 批量上传文件 -function uploadFiles(params, callback) { - var self = this; - - // 判断多大的文件使用分片上传 - var SliceSize = params.SliceSize === undefined ? self.options.SliceSize : params.SliceSize; - - // 汇总返回进度 - var TotalSize = 0; - var TotalFinish = 0; - var onTotalProgress = util.throttleOnProgress.call(self, TotalFinish, params.onProgress); - - // 汇总返回回调 - var unFinishCount = params.files.length; - var _onTotalFileFinish = params.onFileFinish; - var resultList = Array(unFinishCount); - var onTotalFileFinish = function (err, data, options) { - onTotalProgress(null, true); - _onTotalFileFinish && _onTotalFileFinish(err, data, options); - resultList[options.Index] = { - options: options, - error: err, - data: data - }; - if (--unFinishCount <= 0 && callback) { - callback(null, {files: resultList}); - } - }; - - // 开始处理每个文件 - var taskList = []; - var count = params.files.length; - util.each(params.files, function (fileParams, index) { - fs.stat(fileParams.FilePath, function (err, stat) { - var isDir = stat ? stat.isDirectory() : false; - var FileSize = fileParams.ContentLength = stat ? stat.size : 0; - var fileInfo = {Index: index, TaskId: ''}; - - // 更新文件总大小 - TotalSize += FileSize; - - // 整理 option,用于返回给回调 - util.each(fileParams, function (v, k) { - if (typeof v !== 'object' && typeof v !== 'function') { - fileInfo[k] = v; - } - }); - - // 处理单个文件 TaskReady - var _onTaskReady = fileParams.onTaskReady; - var onTaskReady = function (tid) { - fileInfo.TaskId = tid; - _onTaskReady && _onTaskReady(tid); - }; - fileParams.onTaskReady = onTaskReady; - - // 处理单个文件进度 - var PreAddSize = 0; - var _onProgress = fileParams.onProgress; - var onProgress = function (info) { - TotalFinish = TotalFinish - PreAddSize + info.loaded; - PreAddSize = info.loaded; - _onProgress && _onProgress(info); - onTotalProgress({loaded: TotalFinish, total: TotalSize}); - }; - fileParams.onProgress = onProgress; - - // 处理单个文件完成 - var _onFileFinish = fileParams.onFileFinish; - var onFileFinish = function (err, data) { - _onFileFinish && _onFileFinish(err, data); - onTotalFileFinish && onTotalFileFinish(err, data, fileInfo); - }; - - // 添加上传任务 - var api = FileSize <= SliceSize || isDir ? 'putObject' : 'sliceUploadFile'; - if (api === 'putObject') { - fileParams.Body = isDir ? '' : fs.createReadStream(fileParams.FilePath); - fileParams.Body.isSdkCreated = true; - } - taskList.push({ - api: api, - params: fileParams, - callback: onFileFinish, - }); - --count === 0 && self._addTasks(taskList); - }); + --count === 0 && self._addTasks(taskList); }); + }); } // 分片复制文件 function sliceCopyFile(params, callback) { - var ep = new EventProxy(); - - var self = this; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var CopySource = params.CopySource; - var m = util.getSourceParams.call(this, CopySource); - if (!m) { - callback(util.error(new Error('CopySource format error'))); - return; - } + var ep = new EventProxy(); - var SourceBucket = m.Bucket; - var SourceRegion = m.Region; - var SourceKey = decodeURIComponent(m.Key); - var CopySliceSize = params.CopySliceSize === undefined ? self.options.CopySliceSize : params.CopySliceSize; - CopySliceSize = Math.max(0, CopySliceSize); - - var ChunkSize = params.CopyChunkSize || this.options.CopyChunkSize; - var ChunkParallel = this.options.CopyChunkParallelLimit; - var ChunkRetryTimes = this.options.ChunkRetryTimes + 1; - - var ChunkCount = 0; - var FinishSize = 0; - var FileSize; - var onProgress; - var SourceResHeaders = {}; - var SourceHeaders = {}; - var TargetHeader = {}; - - // 分片复制完成,开始 multipartComplete 操作 - ep.on('copy_slice_complete', function (UploadData) { - var metaHeaders = {}; - util.each(params.Headers, function (val, k) { - if (k.toLowerCase().indexOf('x-cos-meta-') === 0) metaHeaders[k] = val; - }); - var Parts = util.map(UploadData.PartList, function (item) { - return { - PartNumber: item.PartNumber, - ETag: item.ETag, - }; - }); - // 完成上传的请求也做重试 - Async.retry(ChunkRetryTimes, function (tryCallback) { - self.multipartComplete({ - Bucket: Bucket, - Region: Region, - Key: Key, - UploadId: UploadData.UploadId, - Parts: Parts, - }, tryCallback); - }, function (err, data) { - session.removeUsing(UploadData.UploadId); // 标记 UploadId 没被使用了,因为复制没提供重试,所以只要出错,就是 UploadId 停用了。 - if (err) { - onProgress(null, true); - return callback(err); - } - session.removeUploadId.call(self, UploadData.UploadId); - onProgress({loaded: FileSize, total: FileSize}, true); - callback(null, data); - }); + var self = this; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var CopySource = params.CopySource; + var m = util.getSourceParams.call(this, CopySource); + if (!m) { + callback(util.error(new Error('CopySource format error'))); + return; + } + + var SourceBucket = m.Bucket; + var SourceRegion = m.Region; + var SourceKey = decodeURIComponent(m.Key); + var CopySliceSize = params.CopySliceSize === undefined ? self.options.CopySliceSize : params.CopySliceSize; + CopySliceSize = Math.max(0, CopySliceSize); + + var ChunkSize = params.CopyChunkSize || this.options.CopyChunkSize; + var ChunkParallel = this.options.CopyChunkParallelLimit; + var ChunkRetryTimes = this.options.ChunkRetryTimes + 1; + + var ChunkCount = 0; + var FinishSize = 0; + var FileSize; + var onProgress; + var SourceResHeaders = {}; + var SourceHeaders = {}; + var TargetHeader = {}; + + // 分片复制完成,开始 multipartComplete 操作 + ep.on('copy_slice_complete', function (UploadData) { + var metaHeaders = {}; + util.each(params.Headers, function (val, k) { + if (k.toLowerCase().indexOf('x-cos-meta-') === 0) metaHeaders[k] = val; }); + var Parts = util.map(UploadData.PartList, function (item) { + return { + PartNumber: item.PartNumber, + ETag: item.ETag, + }; + }); + // 完成上传的请求也做重试 + Async.retry( + ChunkRetryTimes, + function (tryCallback) { + self.multipartComplete( + { + Bucket: Bucket, + Region: Region, + Key: Key, + UploadId: UploadData.UploadId, + Parts: Parts, + }, + tryCallback, + ); + }, + function (err, data) { + session.removeUsing(UploadData.UploadId); // 标记 UploadId 没被使用了,因为复制没提供重试,所以只要出错,就是 UploadId 停用了。 + if (err) { + onProgress(null, true); + return callback(err); + } + session.removeUploadId.call(self, UploadData.UploadId); + onProgress({ loaded: FileSize, total: FileSize }, true); + callback(null, data); + }, + ); + }); - ep.on('get_copy_data_finish',function (UploadData) { - // 处理 UploadId 缓存 - var uuid = session.getCopyFileId(CopySource, SourceResHeaders, ChunkSize, Bucket, Key); - uuid && session.saveUploadId.call(self, uuid, UploadData.UploadId, self.options.UploadIdCacheLimit); // 缓存 UploadId - session.setUsing(UploadData.UploadId); // 标记 UploadId 为正在使用 + ep.on('get_copy_data_finish', function (UploadData) { + // 处理 UploadId 缓存 + var uuid = session.getCopyFileId(CopySource, SourceResHeaders, ChunkSize, Bucket, Key); + uuid && session.saveUploadId.call(self, uuid, UploadData.UploadId, self.options.UploadIdCacheLimit); // 缓存 UploadId + session.setUsing(UploadData.UploadId); // 标记 UploadId 为正在使用 - var needCopySlices = util.filter(UploadData.PartList, function (SliceItem) { - if (SliceItem['Uploaded']) { - FinishSize += SliceItem['PartNumber'] >= ChunkCount ? (FileSize % ChunkSize || ChunkSize) : ChunkSize; - } - return !SliceItem['Uploaded']; - }); - Async.eachLimit(needCopySlices, ChunkParallel, function (SliceItem, asyncCallback) { - var PartNumber = SliceItem.PartNumber; - var CopySourceRange = SliceItem.CopySourceRange; - var currentSize = SliceItem.end - SliceItem.start; - Async.retry(ChunkRetryTimes, function (tryCallback) { - copySliceItem.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - CopySource: CopySource, - UploadId: UploadData.UploadId, - PartNumber: PartNumber, - CopySourceRange: CopySourceRange, - }, tryCallback); - }, function (err,data) { - if (err) return asyncCallback(err); - FinishSize += currentSize; - onProgress({loaded: FinishSize, total: FileSize}); - SliceItem.ETag = data.ETag; - asyncCallback(err || null, data); - }); - }, function (err) { - if (err) { - session.removeUsing(UploadData.UploadId); // 标记 UploadId 没被使用了,因为复制没提供重试,所以只要出错,就是 UploadId 停用了。 - onProgress(null, true); - return callback(err); - } - ep.emit('copy_slice_complete', UploadData); - }); + var needCopySlices = util.filter(UploadData.PartList, function (SliceItem) { + if (SliceItem['Uploaded']) { + FinishSize += SliceItem['PartNumber'] >= ChunkCount ? FileSize % ChunkSize || ChunkSize : ChunkSize; + } + return !SliceItem['Uploaded']; }); - - ep.on('get_chunk_size_finish', function () { - var createNewUploadId = function () { - self.multipartInit({ + Async.eachLimit( + needCopySlices, + ChunkParallel, + function (SliceItem, asyncCallback) { + var PartNumber = SliceItem.PartNumber; + var CopySourceRange = SliceItem.CopySourceRange; + var currentSize = SliceItem.end - SliceItem.start; + Async.retry( + ChunkRetryTimes, + function (tryCallback) { + copySliceItem.call( + self, + { Bucket: Bucket, Region: Region, Key: Key, - Headers: TargetHeader, - }, function (err,data) { - if (err) return callback(err); - params.UploadId = data.UploadId; - ep.emit('get_copy_data_finish', {UploadId: params.UploadId, PartList: params.PartList}); - }); - }; + CopySource: CopySource, + UploadId: UploadData.UploadId, + PartNumber: PartNumber, + CopySourceRange: CopySourceRange, + }, + tryCallback, + ); + }, + function (err, data) { + if (err) return asyncCallback(err); + FinishSize += currentSize; + onProgress({ loaded: FinishSize, total: FileSize }); + SliceItem.ETag = data.ETag; + asyncCallback(err || null, data); + }, + ); + }, + function (err) { + if (err) { + session.removeUsing(UploadData.UploadId); // 标记 UploadId 没被使用了,因为复制没提供重试,所以只要出错,就是 UploadId 停用了。 + onProgress(null, true); + return callback(err); + } + ep.emit('copy_slice_complete', UploadData); + }, + ); + }); - // 在本地找可用的 UploadId - var uuid = session.getCopyFileId(CopySource, SourceResHeaders, ChunkSize, Bucket, Key); - var LocalUploadIdList = session.getUploadIdList.call(self, uuid); - if (!uuid || !LocalUploadIdList) return createNewUploadId(); + ep.on('get_chunk_size_finish', function () { + var createNewUploadId = function () { + self.multipartInit( + { + Bucket: Bucket, + Region: Region, + Key: Key, + Headers: TargetHeader, + }, + function (err, data) { + if (err) return callback(err); + params.UploadId = data.UploadId; + ep.emit('get_copy_data_finish', { UploadId: params.UploadId, PartList: params.PartList }); + }, + ); + }; - var next = function (index) { - // 如果本地找不到可用 UploadId,再一个个遍历校验远端 - if (index >= LocalUploadIdList.length) return createNewUploadId(); - var UploadId = LocalUploadIdList[index]; - // 如果正在被使用,跳过 + // 在本地找可用的 UploadId + var uuid = session.getCopyFileId(CopySource, SourceResHeaders, ChunkSize, Bucket, Key); + var LocalUploadIdList = session.getUploadIdList.call(self, uuid); + if (!uuid || !LocalUploadIdList) return createNewUploadId(); + + var next = function (index) { + // 如果本地找不到可用 UploadId,再一个个遍历校验远端 + if (index >= LocalUploadIdList.length) return createNewUploadId(); + var UploadId = LocalUploadIdList[index]; + // 如果正在被使用,跳过 + if (session.using[UploadId]) return next(index + 1); + // 判断 UploadId 是否存在线上 + wholeMultipartListPart.call( + self, + { + Bucket: Bucket, + Region: Region, + Key: Key, + UploadId: UploadId, + }, + function (err, PartListData) { + if (err) { + // 如果 UploadId 获取会出错,跳过并删除 + session.removeUploadId.call(self, UploadId); + next(index + 1); + } else { + // 如果异步回来 UploadId 已经被用了,也跳过 if (session.using[UploadId]) return next(index + 1); - // 判断 UploadId 是否存在线上 - wholeMultipartListPart.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - UploadId: UploadId, - }, function (err, PartListData) { - if (err) { - // 如果 UploadId 获取会出错,跳过并删除 - session.removeUploadId.call(self, UploadId); - next(index + 1); - } else { - // 如果异步回来 UploadId 已经被用了,也跳过 - if (session.using[UploadId]) return next(index + 1); - // 找到可用 UploadId - var finishETagMap = {}; - var offset = 0; - util.each(PartListData.PartList, function (PartItem) { - var size = parseInt(PartItem.Size); - var end = offset + size - 1; - finishETagMap[PartItem.PartNumber + '|' + offset + '|' + end] = PartItem.ETag; - offset += size; - }); - util.each(params.PartList, function (PartItem) { - var ETag = finishETagMap[PartItem.PartNumber + '|' + PartItem.start + '|' + PartItem.end]; - if (ETag) { - PartItem.ETag = ETag; - PartItem.Uploaded = true; - } - }); - ep.emit('get_copy_data_finish', {UploadId: UploadId, PartList: params.PartList}); - } + // 找到可用 UploadId + var finishETagMap = {}; + var offset = 0; + util.each(PartListData.PartList, function (PartItem) { + var size = parseInt(PartItem.Size); + var end = offset + size - 1; + finishETagMap[PartItem.PartNumber + '|' + offset + '|' + end] = PartItem.ETag; + offset += size; }); + util.each(params.PartList, function (PartItem) { + var ETag = finishETagMap[PartItem.PartNumber + '|' + PartItem.start + '|' + PartItem.end]; + if (ETag) { + PartItem.ETag = ETag; + PartItem.Uploaded = true; + } + }); + ep.emit('get_copy_data_finish', { UploadId: UploadId, PartList: params.PartList }); + } + }, + ); + }; + next(0); + }); + + ep.on('get_file_size_finish', function () { + // 控制分片大小 + (function () { + var SIZE = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 1024 * 2, 1024 * 4, 1024 * 5]; + var AutoChunkSize = 1024 * 1024; + for (var i = 0; i < SIZE.length; i++) { + AutoChunkSize = SIZE[i] * 1024 * 1024; + if (FileSize / AutoChunkSize <= self.options.MaxPartNumber) break; + } + params.ChunkSize = ChunkSize = Math.max(ChunkSize, AutoChunkSize); + ChunkCount = Math.ceil(FileSize / ChunkSize); + + var list = []; + for (var partNumber = 1; partNumber <= ChunkCount; partNumber++) { + var start = (partNumber - 1) * ChunkSize; + var end = partNumber * ChunkSize < FileSize ? partNumber * ChunkSize - 1 : FileSize - 1; + var item = { + PartNumber: partNumber, + start: start, + end: end, + CopySourceRange: 'bytes=' + start + '-' + end, }; - next(0); - }); + list.push(item); + } + params.PartList = list; + })(); - ep.on('get_file_size_finish', function () { - // 控制分片大小 - (function () { - var SIZE = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 1024 * 2, 1024 * 4, 1024 * 5]; - var AutoChunkSize = 1024 * 1024; - for (var i = 0; i < SIZE.length; i++) { - AutoChunkSize = SIZE[i] * 1024 * 1024; - if (FileSize / AutoChunkSize <= self.options.MaxPartNumber) break; - } - params.ChunkSize = ChunkSize = Math.max(ChunkSize, AutoChunkSize); - ChunkCount = Math.ceil(FileSize / ChunkSize); - - var list = []; - for (var partNumber = 1; partNumber <= ChunkCount; partNumber++) { - var start = (partNumber - 1) * ChunkSize; - var end = partNumber * ChunkSize < FileSize ? (partNumber * ChunkSize - 1) : FileSize - 1; - var item = { - PartNumber: partNumber, - start: start, - end: end, - CopySourceRange: "bytes=" + start + "-" + end, - }; - list.push(item); - } - params.PartList = list; - })(); + if (params.Headers['x-cos-metadata-directive'] === 'Replaced') { + TargetHeader = params.Headers; + } else { + TargetHeader = SourceHeaders; + } + TargetHeader['x-cos-storage-class'] = params.Headers['x-cos-storage-class'] || SourceHeaders['x-cos-storage-class']; + TargetHeader = util.clearKey(TargetHeader); + /** + * 对于归档存储的对象,如果未恢复副本,则不允许 Copy + */ + if (SourceHeaders['x-cos-storage-class'] === 'ARCHIVE' || SourceHeaders['x-cos-storage-class'] === 'DEEP_ARCHIVE') { + var restoreHeader = SourceHeaders['x-cos-restore']; + if (!restoreHeader || restoreHeader === 'ongoing-request="true"') { + callback(util.error(new Error('Unrestored archive object is not allowed to be copied'))); + return; + } + } + /** + * 去除一些无用的头部,规避 multipartInit 出错 + * 这些头部通常是在 putObjectCopy 时才使用 + */ + delete TargetHeader['x-cos-copy-source']; + delete TargetHeader['x-cos-metadata-directive']; + delete TargetHeader['x-cos-copy-source-If-Modified-Since']; + delete TargetHeader['x-cos-copy-source-If-Unmodified-Since']; + delete TargetHeader['x-cos-copy-source-If-Match']; + delete TargetHeader['x-cos-copy-source-If-None-Match']; + ep.emit('get_chunk_size_finish'); + }); - if (params.Headers['x-cos-metadata-directive'] === 'Replaced') { - TargetHeader = params.Headers; + // 获取远端复制源文件的大小 + self.headObject( + { + Bucket: SourceBucket, + Region: SourceRegion, + Key: SourceKey, + }, + function (err, data) { + if (err) { + if (err.statusCode && err.statusCode === 404) { + callback(util.error(err, { ErrorStatus: SourceKey + ' Not Exist' })); } else { - TargetHeader = SourceHeaders; - } - TargetHeader['x-cos-storage-class'] = params.Headers['x-cos-storage-class'] || SourceHeaders['x-cos-storage-class']; - TargetHeader = util.clearKey(TargetHeader); - /** - * 对于归档存储的对象,如果未恢复副本,则不允许 Copy - */ - if (SourceHeaders['x-cos-storage-class'] === 'ARCHIVE' || SourceHeaders['x-cos-storage-class'] === 'DEEP_ARCHIVE') { - var restoreHeader = SourceHeaders['x-cos-restore']; - if (!restoreHeader || restoreHeader === 'ongoing-request="true"') { - callback(util.error(new Error('Unrestored archive object is not allowed to be copied'))); - return; - } - } - /** - * 去除一些无用的头部,规避 multipartInit 出错 - * 这些头部通常是在 putObjectCopy 时才使用 - */ - delete TargetHeader['x-cos-copy-source']; - delete TargetHeader['x-cos-metadata-directive']; - delete TargetHeader['x-cos-copy-source-If-Modified-Since']; - delete TargetHeader['x-cos-copy-source-If-Unmodified-Since']; - delete TargetHeader['x-cos-copy-source-If-Match']; - delete TargetHeader['x-cos-copy-source-If-None-Match']; - ep.emit('get_chunk_size_finish'); - }); - - // 获取远端复制源文件的大小 - self.headObject({ - Bucket: SourceBucket, - Region: SourceRegion, - Key: SourceKey, - },function(err, data) { - if (err) { - if (err.statusCode && err.statusCode === 404) { - callback(util.error(err, {ErrorStatus: SourceKey + ' Not Exist'})); - } else { - callback(err); - } - return; + callback(err); } + return; + } - FileSize = params.FileSize = data.headers['content-length']; - if (FileSize === undefined || !FileSize) { - callback(util.error(new Error('get Content-Length error, please add "Content-Length" to CORS ExposeHeader setting.( 获取Content-Length失败,请在CORS ExposeHeader设置中添加Content-Length,请参考文档:https://cloud.tencent.com/document/product/436/13318 )'))); - return; - } + FileSize = params.FileSize = data.headers['content-length']; + if (FileSize === undefined || !FileSize) { + callback( + util.error( + new Error( + 'get Content-Length error, please add "Content-Length" to CORS ExposeHeader setting.( 获取Content-Length失败,请在CORS ExposeHeader设置中添加Content-Length,请参考文档:https://cloud.tencent.com/document/product/436/13318 )', + ), + ), + ); + return; + } - onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); + onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); - // 开始上传 - if (FileSize <= CopySliceSize) { - if (!params.Headers['x-cos-metadata-directive']) { - params.Headers['x-cos-metadata-directive'] = 'Copy'; - } - self.putObjectCopy(params, function (err, data) { - if (err) { - onProgress(null, true); - return callback(err); - } - onProgress({loaded: FileSize, total: FileSize}, true); - callback(err, data); - }); - } else { - var resHeaders = data.headers; - SourceResHeaders = resHeaders; - SourceHeaders = { - 'Cache-Control': resHeaders['cache-control'], - 'Content-Disposition': resHeaders['content-disposition'], - 'Content-Encoding': resHeaders['content-encoding'], - 'Content-Type': resHeaders['content-type'], - 'Expires': resHeaders['expires'], - 'x-cos-storage-class': resHeaders['x-cos-storage-class'], - }; - util.each(resHeaders, function (v, k) { - var metaPrefix = 'x-cos-meta-'; - if (k.indexOf(metaPrefix) === 0 && k.length > metaPrefix.length) { - SourceHeaders[k] = v; - } - }); - ep.emit('get_file_size_finish'); + // 开始上传 + if (FileSize <= CopySliceSize) { + if (!params.Headers['x-cos-metadata-directive']) { + params.Headers['x-cos-metadata-directive'] = 'Copy'; } - }); + self.putObjectCopy(params, function (err, data) { + if (err) { + onProgress(null, true); + return callback(err); + } + onProgress({ loaded: FileSize, total: FileSize }, true); + callback(err, data); + }); + } else { + var resHeaders = data.headers; + SourceResHeaders = resHeaders; + SourceHeaders = { + 'Cache-Control': resHeaders['cache-control'], + 'Content-Disposition': resHeaders['content-disposition'], + 'Content-Encoding': resHeaders['content-encoding'], + 'Content-Type': resHeaders['content-type'], + Expires: resHeaders['expires'], + 'x-cos-storage-class': resHeaders['x-cos-storage-class'], + }; + util.each(resHeaders, function (v, k) { + var metaPrefix = 'x-cos-meta-'; + if (k.indexOf(metaPrefix) === 0 && k.length > metaPrefix.length) { + SourceHeaders[k] = v; + } + }); + ep.emit('get_file_size_finish'); + } + }, + ); } // 复制指定分片 function copySliceItem(params, callback) { - var TaskId = params.TaskId; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var CopySource = params.CopySource; - var UploadId = params.UploadId; - var PartNumber = params.PartNumber * 1; - var CopySourceRange = params.CopySourceRange; - - var ChunkRetryTimes = this.options.ChunkRetryTimes + 1; - var self = this; - - Async.retry(ChunkRetryTimes, function (tryCallback) { - self.uploadPartCopy({ - TaskId: TaskId, - Bucket: Bucket, - Region: Region, - Key: Key, - CopySource: CopySource, - UploadId: UploadId, - PartNumber:PartNumber, - CopySourceRange:CopySourceRange, - },function (err,data) { - tryCallback(err || null, data); - }) - }, function (err, data) { - return callback(err, data); - }); + var TaskId = params.TaskId; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var CopySource = params.CopySource; + var UploadId = params.UploadId; + var PartNumber = params.PartNumber * 1; + var CopySourceRange = params.CopySourceRange; + + var ChunkRetryTimes = this.options.ChunkRetryTimes + 1; + var self = this; + + Async.retry( + ChunkRetryTimes, + function (tryCallback) { + self.uploadPartCopy( + { + TaskId: TaskId, + Bucket: Bucket, + Region: Region, + Key: Key, + CopySource: CopySource, + UploadId: UploadId, + PartNumber: PartNumber, + CopySourceRange: CopySourceRange, + }, + function (err, data) { + tryCallback(err || null, data); + }, + ); + }, + function (err, data) { + return callback(err, data); + }, + ); } // 分片下载文件 function downloadFile(params, callback) { - var self = this; - var TaskId = params.TaskId || util.uuid(); - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var FilePath = params.FilePath; - var FileSize; - var FinishSize = 0; - var onProgress; - var ChunkSize = params.ChunkSize || 1024 * 1024; - var ParallelLimit = params.ParallelLimit || 5; - var RetryTimes = params.RetryTimes || 3; - var ep = new EventProxy(); - var PartList; - var aborted = false; - var head = {}; - - ep.on('error', function (err) { - callback(err); - }); - - ep.on('get_file_info', function () { - // 获取远端复制源文件的大小 - self.headObject({ - Bucket: Bucket, - Region: Region, - Key: Key, - },function(err, data) { - if (err) return ep.emit('error', err); - - // 获取文件大小 - FileSize = params.FileSize = parseInt(data.headers['content-length']); - if (FileSize === undefined || !FileSize) { - callback(util.error(new Error('get Content-Length error, please add "Content-Length" to CORS ExposeHeader setting.( 获取Content-Length失败,请在CORS ExposeHeader设置中添加Content-Length,请参考文档:https://cloud.tencent.com/document/product/436/13318 )'))); - return; - } + var self = this; + var TaskId = params.TaskId || util.uuid(); + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var FilePath = params.FilePath; + var FileSize; + var FinishSize = 0; + var onProgress; + var ChunkSize = params.ChunkSize || 1024 * 1024; + var ParallelLimit = params.ParallelLimit || 5; + var RetryTimes = params.RetryTimes || 3; + var ep = new EventProxy(); + var PartList; + var aborted = false; + var head = {}; + + ep.on('error', function (err) { + callback(err); + }); - // 归档文件不支持下载 - const resHeaders = data.headers; - const storageClass = resHeaders['x-cos-storage-class'] || ''; - const restoreStatus = resHeaders['x-cos-restore'] || ''; - if ( - ['DEEP_ARCHIVE', 'ARCHIVE'].includes(storageClass) && - (!restoreStatus || restoreStatus === 'ongoing-request="true"') - ) { - // 自定义返回的错误码 与cos api无关 - return callback({statusCode: 403, header: resHeaders, code: 'CannotDownload', message: 'Archive object can not download, please restore to Standard storage class.'}); - } + ep.on('get_file_info', function () { + // 获取远端复制源文件的大小 + self.headObject( + { + Bucket: Bucket, + Region: Region, + Key: Key, + }, + function (err, data) { + if (err) return ep.emit('error', err); + + // 获取文件大小 + FileSize = params.FileSize = parseInt(data.headers['content-length']); + if (FileSize === undefined || !FileSize) { + callback( + util.error( + new Error( + 'get Content-Length error, please add "Content-Length" to CORS ExposeHeader setting.( 获取Content-Length失败,请在CORS ExposeHeader设置中添加Content-Length,请参考文档:https://cloud.tencent.com/document/product/436/13318 )', + ), + ), + ); + return; + } - // 整理文件信息 - head = { - ETag: data.ETag, - size: FileSize, - mtime: resHeaders['last-modified'], - crc64ecma: resHeaders['x-cos-hash-crc64ecma'], - }; + // 归档文件不支持下载 + const resHeaders = data.headers; + const storageClass = resHeaders['x-cos-storage-class'] || ''; + const restoreStatus = resHeaders['x-cos-restore'] || ''; + if ( + ['DEEP_ARCHIVE', 'ARCHIVE'].includes(storageClass) && + (!restoreStatus || restoreStatus === 'ongoing-request="true"') + ) { + // 自定义返回的错误码 与cos api无关 + return callback({ + statusCode: 403, + header: resHeaders, + code: 'CannotDownload', + message: 'Archive object can not download, please restore to Standard storage class.', + }); + } - // 处理进度反馈 - onProgress = util.throttleOnProgress.call(self, FileSize, function (info) { - if (aborted) return; - params.onProgress(info); - }); + // 整理文件信息 + head = { + ETag: data.ETag, + size: FileSize, + mtime: resHeaders['last-modified'], + crc64ecma: resHeaders['x-cos-hash-crc64ecma'], + }; - if (FileSize <= ChunkSize) { - // 小文件直接单请求下载 - self.getObject({ - TaskId: TaskId, - Bucket: Bucket, - Region: Region, - Key: Key, - onProgress: onProgress, - Output: fs.createWriteStream(FilePath), - }, function (err, data) { - if (err) { - onProgress(null, true); - return callback(err); - } - onProgress({loaded: FileSize, total: FileSize}, true); - callback(err, data); - }); - } else { - // 大文件分片下载 - ep.emit('calc_suitable_chunk_size'); - } + // 处理进度反馈 + onProgress = util.throttleOnProgress.call(self, FileSize, function (info) { + if (aborted) return; + params.onProgress(info); }); - }); - - // 计算合适的分片大小 - ep.on('calc_suitable_chunk_size', function (SourceHeaders) { - // 控制分片大小 - var SIZE = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 1024 * 2, 1024 * 4, 1024 * 5]; - var AutoChunkSize = 1024 * 1024; - for (var i = 0; i < SIZE.length; i++) { - AutoChunkSize = SIZE[i] * 1024 * 1024; - if (FileSize / AutoChunkSize <= self.options.MaxPartNumber) break; - } - params.ChunkSize = ChunkSize = Math.max(ChunkSize, AutoChunkSize); - - var ChunkCount = Math.ceil(FileSize / ChunkSize); - - var list = []; - for (var partNumber = 1; partNumber <= ChunkCount; partNumber++) { - var start = (partNumber - 1) * ChunkSize; - var end = partNumber * ChunkSize < FileSize ? (partNumber * ChunkSize - 1) : FileSize - 1; - var item = { - PartNumber: partNumber, - start: start, - end: end, - }; - list.push(item); + if (FileSize <= ChunkSize) { + // 小文件直接单请求下载 + self.getObject( + { + TaskId: TaskId, + Bucket: Bucket, + Region: Region, + Key: Key, + onProgress: onProgress, + Output: fs.createWriteStream(FilePath), + }, + function (err, data) { + if (err) { + onProgress(null, true); + return callback(err); + } + onProgress({ loaded: FileSize, total: FileSize }, true); + callback(err, data); + }, + ); + } else { + // 大文件分片下载 + ep.emit('calc_suitable_chunk_size'); } - PartList = list; + }, + ); + }); - ep.emit('prepare_file'); - }); + // 计算合适的分片大小 + ep.on('calc_suitable_chunk_size', function (SourceHeaders) { + // 控制分片大小 + var SIZE = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 1024 * 2, 1024 * 4, 1024 * 5]; + var AutoChunkSize = 1024 * 1024; + for (var i = 0; i < SIZE.length; i++) { + AutoChunkSize = SIZE[i] * 1024 * 1024; + if (FileSize / AutoChunkSize <= self.options.MaxPartNumber) break; + } + params.ChunkSize = ChunkSize = Math.max(ChunkSize, AutoChunkSize); + + var ChunkCount = Math.ceil(FileSize / ChunkSize); + + var list = []; + for (var partNumber = 1; partNumber <= ChunkCount; partNumber++) { + var start = (partNumber - 1) * ChunkSize; + var end = partNumber * ChunkSize < FileSize ? partNumber * ChunkSize - 1 : FileSize - 1; + var item = { + PartNumber: partNumber, + start: start, + end: end, + }; + list.push(item); + } + PartList = list; - // 准备要下载的空文件 - ep.on('prepare_file', function (SourceHeaders) { - fs.writeFile(FilePath, '', err => { - if (err) { - ep.emit('error', err.code === 'EISDIR' ? { code: 'exist_same_dir', message: FilePath } : err); - } else { - ep.emit('start_download_chunks'); - } - }); + ep.emit('prepare_file'); + }); + + // 准备要下载的空文件 + ep.on('prepare_file', function (SourceHeaders) { + fs.writeFile(FilePath, '', (err) => { + if (err) { + ep.emit('error', err.code === 'EISDIR' ? { code: 'exist_same_dir', message: FilePath } : err); + } else { + ep.emit('start_download_chunks'); + } }); + }); - // 计算合适的分片大小 - var result; - ep.on('start_download_chunks', function (SourceHeaders) { - onProgress({loaded: 0, total: FileSize}, true); - var maxPartNumber = PartList.length; - Async.eachLimit(PartList, ParallelLimit, function (part, nextChunk) { + // 计算合适的分片大小 + var result; + ep.on('start_download_chunks', function (SourceHeaders) { + onProgress({ loaded: 0, total: FileSize }, true); + var maxPartNumber = PartList.length; + Async.eachLimit( + PartList, + ParallelLimit, + function (part, nextChunk) { + if (aborted) return; + Async.retry( + RetryTimes, + function (tryCallback) { if (aborted) return; - Async.retry(RetryTimes, function (tryCallback) { - if (aborted) return; - // FinishSize - var Headers = util.clone(params.Headers); - Headers.Range = "bytes=" + part.start + "-" + part.end; - const writeStream = fs.createWriteStream(FilePath, { - start: part.start, - flags: 'r+' - }); - var preAddSize = 0; - var chunkReadSize = part.end - part.start; - self.getObject({ - TaskId: TaskId, - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - Query: params.Query, - Headers: Headers, - onProgress: function (data) { - if (aborted) return; - FinishSize += data.loaded - preAddSize; - preAddSize = data.loaded; - onProgress({loaded: FinishSize, total: FileSize}); - }, - Output: writeStream, - }, function (err, data) { - if (aborted) return; - - // 处理错误和进度 - if (err) { - FinishSize -= preAddSize; - return tryCallback(err); - } - - // 处理返回值 - if (part.PartNumber === maxPartNumber) result = data; - var chunkHeaders = data.headers || {}; - - - var contentRanges = chunkHeaders['content-range'] || ''; // content-range 格式:"bytes 3145728-4194303/68577051" - var totalSize = parseInt(contentRanges.split('/')[1] || 0); - - // 只校验文件大小和 crc64 是否有变更 - var changed; - if (chunkHeaders['x-cos-hash-crc64ecma'] !== head.crc64ecma) changed = 'download error, x-cos-hash-crc64ecma has changed.'; - else if (totalSize !== head.size) changed = 'download error, Last-Modified has changed.'; - // else if (data.ETag !== head.ETag) error = 'download error, ETag has changed.'; - // else if (chunkHeaders['last-modified'] !== head.mtime) error = 'download error, Last-Modified has changed.'; - - // 如果 - if (changed) { - FinishSize -= preAddSize; - onProgress({loaded: FinishSize, total: FileSize}); - ep.emit('error', { - code: 'ObjectHasChanged', - message: changed, - statusCode: data.statusCode, - header: chunkHeaders, - }); - self.emit('inner-kill-task', {TaskId: TaskId}); - } else { - FinishSize += chunkReadSize - preAddSize; - part.loaded = true; - onProgress({loaded: FinishSize, total: FileSize}); - tryCallback(err, data); - } - }); - }, function (err, data) { - if (aborted) return; - nextChunk(err, data); + // FinishSize + var Headers = util.clone(params.Headers); + Headers.Range = 'bytes=' + part.start + '-' + part.end; + const writeStream = fs.createWriteStream(FilePath, { + start: part.start, + flags: 'r+', }); - }, function (err, data) { + var preAddSize = 0; + var chunkReadSize = part.end - part.start; + self.getObject( + { + TaskId: TaskId, + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + Query: params.Query, + Headers: Headers, + onProgress: function (data) { + if (aborted) return; + FinishSize += data.loaded - preAddSize; + preAddSize = data.loaded; + onProgress({ loaded: FinishSize, total: FileSize }); + }, + Output: writeStream, + }, + function (err, data) { + if (aborted) return; + + // 处理错误和进度 + if (err) { + FinishSize -= preAddSize; + return tryCallback(err); + } + + // 处理返回值 + if (part.PartNumber === maxPartNumber) result = data; + var chunkHeaders = data.headers || {}; + + var contentRanges = chunkHeaders['content-range'] || ''; // content-range 格式:"bytes 3145728-4194303/68577051" + var totalSize = parseInt(contentRanges.split('/')[1] || 0); + + // 只校验文件大小和 crc64 是否有变更 + var changed; + if (chunkHeaders['x-cos-hash-crc64ecma'] !== head.crc64ecma) + changed = 'download error, x-cos-hash-crc64ecma has changed.'; + else if (totalSize !== head.size) changed = 'download error, Last-Modified has changed.'; + // else if (data.ETag !== head.ETag) error = 'download error, ETag has changed.'; + // else if (chunkHeaders['last-modified'] !== head.mtime) error = 'download error, Last-Modified has changed.'; + + // 如果 + if (changed) { + FinishSize -= preAddSize; + onProgress({ loaded: FinishSize, total: FileSize }); + ep.emit('error', { + code: 'ObjectHasChanged', + message: changed, + statusCode: data.statusCode, + header: chunkHeaders, + }); + self.emit('inner-kill-task', { TaskId: TaskId }); + } else { + FinishSize += chunkReadSize - preAddSize; + part.loaded = true; + onProgress({ loaded: FinishSize, total: FileSize }); + tryCallback(err, data); + } + }, + ); + }, + function (err, data) { if (aborted) return; - onProgress({loaded: FileSize, total: FileSize}, true); - if (err) return ep.emit('error', err); - ep.emit('download_chunks_complete'); - }); - }); + nextChunk(err, data); + }, + ); + }, + function (err, data) { + if (aborted) return; + onProgress({ loaded: FileSize, total: FileSize }, true); + if (err) return ep.emit('error', err); + ep.emit('download_chunks_complete'); + }, + ); + }); - // 下载已完成 - ep.on('download_chunks_complete', function () { - callback(null, result); - }); + // 下载已完成 + ep.on('download_chunks_complete', function () { + callback(null, result); + }); - // 监听 取消任务 - var killTask = function () { - aborted = true; - }; - TaskId && self.on('inner-kill-task', killTask); + // 监听 取消任务 + var killTask = function () { + aborted = true; + }; + TaskId && self.on('inner-kill-task', killTask); - ep.emit('get_file_info'); + ep.emit('get_file_info'); } - var API_MAP = { - sliceUploadFile: sliceUploadFile, - abortUploadTask: abortUploadTask, - uploadFile: uploadFile, - uploadFiles: uploadFiles, - sliceCopyFile: sliceCopyFile, - downloadFile: downloadFile, + sliceUploadFile: sliceUploadFile, + abortUploadTask: abortUploadTask, + uploadFile: uploadFile, + uploadFiles: uploadFiles, + sliceCopyFile: sliceCopyFile, + downloadFile: downloadFile, }; module.exports.init = function (COS, task) { - task.transferToTaskMethod(API_MAP, 'sliceUploadFile'); - util.each(API_MAP, function (fn, apiName) { - COS.prototype[apiName] = util.apiWrapper(apiName, fn); - }); + task.transferToTaskMethod(API_MAP, 'sliceUploadFile'); + util.each(API_MAP, function (fn, apiName) { + COS.prototype[apiName] = util.apiWrapper(apiName, fn); + }); }; diff --git a/sdk/async.js b/sdk/async.js index 4fc1218..4676c81 100644 --- a/sdk/async.js +++ b/sdk/async.js @@ -1,60 +1,59 @@ var eachLimit = function (arr, limit, iterator, callback) { - callback = callback || function () {}; - if (!arr.length || limit <= 0) { - return callback(); - } - - var completed = 0; - var started = 0; - var running = 0; + callback = callback || function () {}; + if (!arr.length || limit <= 0) { + return callback(); + } - (function replenish () { - if (completed >= arr.length) { - return callback(); - } + var completed = 0; + var started = 0; + var running = 0; - while (running < limit && started < arr.length) { - started += 1; - running += 1; - iterator(arr[started - 1], function (err) { + (function replenish() { + if (completed >= arr.length) { + return callback(); + } - if (err) { - callback(err); - callback = function () {}; - } else { - completed += 1; - running -= 1; - if (completed >= arr.length) { - callback(); - } else { - replenish(); - } - } - }); + while (running < limit && started < arr.length) { + started += 1; + running += 1; + iterator(arr[started - 1], function (err) { + if (err) { + callback(err); + callback = function () {}; + } else { + completed += 1; + running -= 1; + if (completed >= arr.length) { + callback(); + } else { + replenish(); + } } - })(); + }); + } + })(); }; var retry = function (times, iterator, callback) { - var next = function (index) { - iterator(function (err, data) { - if (err && index < times) { - next(index + 1); - } else { - callback(err, data); - } - }); - }; - if (times < 1) { - callback(); - } else { - next(1); - } + var next = function (index) { + iterator(function (err, data) { + if (err && index < times) { + next(index + 1); + } else { + callback(err, data); + } + }); + }; + if (times < 1) { + callback(); + } else { + next(1); + } }; var async = { - eachLimit: eachLimit, - retry: retry + eachLimit: eachLimit, + retry: retry, }; -module.exports = async; \ No newline at end of file +module.exports = async; diff --git a/sdk/base.js b/sdk/base.js index 87f804a..b5f3564 100644 --- a/sdk/base.js +++ b/sdk/base.js @@ -5,7 +5,6 @@ var Stream = require('stream'); var util = require('./util'); var fs = require('fs'); - // Bucket 相关 /** @@ -15,54 +14,63 @@ var fs = require('fs'); * @param {Function} callback 回调函数,必须 */ function getService(params, callback) { - - if (typeof params === 'function') { - callback = params; - params = {}; + if (typeof params === 'function') { + callback = params; + params = {}; + } + var protocol = this.options.Protocol || (util.isBrowser && location.protocol === 'http:' ? 'http:' : 'https:'); + var domain = this.options.ServiceDomain; + var appId = params.AppId || this.options.appId; + var region = params.Region; + if (domain) { + domain = domain + .replace(/\{\{AppId\}\}/gi, appId || '') + .replace(/\{\{Region\}\}/gi, region || '') + .replace(/\{\{.*?\}\}/gi, ''); + if (!/^[a-zA-Z]+:\/\//.test(domain)) { + domain = protocol + '//' + domain; } - var protocol = this.options.Protocol || (util.isBrowser && location.protocol === 'http:' ? 'http:' : 'https:'); - var domain = this.options.ServiceDomain; - var appId = params.AppId || this.options.appId; - var region = params.Region; - if (domain) { - domain = domain.replace(/\{\{AppId\}\}/ig, appId || '') - .replace(/\{\{Region\}\}/ig, region || '').replace(/\{\{.*?\}\}/ig, ''); - if (!/^[a-zA-Z]+:\/\//.test(domain)) { - domain = protocol + '//' + domain; - } - if (domain.slice(-1) === '/') { - domain = domain.slice(0, -1); - } - } else if (region) { - domain = protocol + '//cos.' + region + '.myqcloud.com'; - } else { - domain = protocol + '//service.cos.myqcloud.com'; + if (domain.slice(-1) === '/') { + domain = domain.slice(0, -1); } + } else if (region) { + domain = protocol + '//cos.' + region + '.myqcloud.com'; + } else { + domain = protocol + '//service.cos.myqcloud.com'; + } - var SignHost = ''; - var standardHost = region ? 'cos.' + region + '.myqcloud.com' : 'service.cos.myqcloud.com'; - var urlHost = domain.replace(/^https?:\/\/([^/]+)(\/.*)?$/, '$1'); - if (standardHost === urlHost) SignHost = standardHost; - - submitRequest.call(this, { - Action: 'name/cos:GetService', - url: domain, - method: 'GET', - headers: params.Headers, - SignHost: SignHost, - }, function (err, data) { - if (err) return callback(err); - var buckets = (data && data.ListAllMyBucketsResult && data.ListAllMyBucketsResult.Buckets - && data.ListAllMyBucketsResult.Buckets.Bucket) || []; - buckets = util.isArray(buckets) ? buckets : [buckets]; - var owner = (data && data.ListAllMyBucketsResult && data.ListAllMyBucketsResult.Owner) || {}; - callback(null, { - Buckets: buckets, - Owner: owner, - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var SignHost = ''; + var standardHost = region ? 'cos.' + region + '.myqcloud.com' : 'service.cos.myqcloud.com'; + var urlHost = domain.replace(/^https?:\/\/([^/]+)(\/.*)?$/, '$1'); + if (standardHost === urlHost) SignHost = standardHost; + + submitRequest.call( + this, + { + Action: 'name/cos:GetService', + url: domain, + method: 'GET', + headers: params.Headers, + SignHost: SignHost, + }, + function (err, data) { + if (err) return callback(err); + var buckets = + (data && + data.ListAllMyBucketsResult && + data.ListAllMyBucketsResult.Buckets && + data.ListAllMyBucketsResult.Buckets.Bucket) || + []; + buckets = util.isArray(buckets) ? buckets : [buckets]; + var owner = (data && data.ListAllMyBucketsResult && data.ListAllMyBucketsResult.Owner) || {}; + callback(null, { + Buckets: buckets, + Owner: owner, + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -80,37 +88,40 @@ function getService(params, callback) { * @return {String} data.Location 操作地址 */ function putBucket(params, callback) { - - var self = this; - - var xml = ''; - var conf = {}; - if (params.BucketAZConfig) conf.BucketAZConfig = params.BucketAZConfig; - if (params.BucketArchConfig) conf.BucketArchConfig = params.BucketArchConfig; - if (conf.BucketAZConfig || conf.BucketArchConfig) xml = util.json2xml({CreateBucketConfiguration: conf}); - - submitRequest.call(this, { - Action: 'name/cos:PutBucket', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - body: xml, - }, function (err, data) { - if (err) return callback(err); - var url = getUrl({ - protocol: self.options.Protocol, - domain: self.options.Domain, - bucket: params.Bucket, - region: params.Region, - isLocation: true, - }); - callback(null, { - Location: url, - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var self = this; + + var xml = ''; + var conf = {}; + if (params.BucketAZConfig) conf.BucketAZConfig = params.BucketAZConfig; + if (params.BucketArchConfig) conf.BucketArchConfig = params.BucketArchConfig; + if (conf.BucketAZConfig || conf.BucketArchConfig) xml = util.json2xml({ CreateBucketConfiguration: conf }); + + submitRequest.call( + this, + { + Action: 'name/cos:PutBucket', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + body: xml, + }, + function (err, data) { + if (err) return callback(err); + var url = getUrl({ + protocol: self.options.Protocol, + domain: self.options.Domain, + bucket: params.Bucket, + region: params.Region, + isLocation: true, + }); + callback(null, { + Location: url, + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -125,13 +136,17 @@ function putBucket(params, callback) { * @return {Boolean} data.BucketAuth 是否有 Bucket 的访问权限 */ function headBucket(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:HeadBucket', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - method: 'HEAD', - }, callback); + submitRequest.call( + this, + { + Action: 'name/cos:HeadBucket', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + method: 'HEAD', + }, + callback, + ); } /** @@ -150,40 +165,44 @@ function headBucket(params, callback) { * @return {Object} data.ListBucketResult 返回的 object 列表信息 */ function getBucket(params, callback) { - var reqParams = {}; - reqParams['prefix'] = params['Prefix'] || ''; - reqParams['delimiter'] = params['Delimiter']; - reqParams['marker'] = params['Marker']; - reqParams['max-keys'] = params['MaxKeys']; - reqParams['encoding-type'] = params['EncodingType']; - - submitRequest.call(this, { - Action: 'name/cos:GetBucket', - ResourceKey: reqParams['prefix'], - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - qs: reqParams, - }, function (err, data) { - if (err) return callback(err); - var ListBucketResult = data.ListBucketResult || {}; - var Contents = ListBucketResult.Contents || []; - var CommonPrefixes = ListBucketResult.CommonPrefixes || []; - - Contents = util.isArray(Contents) ? Contents : [Contents]; - CommonPrefixes = util.isArray(CommonPrefixes) ? CommonPrefixes : [CommonPrefixes]; - - var result = util.clone(ListBucketResult); - util.extend(result, { - Contents: Contents, - CommonPrefixes: CommonPrefixes, - statusCode: data.statusCode, - headers: data.headers, - }); - - callback(null, result); - }); + var reqParams = {}; + reqParams['prefix'] = params['Prefix'] || ''; + reqParams['delimiter'] = params['Delimiter']; + reqParams['marker'] = params['Marker']; + reqParams['max-keys'] = params['MaxKeys']; + reqParams['encoding-type'] = params['EncodingType']; + + submitRequest.call( + this, + { + Action: 'name/cos:GetBucket', + ResourceKey: reqParams['prefix'], + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + qs: reqParams, + }, + function (err, data) { + if (err) return callback(err); + var ListBucketResult = data.ListBucketResult || {}; + var Contents = ListBucketResult.Contents || []; + var CommonPrefixes = ListBucketResult.CommonPrefixes || []; + + Contents = util.isArray(Contents) ? Contents : [Contents]; + CommonPrefixes = util.isArray(CommonPrefixes) ? CommonPrefixes : [CommonPrefixes]; + + var result = util.clone(ListBucketResult); + util.extend(result, { + Contents: Contents, + CommonPrefixes: CommonPrefixes, + statusCode: data.statusCode, + headers: data.headers, + }); + + callback(null, result); + }, + ); } /** @@ -197,23 +216,27 @@ function getBucket(params, callback) { * @return {String} data.Location 操作地址 */ function deleteBucket(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucket', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - method: 'DELETE', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + submitRequest.call( + this, + { + Action: 'name/cos:DeleteBucket', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + method: 'DELETE', + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -230,44 +253,48 @@ function deleteBucket(params, callback) { * @return {Object} data 返回的数据 */ function putBucketAcl(params, callback) { - var headers = params.Headers; - - var xml = ''; - if (params['AccessControlPolicy']) { - var AccessControlPolicy = util.clone(params['AccessControlPolicy'] || {}); - var Grants = AccessControlPolicy.Grants || AccessControlPolicy.Grant; - Grants = util.isArray(Grants) ? Grants : [Grants]; - delete AccessControlPolicy.Grant; - delete AccessControlPolicy.Grants; - AccessControlPolicy.AccessControlList = {Grant: Grants}; - xml = util.json2xml({AccessControlPolicy: AccessControlPolicy}); - - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - } + var headers = params.Headers; - // Grant Header 去重 - util.each(headers, function (val, key) { - if (key.indexOf('x-cos-grant-') === 0) { - headers[key] = uniqGrant(headers[key]); - } - }); + var xml = ''; + if (params['AccessControlPolicy']) { + var AccessControlPolicy = util.clone(params['AccessControlPolicy'] || {}); + var Grants = AccessControlPolicy.Grants || AccessControlPolicy.Grant; + Grants = util.isArray(Grants) ? Grants : [Grants]; + delete AccessControlPolicy.Grant; + delete AccessControlPolicy.Grants; + AccessControlPolicy.AccessControlList = { Grant: Grants }; + xml = util.json2xml({ AccessControlPolicy: AccessControlPolicy }); - submitRequest.call(this, { - Action: 'name/cos:PutBucketACL', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - headers: headers, - action: 'acl', - body: xml, - }, function (err, data) { - if (err) return callback(err); - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + } + + // Grant Header 去重 + util.each(headers, function (val, key) { + if (key.indexOf('x-cos-grant-') === 0) { + headers[key] = uniqGrant(headers[key]); + } + }); + + submitRequest.call( + this, + { + Action: 'name/cos:PutBucketACL', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + headers: headers, + action: 'acl', + body: xml, + }, + function (err, data) { + if (err) return callback(err); + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -281,32 +308,35 @@ function putBucketAcl(params, callback) { * @return {Object} data.AccessControlPolicy 访问权限信息 */ function getBucketAcl(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetBucketACL', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'acl', - }, function (err, data) { - if (err) return callback(err); - var AccessControlPolicy = data.AccessControlPolicy || {}; - var Owner = AccessControlPolicy.Owner || {}; - var Grant = AccessControlPolicy.AccessControlList && AccessControlPolicy.AccessControlList.Grant || []; - Grant = util.isArray(Grant) ? Grant : [Grant]; - var result = decodeAcl(AccessControlPolicy); - if (data.headers && data.headers['x-cos-acl']) { - result.ACL = data.headers['x-cos-acl']; - } - result = util.extend(result, { - Owner: Owner, - Grants: Grant, - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); + submitRequest.call( + this, + { + Action: 'name/cos:GetBucketACL', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'acl', + }, + function (err, data) { + if (err) return callback(err); + var AccessControlPolicy = data.AccessControlPolicy || {}; + var Owner = AccessControlPolicy.Owner || {}; + var Grant = (AccessControlPolicy.AccessControlList && AccessControlPolicy.AccessControlList.Grant) || []; + Grant = util.isArray(Grant) ? Grant : [Grant]; + var result = decodeAcl(AccessControlPolicy); + if (data.headers && data.headers['x-cos-acl']) { + result.ACL = data.headers['x-cos-acl']; + } + result = util.extend(result, { + Owner: Owner, + Grants: Grant, + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }, + ); } /** @@ -321,43 +351,46 @@ function getBucketAcl(params, callback) { * @return {Object} data 返回的数据 */ function putBucketCors(params, callback) { - - var CORSConfiguration = params['CORSConfiguration'] || {}; - var CORSRules = CORSConfiguration['CORSRules'] || params['CORSRules'] || []; - CORSRules = util.clone(util.isArray(CORSRules) ? CORSRules : [CORSRules]); - util.each(CORSRules, function (rule) { - util.each(['AllowedOrigin', 'AllowedHeader', 'AllowedMethod', 'ExposeHeader'], function (key) { - var sKey = key + 's'; - var val = rule[sKey] || rule[key] || []; - delete rule[sKey]; - rule[key] = util.isArray(val) ? val : [val]; - }); + var CORSConfiguration = params['CORSConfiguration'] || {}; + var CORSRules = CORSConfiguration['CORSRules'] || params['CORSRules'] || []; + CORSRules = util.clone(util.isArray(CORSRules) ? CORSRules : [CORSRules]); + util.each(CORSRules, function (rule) { + util.each(['AllowedOrigin', 'AllowedHeader', 'AllowedMethod', 'ExposeHeader'], function (key) { + var sKey = key + 's'; + var val = rule[sKey] || rule[key] || []; + delete rule[sKey]; + rule[key] = util.isArray(val) ? val : [val]; }); + }); - var Conf = {CORSRule: CORSRules}; - if (params.ResponseVary) Conf.ResponseVary = params.ResponseVary; - - var xml = util.json2xml({CORSConfiguration: Conf}); + var Conf = { CORSRule: CORSRules }; + if (params.ResponseVary) Conf.ResponseVary = params.ResponseVary; - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + var xml = util.json2xml({ CORSConfiguration: Conf }); - submitRequest.call(this, { - Action: 'name/cos:PutBucketCORS', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'cors', - headers: headers, - }, function (err, data) { - if (err) return callback(err); - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call( + this, + { + Action: 'name/cos:PutBucketCORS', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'cors', + headers: headers, + }, + function (err, data) { + if (err) return callback(err); + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -371,48 +404,52 @@ function putBucketCors(params, callback) { * @return {Object} data.CORSRules Bucket的跨域设置 */ function getBucketCors(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketCORS', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'cors', - }, function (err, data) { - if (err) { - if (err.statusCode === 404 && err.error && err.error.Code === 'NoSuchCORSConfiguration') { - var result = { - CORSRules: [], - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; + submitRequest.call( + this, + { + Action: 'name/cos:GetBucketCORS', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'cors', + }, + function (err, data) { + if (err) { + if (err.statusCode === 404 && err.error && err.error.Code === 'NoSuchCORSConfiguration') { + var result = { + CORSRules: [], + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); } - var CORSConfiguration = data.CORSConfiguration || {}; - var CORSRules = CORSConfiguration.CORSRules || CORSConfiguration.CORSRule || []; - CORSRules = util.clone(util.isArray(CORSRules) ? CORSRules : [CORSRules]); - var ResponseVary = CORSConfiguration.ResponseVary; - - util.each(CORSRules, function (rule) { - util.each(['AllowedOrigin', 'AllowedHeader', 'AllowedMethod', 'ExposeHeader'], function (key) { - var sKey = key + 's'; - var val = rule[sKey] || rule[key] || []; - delete rule[key]; - rule[sKey] = util.isArray(val) ? val : [val]; - }); - }); + return; + } + var CORSConfiguration = data.CORSConfiguration || {}; + var CORSRules = CORSConfiguration.CORSRules || CORSConfiguration.CORSRule || []; + CORSRules = util.clone(util.isArray(CORSRules) ? CORSRules : [CORSRules]); + var ResponseVary = CORSConfiguration.ResponseVary; - callback(null, { - CORSRules: CORSRules, - ResponseVary: ResponseVary, - statusCode: data.statusCode, - headers: data.headers, + util.each(CORSRules, function (rule) { + util.each(['AllowedOrigin', 'AllowedHeader', 'AllowedMethod', 'ExposeHeader'], function (key) { + var sKey = key + 's'; + var val = rule[sKey] || rule[key] || []; + delete rule[key]; + rule[sKey] = util.isArray(val) ? val : [val]; }); - }); + }); + + callback(null, { + CORSRules: CORSRules, + ResponseVary: ResponseVary, + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -425,24 +462,28 @@ function getBucketCors(params, callback) { * @return {Object} data 返回的数据 */ function deleteBucketCors(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketCORS', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'cors', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode || err.statusCode, - headers: data.headers, - }); - }); + submitRequest.call( + this, + { + Action: 'name/cos:DeleteBucketCORS', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'cors', + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode || err.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -455,49 +496,56 @@ function deleteBucketCors(params, callback) { * @return {Object} data 返回数据,包含地域信息 LocationConstraint */ function getBucketLocation(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketLocation', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'location', - }, callback); + submitRequest.call( + this, + { + Action: 'name/cos:GetBucketLocation', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'location', + }, + callback, + ); } function putBucketPolicy(params, callback) { - var Policy = params['Policy']; - try { - if (typeof Policy === 'string') Policy = JSON.parse(Policy); - } catch (e) { - } - if (!Policy || typeof Policy === 'string') return callback(util.error(new Error('Policy format error'))); - var PolicyStr = JSON.stringify(Policy); - if (!Policy.version) Policy.version = '2.0'; + var Policy = params['Policy']; + try { + if (typeof Policy === 'string') Policy = JSON.parse(Policy); + } catch (e) {} + if (!Policy || typeof Policy === 'string') return callback(util.error(new Error('Policy format error'))); + var PolicyStr = JSON.stringify(Policy); + if (!Policy.version) Policy.version = '2.0'; - var headers = params.Headers; - headers['Content-Type'] = 'application/json'; - headers['Content-MD5'] = util.binaryBase64(util.md5(PolicyStr)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketPolicy', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - action: 'policy', - body: PolicyStr, - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var headers = params.Headers; + headers['Content-Type'] = 'application/json'; + headers['Content-MD5'] = util.binaryBase64(util.md5(PolicyStr)); + + submitRequest.call( + this, + { + Action: 'name/cos:PutBucketPolicy', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + action: 'policy', + body: PolicyStr, + headers: headers, + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -510,38 +558,41 @@ function putBucketPolicy(params, callback) { * @return {Object} data 返回数据 */ function getBucketPolicy(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketPolicy', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'policy', - rawBody: true, - }, function (err, data) { - if (err) { - if (err.statusCode && err.statusCode === 403) { - return callback(util.error(err, {ErrorStatus: 'Access Denied'})); - } - if (err.statusCode && err.statusCode === 405) { - return callback(util.error(err, {ErrorStatus: 'Method Not Allowed'})); - } - if (err.statusCode && err.statusCode === 404) { - return callback(util.error(err, {ErrorStatus: 'Policy Not Found'})); - } - return callback(err); + submitRequest.call( + this, + { + Action: 'name/cos:GetBucketPolicy', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'policy', + rawBody: true, + }, + function (err, data) { + if (err) { + if (err.statusCode && err.statusCode === 403) { + return callback(util.error(err, { ErrorStatus: 'Access Denied' })); } - var Policy = {}; - try { - Policy = JSON.parse(data.body); - } catch (e) { + if (err.statusCode && err.statusCode === 405) { + return callback(util.error(err, { ErrorStatus: 'Method Not Allowed' })); } - callback(null, { - Policy: Policy, - statusCode: data.statusCode, - headers: data.headers, - }); - }); + if (err.statusCode && err.statusCode === 404) { + return callback(util.error(err, { ErrorStatus: 'Policy Not Found' })); + } + return callback(err); + } + var Policy = {}; + try { + Policy = JSON.parse(data.body); + } catch (e) {} + callback(null, { + Policy: Policy, + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -554,24 +605,28 @@ function getBucketPolicy(params, callback) { * @return {Object} data 返回的数据 */ function deleteBucketPolicy(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketPolicy', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'policy', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode || err.statusCode, - headers: data.headers, - }); - }); + submitRequest.call( + this, + { + Action: 'name/cos:DeleteBucketPolicy', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'policy', + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode || err.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -585,35 +640,38 @@ function deleteBucketPolicy(params, callback) { * @return {Object} data 返回数据 */ function putBucketTagging(params, callback) { + var Tagging = params['Tagging'] || {}; + var Tags = Tagging.TagSet || Tagging.Tags || params['Tags'] || []; + Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); + var xml = util.json2xml({ Tagging: { TagSet: { Tag: Tags } } }); - var Tagging = params['Tagging'] || {}; - var Tags = Tagging.TagSet || Tagging.Tags || params['Tags'] || []; - Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); - var xml = util.json2xml({Tagging: {TagSet: {Tag: Tags}}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketTagging', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'tagging', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call( + this, + { + Action: 'name/cos:PutBucketTagging', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'tagging', + headers: headers, + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -626,40 +684,42 @@ function putBucketTagging(params, callback) { * @return {Object} data 返回数据 */ function getBucketTagging(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetBucketTagging', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'tagging', - }, function (err, data) { - if (err) { - if (err.statusCode === 404 && err.error && (err.error === "Not Found" || err.error.Code === 'NoSuchTagSet')) { - var result = { - Tags: [], - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - var Tags = []; - try { - Tags = data.Tagging.TagSet.Tag || []; - } catch (e) { + submitRequest.call( + this, + { + Action: 'name/cos:GetBucketTagging', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'tagging', + }, + function (err, data) { + if (err) { + if (err.statusCode === 404 && err.error && (err.error === 'Not Found' || err.error.Code === 'NoSuchTagSet')) { + var result = { + Tags: [], + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); } - Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); - callback(null, { - Tags: Tags, - statusCode: data.statusCode, - headers: data.headers, - }); - }); + return; + } + var Tags = []; + try { + Tags = data.Tagging.TagSet.Tag || []; + } catch (e) {} + Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); + callback(null, { + Tags: Tags, + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -672,248 +732,285 @@ function getBucketTagging(params, callback) { * @return {Object} data 返回的数据 */ function deleteBucketTagging(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketTagging', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'tagging', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + submitRequest.call( + this, + { + Action: 'name/cos:DeleteBucketTagging', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'tagging', + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } function putBucketLifecycle(params, callback) { + var LifecycleConfiguration = params['LifecycleConfiguration'] || {}; + var Rules = LifecycleConfiguration.Rules || params.Rules || []; + Rules = util.clone(Rules); + var xml = util.json2xml({ LifecycleConfiguration: { Rule: Rules } }); - var LifecycleConfiguration = params['LifecycleConfiguration'] || {}; - var Rules = LifecycleConfiguration.Rules || params.Rules || []; - Rules = util.clone(Rules); - var xml = util.json2xml({LifecycleConfiguration: {Rule: Rules}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketLifecycle', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'lifecycle', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call( + this, + { + Action: 'name/cos:PutBucketLifecycle', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'lifecycle', + headers: headers, + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } function getBucketLifecycle(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketLifecycle', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'lifecycle', - }, function (err, data) { - if (err) { - if (err.statusCode === 404 && err.error && err.error.Code === 'NoSuchLifecycleConfiguration') { - var result = { - Rules: [], - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - var Rules = []; - try { - Rules = data.LifecycleConfiguration.Rule || []; - } catch (e) { + submitRequest.call( + this, + { + Action: 'name/cos:GetBucketLifecycle', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'lifecycle', + }, + function (err, data) { + if (err) { + if (err.statusCode === 404 && err.error && err.error.Code === 'NoSuchLifecycleConfiguration') { + var result = { + Rules: [], + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); } - Rules = util.clone(util.isArray(Rules) ? Rules : [Rules]); - callback(null, { - Rules: Rules, - statusCode: data.statusCode, - headers: data.headers, - }); - }); + return; + } + var Rules = []; + try { + Rules = data.LifecycleConfiguration.Rule || []; + } catch (e) {} + Rules = util.clone(util.isArray(Rules) ? Rules : [Rules]); + callback(null, { + Rules: Rules, + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } function deleteBucketLifecycle(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketLifecycle', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'lifecycle', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + submitRequest.call( + this, + { + Action: 'name/cos:DeleteBucketLifecycle', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'lifecycle', + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } function putBucketVersioning(params, callback) { + if (!params['VersioningConfiguration']) { + callback(util.error(new Error('missing param VersioningConfiguration'))); + return; + } + var VersioningConfiguration = params['VersioningConfiguration'] || {}; + var xml = util.json2xml({ VersioningConfiguration: VersioningConfiguration }); - if (!params['VersioningConfiguration']) { - callback(util.error(new Error('missing param VersioningConfiguration'))); - return; - } - var VersioningConfiguration = params['VersioningConfiguration'] || {}; - var xml = util.json2xml({VersioningConfiguration: VersioningConfiguration}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketVersioning', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'versioning', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call( + this, + { + Action: 'name/cos:PutBucketVersioning', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'versioning', + headers: headers, + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } function getBucketVersioning(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketVersioning', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'versioning', - }, function (err, data) { - if (!err) { - !data.VersioningConfiguration && (data.VersioningConfiguration = {}); - } - callback(err, data); - }); + submitRequest.call( + this, + { + Action: 'name/cos:GetBucketVersioning', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'versioning', + }, + function (err, data) { + if (!err) { + !data.VersioningConfiguration && (data.VersioningConfiguration = {}); + } + callback(err, data); + }, + ); } function putBucketReplication(params, callback) { - var ReplicationConfiguration = util.clone(params.ReplicationConfiguration); - var xml = util.json2xml({ReplicationConfiguration: ReplicationConfiguration}); - xml = xml.replace(/<(\/?)Rules>/ig, '<$1Rule>'); - xml = xml.replace(/<(\/?)Tags>/ig, '<$1Tag>'); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + var ReplicationConfiguration = util.clone(params.ReplicationConfiguration); + var xml = util.json2xml({ ReplicationConfiguration: ReplicationConfiguration }); + xml = xml.replace(/<(\/?)Rules>/gi, '<$1Rule>'); + xml = xml.replace(/<(\/?)Tags>/gi, '<$1Tag>'); - submitRequest.call(this, { - Action: 'name/cos:PutBucketReplication', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'replication', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call( + this, + { + Action: 'name/cos:PutBucketReplication', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'replication', + headers: headers, + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } function getBucketReplication(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketReplication', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'replication', - }, function (err, data) { - if (err) { - if (err.statusCode === 404 && err.error && (err.error === 'Not Found' || err.error.Code === 'ReplicationConfigurationnotFoundError')) { - var result = { - ReplicationConfiguration: {Rules: []}, - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - if (!err) { - !data.ReplicationConfiguration && (data.ReplicationConfiguration = {}); - } - if (data.ReplicationConfiguration.Rule) { - data.ReplicationConfiguration.Rules = util.makeArray(data.ReplicationConfiguration.Rule); - delete data.ReplicationConfiguration.Rule; + submitRequest.call( + this, + { + Action: 'name/cos:GetBucketReplication', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'replication', + }, + function (err, data) { + if (err) { + if ( + err.statusCode === 404 && + err.error && + (err.error === 'Not Found' || err.error.Code === 'ReplicationConfigurationnotFoundError') + ) { + var result = { + ReplicationConfiguration: { Rules: [] }, + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); } - callback(err, data); - }); + return; + } + if (!err) { + !data.ReplicationConfiguration && (data.ReplicationConfiguration = {}); + } + if (data.ReplicationConfiguration.Rule) { + data.ReplicationConfiguration.Rules = util.makeArray(data.ReplicationConfiguration.Rule); + delete data.ReplicationConfiguration.Rule; + } + callback(err, data); + }, + ); } function deleteBucketReplication(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketReplication', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'replication', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + submitRequest.call( + this, + { + Action: 'name/cos:DeleteBucketReplication', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'replication', + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -931,43 +1028,46 @@ function deleteBucketReplication(params, callback) { * @return {Object} data 返回数据 */ function putBucketWebsite(params, callback) { + if (!params['WebsiteConfiguration']) { + callback(util.error(new Error('missing param WebsiteConfiguration'))); + return; + } - if (!params['WebsiteConfiguration']) { - callback(util.error(new Error('missing param WebsiteConfiguration'))); - return; - } - - var WebsiteConfiguration = util.clone(params['WebsiteConfiguration'] || {}); - var RoutingRules = WebsiteConfiguration['RoutingRules'] || WebsiteConfiguration['RoutingRule'] || []; - RoutingRules = util.isArray(RoutingRules) ? RoutingRules : [RoutingRules]; - delete WebsiteConfiguration.RoutingRule; - delete WebsiteConfiguration.RoutingRules; - if (RoutingRules.length) WebsiteConfiguration.RoutingRules = { RoutingRule: RoutingRules }; - var xml = util.json2xml({ WebsiteConfiguration: WebsiteConfiguration }); + var WebsiteConfiguration = util.clone(params['WebsiteConfiguration'] || {}); + var RoutingRules = WebsiteConfiguration['RoutingRules'] || WebsiteConfiguration['RoutingRule'] || []; + RoutingRules = util.isArray(RoutingRules) ? RoutingRules : [RoutingRules]; + delete WebsiteConfiguration.RoutingRule; + delete WebsiteConfiguration.RoutingRules; + if (RoutingRules.length) WebsiteConfiguration.RoutingRules = { RoutingRule: RoutingRules }; + var xml = util.json2xml({ WebsiteConfiguration: WebsiteConfiguration }); - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketWebsite', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'website', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call( + this, + { + Action: 'name/cos:PutBucketWebsite', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'website', + headers: headers, + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -980,43 +1080,46 @@ function putBucketWebsite(params, callback) { * @return {Object} data 返回数据 */ function getBucketWebsite(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetBucketWebsite', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - action: 'website', - }, function (err, data) { - if (err) { - if(err.statusCode === 404 && err.error.Code === 'NoSuchWebsiteConfiguration'){ - var result = { - WebsiteConfiguration: {}, - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; + submitRequest.call( + this, + { + Action: 'name/cos:GetBucketWebsite', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + action: 'website', + }, + function (err, data) { + if (err) { + if (err.statusCode === 404 && err.error.Code === 'NoSuchWebsiteConfiguration') { + var result = { + WebsiteConfiguration: {}, + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); } + return; + } - var WebsiteConfiguration = data.WebsiteConfiguration || {}; - if (WebsiteConfiguration['RoutingRules']) { - var RoutingRules = util.clone(WebsiteConfiguration['RoutingRules'].RoutingRule || []); - RoutingRules = util.makeArray(RoutingRules); - WebsiteConfiguration.RoutingRules = RoutingRules; - } + var WebsiteConfiguration = data.WebsiteConfiguration || {}; + if (WebsiteConfiguration['RoutingRules']) { + var RoutingRules = util.clone(WebsiteConfiguration['RoutingRules'].RoutingRule || []); + RoutingRules = util.makeArray(RoutingRules); + WebsiteConfiguration.RoutingRules = RoutingRules; + } - callback(null, { - WebsiteConfiguration: WebsiteConfiguration, - statusCode: data.statusCode, - headers: data.headers, - }); - }); + callback(null, { + WebsiteConfiguration: WebsiteConfiguration, + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -1029,25 +1132,28 @@ function getBucketWebsite(params, callback) { * @return {Object} data 返回数据 */ function deleteBucketWebsite(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketWebsite', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'website', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + submitRequest.call( + this, + { + Action: 'name/cos:DeleteBucketWebsite', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'website', + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -1065,42 +1171,45 @@ function deleteBucketWebsite(params, callback) { * @return {Object} data 返回数据 */ function putBucketReferer(params, callback) { + if (!params['RefererConfiguration']) { + callback(util.error(new Error('missing param RefererConfiguration'))); + return; + } - if (!params['RefererConfiguration']) { - callback(util.error(new Error('missing param RefererConfiguration'))); - return; - } - - var RefererConfiguration = util.clone(params['RefererConfiguration'] || {}); - var DomainList = RefererConfiguration['DomainList'] || {}; - var Domains = DomainList['Domains'] || DomainList['Domain'] || []; - Domains = util.isArray(Domains) ? Domains : [Domains]; - if (Domains.length) RefererConfiguration.DomainList = {Domain: Domains}; - var xml = util.json2xml({ RefererConfiguration: RefererConfiguration }); + var RefererConfiguration = util.clone(params['RefererConfiguration'] || {}); + var DomainList = RefererConfiguration['DomainList'] || {}; + var Domains = DomainList['Domains'] || DomainList['Domain'] || []; + Domains = util.isArray(Domains) ? Domains : [Domains]; + if (Domains.length) RefererConfiguration.DomainList = { Domain: Domains }; + var xml = util.json2xml({ RefererConfiguration: RefererConfiguration }); - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketReferer', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'referer', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call( + this, + { + Action: 'name/cos:PutBucketReferer', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'referer', + headers: headers, + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -1113,42 +1222,45 @@ function putBucketReferer(params, callback) { * @return {Object} data 返回数据 */ function getBucketReferer(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetBucketReferer', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - action: 'referer', - }, function (err, data) { - if (err) { - if(err.statusCode === 404 && err.error.Code === 'NoSuchRefererConfiguration'){ - var result = { - WebsiteConfiguration: {}, - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; + submitRequest.call( + this, + { + Action: 'name/cos:GetBucketReferer', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + action: 'referer', + }, + function (err, data) { + if (err) { + if (err.statusCode === 404 && err.error.Code === 'NoSuchRefererConfiguration') { + var result = { + WebsiteConfiguration: {}, + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); } + return; + } - var RefererConfiguration = data.RefererConfiguration || {}; - if (RefererConfiguration['DomainList']) { - var Domains = util.makeArray(RefererConfiguration['DomainList'].Domain || []); - RefererConfiguration.DomainList = {Domains: Domains}; - } + var RefererConfiguration = data.RefererConfiguration || {}; + if (RefererConfiguration['DomainList']) { + var Domains = util.makeArray(RefererConfiguration['DomainList'].Domain || []); + RefererConfiguration.DomainList = { Domains: Domains }; + } - callback(null, { - RefererConfiguration: RefererConfiguration, - statusCode: data.statusCode, - headers: data.headers, - }); - }); + callback(null, { + RefererConfiguration: RefererConfiguration, + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -1161,35 +1273,38 @@ function getBucketReferer(params, callback) { * @return {Object} data 返回数据 */ function putBucketDomain(params, callback) { + var DomainConfiguration = params['DomainConfiguration'] || {}; + var DomainRule = DomainConfiguration.DomainRule || params.DomainRule || []; + DomainRule = util.clone(DomainRule); + var xml = util.json2xml({ DomainConfiguration: { DomainRule: DomainRule } }); - var DomainConfiguration = params['DomainConfiguration'] || {}; - var DomainRule = DomainConfiguration.DomainRule || params.DomainRule || []; - DomainRule = util.clone(DomainRule); - var xml = util.json2xml({DomainConfiguration: {DomainRule: DomainRule}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketDomain', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'domain', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call( + this, + { + Action: 'name/cos:PutBucketDomain', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'domain', + headers: headers, + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -1202,29 +1317,31 @@ function putBucketDomain(params, callback) { * @return {Object} data 返回数据 */ function getBucketDomain(params, callback) { + submitRequest.call( + this, + { + Action: 'name/cos:GetBucketDomain', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'domain', + }, + function (err, data) { + if (err) return callback(err); - submitRequest.call(this, { - Action: 'name/cos:GetBucketDomain', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'domain', - }, function (err, data) { - if (err) return callback(err); - - var DomainRule = []; - try { - DomainRule = data.DomainConfiguration.DomainRule || []; - } catch (e) { - } - DomainRule = util.clone(util.isArray(DomainRule) ? DomainRule : [DomainRule]); - callback(null, { - DomainRule: DomainRule, - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var DomainRule = []; + try { + DomainRule = data.DomainConfiguration.DomainRule || []; + } catch (e) {} + DomainRule = util.clone(util.isArray(DomainRule) ? DomainRule : [DomainRule]); + callback(null, { + DomainRule: DomainRule, + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -1237,25 +1354,28 @@ function getBucketDomain(params, callback) { * @return {Object} data 返回数据 */ function deleteBucketDomain(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketDomain', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'domain', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + submitRequest.call( + this, + { + Action: 'name/cos:DeleteBucketDomain', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'domain', + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -1267,35 +1387,39 @@ function deleteBucketDomain(params, callback) { * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 * @return {Object} data 返回数据 */ -function putBucketOrigin(params, callback){ - var OriginConfiguration = params['OriginConfiguration'] || {}; - var OriginRule = OriginConfiguration.OriginRule || params.OriginRule || []; - OriginRule = util.clone(OriginRule); - var xml = util.json2xml({OriginConfiguration: {OriginRule: OriginRule}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); +function putBucketOrigin(params, callback) { + var OriginConfiguration = params['OriginConfiguration'] || {}; + var OriginRule = OriginConfiguration.OriginRule || params.OriginRule || []; + OriginRule = util.clone(OriginRule); + var xml = util.json2xml({ OriginConfiguration: { OriginRule: OriginRule } }); - submitRequest.call(this, { - Action: 'name/cos:PutBucketOrigin', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'origin', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call( + this, + { + Action: 'name/cos:PutBucketOrigin', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'origin', + headers: headers, + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -1308,29 +1432,31 @@ function putBucketOrigin(params, callback){ * @return {Object} data 返回数据 */ function getBucketOrigin(params, callback) { + submitRequest.call( + this, + { + Action: 'name/cos:GetBucketOrigin', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'origin', + }, + function (err, data) { + if (err) return callback(err); - submitRequest.call(this, { - Action: 'name/cos:GetBucketOrigin', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'origin', - }, function (err, data) { - if (err) return callback(err); - - var OriginRule = []; - try { - OriginRule = data.OriginConfiguration.OriginRule || []; - } catch (e) { - } - OriginRule = util.clone(util.isArray(OriginRule) ? OriginRule : [OriginRule]); - callback(null, { - OriginRule: OriginRule, - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var OriginRule = []; + try { + OriginRule = data.OriginConfiguration.OriginRule || []; + } catch (e) {} + OriginRule = util.clone(util.isArray(OriginRule) ? OriginRule : [OriginRule]); + callback(null, { + OriginRule: OriginRule, + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -1343,25 +1469,28 @@ function getBucketOrigin(params, callback) { * @return {Object} data 返回数据 */ function deleteBucketOrigin(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketOrigin', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'origin', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + submitRequest.call( + this, + { + Action: 'name/cos:DeleteBucketOrigin', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'origin', + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -1375,33 +1504,37 @@ function deleteBucketOrigin(params, callback) { * @return {Object} data 返回数据 */ function putBucketLogging(params, callback) { - var xml = util.json2xml({ - BucketLoggingStatus: params['BucketLoggingStatus'] || '' - }); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + var xml = util.json2xml({ + BucketLoggingStatus: params['BucketLoggingStatus'] || '', + }); - submitRequest.call(this, { - Action: 'name/cos:PutBucketLogging', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'logging', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call( + this, + { + Action: 'name/cos:PutBucketLogging', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'logging', + headers: headers, + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -1414,21 +1547,25 @@ function putBucketLogging(params, callback) { * @return {Object} data 返回数据 */ function getBucketLogging(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketLogging', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'logging', - }, function (err, data) { - if (err) return callback(err); - callback(null, { - BucketLoggingStatus: data.BucketLoggingStatus, - statusCode: data.statusCode, - headers: data.headers, - }); - }); + submitRequest.call( + this, + { + Action: 'name/cos:GetBucketLogging', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'logging', + }, + function (err, data) { + if (err) return callback(err); + callback(null, { + BucketLoggingStatus: data.BucketLoggingStatus, + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -1443,56 +1580,61 @@ function getBucketLogging(params, callback) { * @return {Object} data 返回数据 */ function putBucketInventory(params, callback) { - var InventoryConfiguration = util.clone(params['InventoryConfiguration']); + var InventoryConfiguration = util.clone(params['InventoryConfiguration']); - if (InventoryConfiguration.OptionalFields) { - var Field = InventoryConfiguration.OptionalFields || []; - InventoryConfiguration.OptionalFields = { - Field: Field - }; - } + if (InventoryConfiguration.OptionalFields) { + var Field = InventoryConfiguration.OptionalFields || []; + InventoryConfiguration.OptionalFields = { + Field: Field, + }; + } - if (InventoryConfiguration.Destination - && InventoryConfiguration.Destination.COSBucketDestination - && InventoryConfiguration.Destination.COSBucketDestination.Encryption - ) { - var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; - if (Object.keys(Encryption).indexOf('SSECOS') > -1) { - Encryption['SSE-COS'] = Encryption['SSECOS']; - delete Encryption['SSECOS']; - } + if ( + InventoryConfiguration.Destination && + InventoryConfiguration.Destination.COSBucketDestination && + InventoryConfiguration.Destination.COSBucketDestination.Encryption + ) { + var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; + if (Object.keys(Encryption).indexOf('SSECOS') > -1) { + Encryption['SSE-COS'] = Encryption['SSECOS']; + delete Encryption['SSECOS']; } + } - var xml = util.json2xml({ - InventoryConfiguration: InventoryConfiguration - }); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + var xml = util.json2xml({ + InventoryConfiguration: InventoryConfiguration, + }); - submitRequest.call(this, { - Action: 'name/cos:PutBucketInventory', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'inventory', - qs: { - id: params['Id'] - }, - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call( + this, + { + Action: 'name/cos:PutBucketInventory', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'inventory', + qs: { + id: params['Id'], + }, + headers: headers, + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -1506,44 +1648,53 @@ function putBucketInventory(params, callback) { * @return {Object} data 返回数据 */ function getBucketInventory(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketInventory', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'inventory', - qs: { - id: params['Id'] - } - }, function (err, data) { - if (err) return callback(err); + submitRequest.call( + this, + { + Action: 'name/cos:GetBucketInventory', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'inventory', + qs: { + id: params['Id'], + }, + }, + function (err, data) { + if (err) return callback(err); - var InventoryConfiguration = data['InventoryConfiguration']; - if (InventoryConfiguration && InventoryConfiguration.OptionalFields && InventoryConfiguration.OptionalFields.Field) { - var Field = InventoryConfiguration.OptionalFields.Field; - if (!util.isArray(Field)) { - Field = [Field]; - } - InventoryConfiguration.OptionalFields = Field; + var InventoryConfiguration = data['InventoryConfiguration']; + if ( + InventoryConfiguration && + InventoryConfiguration.OptionalFields && + InventoryConfiguration.OptionalFields.Field + ) { + var Field = InventoryConfiguration.OptionalFields.Field; + if (!util.isArray(Field)) { + Field = [Field]; } - if (InventoryConfiguration.Destination - && InventoryConfiguration.Destination.COSBucketDestination - && InventoryConfiguration.Destination.COSBucketDestination.Encryption - ) { - var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; - if (Object.keys(Encryption).indexOf('SSE-COS') > -1) { - Encryption['SSECOS'] = Encryption['SSE-COS']; - delete Encryption['SSE-COS']; - } + InventoryConfiguration.OptionalFields = Field; + } + if ( + InventoryConfiguration.Destination && + InventoryConfiguration.Destination.COSBucketDestination && + InventoryConfiguration.Destination.COSBucketDestination.Encryption + ) { + var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; + if (Object.keys(Encryption).indexOf('SSE-COS') > -1) { + Encryption['SSECOS'] = Encryption['SSE-COS']; + delete Encryption['SSE-COS']; } + } - callback(null, { - InventoryConfiguration: InventoryConfiguration, - statusCode: data.statusCode, - headers: data.headers, - }); - }); + callback(null, { + InventoryConfiguration: InventoryConfiguration, + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -1557,210 +1708,244 @@ function getBucketInventory(params, callback) { * @return {Object} data 返回数据 */ function listBucketInventory(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:ListBucketInventory', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'inventory', - qs: { - 'continuation-token': params['ContinuationToken'] + submitRequest.call( + this, + { + Action: 'name/cos:ListBucketInventory', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'inventory', + qs: { + 'continuation-token': params['ContinuationToken'], + }, + }, + function (err, data) { + if (err) return callback(err); + var ListInventoryConfigurationResult = data['ListInventoryConfigurationResult']; + var InventoryConfigurations = ListInventoryConfigurationResult.InventoryConfiguration || []; + InventoryConfigurations = util.isArray(InventoryConfigurations) + ? InventoryConfigurations + : [InventoryConfigurations]; + delete ListInventoryConfigurationResult['InventoryConfiguration']; + util.each(InventoryConfigurations, function (InventoryConfiguration) { + if ( + InventoryConfiguration && + InventoryConfiguration.OptionalFields && + InventoryConfiguration.OptionalFields.Field + ) { + var Field = InventoryConfiguration.OptionalFields.Field; + if (!util.isArray(Field)) { + Field = [Field]; + } + InventoryConfiguration.OptionalFields = Field; } - }, function (err, data) { - if (err) return callback(err); - var ListInventoryConfigurationResult = data['ListInventoryConfigurationResult']; - var InventoryConfigurations = ListInventoryConfigurationResult.InventoryConfiguration || []; - InventoryConfigurations = util.isArray(InventoryConfigurations) ? InventoryConfigurations : [InventoryConfigurations]; - delete ListInventoryConfigurationResult['InventoryConfiguration']; - util.each(InventoryConfigurations, function (InventoryConfiguration) { - if (InventoryConfiguration && InventoryConfiguration.OptionalFields && InventoryConfiguration.OptionalFields.Field) { - var Field = InventoryConfiguration.OptionalFields.Field; - if (!util.isArray(Field)) { - Field = [Field]; - } - InventoryConfiguration.OptionalFields = Field; - } - if (InventoryConfiguration.Destination - && InventoryConfiguration.Destination.COSBucketDestination - && InventoryConfiguration.Destination.COSBucketDestination.Encryption - ) { - var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; - if (Object.keys(Encryption).indexOf('SSE-COS') > -1) { - Encryption['SSECOS'] = Encryption['SSE-COS']; - delete Encryption['SSE-COS']; - } - } - }); - ListInventoryConfigurationResult.InventoryConfigurations = InventoryConfigurations; - util.extend(ListInventoryConfigurationResult, { - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, ListInventoryConfigurationResult); - }); + if ( + InventoryConfiguration.Destination && + InventoryConfiguration.Destination.COSBucketDestination && + InventoryConfiguration.Destination.COSBucketDestination.Encryption + ) { + var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; + if (Object.keys(Encryption).indexOf('SSE-COS') > -1) { + Encryption['SSECOS'] = Encryption['SSE-COS']; + delete Encryption['SSE-COS']; + } + } + }); + ListInventoryConfigurationResult.InventoryConfigurations = InventoryConfigurations; + util.extend(ListInventoryConfigurationResult, { + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, ListInventoryConfigurationResult); + }, + ); } /** * 删除 Bucket 的清单任务 * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Id 清单任务的名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function deleteBucketInventory(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketInventory', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'inventory', - qs: { - id: params['Id'] - } - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Id 清单任务的名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function deleteBucketInventory(params, callback) { + submitRequest.call( + this, + { + Action: 'name/cos:DeleteBucketInventory', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'inventory', + qs: { + id: params['Id'], + }, + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /* 全球加速 */ function putBucketAccelerate(params, callback) { + if (!params['AccelerateConfiguration']) { + callback(util.error(new Error('missing param AccelerateConfiguration'))); + return; + } - if (!params['AccelerateConfiguration']) { - callback(util.error(new Error('missing param AccelerateConfiguration'))); - return; - } - - var configuration = { AccelerateConfiguration: params.AccelerateConfiguration || {} }; + var configuration = { AccelerateConfiguration: params.AccelerateConfiguration || {} }; - var xml = util.json2xml(configuration); + var xml = util.json2xml(configuration); - var headers = {}; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + var headers = {}; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - submitRequest.call(this, { - Action: 'name/cos:PutBucketAccelerate', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'accelerate', - headers: headers, - }, function (err, data) { - if (err) return callback(err); - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + submitRequest.call( + this, + { + Action: 'name/cos:PutBucketAccelerate', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'accelerate', + headers: headers, + }, + function (err, data) { + if (err) return callback(err); + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } function getBucketAccelerate(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketAccelerate', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - action: 'accelerate', - }, function (err, data) { - if (!err) { - !data.AccelerateConfiguration && (data.AccelerateConfiguration = {}); - } - callback(err, data); - }); + submitRequest.call( + this, + { + Action: 'name/cos:GetBucketAccelerate', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + action: 'accelerate', + }, + function (err, data) { + if (!err) { + !data.AccelerateConfiguration && (data.AccelerateConfiguration = {}); + } + callback(err, data); + }, + ); } function putBucketEncryption(params, callback) { - var conf = params.ServerSideEncryptionConfiguration || {}; - var Rules = conf.Rule || conf.Rules || []; - var xml = util.json2xml({ServerSideEncryptionConfiguration: {Rule:Rules}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + var conf = params.ServerSideEncryptionConfiguration || {}; + var Rules = conf.Rule || conf.Rules || []; + var xml = util.json2xml({ ServerSideEncryptionConfiguration: { Rule: Rules } }); - submitRequest.call(this, { - Action: 'name/cos:PutBucketEncryption', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'encryption', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call( + this, + { + Action: 'name/cos:PutBucketEncryption', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'encryption', + headers: headers, + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } function getBucketEncryption(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketEncryption', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'encryption', - }, function (err, data) { - if (err) { - if (err.statusCode === 404 && err.code === 'NoSuchEncryptionConfiguration') { - var result = { - EncryptionConfiguration: {Rules: []}, - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; + submitRequest.call( + this, + { + Action: 'name/cos:GetBucketEncryption', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'encryption', + }, + function (err, data) { + if (err) { + if (err.statusCode === 404 && err.code === 'NoSuchEncryptionConfiguration') { + var result = { + EncryptionConfiguration: { Rules: [] }, + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); } - var Rules = util.makeArray(data.EncryptionConfiguration && data.EncryptionConfiguration.Rule || []); - data.EncryptionConfiguration = {Rules: Rules}; - callback(err, data); - }); + return; + } + var Rules = util.makeArray((data.EncryptionConfiguration && data.EncryptionConfiguration.Rule) || []); + data.EncryptionConfiguration = { Rules: Rules }; + callback(err, data); + }, + ); } function deleteBucketEncryption(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketReplication', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'encryption', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + submitRequest.call( + this, + { + Action: 'name/cos:DeleteBucketReplication', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'encryption', + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } // Object 相关 @@ -1778,69 +1963,76 @@ function deleteBucketEncryption(params, callback) { * @return {Boolean} data.NotModified 是否在 IfModifiedSince 时间点之后未修改该 object,则为 true */ function headObject(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:HeadObject', - method: 'HEAD', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - VersionId: params.VersionId, - headers: params.Headers, - }, function (err, data) { - if (err) { - var statusCode = err.statusCode; - if (params.Headers['If-Modified-Since'] && statusCode && statusCode === 304) { - return callback(null, { - NotModified: true, - statusCode: statusCode, - }); - } - return callback(err); + submitRequest.call( + this, + { + Action: 'name/cos:HeadObject', + method: 'HEAD', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + VersionId: params.VersionId, + headers: params.Headers, + }, + function (err, data) { + if (err) { + var statusCode = err.statusCode; + if (params.Headers['If-Modified-Since'] && statusCode && statusCode === 304) { + return callback(null, { + NotModified: true, + statusCode: statusCode, + }); } - data.ETag = util.attr(data.headers, 'etag', ''); - callback(null, data); - }); + return callback(err); + } + data.ETag = util.attr(data.headers, 'etag', ''); + callback(null, data); + }, + ); } - function listObjectVersions(params, callback) { - var reqParams = {}; - reqParams['prefix'] = params['Prefix'] || ''; - reqParams['delimiter'] = params['Delimiter']; - reqParams['key-marker'] = params['KeyMarker']; - reqParams['version-id-marker'] = params['VersionIdMarker']; - reqParams['max-keys'] = params['MaxKeys']; - reqParams['encoding-type'] = params['EncodingType']; - - submitRequest.call(this, { - Action: 'name/cos:GetBucketObjectVersions', - ResourceKey: reqParams['prefix'], - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - qs: reqParams, - action: 'versions', - }, function (err, data) { - if (err) return callback(err); - var ListVersionsResult = data.ListVersionsResult || {}; - var DeleteMarkers = ListVersionsResult.DeleteMarker || []; - DeleteMarkers = util.isArray(DeleteMarkers) ? DeleteMarkers : [DeleteMarkers]; - var Versions = ListVersionsResult.Version || []; - Versions = util.isArray(Versions) ? Versions : [Versions]; - - var result = util.clone(ListVersionsResult); - delete result.DeleteMarker; - delete result.Version; - util.extend(result, { - DeleteMarkers: DeleteMarkers, - Versions: Versions, - statusCode: data.statusCode, - headers: data.headers, - }); - - callback(null, result); - }); + var reqParams = {}; + reqParams['prefix'] = params['Prefix'] || ''; + reqParams['delimiter'] = params['Delimiter']; + reqParams['key-marker'] = params['KeyMarker']; + reqParams['version-id-marker'] = params['VersionIdMarker']; + reqParams['max-keys'] = params['MaxKeys']; + reqParams['encoding-type'] = params['EncodingType']; + + submitRequest.call( + this, + { + Action: 'name/cos:GetBucketObjectVersions', + ResourceKey: reqParams['prefix'], + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + qs: reqParams, + action: 'versions', + }, + function (err, data) { + if (err) return callback(err); + var ListVersionsResult = data.ListVersionsResult || {}; + var DeleteMarkers = ListVersionsResult.DeleteMarker || []; + DeleteMarkers = util.isArray(DeleteMarkers) ? DeleteMarkers : [DeleteMarkers]; + var Versions = ListVersionsResult.Version || []; + Versions = util.isArray(Versions) ? Versions : [Versions]; + + var result = util.clone(ListVersionsResult); + delete result.DeleteMarker; + delete result.Version; + util.extend(result, { + DeleteMarkers: DeleteMarkers, + Versions: Versions, + statusCode: data.statusCode, + headers: data.headers, + }); + + callback(null, result); + }, + ); } /** @@ -1865,118 +2057,121 @@ function listObjectVersions(params, callback) { * @param {Object} data 为对应的 object 数据,包括 body 和 headers */ function getObject(params, callback) { - var reqParams = params.Query || {}; - var reqParamsStr = params.QueryString || ''; - - reqParams['response-content-type'] = params['ResponseContentType']; - reqParams['response-content-language'] = params['ResponseContentLanguage']; - reqParams['response-expires'] = params['ResponseExpires']; - reqParams['response-cache-control'] = params['ResponseCacheControl']; - reqParams['response-content-disposition'] = params['ResponseContentDisposition']; - reqParams['response-content-encoding'] = params['ResponseContentEncoding']; - - var BodyType; - - var self = this; - var outputStream = params.Output; - if (params.ReturnStream) { - outputStream = new Stream.PassThrough(); - BodyType = 'stream'; - } else if (outputStream && typeof outputStream === 'string') { - outputStream = fs.createWriteStream(outputStream); - BodyType = 'stream'; - } else if (outputStream && typeof outputStream.pipe === 'function') { - BodyType = 'stream'; - } else { - BodyType = 'buffer'; - } - - var onProgress = params.onProgress; - var onDownloadProgress = (function () { - var time0 = Date.now(); - var size0 = 0; - var FinishSize = 0; - var FileSize = 0; - var progressTimer; - var update = function () { - progressTimer = 0; - if (onProgress && (typeof onProgress === 'function')) { - var time1 = Date.now(); - var speed = parseInt((FinishSize - size0) / ((time1 - time0) / 1000) * 100) / 100 || 0; - var percent = parseInt(FinishSize / FileSize * 100) / 100 || 0; - time0 = time1; - size0 = FinishSize; - try { - onProgress({ - loaded: FinishSize, - total: FileSize, - speed: speed, - percent: percent - }); - } catch (e) { - } - } - }; - return function (info, immediately) { - if (info && info.loaded) { - FinishSize = info.loaded; - FileSize = info.total; - } - if (immediately) { - clearTimeout(progressTimer); - update(); - } else { - if (progressTimer) return; - progressTimer = setTimeout(update, self.options.ProgressInterval || 1000); - } - }; - })(); + var reqParams = params.Query || {}; + var reqParamsStr = params.QueryString || ''; + + reqParams['response-content-type'] = params['ResponseContentType']; + reqParams['response-content-language'] = params['ResponseContentLanguage']; + reqParams['response-expires'] = params['ResponseExpires']; + reqParams['response-cache-control'] = params['ResponseCacheControl']; + reqParams['response-content-disposition'] = params['ResponseContentDisposition']; + reqParams['response-content-encoding'] = params['ResponseContentEncoding']; + + var BodyType; + + var self = this; + var outputStream = params.Output; + if (params.ReturnStream) { + outputStream = new Stream.PassThrough(); + BodyType = 'stream'; + } else if (outputStream && typeof outputStream === 'string') { + outputStream = fs.createWriteStream(outputStream); + BodyType = 'stream'; + } else if (outputStream && typeof outputStream.pipe === 'function') { + BodyType = 'stream'; + } else { + BodyType = 'buffer'; + } - // 如果用户自己传入了 output - submitRequest.call(this, { - Action: 'name/cos:GetObject', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - VersionId: params.VersionId, - headers: params.Headers, - qs: reqParams, - qsStr: reqParamsStr, - rawBody: true, - outputStream: outputStream, - onDownloadProgress: onDownloadProgress, - }, function (err, data) { - onDownloadProgress(null, true); - if (err) { - var statusCode = err.statusCode; - if (params.Headers['If-Modified-Since'] && statusCode && statusCode === 304) { - return callback(null, {NotModified: true}); - } - if (outputStream) outputStream.emit('error', err); - return callback(err); + var onProgress = params.onProgress; + var onDownloadProgress = (function () { + var time0 = Date.now(); + var size0 = 0; + var FinishSize = 0; + var FileSize = 0; + var progressTimer; + var update = function () { + progressTimer = 0; + if (onProgress && typeof onProgress === 'function') { + var time1 = Date.now(); + var speed = parseInt(((FinishSize - size0) / ((time1 - time0) / 1000)) * 100) / 100 || 0; + var percent = parseInt((FinishSize / FileSize) * 100) / 100 || 0; + time0 = time1; + size0 = FinishSize; + try { + onProgress({ + loaded: FinishSize, + total: FileSize, + speed: speed, + percent: percent, + }); + } catch (e) {} + } + }; + return function (info, immediately) { + if (info && info.loaded) { + FinishSize = info.loaded; + FileSize = info.total; + } + if (immediately) { + clearTimeout(progressTimer); + update(); + } else { + if (progressTimer) return; + progressTimer = setTimeout(update, self.options.ProgressInterval || 1000); + } + }; + })(); + + // 如果用户自己传入了 output + submitRequest.call( + this, + { + Action: 'name/cos:GetObject', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + VersionId: params.VersionId, + headers: params.Headers, + qs: reqParams, + qsStr: reqParamsStr, + rawBody: true, + outputStream: outputStream, + onDownloadProgress: onDownloadProgress, + }, + function (err, data) { + onDownloadProgress(null, true); + if (err) { + var statusCode = err.statusCode; + if (params.Headers['If-Modified-Since'] && statusCode && statusCode === 304) { + return callback(null, { NotModified: true }); } - var result = {}; - if (data.body) { - if (BodyType === 'buffer') { - result.Body = Buffer.from(data.body); - } else if (BodyType === 'string') { - result.Body = data.body; - } + if (outputStream) outputStream.emit('error', err); + return callback(err); + } + var result = {}; + if (data.body) { + if (BodyType === 'buffer') { + result.Body = Buffer.from(data.body); + } else if (BodyType === 'string') { + result.Body = data.body; } - util.extend(result, { - ETag: util.attr(data.headers, 'etag', ''), - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); - if (params.ReturnStream) return outputStream; + } + util.extend(result, { + ETag: util.attr(data.headers, 'etag', ''), + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }, + ); + if (params.ReturnStream) return outputStream; } function getObjectStream(params, callback) { - params.ReturnStream = true; - return getObject.call(this, params, callback); + params.ReturnStream = true; + return getObject.call(this, params, callback); } /** @@ -2009,54 +2204,58 @@ function getObjectStream(params, callback) { * @return {String} data.ETag 为对应上传文件的 ETag 值 */ function putObject(params, callback) { - var self = this; - var FileSize = params.ContentLength; - var onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); + var self = this; + var FileSize = params.ContentLength; + var onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); - // 特殊处理 Cache-Control、Content-Type,避免代理更改这两个字段导致写入到 Object 属性里 - var headers = params.Headers; - if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = ''; + // 特殊处理 Cache-Control、Content-Type,避免代理更改这两个字段导致写入到 Object 属性里 + var headers = params.Headers; + if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = ''; - util.getBodyMd5(self.options.UploadCheckContentMd5, params.Body, function (md5) { - if (md5) (params.Headers['Content-MD5'] = util.binaryBase64(md5)); - if (params.ContentLength !== undefined) { - params.Headers['Content-Length'] = params.ContentLength; + util.getBodyMd5(self.options.UploadCheckContentMd5, params.Body, function (md5) { + if (md5) params.Headers['Content-MD5'] = util.binaryBase64(md5); + if (params.ContentLength !== undefined) { + params.Headers['Content-Length'] = params.ContentLength; + } + onProgress(null, true); // 任务状态开始 uploading + submitRequest.call( + self, + { + Action: 'name/cos:PutObject', + TaskId: params.TaskId, + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + qs: params.Query, + body: params.Body, + onProgress: onProgress, + }, + function (err, data) { + if (err) { + onProgress(null, true); + return callback(err); } - onProgress(null, true); // 任务状态开始 uploading - submitRequest.call(self, { - Action: 'name/cos:PutObject', - TaskId: params.TaskId, - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - qs: params.Query, - body: params.Body, - onProgress: onProgress, - }, function (err, data) { - if (err) { - onProgress(null, true); - return callback(err); - } - onProgress({loaded: FileSize, total: FileSize}, true); - if (data) { - var url = getUrl({ - ForcePathStyle: self.options.ForcePathStyle, - protocol: self.options.Protocol, - domain: self.options.Domain, - bucket: params.Bucket, - region: !self.options.UseAccelerate ? params.Region : 'accelerate', - object: params.Key, - }); - url = url.substr(url.indexOf('://') + 3); - data.Location = url; - if (data.headers && data.headers.etag) data.ETag = data.headers.etag; - return callback(null, data); - } - callback(null, data); - }); - }); + onProgress({ loaded: FileSize, total: FileSize }, true); + if (data) { + var url = getUrl({ + ForcePathStyle: self.options.ForcePathStyle, + protocol: self.options.Protocol, + domain: self.options.Domain, + bucket: params.Bucket, + region: !self.options.UseAccelerate ? params.Region : 'accelerate', + object: params.Key, + }); + url = url.substr(url.indexOf('://') + 3); + data.Location = url; + if (data.headers && data.headers.etag) data.ETag = data.headers.etag; + return callback(null, data); + } + callback(null, data); + }, + ); + }); } /** @@ -2070,28 +2269,32 @@ function putObject(params, callback) { * @param {Object} data 删除操作成功之后返回的数据 */ function deleteObject(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteObject', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - VersionId: params.VersionId, - }, function (err, data) { - if (err) { - var statusCode = err.statusCode; - if (statusCode && statusCode === 404) { - return callback(null, {BucketNotFound: true, statusCode: statusCode,}); - } else { - return callback(err); - } + submitRequest.call( + this, + { + Action: 'name/cos:DeleteObject', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + VersionId: params.VersionId, + }, + function (err, data) { + if (err) { + var statusCode = err.statusCode; + if (statusCode && statusCode === 404) { + return callback(null, { BucketNotFound: true, statusCode: statusCode }); + } else { + return callback(err); } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -2106,39 +2309,43 @@ function deleteObject(params, callback) { * @return {Object} data.AccessControlPolicy 权限列表 */ function getObjectAcl(params, callback) { - var reqParams = {}; + var reqParams = {}; - if (params.VersionId) { - reqParams.versionId = params.VersionId; - } - submitRequest.call(this, { - Action: 'name/cos:GetObjectACL', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - qs: reqParams, - action: 'acl', - }, function (err, data) { - if (err) return callback(err); - var AccessControlPolicy = data.AccessControlPolicy || {}; - var Owner = AccessControlPolicy.Owner || {}; - var Grant = AccessControlPolicy.AccessControlList && AccessControlPolicy.AccessControlList.Grant || []; - Grant = util.isArray(Grant) ? Grant : [Grant]; - var result = decodeAcl(AccessControlPolicy); - delete result.GrantWrite; - if (data.headers && data.headers['x-cos-acl']) { - result.ACL = data.headers['x-cos-acl']; - } - result = util.extend(result, { - Owner: Owner, - Grants: Grant, - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); + if (params.VersionId) { + reqParams.versionId = params.VersionId; + } + submitRequest.call( + this, + { + Action: 'name/cos:GetObjectACL', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + qs: reqParams, + action: 'acl', + }, + function (err, data) { + if (err) return callback(err); + var AccessControlPolicy = data.AccessControlPolicy || {}; + var Owner = AccessControlPolicy.Owner || {}; + var Grant = (AccessControlPolicy.AccessControlList && AccessControlPolicy.AccessControlList.Grant) || []; + Grant = util.isArray(Grant) ? Grant : [Grant]; + var result = decodeAcl(AccessControlPolicy); + delete result.GrantWrite; + if (data.headers && data.headers['x-cos-acl']) { + result.ACL = data.headers['x-cos-acl']; + } + result = util.extend(result, { + Owner: Owner, + Grants: Grant, + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }, + ); } /** @@ -2152,45 +2359,49 @@ function getObjectAcl(params, callback) { * @return {Object} data 返回的数据 */ function putObjectAcl(params, callback) { - var headers = params.Headers; - - var xml = ''; - if (params['AccessControlPolicy']) { - var AccessControlPolicy = util.clone(params['AccessControlPolicy'] || {}); - var Grants = AccessControlPolicy.Grants || AccessControlPolicy.Grant; - Grants = util.isArray(Grants) ? Grants : [Grants]; - delete AccessControlPolicy.Grant; - delete AccessControlPolicy.Grants; - AccessControlPolicy.AccessControlList = {Grant: Grants}; - xml = util.json2xml({AccessControlPolicy: AccessControlPolicy}); - - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - } + var headers = params.Headers; - // Grant Header 去重 - util.each(headers, function (val, key) { - if (key.indexOf('x-cos-grant-') === 0) { - headers[key] = uniqGrant(headers[key]); - } - }); + var xml = ''; + if (params['AccessControlPolicy']) { + var AccessControlPolicy = util.clone(params['AccessControlPolicy'] || {}); + var Grants = AccessControlPolicy.Grants || AccessControlPolicy.Grant; + Grants = util.isArray(Grants) ? Grants : [Grants]; + delete AccessControlPolicy.Grant; + delete AccessControlPolicy.Grants; + AccessControlPolicy.AccessControlList = { Grant: Grants }; + xml = util.json2xml({ AccessControlPolicy: AccessControlPolicy }); - submitRequest.call(this, { - Action: 'name/cos:PutObjectACL', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - action: 'acl', - headers: headers, - body: xml, - }, function (err, data) { - if (err) return callback(err); - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + } + + // Grant Header 去重 + util.each(headers, function (val, key) { + if (key.indexOf('x-cos-grant-') === 0) { + headers[key] = uniqGrant(headers[key]); + } + }); + + submitRequest.call( + this, + { + Action: 'name/cos:PutObjectACL', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + action: 'acl', + headers: headers, + body: xml, + }, + function (err, data) { + if (err) return callback(err); + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -2204,41 +2415,44 @@ function putObjectAcl(params, callback) { * @return {Object} data 返回的数据 */ function optionsObject(params, callback) { - - var headers = params.Headers; - headers['Origin'] = params['Origin']; - headers['Access-Control-Request-Method'] = params['AccessControlRequestMethod']; - headers['Access-Control-Request-Headers'] = params['AccessControlRequestHeaders']; - - submitRequest.call(this, { - Action: 'name/cos:OptionsObject', - method: 'OPTIONS', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: headers, - }, function (err, data) { - if (err) { - if (err.statusCode && err.statusCode === 403) { - return callback(null, { - OptionsForbidden: true, - statusCode: err.statusCode - }); - } - return callback(err); + var headers = params.Headers; + headers['Origin'] = params['Origin']; + headers['Access-Control-Request-Method'] = params['AccessControlRequestMethod']; + headers['Access-Control-Request-Headers'] = params['AccessControlRequestHeaders']; + + submitRequest.call( + this, + { + Action: 'name/cos:OptionsObject', + method: 'OPTIONS', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: headers, + }, + function (err, data) { + if (err) { + if (err.statusCode && err.statusCode === 403) { + return callback(null, { + OptionsForbidden: true, + statusCode: err.statusCode, + }); } + return callback(err); + } - var headers = data.headers || {}; - callback(null, { - AccessControlAllowOrigin: headers['access-control-allow-origin'], - AccessControlAllowMethods: headers['access-control-allow-methods'], - AccessControlAllowHeaders: headers['access-control-allow-headers'], - AccessControlExposeHeaders: headers['access-control-expose-headers'], - AccessControlMaxAge: headers['access-control-max-age'], - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var headers = data.headers || {}; + callback(null, { + AccessControlAllowOrigin: headers['access-control-allow-origin'], + AccessControlAllowMethods: headers['access-control-allow-methods'], + AccessControlAllowHeaders: headers['access-control-allow-headers'], + AccessControlExposeHeaders: headers['access-control-expose-headers'], + AccessControlMaxAge: headers['access-control-max-age'], + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -2269,169 +2483,189 @@ function optionsObject(params, callback) { * @param {String} x-cos-meta-* 允许用户自定义的头部信息,将作为 Object 元数据返回。大小限制2K。 */ function putObjectCopy(params, callback) { + // 特殊处理 Cache-Control + var headers = params.Headers; + if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = ''; - // 特殊处理 Cache-Control - var headers = params.Headers; - if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = ''; - - var CopySource = params.CopySource || ''; - var m = util.getSourceParams.call(this, CopySource); - if (!m) { - callback(util.error(new Error('CopySource format error'))); - return; - } - - var SourceBucket = m.Bucket; - var SourceRegion = m.Region; - var SourceKey = decodeURIComponent(m.Key); - - submitRequest.call(this, { - Scope: [{ - action: 'name/cos:GetObject', - bucket: SourceBucket, - region: SourceRegion, - prefix: SourceKey, - }, { - action: 'name/cos:PutObject', - bucket: params.Bucket, - region: params.Region, - prefix: params.Key, - }], - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - VersionId: params.VersionId, - headers: params.Headers, - }, function (err, data) { - if (err) return callback(err); - var result = util.clone(data.CopyObjectResult || {}); - util.extend(result, { - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); + var CopySource = params.CopySource || ''; + var m = util.getSourceParams.call(this, CopySource); + if (!m) { + callback(util.error(new Error('CopySource format error'))); + return; + } + + var SourceBucket = m.Bucket; + var SourceRegion = m.Region; + var SourceKey = decodeURIComponent(m.Key); + + submitRequest.call( + this, + { + Scope: [ + { + action: 'name/cos:GetObject', + bucket: SourceBucket, + region: SourceRegion, + prefix: SourceKey, + }, + { + action: 'name/cos:PutObject', + bucket: params.Bucket, + region: params.Region, + prefix: params.Key, + }, + ], + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + VersionId: params.VersionId, + headers: params.Headers, + }, + function (err, data) { + if (err) return callback(err); + var result = util.clone(data.CopyObjectResult || {}); + util.extend(result, { + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }, + ); } function uploadPartCopy(params, callback) { + var CopySource = params.CopySource || ''; + var m = util.getSourceParams.call(this, CopySource); + if (!m) { + callback(util.error(new Error('CopySource format error'))); + return; + } - var CopySource = params.CopySource || ''; - var m = util.getSourceParams.call(this, CopySource); - if (!m) { - callback(util.error(new Error('CopySource format error'))); - return; - } - - var SourceBucket = m.Bucket; - var SourceRegion = m.Region; - var SourceKey = decodeURIComponent(m.Key); - - submitRequest.call(this, { - Scope: [{ - action: 'name/cos:GetObject', - bucket: SourceBucket, - region: SourceRegion, - prefix: SourceKey, - }, { - action: 'name/cos:PutObject', - bucket: params.Bucket, - region: params.Region, - prefix: params.Key, - }], - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - VersionId: params.VersionId, - qs: { - partNumber: params['PartNumber'], - uploadId: params['UploadId'], + var SourceBucket = m.Bucket; + var SourceRegion = m.Region; + var SourceKey = decodeURIComponent(m.Key); + + submitRequest.call( + this, + { + Scope: [ + { + action: 'name/cos:GetObject', + bucket: SourceBucket, + region: SourceRegion, + prefix: SourceKey, }, - headers: params.Headers, - }, function (err, data) { - if (err) return callback(err); - var result = util.clone(data.CopyPartResult || {}); - util.extend(result, { - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); + { + action: 'name/cos:PutObject', + bucket: params.Bucket, + region: params.Region, + prefix: params.Key, + }, + ], + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + VersionId: params.VersionId, + qs: { + partNumber: params['PartNumber'], + uploadId: params['UploadId'], + }, + headers: params.Headers, + }, + function (err, data) { + if (err) return callback(err); + var result = util.clone(data.CopyPartResult || {}); + util.extend(result, { + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }, + ); } function deleteMultipleObject(params, callback) { - var Objects = params.Objects || []; - var Quiet = params.Quiet; - Objects = util.isArray(Objects) ? Objects : [Objects]; - - var xml = util.json2xml({Delete: {Object: Objects, Quiet: Quiet || false}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - var Scope = util.map(Objects, function (v) { - return { - action: 'name/cos:DeleteObject', - bucket: params.Bucket, - region: params.Region, - prefix: v.Key, - }; - }); + var Objects = params.Objects || []; + var Quiet = params.Quiet; + Objects = util.isArray(Objects) ? Objects : [Objects]; - submitRequest.call(this, { - Scope: Scope, - method: 'POST', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'delete', - headers: headers, - }, function (err, data) { - if (err) return callback(err); - var DeleteResult = data.DeleteResult || {}; - var Deleted = DeleteResult.Deleted || []; - var Errors = DeleteResult.Error || []; + var xml = util.json2xml({ Delete: { Object: Objects, Quiet: Quiet || false } }); - Deleted = util.isArray(Deleted) ? Deleted : [Deleted]; - Errors = util.isArray(Errors) ? Errors : [Errors]; + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + var Scope = util.map(Objects, function (v) { + return { + action: 'name/cos:DeleteObject', + bucket: params.Bucket, + region: params.Region, + prefix: v.Key, + }; + }); - var result = util.clone(DeleteResult); - util.extend(result, { - Error: Errors, - Deleted: Deleted, - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); + submitRequest.call( + this, + { + Scope: Scope, + method: 'POST', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'delete', + headers: headers, + }, + function (err, data) { + if (err) return callback(err); + var DeleteResult = data.DeleteResult || {}; + var Deleted = DeleteResult.Deleted || []; + var Errors = DeleteResult.Error || []; + + Deleted = util.isArray(Deleted) ? Deleted : [Deleted]; + Errors = util.isArray(Errors) ? Errors : [Errors]; + + var result = util.clone(DeleteResult); + util.extend(result, { + Error: Errors, + Deleted: Deleted, + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }, + ); } function restoreObject(params, callback) { - var headers = params.Headers; - if (!params['RestoreRequest']) { - callback(util.error(new Error('missing param RestoreRequest'))); - return; - } + var headers = params.Headers; + if (!params['RestoreRequest']) { + callback(util.error(new Error('missing param RestoreRequest'))); + return; + } - var RestoreRequest = params.RestoreRequest || {}; - var xml = util.json2xml({RestoreRequest: RestoreRequest}); + var RestoreRequest = params.RestoreRequest || {}; + var xml = util.json2xml({ RestoreRequest: RestoreRequest }); - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - submitRequest.call(this, { - Action: 'name/cos:RestoreObject', - method: 'POST', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - VersionId: params.VersionId, - body: xml, - action: 'restore', - headers: headers, - }, callback); + submitRequest.call( + this, + { + Action: 'name/cos:RestoreObject', + method: 'POST', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + VersionId: params.VersionId, + body: xml, + action: 'restore', + headers: headers, + }, + callback, + ); } /** @@ -2445,37 +2679,40 @@ function restoreObject(params, callback) { * @return {Object} data 返回数据 */ function putObjectTagging(params, callback) { + var Tagging = params['Tagging'] || {}; + var Tags = Tagging.TagSet || Tagging.Tags || params['Tags'] || []; + Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); + var xml = util.json2xml({ Tagging: { TagSet: { Tag: Tags } } }); - var Tagging = params['Tagging'] || {}; - var Tags = Tagging.TagSet || Tagging.Tags || params['Tags'] || []; - Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); - var xml = util.json2xml({Tagging: {TagSet: {Tag: Tags}}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutObjectTagging', - method: 'PUT', - Bucket: params.Bucket, - Key: params.Key, - Region: params.Region, - body: xml, - action: 'tagging', - headers: headers, - VersionId: params.VersionId, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call( + this, + { + Action: 'name/cos:PutObjectTagging', + method: 'PUT', + Bucket: params.Bucket, + Key: params.Key, + Region: params.Region, + body: xml, + action: 'tagging', + headers: headers, + VersionId: params.VersionId, + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -2488,42 +2725,44 @@ function putObjectTagging(params, callback) { * @return {Object} data 返回数据 */ function getObjectTagging(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetObjectTagging', - method: 'GET', - Key: params.Key, - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'tagging', - VersionId: params.VersionId, - }, function (err, data) { - if (err) { - if (err.statusCode === 404 && err.error && (err.error === "Not Found" || err.error.Code === 'NoSuchTagSet')) { - var result = { - Tags: [], - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - var Tags = []; - try { - Tags = data.Tagging.TagSet.Tag || []; - } catch (e) { + submitRequest.call( + this, + { + Action: 'name/cos:GetObjectTagging', + method: 'GET', + Key: params.Key, + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'tagging', + VersionId: params.VersionId, + }, + function (err, data) { + if (err) { + if (err.statusCode === 404 && err.error && (err.error === 'Not Found' || err.error.Code === 'NoSuchTagSet')) { + var result = { + Tags: [], + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); } - Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); - callback(null, { - Tags: Tags, - statusCode: data.statusCode, - headers: data.headers, - }); - }); + return; + } + var Tags = []; + try { + Tags = data.Tagging.TagSet.Tag || []; + } catch (e) {} + Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); + callback(null, { + Tags: Tags, + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -2536,26 +2775,30 @@ function getObjectTagging(params, callback) { * @return {Object} data 返回的数据 */ function deleteObjectTagging(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteObjectTagging', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - action: 'tagging', - VersionId: params.VersionId, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + submitRequest.call( + this, + { + Action: 'name/cos:DeleteObjectTagging', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + action: 'tagging', + VersionId: params.VersionId, + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -2569,87 +2812,97 @@ function deleteObjectTagging(params, callback) { * @return {Object} data 返回的数据 */ function selectObjectContent(params, callback) { - var SelectType = params['SelectType']; - if (!SelectType) return callback(util.error(new Error('missing param SelectType'))); + var SelectType = params['SelectType']; + if (!SelectType) return callback(util.error(new Error('missing param SelectType'))); - var SelectRequest = params['SelectRequest'] || {}; - var xml = util.json2xml({SelectRequest: SelectRequest}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + var SelectRequest = params['SelectRequest'] || {}; + var xml = util.json2xml({ SelectRequest: SelectRequest }); - var outputStream; - var selectResult = {}; - var SelectStream = require('./select-stream'); - if (params.ReturnStream && params.DataType === 'raw') { // 流 && raw 直接原样数据吐回 - outputStream = new Stream.PassThrough(); - } else { // 包含 params.ReturnStream || !params.ReturnStream - outputStream = new SelectStream(); - outputStream.on('message:progress', function (progress) { - if (typeof params.onProgress === 'function') params.onProgress(progress); - }); - outputStream.on('message:stats', function (stats) { - selectResult.stats = stats; - }); - outputStream.on('message:error', function (error) { - selectResult.error = error; - }); - } - submitRequest.call(this, { - Action: 'name/cos:GetObject', - method: 'POST', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - action: 'select', - qs: { - 'select-type': params['SelectType'], - }, - VersionId: params.VersionId, - body: xml, - rawBody: true, - outputStream: outputStream, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - if (outputStream) outputStream.emit('error', err); - return callback(err); - } else if (selectResult.error) { - return callback(util.extend(selectResult.error, { - statusCode: data.statusCode, - headers: data.headers, - })); - } - var result = { + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + var outputStream; + var selectResult = {}; + var SelectStream = require('./select-stream'); + if (params.ReturnStream && params.DataType === 'raw') { + // 流 && raw 直接原样数据吐回 + outputStream = new Stream.PassThrough(); + } else { + // 包含 params.ReturnStream || !params.ReturnStream + outputStream = new SelectStream(); + outputStream.on('message:progress', function (progress) { + if (typeof params.onProgress === 'function') params.onProgress(progress); + }); + outputStream.on('message:stats', function (stats) { + selectResult.stats = stats; + }); + outputStream.on('message:error', function (error) { + selectResult.error = error; + }); + } + submitRequest.call( + this, + { + Action: 'name/cos:GetObject', + method: 'POST', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + action: 'select', + qs: { + 'select-type': params['SelectType'], + }, + VersionId: params.VersionId, + body: xml, + rawBody: true, + outputStream: outputStream, + }, + function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, { statusCode: err.statusCode }); + } else if (err) { + if (outputStream) outputStream.emit('error', err); + return callback(err); + } else if (selectResult.error) { + return callback( + util.extend(selectResult.error, { statusCode: data.statusCode, headers: data.headers, - }; - // 只要流里有解析出 stats,就返回 Stats - if (selectResult.stats) result.Stats = selectResult.stats; - // 只要有 records,就返回 Payload - if (selectResult.records) result.Payload = Buffer.concat(selectResult.records); - callback(null, result); - }); - if (!params.ReturnStream && params.DataType !== 'raw') { - selectResult.records = []; - outputStream.pipe(new Stream.Writable({ - write: function (chunk, encoding, callback) { - selectResult.records.push(chunk); - callback(); - }, - writev: function (chunks, encoding, callback) { - chunks.forEach(function (item) { - selectResult.records.push(chunks); - }); - callback(); - }, - })); - outputStream.pipe(outputStream); - } - if (params.ReturnStream) return outputStream; + }), + ); + } + var result = { + statusCode: data.statusCode, + headers: data.headers, + }; + // 只要流里有解析出 stats,就返回 Stats + if (selectResult.stats) result.Stats = selectResult.stats; + // 只要有 records,就返回 Payload + if (selectResult.records) result.Payload = Buffer.concat(selectResult.records); + callback(null, result); + }, + ); + if (!params.ReturnStream && params.DataType !== 'raw') { + selectResult.records = []; + outputStream.pipe( + new Stream.Writable({ + write: function (chunk, encoding, callback) { + selectResult.records.push(chunk); + callback(); + }, + writev: function (chunks, encoding, callback) { + chunks.forEach(function (item) { + selectResult.records.push(chunks); + }); + callback(); + }, + }), + ); + outputStream.pipe(outputStream); + } + if (params.ReturnStream) return outputStream; } /** @@ -2664,14 +2917,12 @@ function selectObjectContent(params, callback) { * @return {Object} Stream 返回值 */ function selectObjectContentStream(params, callback) { - params.ReturnStream = true; - return selectObjectContent.call(this, params, callback); + params.ReturnStream = true; + return selectObjectContent.call(this, params, callback); } - // 分块上传 - /** * 初始化分块上传 * @param {Object} params 参数对象,必须 @@ -2695,34 +2946,41 @@ function selectObjectContentStream(params, callback) { * @return {Object} data 返回的数据 */ function multipartInit(params, callback) { + // 特殊处理 Cache-Control + var headers = params.Headers; - // 特殊处理 Cache-Control - var headers = params.Headers; - - // 特殊处理 Cache-Control、Content-Type - if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = ''; - if (!headers['Content-Type'] && !headers['content-type']) headers['Content-Type'] = params.Body && params.Body.type || ''; + // 特殊处理 Cache-Control、Content-Type + if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = ''; + if (!headers['Content-Type'] && !headers['content-type']) + headers['Content-Type'] = (params.Body && params.Body.type) || ''; - submitRequest.call(this, { - Action: 'name/cos:InitiateMultipartUpload', - method: 'POST', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - action: 'uploads', - headers: params.Headers, - qs: params.Query, - }, function (err, data) { - if (err) return callback(err); - data = util.clone(data || {}); - if (data && data.InitiateMultipartUploadResult) { - return callback(null, util.extend(data.InitiateMultipartUploadResult, { - statusCode: data.statusCode, - headers: data.headers, - })); - } - callback(null, data); - }); + submitRequest.call( + this, + { + Action: 'name/cos:InitiateMultipartUpload', + method: 'POST', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + action: 'uploads', + headers: params.Headers, + qs: params.Query, + }, + function (err, data) { + if (err) return callback(err); + data = util.clone(data || {}); + if (data && data.InitiateMultipartUploadResult) { + return callback( + null, + util.extend(data.InitiateMultipartUploadResult, { + statusCode: data.statusCode, + headers: data.headers, + }), + ); + } + callback(null, data); + }, + ); } /** @@ -2742,36 +3000,38 @@ function multipartInit(params, callback) { * @return {Object} data.ETag 返回的文件分块 sha1 值 */ function multipartUpload(params, callback) { - - var self = this; - util.getFileSize('multipartUpload', params, function () { - util.getBodyMd5(self.options.UploadCheckContentMd5, params.Body, function (md5) { - if (md5) params.Headers['Content-MD5'] = util.binaryBase64(md5); - submitRequest.call(self, { - Action: 'name/cos:UploadPart', - TaskId: params.TaskId, - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - qs: { - partNumber: params['PartNumber'], - uploadId: params['UploadId'], - }, - headers: params.Headers, - onProgress: params.onProgress, - body: params.Body || null - }, function (err, data) { - if (err) return callback(err); - callback(null, { - ETag: util.attr(data.headers, 'etag', ''), - statusCode: data.statusCode, - headers: data.headers, - }); - }); - }); + var self = this; + util.getFileSize('multipartUpload', params, function () { + util.getBodyMd5(self.options.UploadCheckContentMd5, params.Body, function (md5) { + if (md5) params.Headers['Content-MD5'] = util.binaryBase64(md5); + submitRequest.call( + self, + { + Action: 'name/cos:UploadPart', + TaskId: params.TaskId, + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + qs: { + partNumber: params['PartNumber'], + uploadId: params['UploadId'], + }, + headers: params.Headers, + onProgress: params.onProgress, + body: params.Body || null, + }, + function (err, data) { + if (err) return callback(err); + callback(null, { + ETag: util.attr(data.headers, 'etag', ''), + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); }); - + }); } /** @@ -2789,72 +3049,76 @@ function multipartUpload(params, callback) { * @return {Object} data.CompleteMultipartUpload 完成分块上传后的文件信息,包括Location, Bucket, Key 和 ETag */ function multipartComplete(params, callback) { - var self = this; + var self = this; - var UploadId = params.UploadId; + var UploadId = params.UploadId; - var Parts = params['Parts']; + var Parts = params['Parts']; - for (var i = 0, len = Parts.length; i < len; i++) { - if (Parts[i]['ETag'].indexOf('"') === 0) { - continue; - } - Parts[i]['ETag'] = '"' + Parts[i]['ETag'] + '"'; + for (var i = 0, len = Parts.length; i < len; i++) { + if (Parts[i]['ETag'].indexOf('"') === 0) { + continue; } + Parts[i]['ETag'] = '"' + Parts[i]['ETag'] + '"'; + } - var xml = util.json2xml({CompleteMultipartUpload: {Part: Parts}}); - // CSP/ceph CompleteMultipartUpload 接口 body 写死了限制 1MB,这里醉倒 10000 片时,xml 字符串去掉空格853KB - xml = xml.replace(/\n\s*/g, ''); + var xml = util.json2xml({ CompleteMultipartUpload: { Part: Parts } }); + // CSP/ceph CompleteMultipartUpload 接口 body 写死了限制 1MB,这里醉倒 10000 片时,xml 字符串去掉空格853KB + xml = xml.replace(/\n\s*/g, ''); - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - submitRequest.call(this, { - Action: 'name/cos:CompleteMultipartUpload', - method: 'POST', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - qs: { - uploadId: UploadId - }, - body: xml, - headers: headers, - }, function (err, data) { - if (err) return callback(err); - var url = getUrl({ - ForcePathStyle: self.options.ForcePathStyle, - protocol: self.options.Protocol, - domain: self.options.Domain, - bucket: params.Bucket, - region: params.Region, - object: params.Key, - isLocation: true, - }); - var res = data.CompleteMultipartUploadResult || {}; - if (res.ProcessResults) { - if (res && res.ProcessResults) { - res.UploadResult = { - OriginalInfo: { - Key: res.Key, - Location: url, - ETag: res.ETag, - ImageInfo: res.ImageInfo, - }, - ProcessResults: res.ProcessResults, - }; - delete res.ImageInfo; - delete res.ProcessResults; - } + submitRequest.call( + this, + { + Action: 'name/cos:CompleteMultipartUpload', + method: 'POST', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + qs: { + uploadId: UploadId, + }, + body: xml, + headers: headers, + }, + function (err, data) { + if (err) return callback(err); + var url = getUrl({ + ForcePathStyle: self.options.ForcePathStyle, + protocol: self.options.Protocol, + domain: self.options.Domain, + bucket: params.Bucket, + region: params.Region, + object: params.Key, + isLocation: true, + }); + var res = data.CompleteMultipartUploadResult || {}; + if (res.ProcessResults) { + if (res && res.ProcessResults) { + res.UploadResult = { + OriginalInfo: { + Key: res.Key, + Location: url, + ETag: res.ETag, + ImageInfo: res.ImageInfo, + }, + ProcessResults: res.ProcessResults, + }; + delete res.ImageInfo; + delete res.ProcessResults; } - var result = util.extend(res, { - Location: url, - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); + } + var result = util.extend(res, { + Location: url, + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }, + ); } /** @@ -2874,43 +3138,47 @@ function multipartComplete(params, callback) { * @return {Object} data.ListMultipartUploadsResult 分块上传任务信息 */ function multipartList(params, callback) { - var reqParams = {}; + var reqParams = {}; - reqParams['delimiter'] = params['Delimiter']; - reqParams['encoding-type'] = params['EncodingType']; - reqParams['prefix'] = params['Prefix'] || ''; + reqParams['delimiter'] = params['Delimiter']; + reqParams['encoding-type'] = params['EncodingType']; + reqParams['prefix'] = params['Prefix'] || ''; - reqParams['max-uploads'] = params['MaxUploads']; + reqParams['max-uploads'] = params['MaxUploads']; - reqParams['key-marker'] = params['KeyMarker']; - reqParams['upload-id-marker'] = params['UploadIdMarker']; + reqParams['key-marker'] = params['KeyMarker']; + reqParams['upload-id-marker'] = params['UploadIdMarker']; - reqParams = util.clearKey(reqParams); + reqParams = util.clearKey(reqParams); - submitRequest.call(this, { - Action: 'name/cos:ListMultipartUploads', - ResourceKey: reqParams['prefix'], - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - qs: reqParams, - action: 'uploads', - }, function (err, data) { - if (err) return callback(err); + submitRequest.call( + this, + { + Action: 'name/cos:ListMultipartUploads', + ResourceKey: reqParams['prefix'], + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + qs: reqParams, + action: 'uploads', + }, + function (err, data) { + if (err) return callback(err); - if (data && data.ListMultipartUploadsResult) { - var Upload = data.ListMultipartUploadsResult.Upload || []; - Upload = util.isArray(Upload) ? Upload : [Upload]; - data.ListMultipartUploadsResult.Upload = Upload; - } - var result = util.clone(data.ListMultipartUploadsResult || {}); - util.extend(result, { - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); + if (data && data.ListMultipartUploadsResult) { + var Upload = data.ListMultipartUploadsResult.Upload || []; + Upload = util.isArray(Upload) ? Upload : [Upload]; + data.ListMultipartUploadsResult.Upload = Upload; + } + var result = util.clone(data.ListMultipartUploadsResult || {}); + util.extend(result, { + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }, + ); } /** @@ -2929,35 +3197,39 @@ function multipartList(params, callback) { * @return {Object} data.ListMultipartUploadsResult 分块信息 */ function multipartListPart(params, callback) { - var reqParams = {}; - - reqParams['uploadId'] = params['UploadId']; - reqParams['encoding-type'] = params['EncodingType']; - reqParams['max-parts'] = params['MaxParts']; - reqParams['part-number-marker'] = params['PartNumberMarker']; - - submitRequest.call(this, { - Action: 'name/cos:ListParts', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - qs: reqParams, - }, function (err, data) { - if (err) return callback(err); - var ListPartsResult = data.ListPartsResult || {}; - var Part = ListPartsResult.Part || []; - Part = util.isArray(Part) ? Part : [Part]; - - ListPartsResult.Part = Part; - var result = util.clone(ListPartsResult); - util.extend(result, { - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); + var reqParams = {}; + + reqParams['uploadId'] = params['UploadId']; + reqParams['encoding-type'] = params['EncodingType']; + reqParams['max-parts'] = params['MaxParts']; + reqParams['part-number-marker'] = params['PartNumberMarker']; + + submitRequest.call( + this, + { + Action: 'name/cos:ListParts', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + qs: reqParams, + }, + function (err, data) { + if (err) return callback(err); + var ListPartsResult = data.ListPartsResult || {}; + var Part = ListPartsResult.Part || []; + Part = util.isArray(Part) ? Part : [Part]; + + ListPartsResult.Part = Part; + var result = util.clone(ListPartsResult); + util.extend(result, { + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }, + ); } /** @@ -2972,24 +3244,28 @@ function multipartListPart(params, callback) { * @return {Object} data 返回的数据 */ function multipartAbort(params, callback) { - var reqParams = {}; - - reqParams['uploadId'] = params['UploadId']; - submitRequest.call(this, { - Action: 'name/cos:AbortMultipartUpload', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - qs: reqParams, - }, function (err, data) { - if (err) return callback(err); - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); + var reqParams = {}; + + reqParams['uploadId'] = params['UploadId']; + submitRequest.call( + this, + { + Action: 'name/cos:AbortMultipartUpload', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + qs: reqParams, + }, + function (err, data) { + if (err) return callback(err); + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }, + ); } /** @@ -3020,12 +3296,14 @@ function multipartAbort(params, callback) { * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 * @return {Object} data 返回的数据 */ - function appendObject(params, callback) { +function appendObject(params, callback) { // 特殊处理 Cache-Control、Content-Type,避免代理更改这两个字段导致写入到 Object 属性里 var headers = params.Headers; if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = ''; - submitRequest.call(this, { + submitRequest.call( + this, + { Action: 'name/cos:AppendObject', method: 'POST', Bucket: params.Bucket, @@ -3034,13 +3312,15 @@ function multipartAbort(params, callback) { Key: params.Key, body: params.Body, qs: { - position: params.Position + position: params.Position, }, headers: params.Headers, - }, function (err, data) { + }, + function (err, data) { if (err) return callback(err); callback(null, data); - }); + }, + ); } /** @@ -3057,11 +3337,13 @@ function request(params, callback) { var Query = params.Query || {}; // 处理 url if (params.Url) { - var m = params.Url.match(/^https?:\/\/([^/]+)(\/[^?#]*)?(\?[^#]*)?(#.*)?$/) - var urlPath = m && m[2] || ''; + var m = params.Url.match(/^https?:\/\/([^/]+)(\/[^?#]*)?(\?[^#]*)?(#.*)?$/); + var urlPath = (m && m[2]) || ''; if (urlPath && !params.Key) params.Key = urlPath.substr(1); } - submitRequest.call(this, { + submitRequest.call( + this, + { method: params.Method, Bucket: params.Bucket, Region: params.Region, @@ -3072,14 +3354,16 @@ function request(params, callback) { body: params.Body, url: params.Url, rawBody: params.RawBody, - }, function (err, data) { + }, + function (err, data) { if (err) return callback(err); if (data && data.body) { - data.Body = data.body; - delete data.body; + data.Body = data.body; + delete data.body; } callback(err, data); - }); + }, + ); } /** @@ -3091,30 +3375,30 @@ function request(params, callback) { * @return {String} data 返回签名字符串 */ function getAuth(params) { - var self = this; - return util.getAuth({ - SecretId: params.SecretId || this.options.SecretId || '', - SecretKey: params.SecretKey || this.options.SecretKey || '', - Bucket: params.Bucket, - Region: params.Region, - Method: params.Method, - Key: params.Key, - Query: params.Query, - Headers: params.Headers, - Expires: params.Expires, - UseRawKey: self.options.UseRawKey, - SystemClockOffset: self.options.SystemClockOffset, - }); + var self = this; + return util.getAuth({ + SecretId: params.SecretId || this.options.SecretId || '', + SecretKey: params.SecretKey || this.options.SecretKey || '', + Bucket: params.Bucket, + Region: params.Region, + Method: params.Method, + Key: params.Key, + Query: params.Query, + Headers: params.Headers, + Expires: params.Expires, + UseRawKey: self.options.UseRawKey, + SystemClockOffset: self.options.SystemClockOffset, + }); } function getV4Auth(params) { - return util.getV4Auth({ - SecretId: params.SecretId || this.options.SecretId || '', - SecretKey: params.SecretKey || this.options.SecretKey || '', - Bucket: params.Bucket, - Key: params.Key, - Expires: params.Expires, - }); + return util.getV4Auth({ + SecretId: params.SecretId || this.options.SecretId || '', + SecretKey: params.SecretKey || this.options.SecretKey || '', + Bucket: params.Bucket, + Key: params.Key, + Expires: params.Expires, + }); } /** @@ -3130,924 +3414,991 @@ function getV4Auth(params) { * @return {Object} data 返回的数据 */ function getObjectUrl(params, callback) { - var self = this; - var useAccelerate = params.UseAccelerate === undefined ? self.options.UseAccelerate : params.UseAccelerate; - var url = getUrl({ - ForcePathStyle: self.options.ForcePathStyle, - protocol: params.Protocol || self.options.Protocol, - domain: params.Domain || self.options.Domain, - bucket: params.Bucket, - region: useAccelerate ? 'accelerate' : params.Region, - object: params.Key, - }); - - var queryParamsStr = ''; - if(params.Query){ - queryParamsStr += util.obj2str(params.Query); - } - if(params.QueryString){ - queryParamsStr += (queryParamsStr ? '&' : '') + params.QueryString; - } - - var syncUrl = url; - if (params.Sign !== undefined && !params.Sign) { - queryParamsStr && (syncUrl += '?' + queryParamsStr); - callback(null, {Url: syncUrl}); - return syncUrl; - } + var self = this; + var useAccelerate = params.UseAccelerate === undefined ? self.options.UseAccelerate : params.UseAccelerate; + var url = getUrl({ + ForcePathStyle: self.options.ForcePathStyle, + protocol: params.Protocol || self.options.Protocol, + domain: params.Domain || self.options.Domain, + bucket: params.Bucket, + region: useAccelerate ? 'accelerate' : params.Region, + object: params.Key, + }); - // 签名加上 Host,避免跨桶访问 - var SignHost = getSignHost.call(this, {Bucket: params.Bucket, Region: params.Region, UseAccelerate: params.UseAccelerate, Url: url}); - var AuthData = getAuthorizationAsync.call(this, { - Action: ((params.Method || '').toUpperCase() === 'PUT' ? 'name/cos:PutObject' : 'name/cos:GetObject'), - Bucket: params.Bucket || '', - Region: params.Region || '', - Method: params.Method || 'get', - Key: params.Key, - Expires: params.Expires, - Headers: params.Headers, - Query: params.Query, - SignHost: SignHost, - ForceSignHost: params.ForceSignHost === false ? false : self.options.ForceSignHost, // getObjectUrl支持传参ForceSignHost - }, function (err, AuthData) { - if (!callback) return; - if (err) { - callback(err); - return; - } + var queryParamsStr = ''; + if (params.Query) { + queryParamsStr += util.obj2str(params.Query); + } + if (params.QueryString) { + queryParamsStr += (queryParamsStr ? '&' : '') + params.QueryString; + } - // 兼容万象url qUrlParamList需要再encode一次 - var replaceUrlParamList = function(url) { - var urlParams = url.match(/q-url-param-list.*?(?=&)/g)[0]; - var encodedParams = 'q-url-param-list=' + encodeURIComponent(urlParams.replace(/q-url-param-list=/, '')).toLowerCase(); - var reg = new RegExp(urlParams, 'g'); - var replacedUrl = url.replace(reg, encodedParams); - return replacedUrl; - } + var syncUrl = url; + if (params.Sign !== undefined && !params.Sign) { + queryParamsStr && (syncUrl += '?' + queryParamsStr); + callback(null, { Url: syncUrl }); + return syncUrl; + } - var signUrl = url; - signUrl += '?' + (AuthData.Authorization.indexOf('q-signature') > -1 ? - replaceUrlParamList(AuthData.Authorization) : 'sign=' + encodeURIComponent(AuthData.Authorization)); - AuthData.SecurityToken && (signUrl += '&x-cos-security-token=' + AuthData.SecurityToken); - AuthData.ClientIP && (signUrl += '&clientIP=' + AuthData.ClientIP); - AuthData.ClientUA && (signUrl += '&clientUA=' + AuthData.ClientUA); - AuthData.Token && (signUrl += '&token=' + AuthData.Token); - queryParamsStr && (signUrl += '&' + queryParamsStr); - setTimeout(function () { - callback(null, {Url: signUrl}); - }); - }); + // 签名加上 Host,避免跨桶访问 + var SignHost = getSignHost.call(this, { + Bucket: params.Bucket, + Region: params.Region, + UseAccelerate: params.UseAccelerate, + Url: url, + }); + var AuthData = getAuthorizationAsync.call( + this, + { + Action: (params.Method || '').toUpperCase() === 'PUT' ? 'name/cos:PutObject' : 'name/cos:GetObject', + Bucket: params.Bucket || '', + Region: params.Region || '', + Method: params.Method || 'get', + Key: params.Key, + Expires: params.Expires, + Headers: params.Headers, + Query: params.Query, + SignHost: SignHost, + ForceSignHost: params.ForceSignHost === false ? false : self.options.ForceSignHost, // getObjectUrl支持传参ForceSignHost + }, + function (err, AuthData) { + if (!callback) return; + if (err) { + callback(err); + return; + } - if (AuthData) { - syncUrl += '?' + AuthData.Authorization + - (AuthData.SecurityToken ? '&x-cos-security-token=' + AuthData.SecurityToken : ''); - queryParamsStr && (syncUrl += '&' + queryParamsStr); - } else{ - queryParamsStr && (syncUrl += '?' + queryParamsStr); - } - return syncUrl; + // 兼容万象url qUrlParamList需要再encode一次 + var replaceUrlParamList = function (url) { + var urlParams = url.match(/q-url-param-list.*?(?=&)/g)[0]; + var encodedParams = + 'q-url-param-list=' + encodeURIComponent(urlParams.replace(/q-url-param-list=/, '')).toLowerCase(); + var reg = new RegExp(urlParams, 'g'); + var replacedUrl = url.replace(reg, encodedParams); + return replacedUrl; + }; + + var signUrl = url; + signUrl += + '?' + + (AuthData.Authorization.indexOf('q-signature') > -1 + ? replaceUrlParamList(AuthData.Authorization) + : 'sign=' + encodeURIComponent(AuthData.Authorization)); + AuthData.SecurityToken && (signUrl += '&x-cos-security-token=' + AuthData.SecurityToken); + AuthData.ClientIP && (signUrl += '&clientIP=' + AuthData.ClientIP); + AuthData.ClientUA && (signUrl += '&clientUA=' + AuthData.ClientUA); + AuthData.Token && (signUrl += '&token=' + AuthData.Token); + queryParamsStr && (signUrl += '&' + queryParamsStr); + setTimeout(function () { + callback(null, { Url: signUrl }); + }); + }, + ); + + if (AuthData) { + syncUrl += + '?' + AuthData.Authorization + (AuthData.SecurityToken ? '&x-cos-security-token=' + AuthData.SecurityToken : ''); + queryParamsStr && (syncUrl += '&' + queryParamsStr); + } else { + queryParamsStr && (syncUrl += '?' + queryParamsStr); + } + return syncUrl; } - /** * 私有方法 */ function decodeAcl(AccessControlPolicy) { - var result = { - GrantFullControl: [], - GrantWrite: [], - GrantRead: [], - GrantReadAcp: [], - GrantWriteAcp: [], - ACL: '', - }; - var GrantMap = { - 'FULL_CONTROL': 'GrantFullControl', - 'WRITE': 'GrantWrite', - 'READ': 'GrantRead', - 'READ_ACP': 'GrantReadAcp', - 'WRITE_ACP': 'GrantWriteAcp', - }; - var AccessControlList = AccessControlPolicy && AccessControlPolicy.AccessControlList || {}; - var Grant = AccessControlList.Grant; - if (Grant) { - Grant = util.isArray(Grant) ? Grant : [Grant]; - } - var PublicAcl = {READ: 0, WRITE: 0, FULL_CONTROL: 0}; - Grant && Grant.length && util.each(Grant, function (item) { - if (item.Grantee.ID === 'qcs::cam::anyone:anyone' || item.Grantee.URI === 'http://cam.qcloud.com/groups/global/AllUsers') { - PublicAcl[item.Permission] = 1; - } else if (item.Grantee.ID !== AccessControlPolicy.Owner.ID) { - result[GrantMap[item.Permission]].push('id="' + item.Grantee.ID + '"'); - } - }); - if (PublicAcl.FULL_CONTROL || (PublicAcl.WRITE && PublicAcl.READ)) { - result.ACL = 'public-read-write'; - } else if (PublicAcl.READ) { - result.ACL = 'public-read'; - } else { - result.ACL = 'private'; - } - util.each(GrantMap, function (item) { - result[item] = uniqGrant(result[item].join(',')); + var result = { + GrantFullControl: [], + GrantWrite: [], + GrantRead: [], + GrantReadAcp: [], + GrantWriteAcp: [], + ACL: '', + }; + var GrantMap = { + FULL_CONTROL: 'GrantFullControl', + WRITE: 'GrantWrite', + READ: 'GrantRead', + READ_ACP: 'GrantReadAcp', + WRITE_ACP: 'GrantWriteAcp', + }; + var AccessControlList = (AccessControlPolicy && AccessControlPolicy.AccessControlList) || {}; + var Grant = AccessControlList.Grant; + if (Grant) { + Grant = util.isArray(Grant) ? Grant : [Grant]; + } + var PublicAcl = { READ: 0, WRITE: 0, FULL_CONTROL: 0 }; + Grant && + Grant.length && + util.each(Grant, function (item) { + if ( + item.Grantee.ID === 'qcs::cam::anyone:anyone' || + item.Grantee.URI === 'http://cam.qcloud.com/groups/global/AllUsers' + ) { + PublicAcl[item.Permission] = 1; + } else if (item.Grantee.ID !== AccessControlPolicy.Owner.ID) { + result[GrantMap[item.Permission]].push('id="' + item.Grantee.ID + '"'); + } }); - return result; + if (PublicAcl.FULL_CONTROL || (PublicAcl.WRITE && PublicAcl.READ)) { + result.ACL = 'public-read-write'; + } else if (PublicAcl.READ) { + result.ACL = 'public-read'; + } else { + result.ACL = 'private'; + } + util.each(GrantMap, function (item) { + result[item] = uniqGrant(result[item].join(',')); + }); + return result; } // Grant 去重 function uniqGrant(str) { - var arr = str.split(','); - var exist = {}; - var i, item; - for (i = 0; i < arr.length; ) { - item = arr[i].trim(); - if (exist[item]) { - arr.splice(i, 1); - } else { - exist[item] = true; - arr[i] = item; - i++; - } + var arr = str.split(','); + var exist = {}; + var i, item; + for (i = 0; i < arr.length; ) { + item = arr[i].trim(); + if (exist[item]) { + arr.splice(i, 1); + } else { + exist[item] = true; + arr[i] = item; + i++; } - return arr.join(','); + } + return arr.join(','); } // 生成操作 url function getUrl(params) { - var longBucket = params.bucket; - var shortBucket = longBucket.substr(0, longBucket.lastIndexOf('-')); - var appId = longBucket.substr(longBucket.lastIndexOf('-') + 1); - var domain = params.domain; - var region = params.region; - var object = params.object; - // 兼容不带冒号的http、https - if (['http', 'https'].includes(params.protocol)) { - params.protocol = params.protocol + ':'; - } - var protocol = params.protocol || (util.isBrowser && location.protocol === 'http:' ? 'http:' : 'https:'); - if (!domain) { - if (['cn-south', 'cn-south-2', 'cn-north', 'cn-east', 'cn-southwest', 'sg'].indexOf(region) > -1) { - domain = '{Region}.myqcloud.com'; - } else { - domain = 'cos.{Region}.myqcloud.com'; - } - if (!params.ForcePathStyle) { - domain = '{Bucket}.' + domain; - } + var longBucket = params.bucket; + var shortBucket = longBucket.substr(0, longBucket.lastIndexOf('-')); + var appId = longBucket.substr(longBucket.lastIndexOf('-') + 1); + var domain = params.domain; + var region = params.region; + var object = params.object; + // 兼容不带冒号的http、https + if (['http', 'https'].includes(params.protocol)) { + params.protocol = params.protocol + ':'; + } + var protocol = params.protocol || (util.isBrowser && location.protocol === 'http:' ? 'http:' : 'https:'); + if (!domain) { + if (['cn-south', 'cn-south-2', 'cn-north', 'cn-east', 'cn-southwest', 'sg'].indexOf(region) > -1) { + domain = '{Region}.myqcloud.com'; + } else { + domain = 'cos.{Region}.myqcloud.com'; } - domain = domain.replace(/\{\{AppId\}\}/ig, appId) - .replace(/\{\{Bucket\}\}/ig, shortBucket) - .replace(/\{\{Region\}\}/ig, region) - .replace(/\{\{.*?\}\}/ig, ''); - domain = domain.replace(/\{AppId\}/ig, appId) - .replace(/\{BucketName\}/ig, shortBucket) - .replace(/\{Bucket\}/ig, longBucket) - .replace(/\{Region\}/ig, region) - .replace(/\{.*?\}/ig, ''); - if (!/^[a-zA-Z]+:\/\//.test(domain)) { - domain = protocol + '//' + domain; + if (!params.ForcePathStyle) { + domain = '{Bucket}.' + domain; } + } + domain = domain + .replace(/\{\{AppId\}\}/gi, appId) + .replace(/\{\{Bucket\}\}/gi, shortBucket) + .replace(/\{\{Region\}\}/gi, region) + .replace(/\{\{.*?\}\}/gi, ''); + domain = domain + .replace(/\{AppId\}/gi, appId) + .replace(/\{BucketName\}/gi, shortBucket) + .replace(/\{Bucket\}/gi, longBucket) + .replace(/\{Region\}/gi, region) + .replace(/\{.*?\}/gi, ''); + if (!/^[a-zA-Z]+:\/\//.test(domain)) { + domain = protocol + '//' + domain; + } - // 去掉域名最后的斜杆 - if (domain.slice(-1) === '/') { - domain = domain.slice(0, -1); - } - var url = domain; + // 去掉域名最后的斜杆 + if (domain.slice(-1) === '/') { + domain = domain.slice(0, -1); + } + var url = domain; - if (params.ForcePathStyle) { - url += '/' + longBucket; - } - url += '/'; - if (object) { - url += util.camSafeUrlEncode(object).replace(/%2F/g, '/'); - } + if (params.ForcePathStyle) { + url += '/' + longBucket; + } + url += '/'; + if (object) { + url += util.camSafeUrlEncode(object).replace(/%2F/g, '/'); + } - if (params.isLocation) { - url = url.replace(/^https?:\/\//, ''); - } - return url; + if (params.isLocation) { + url = url.replace(/^https?:\/\//, ''); + } + return url; } var getSignHost = function (opt) { - if (!opt.Bucket || !opt.Region) return ''; - var useAccelerate = opt.UseAccelerate === undefined ? this.options.UseAccelerate : opt.UseAccelerate; - var url = opt.Url || getUrl({ - ForcePathStyle: this.options.ForcePathStyle, - protocol: this.options.Protocol, - domain: this.options.Domain, - bucket: opt.Bucket, - region: useAccelerate ? 'accelerate' : opt.Region, + if (!opt.Bucket || !opt.Region) return ''; + var useAccelerate = opt.UseAccelerate === undefined ? this.options.UseAccelerate : opt.UseAccelerate; + var url = + opt.Url || + getUrl({ + ForcePathStyle: this.options.ForcePathStyle, + protocol: this.options.Protocol, + domain: this.options.Domain, + bucket: opt.Bucket, + region: useAccelerate ? 'accelerate' : opt.Region, }); - var urlHost = url.replace(/^https?:\/\/([^/]+)(\/.*)?$/, '$1'); - var standardHostReg = new RegExp('^([a-z\\d-]+-\\d+\\.)?(cos|cosv6|ci|pic)\\.([a-z\\d-]+)\\.myqcloud\\.com$'); - if (standardHostReg.test(urlHost)) return urlHost; - return ''; -} + var urlHost = url.replace(/^https?:\/\/([^/]+)(\/.*)?$/, '$1'); + var standardHostReg = new RegExp('^([a-z\\d-]+-\\d+\\.)?(cos|cosv6|ci|pic)\\.([a-z\\d-]+)\\.myqcloud\\.com$'); + if (standardHostReg.test(urlHost)) return urlHost; + return ''; +}; // 异步获取签名 function getAuthorizationAsync(params, callback) { + var headers = util.clone(params.Headers); + var headerHost = ''; + util.each(headers, function (v, k) { + (v === '' || ['content-type', 'cache-control'].indexOf(k.toLowerCase()) > -1) && delete headers[k]; + if (k.toLowerCase() === 'host') headerHost = v; + }); - var headers = util.clone(params.Headers); - var headerHost = ''; - util.each(headers, function (v, k) { - (v === '' || ['content-type', 'cache-control'].indexOf(k.toLowerCase()) > -1) && delete headers[k]; - if (k.toLowerCase() === 'host') headerHost = v; - }); - - // ForceSignHost明确传入false才不加入host签名 - var forceSignHost = params.ForceSignHost === false ? false : true; - - // Host 加入签名计算 - if (!headerHost && params.SignHost && forceSignHost) headers.Host = params.SignHost; - - - // 获取凭证的回调,避免用户 callback 多次 - var cbDone = false; - var cb = function (err, AuthData) { - if (cbDone) return; - cbDone = true; - if (AuthData && AuthData.XCosSecurityToken && !AuthData.SecurityToken) { - AuthData = util.clone(AuthData); - AuthData.SecurityToken = AuthData.XCosSecurityToken; - delete AuthData.XCosSecurityToken; - } - callback && callback(err, AuthData); - }; + // ForceSignHost明确传入false才不加入host签名 + var forceSignHost = params.ForceSignHost === false ? false : true; + + // Host 加入签名计算 + if (!headerHost && params.SignHost && forceSignHost) headers.Host = params.SignHost; + + // 获取凭证的回调,避免用户 callback 多次 + var cbDone = false; + var cb = function (err, AuthData) { + if (cbDone) return; + cbDone = true; + if (AuthData && AuthData.XCosSecurityToken && !AuthData.SecurityToken) { + AuthData = util.clone(AuthData); + AuthData.SecurityToken = AuthData.XCosSecurityToken; + delete AuthData.XCosSecurityToken; + } + callback && callback(err, AuthData); + }; - var self = this; - var Bucket = params.Bucket || ''; - var Region = params.Region || ''; + var self = this; + var Bucket = params.Bucket || ''; + var Region = params.Region || ''; - // PathName - var KeyName = params.Key || ''; - if (self.options.ForcePathStyle && Bucket) { - KeyName = Bucket + '/' + KeyName; - } - var Pathname = '/' + KeyName; - - // Action、ResourceKey - var StsData = {}; - var Scope = params.Scope; - if (!Scope) { - var Action = params.Action || ''; - var ResourceKey = params.ResourceKey || params.Key || ''; - Scope = params.Scope || [{ - action: Action, - bucket: Bucket, - region: Region, - prefix: ResourceKey, - }]; + // PathName + var KeyName = params.Key || ''; + if (self.options.ForcePathStyle && Bucket) { + KeyName = Bucket + '/' + KeyName; + } + var Pathname = '/' + KeyName; + + // Action、ResourceKey + var StsData = {}; + var Scope = params.Scope; + if (!Scope) { + var Action = params.Action || ''; + var ResourceKey = params.ResourceKey || params.Key || ''; + Scope = params.Scope || [ + { + action: Action, + bucket: Bucket, + region: Region, + prefix: ResourceKey, + }, + ]; + } + var ScopeKey = util.md5(JSON.stringify(Scope)); + + // STS + self._StsCache = self._StsCache || []; + (function () { + var i, AuthData; + for (i = self._StsCache.length - 1; i >= 0; i--) { + AuthData = self._StsCache[i]; + var compareTime = Math.round(util.getSkewTime(self.options.SystemClockOffset) / 1000) + 30; + if ((AuthData.StartTime && compareTime < AuthData.StartTime) || compareTime >= AuthData.ExpiredTime) { + self._StsCache.splice(i, 1); + continue; + } + if (!AuthData.ScopeLimit || (AuthData.ScopeLimit && AuthData.ScopeKey === ScopeKey)) { + StsData = AuthData; + break; + } } - var ScopeKey = util.md5(JSON.stringify(Scope)); - - // STS - self._StsCache = self._StsCache ||[]; - (function () { - var i, AuthData; - for (i = self._StsCache.length - 1; i >= 0; i--) { - AuthData = self._StsCache[i]; - var compareTime = Math.round(util.getSkewTime(self.options.SystemClockOffset) / 1000) + 30; - if (AuthData.StartTime && compareTime < AuthData.StartTime || compareTime >= AuthData.ExpiredTime) { - self._StsCache.splice(i, 1); - continue; - } - if (!AuthData.ScopeLimit || AuthData.ScopeLimit && AuthData.ScopeKey === ScopeKey) { - StsData = AuthData; - break; + })(); + + var calcAuthByTmpKey = function () { + var KeyTime = ''; + if (StsData.StartTime && params.Expires) + KeyTime = StsData.StartTime + ';' + (StsData.StartTime + params.Expires * 1); + else if (StsData.StartTime && StsData.ExpiredTime) KeyTime = StsData.StartTime + ';' + StsData.ExpiredTime; + var Authorization = util.getAuth({ + SecretId: StsData.TmpSecretId, + SecretKey: StsData.TmpSecretKey, + Method: params.Method, + Pathname: Pathname, + Query: params.Query, + Headers: headers, + Expires: params.Expires, + UseRawKey: self.options.UseRawKey, + SystemClockOffset: self.options.SystemClockOffset, + KeyTime: KeyTime, + ForceSignHost: forceSignHost, + }); + var AuthData = { + Authorization: Authorization, + SecurityToken: StsData.SecurityToken || StsData.XCosSecurityToken || '', + Token: StsData.Token || '', + ClientIP: StsData.ClientIP || '', + ClientUA: StsData.ClientUA || '', + }; + cb(null, AuthData); + }; + var checkAuthError = function (AuthData) { + if (AuthData.Authorization) { + // 检查签名格式 + var formatAllow = false; + var auth = AuthData.Authorization; + if (auth) { + if (auth.indexOf(' ') > -1) { + formatAllow = false; + } else if ( + auth.indexOf('q-sign-algorithm=') > -1 && + auth.indexOf('q-ak=') > -1 && + auth.indexOf('q-sign-time=') > -1 && + auth.indexOf('q-key-time=') > -1 && + auth.indexOf('q-url-param-list=') > -1 + ) { + formatAllow = true; + } else { + try { + auth = Buffer.from(auth, 'base64').toString(); + if ( + auth.indexOf('a=') > -1 && + auth.indexOf('k=') > -1 && + auth.indexOf('t=') > -1 && + auth.indexOf('r=') > -1 && + auth.indexOf('b=') > -1 + ) { + formatAllow = true; } + } catch (e) {} } - })(); - - var calcAuthByTmpKey = function () { - var KeyTime = ''; - if (StsData.StartTime && params.Expires) KeyTime = StsData.StartTime + ';' + (StsData.StartTime + params.Expires * 1); - else if (StsData.StartTime && StsData.ExpiredTime) KeyTime = StsData.StartTime + ';' + StsData.ExpiredTime; - var Authorization = util.getAuth({ - SecretId: StsData.TmpSecretId, - SecretKey: StsData.TmpSecretKey, - Method: params.Method, - Pathname: Pathname, - Query: params.Query, - Headers: headers, - Expires: params.Expires, - UseRawKey: self.options.UseRawKey, - SystemClockOffset: self.options.SystemClockOffset, - KeyTime: KeyTime, - ForceSignHost: forceSignHost, - }); - var AuthData = { - Authorization: Authorization, - SecurityToken: StsData.SecurityToken || StsData.XCosSecurityToken || '', - Token: StsData.Token || '', - ClientIP: StsData.ClientIP || '', - ClientUA: StsData.ClientUA || '', - }; - cb(null, AuthData); - }; - var checkAuthError = function (AuthData) { + } + if (!formatAllow) return util.error(new Error('getAuthorization callback params format error')); + } else { + if (!AuthData.TmpSecretId) return util.error(new Error('getAuthorization callback params missing "TmpSecretId"')); + if (!AuthData.TmpSecretKey) + return util.error(new Error('getAuthorization callback params missing "TmpSecretKey"')); + if (!AuthData.SecurityToken && !AuthData.XCosSecurityToken) + return util.error(new Error('getAuthorization callback params missing "SecurityToken"')); + if (!AuthData.ExpiredTime) return util.error(new Error('getAuthorization callback params missing "ExpiredTime"')); + if (AuthData.ExpiredTime && AuthData.ExpiredTime.toString().length !== 10) + return util.error(new Error('getAuthorization callback params "ExpiredTime" should be 10 digits')); + if (AuthData.StartTime && AuthData.StartTime.toString().length !== 10) + return util.error(new Error('getAuthorization callback params "StartTime" should be 10 StartTime')); + } + return false; + }; + + // 先判断是否有临时密钥 + if (StsData.ExpiredTime && StsData.ExpiredTime - util.getSkewTime(self.options.SystemClockOffset) / 1000 > 60) { + // 如果缓存的临时密钥有效,并还有超过60秒有效期就直接使用 + calcAuthByTmpKey(); + } else if (self.options.getAuthorization) { + // 外部计算签名或获取临时密钥 + self.options.getAuthorization.call( + self, + { + Bucket: Bucket, + Region: Region, + Method: params.Method, + Key: KeyName, + Pathname: Pathname, + Query: params.Query, + Headers: headers, + Scope: Scope, + SystemClockOffset: self.options.SystemClockOffset, + ForceSignHost: forceSignHost, + }, + function (AuthData) { + if (typeof AuthData === 'string') AuthData = { Authorization: AuthData }; + var AuthError = checkAuthError(AuthData); + if (AuthError) return cb(AuthError); if (AuthData.Authorization) { - // 检查签名格式 - var formatAllow = false; - var auth = AuthData.Authorization; - if (auth) { - if (auth.indexOf(' ') > -1) { - formatAllow = false; - } else if (auth.indexOf('q-sign-algorithm=') > -1 && - auth.indexOf('q-ak=') > -1 && - auth.indexOf('q-sign-time=') > -1 && - auth.indexOf('q-key-time=') > -1 && - auth.indexOf('q-url-param-list=') > -1) { - formatAllow = true; - } else { - try { - auth = Buffer.from(auth, 'base64').toString(); - if (auth.indexOf('a=') > -1 && - auth.indexOf('k=') > -1 && - auth.indexOf('t=') > -1 && - auth.indexOf('r=') > -1 && - auth.indexOf('b=') > -1) { - formatAllow = true; - } - } catch (e) {} - } - } - if (!formatAllow) return util.error(new Error('getAuthorization callback params format error')); + cb(null, AuthData); } else { - if (!AuthData.TmpSecretId) return util.error(new Error('getAuthorization callback params missing "TmpSecretId"')); - if (!AuthData.TmpSecretKey) return util.error(new Error('getAuthorization callback params missing "TmpSecretKey"')); - if (!AuthData.SecurityToken && !AuthData.XCosSecurityToken) return util.error(new Error('getAuthorization callback params missing "SecurityToken"')); - if (!AuthData.ExpiredTime) return util.error(new Error('getAuthorization callback params missing "ExpiredTime"')); - if (AuthData.ExpiredTime && AuthData.ExpiredTime.toString().length !== 10) return util.error(new Error('getAuthorization callback params "ExpiredTime" should be 10 digits')); - if (AuthData.StartTime && AuthData.StartTime.toString().length !== 10) return util.error(new Error('getAuthorization callback params "StartTime" should be 10 StartTime')); + StsData = AuthData || {}; + StsData.Scope = Scope; + StsData.ScopeKey = ScopeKey; + self._StsCache.push(StsData); + calcAuthByTmpKey(); } - return false; - }; - - // 先判断是否有临时密钥 - if (StsData.ExpiredTime && StsData.ExpiredTime - (util.getSkewTime(self.options.SystemClockOffset) / 1000) > 60) { // 如果缓存的临时密钥有效,并还有超过60秒有效期就直接使用 + }, + ); + } else if (self.options.getSTS) { + // 外部获取临时密钥 + self.options.getSTS.call( + self, + { + Bucket: Bucket, + Region: Region, + }, + function (data) { + StsData = data || {}; + StsData.Scope = Scope; + StsData.ScopeKey = ScopeKey; + if (!StsData.TmpSecretId) StsData.TmpSecretId = StsData.SecretId; + if (!StsData.TmpSecretKey) StsData.TmpSecretKey = StsData.SecretKey; + var AuthError = checkAuthError(StsData); + if (AuthError) return cb(AuthError); + self._StsCache.push(StsData); calcAuthByTmpKey(); - } else if (self.options.getAuthorization) { // 外部计算签名或获取临时密钥 - self.options.getAuthorization.call(self, { - Bucket: Bucket, - Region: Region, - Method: params.Method, - Key: KeyName, - Pathname: Pathname, - Query: params.Query, - Headers: headers, - Scope: Scope, - SystemClockOffset: self.options.SystemClockOffset, - ForceSignHost: forceSignHost, - }, function (AuthData) { - if (typeof AuthData === 'string') AuthData = {Authorization: AuthData}; - var AuthError = checkAuthError(AuthData); - if (AuthError) return cb(AuthError); - if (AuthData.Authorization) { - cb(null, AuthData); - } else { - StsData = AuthData || {}; - StsData.Scope = Scope; - StsData.ScopeKey = ScopeKey; - self._StsCache.push(StsData); - calcAuthByTmpKey(); - } - }); - } else if (self.options.getSTS) { // 外部获取临时密钥 - self.options.getSTS.call(self, { - Bucket: Bucket, - Region: Region, - }, function (data) { - StsData = data || {}; - StsData.Scope = Scope; - StsData.ScopeKey = ScopeKey; - if (!StsData.TmpSecretId) StsData.TmpSecretId = StsData.SecretId; - if (!StsData.TmpSecretKey) StsData.TmpSecretKey = StsData.SecretKey; - var AuthError = checkAuthError(StsData); - if (AuthError) return cb(AuthError); - self._StsCache.push(StsData); - calcAuthByTmpKey(); - }); - } else { // 内部计算获取签名 - return (function () { - var Authorization = util.getAuth({ - SecretId: params.SecretId || self.options.SecretId, - SecretKey: params.SecretKey || self.options.SecretKey, - Method: params.Method, - Pathname: Pathname, - Query: params.Query, - Headers: headers, - Expires: params.Expires, - UseRawKey: self.options.UseRawKey, - SystemClockOffset: self.options.SystemClockOffset, - ForceSignHost: forceSignHost, - }); - var AuthData = { - Authorization: Authorization, - SecurityToken: self.options.SecurityToken || self.options.XCosSecurityToken, - }; - cb(null, AuthData); - return AuthData; - })(); - } - return ''; + }, + ); + } else { + // 内部计算获取签名 + return (function () { + var Authorization = util.getAuth({ + SecretId: params.SecretId || self.options.SecretId, + SecretKey: params.SecretKey || self.options.SecretKey, + Method: params.Method, + Pathname: Pathname, + Query: params.Query, + Headers: headers, + Expires: params.Expires, + UseRawKey: self.options.UseRawKey, + SystemClockOffset: self.options.SystemClockOffset, + ForceSignHost: forceSignHost, + }); + var AuthData = { + Authorization: Authorization, + SecurityToken: self.options.SecurityToken || self.options.XCosSecurityToken, + }; + cb(null, AuthData); + return AuthData; + })(); + } + return ''; } // 调整时间偏差 function allowRetry(err) { - var allowRetry = false; - var isTimeError = false; - var serverDate = (err.headers && (err.headers.date || err.headers.Date)) || (err.error && err.error.ServerTime); - try { - var errorCode = err.error.Code; - var errorMessage = err.error.Message; - if (errorCode === 'RequestTimeTooSkewed' || - (errorCode === 'AccessDenied' && errorMessage === 'Request has expired')) { - isTimeError = true; - } - } catch (e) { + var allowRetry = false; + var isTimeError = false; + var serverDate = (err.headers && (err.headers.date || err.headers.Date)) || (err.error && err.error.ServerTime); + try { + var errorCode = err.error.Code; + var errorMessage = err.error.Message; + if ( + errorCode === 'RequestTimeTooSkewed' || + (errorCode === 'AccessDenied' && errorMessage === 'Request has expired') + ) { + isTimeError = true; } - if (err) { - if (isTimeError && serverDate) { - var serverTime = Date.parse(serverDate); - if (this.options.CorrectClockSkew && Math.abs(util.getSkewTime(this.options.SystemClockOffset) - serverTime) >= 30000) { - console.error('error: Local time is too skewed.'); - this.options.SystemClockOffset = serverTime - Date.now(); - allowRetry = true; - } - } else if (Math.floor(err.statusCode / 100) === 5) { - allowRetry = true; - } else if (err.code === 'ECONNRESET') { - allowRetry = true; - } + } catch (e) {} + if (err) { + if (isTimeError && serverDate) { + var serverTime = Date.parse(serverDate); + if ( + this.options.CorrectClockSkew && + Math.abs(util.getSkewTime(this.options.SystemClockOffset) - serverTime) >= 30000 + ) { + console.error('error: Local time is too skewed.'); + this.options.SystemClockOffset = serverTime - Date.now(); + allowRetry = true; + } + } else if (Math.floor(err.statusCode / 100) === 5) { + allowRetry = true; + } else if (err.code === 'ECONNRESET') { + allowRetry = true; } - return allowRetry; + } + return allowRetry; } // 获取签名并发起请求 function submitRequest(params, callback) { - var self = this; - - // 处理 headers - !params.headers && (params.headers = {}); - params.headers['User-Agent'] = self.options.UserAgent || ('cos-nodejs-sdk-v5-' + pkg.version); - - // 处理 query - !params.qs && (params.qs = {}); - params.VersionId && (params.qs.versionId = params.VersionId); - params.qs = util.clearKey(params.qs); - - // 清理 undefined 和 null 字段 - params.headers && (params.headers = util.clearKey(params.headers)); - params.qs && (params.qs = util.clearKey(params.qs)); - - var Query = util.clone(params.qs); - params.action && (Query[params.action] = ''); - - var SignHost = params.SignHost || getSignHost.call(this, {Bucket: params.Bucket, Region: params.Region, Url: params.url}); - var next = function (tryTimes) { - var oldClockOffset = self.options.SystemClockOffset; - getAuthorizationAsync.call(self, { - Bucket: params.Bucket || '', - Region: params.Region || '', - Method: params.method, - Key: params.Key, - Query: Query, - Headers: params.headers, - SignHost: SignHost, - Action: params.Action, - ResourceKey: params.ResourceKey, - Scope: params.Scope, - ForceSignHost: self.options.ForceSignHost, - }, function (err, AuthData) { - if (err) return callback(err); - params.AuthData = AuthData; - _submitRequest.call(self, params, function (err, data) { - if (err && - !(params.body && params.body.pipe) && - !params.outputStream && - tryTimes < 2 && - (oldClockOffset !== self.options.SystemClockOffset || allowRetry.call(self, err))) { - if (params.headers) { - delete params.headers.Authorization; - delete params.headers['token']; - delete params.headers['clientIP']; - delete params.headers['clientUA']; - params.headers['x-cos-security-token'] && (delete params.headers['x-cos-security-token']); - params.headers['x-ci-security-token'] && (delete params.headers['x-ci-security-token']); - } - next(tryTimes + 1); - } else { - callback(err, data); - } - }); + var self = this; + + // 处理 headers + !params.headers && (params.headers = {}); + params.headers['User-Agent'] = self.options.UserAgent || 'cos-nodejs-sdk-v5-' + pkg.version; + + // 处理 query + !params.qs && (params.qs = {}); + params.VersionId && (params.qs.versionId = params.VersionId); + params.qs = util.clearKey(params.qs); + + // 清理 undefined 和 null 字段 + params.headers && (params.headers = util.clearKey(params.headers)); + params.qs && (params.qs = util.clearKey(params.qs)); + + var Query = util.clone(params.qs); + params.action && (Query[params.action] = ''); + + var SignHost = + params.SignHost || getSignHost.call(this, { Bucket: params.Bucket, Region: params.Region, Url: params.url }); + var next = function (tryTimes) { + var oldClockOffset = self.options.SystemClockOffset; + getAuthorizationAsync.call( + self, + { + Bucket: params.Bucket || '', + Region: params.Region || '', + Method: params.method, + Key: params.Key, + Query: Query, + Headers: params.headers, + SignHost: SignHost, + Action: params.Action, + ResourceKey: params.ResourceKey, + Scope: params.Scope, + ForceSignHost: self.options.ForceSignHost, + }, + function (err, AuthData) { + if (err) return callback(err); + params.AuthData = AuthData; + _submitRequest.call(self, params, function (err, data) { + if ( + err && + !(params.body && params.body.pipe) && + !params.outputStream && + tryTimes < 2 && + (oldClockOffset !== self.options.SystemClockOffset || allowRetry.call(self, err)) + ) { + if (params.headers) { + delete params.headers.Authorization; + delete params.headers['token']; + delete params.headers['clientIP']; + delete params.headers['clientUA']; + params.headers['x-cos-security-token'] && delete params.headers['x-cos-security-token']; + params.headers['x-ci-security-token'] && delete params.headers['x-ci-security-token']; + } + next(tryTimes + 1); + } else { + callback(err, data); + } }); - }; - next(1); - + }, + ); + }; + next(1); } // 发起请求 function _submitRequest(params, callback) { - var self = this; - var TaskId = params.TaskId; - if (TaskId && !self._isRunningTask(TaskId)) return; - - var bucket = params.Bucket; - var region = params.Region; - var object = params.Key; - var method = params.method || 'GET'; - var url = params.url || params.Url; - var body = params.body; - var rawBody = params.rawBody; - - // 处理 readStream and body - var readStream; - if (body && typeof body.pipe === 'function') { - readStream = body; - body = null; - } + var self = this; + var TaskId = params.TaskId; + if (TaskId && !self._isRunningTask(TaskId)) return; + + var bucket = params.Bucket; + var region = params.Region; + var object = params.Key; + var method = params.method || 'GET'; + var url = params.url || params.Url; + var body = params.body; + var rawBody = params.rawBody; + + // 处理 readStream and body + var readStream; + if (body && typeof body.pipe === 'function') { + readStream = body; + body = null; + } - // url + // url - if (this.options.UseAccelerate) { - region = 'accelerate'; - } - url = url || getUrl({ - ForcePathStyle: self.options.ForcePathStyle, - protocol: self.options.Protocol, - domain: self.options.Domain, - bucket: bucket, - region: region, - object: object, + if (this.options.UseAccelerate) { + region = 'accelerate'; + } + url = + url || + getUrl({ + ForcePathStyle: self.options.ForcePathStyle, + protocol: self.options.Protocol, + domain: self.options.Domain, + bucket: bucket, + region: region, + object: object, }); - if (params.action) { - url = url + '?' + params.action; - } - if (params.qsStr) { - if(url.indexOf('?') > -1){ - url = url + '&' + params.qsStr; - }else{ - url = url + '?' + params.qsStr; - } + if (params.action) { + url = url + '?' + params.action; + } + if (params.qsStr) { + if (url.indexOf('?') > -1) { + url = url + '&' + params.qsStr; + } else { + url = url + '?' + params.qsStr; } + } - var opt = { - method: method, - url: url, - headers: params.headers, - qs: params.qs, - body: body, - }; + var opt = { + method: method, + url: url, + headers: params.headers, + qs: params.qs, + body: body, + }; + + // 兼容ci接口 + var token = 'x-cos-security-token'; + if (util.isCIHost(url)) { + token = 'x-ci-security-token'; + } - // 兼容ci接口 - var token = 'x-cos-security-token'; - if (util.isCIHost(url)) { - token = 'x-ci-security-token'; - } + // 获取签名 + opt.headers.Authorization = params.AuthData.Authorization; + params.AuthData.Token && (opt.headers['token'] = params.AuthData.Token); + params.AuthData.ClientIP && (opt.headers['clientIP'] = params.AuthData.ClientIP); + params.AuthData.ClientUA && (opt.headers['clientUA'] = params.AuthData.ClientUA); + params.AuthData.SecurityToken && (opt.headers[token] = params.AuthData.SecurityToken); + + // 清理 undefined 和 null 字段 + opt.headers && (opt.headers = util.clearKey(opt.headers)); + opt = util.clearKey(opt); + + var Ip = this.options.Ip; + if (Ip) { + opt.url = opt.url.replace(/^(https?:\/\/)([^\/]+)/, function (str, pre, Host) { + opt.headers.Host = Host; + return pre + Ip; + }); + } + if (this.options.StrictSsl !== true) { + opt.strictSSL = this.options.StrictSsl; + } + if (this.options.Proxy) { + opt.proxy = this.options.Proxy; + } + if (typeof this.options.Tunnel === 'boolean') { + opt.tunnel = this.options.Tunnel; + } + if (this.options.Timeout) { + opt.timeout = this.options.Timeout; + } + if (this.options.KeepAlive) { + opt.forever = true; + } + if (!this.options.FollowRedirect) { + opt.followRedirect = false; + } - // 获取签名 - opt.headers.Authorization = params.AuthData.Authorization; - params.AuthData.Token && (opt.headers['token'] = params.AuthData.Token); - params.AuthData.ClientIP && (opt.headers['clientIP'] = params.AuthData.ClientIP); - params.AuthData.ClientUA && (opt.headers['clientUA'] = params.AuthData.ClientUA); - params.AuthData.SecurityToken && (opt.headers[token] = params.AuthData.SecurityToken); - - // 清理 undefined 和 null 字段 - opt.headers && (opt.headers = util.clearKey(opt.headers)); - opt = util.clearKey(opt); - - var Ip = this.options.Ip; - if (Ip) { - opt.url = opt.url.replace(/^(https?:\/\/)([^\/]+)/, function (str, pre, Host) { - opt.headers.Host = Host; - return pre + Ip; - }); - } - if (this.options.StrictSsl !== true) { - opt.strictSSL = this.options.StrictSsl; - } - if (this.options.Proxy) { - opt.proxy = this.options.Proxy; - } - if (typeof this.options.Tunnel === 'boolean') { - opt.tunnel = this.options.Tunnel; - } - if (this.options.Timeout) { - opt.timeout = this.options.Timeout; - } - if (this.options.KeepAlive) { - opt.forever = true; - } - if (!this.options.FollowRedirect) { - opt.followRedirect = false; + // 修复 Content-Type: false 的 Bug,原因 request 模块会获取 request('mime-types).lookup(readStream.path) 作为 Content-Type + // 问题代码位置:https://github.com/request/request/blob/v2.88.1/request.js#L500 + if (readStream) { + var hasContentType = false; + util.each(opt.headers, function (val, key) { + if (key.toLowerCase() === 'content-type') hasContentType = true; + }); + if ( + !hasContentType && // 1. not set Content-Type + readStream.readable && + readStream.path && + readStream.mode && // 2. isFileReadStream + !mime.lookup(readStream.path) // 3. mime return false + ) { + opt.headers['Content-Type'] = 'application/octet-stream'; } + } - // 修复 Content-Type: false 的 Bug,原因 request 模块会获取 request('mime-types).lookup(readStream.path) 作为 Content-Type - // 问题代码位置:https://github.com/request/request/blob/v2.88.1/request.js#L500 - if (readStream) { - var hasContentType = false; - util.each(opt.headers, function (val, key) { - if (key.toLowerCase() === 'content-type') hasContentType = true; - }); - if ( - !hasContentType && // 1. not set Content-Type - readStream.readable && readStream.path && readStream.mode && // 2. isFileReadStream - !mime.lookup(readStream.path) // 3. mime return false - ) { - opt.headers['Content-Type'] = 'application/octet-stream'; - } + // 特殊处理内容到写入流的情况,等待流 finish 后才 callback + if (params.outputStream) callback = util.callbackAfterStreamFinish(params.outputStream, callback); + + self.emit('before-send', opt); + var sender = REQUEST(opt); + var retResponse; + var hasReturned; + var cb = function (err, data) { + TaskId && self.off('inner-kill-task', killTask); + if (hasReturned) return; + hasReturned = true; + var attrs = {}; + retResponse && retResponse.statusCode && (attrs.statusCode = retResponse.statusCode); + retResponse && retResponse.headers && (attrs.headers = retResponse.headers); + if (err) { + err = util.extend(err || {}, attrs); + callback(err, null); + } else { + data = util.extend(data || {}, attrs); + callback(null, data); } - - // 特殊处理内容到写入流的情况,等待流 finish 后才 callback - if (params.outputStream) callback = util.callbackAfterStreamFinish(params.outputStream, callback); - - self.emit('before-send', opt); - var sender = REQUEST(opt); - var retResponse; - var hasReturned; - var cb = function (err, data) { - TaskId && self.off('inner-kill-task', killTask); - if (hasReturned) return; - hasReturned = true; - var attrs = {}; - retResponse && retResponse.statusCode && (attrs.statusCode = retResponse.statusCode); - retResponse && retResponse.headers && (attrs.headers = retResponse.headers); - if (err) { - err = util.extend(err || {}, attrs); - callback(err, null); - } else { - data = util.extend(data || {}, attrs); - callback(null, data); - } - if (sender) { - sender.removeAllListeners && sender.removeAllListeners(); - sender.on('error', function () {}); - sender = null; - } - }; - // 在 request 分配的 socket 上挂载 _lastBytesWritten 属性,记录该 socket 已经发送的字节数 - var markLastBytesWritten = function() { + if (sender) { + sender.removeAllListeners && sender.removeAllListeners(); + sender.on('error', function () {}); + sender = null; + } + }; + // 在 request 分配的 socket 上挂载 _lastBytesWritten 属性,记录该 socket 已经发送的字节数 + var markLastBytesWritten = function () { + try { + Object.defineProperty(sender.req.connection, '_lastBytesWritten', { + enumerable: true, + configurable: true, + writable: true, + value: sender.req.connection.bytesWritten, + }); + } catch (e) {} + }; + + sender.on('error', function (err) { + markLastBytesWritten(); + cb(util.error(err)); + }); + sender.on('response', function (response) { + retResponse = response; + var responseContentLength = response.headers['content-length'] || 0; + var chunkList = []; + var statusCode = response.statusCode; + var statusSuccess = Math.floor(statusCode / 100) === 2; // 200 202 204 206 + if (statusSuccess && params.outputStream) { + sender.on('end', function () { + cb(null, {}); + }); + } else if (responseContentLength >= process.binding('buffer').kMaxLength && opt.method !== 'HEAD') { + cb( + util.error( + new Error( + 'file size large than ' + + process.binding('buffer').kMaxLength + + ', please use "Output" Stream to getObject.', + ), + ), + ); + } else { + var dataHandler = function (chunk) { + chunkList.push(chunk); + }; + var endHandler = function () { try { - Object.defineProperty(sender.req.connection, '_lastBytesWritten', { - enumerable: true, - configurable: true, - writable: true, - value: sender.req.connection.bytesWritten - }); - } catch(e) { + var bodyBuf = Buffer.concat(chunkList); + } catch (e) { + cb(util.error(e)); + return; } - }; + var body = bodyBuf.toString(); - sender.on('error', function (err) { - markLastBytesWritten(); - cb(util.error(err)); - }); - sender.on('response', function (response) { - retResponse = response; - var responseContentLength = response.headers['content-length'] || 0; - var chunkList = []; - var statusCode = response.statusCode; - var statusSuccess = Math.floor(statusCode / 100) === 2; // 200 202 204 206 - if (statusSuccess && params.outputStream) { - sender.on('end', function () { - cb(null, {}); - }); - } else if (responseContentLength >= process.binding('buffer').kMaxLength && opt.method !== 'HEAD') { - cb(util.error(new Error('file size large than ' + process.binding('buffer').kMaxLength + ', please use "Output" Stream to getObject.'))); - } else { - var dataHandler = function (chunk) { - chunkList.push(chunk); - }; - var endHandler = function () { - try { - var bodyBuf = Buffer.concat(chunkList); - } catch (e) { - cb(util.error(e)); - return; - } - var body = bodyBuf.toString(); - - // 不对 body 进行转换,body 直接挂载返回 - if (rawBody && statusSuccess) return cb(null, {body: bodyBuf}); - - // 解析 xml body - var json = {}; - try { - json = body && body.indexOf('<') > -1 && body.indexOf('>') > -1 && util.xml2json(body) || {}; - } catch (e) { - } - - // 处理返回值 - var xmlError = json && json.Error; - if (statusSuccess) { // 正确返回,状态码 2xx 时,body 不会有 Error - cb(null, json); - } else if (xmlError) { // 正常返回了 xml body,且有 Error 节点 - cb(util.error(new Error(xmlError.Message), {code: xmlError.Code, error: xmlError})); - } else if (statusCode) { // 有错误的状态码 - cb(util.error(new Error(response.statusMessage), {code: '' + statusCode})); - } else { // 无状态码,或者获取不到状态码 - cb(util.error(new Error('statusCode error'))); - } - chunkList = null; - }; - sender.on('data', dataHandler); - sender.on('end', endHandler); - } - }); + // 不对 body 进行转换,body 直接挂载返回 + if (rawBody && statusSuccess) return cb(null, { body: bodyBuf }); - // kill task - var killTask = function (data) { - if (data.TaskId === TaskId) { - readStream && readStream.isSdkCreated && readStream.close && readStream.close(); // 如果是 SDK 里从 FilePath 创建的读流,要主动取消 - sender && sender.abort && sender.abort(); - self.off('inner-kill-task', killTask); + // 解析 xml body + var json = {}; + try { + json = (body && body.indexOf('<') > -1 && body.indexOf('>') > -1 && util.xml2json(body)) || {}; + } catch (e) {} + + // 处理返回值 + var xmlError = json && json.Error; + if (statusSuccess) { + // 正确返回,状态码 2xx 时,body 不会有 Error + cb(null, json); + } else if (xmlError) { + // 正常返回了 xml body,且有 Error 节点 + cb(util.error(new Error(xmlError.Message), { code: xmlError.Code, error: xmlError })); + } else if (statusCode) { + // 有错误的状态码 + cb(util.error(new Error(response.statusMessage), { code: '' + statusCode })); + } else { + // 无状态码,或者获取不到状态码 + cb(util.error(new Error('statusCode error'))); } - }; - TaskId && self.on('inner-kill-task', killTask); - - // 请求结束时,在 request 分配的 socket 上挂载 _lastBytesWritten 属性,记录该 socket 已经发送的字节数 - sender.once('end', function() { - markLastBytesWritten(); - }); - - // upload progress - if (params.onProgress && typeof params.onProgress === 'function') { - var contentLength = opt.headers['Content-Length']; - var time0 = Date.now(); - var size0 = 0; - sender.on('drain', function () { - var time1 = Date.now(); - var loaded = 0; - try { - // 已经上传的字节数 = socket当前累计发送的字节数 - 头部长度 - socket以前发送的字节数 - loaded = sender.req.connection.bytesWritten - sender.req._header.length - (sender.req.connection._lastBytesWritten || 0); - } catch (e) { - } - var total = contentLength; - var speed = parseInt((loaded - size0) / ((time1 - time0) / 1000) * 100) / 100 || 0; - var percent = parseInt(loaded / total * 100) / 100 || 0; - time0 = time1; - size0 = loaded; - params.onProgress({ - loaded: loaded, - total: total, - speed: speed, - percent: percent, - }); - }); - } - // download progress - if (params.onDownloadProgress && typeof params.onDownloadProgress === 'function') { - var time0 = Date.now(); - var size0 = 0; - var loaded = 0; - var total = 0; - sender.on('response', function (res) { - total = res.headers['content-length']; - sender.on('data', function (chunk) { - loaded += chunk.length; - var time1 = Date.now(); - var speed = parseInt((loaded - size0) / ((time1 - time0) / 1000) * 100) / 100 || 0; - var percent = parseInt(loaded / total * 100) / 100 || 0; - time0 = time1; - size0 = loaded; - params.onDownloadProgress({ - loaded: loaded, - total: total, - speed: speed, - percent: percent, - }); - }); - }); + chunkList = null; + }; + sender.on('data', dataHandler); + sender.on('end', endHandler); } + }); - // pipe 输入 - if (readStream) { - readStream.on('error', function (err) { - sender && sender.abort && sender.abort(); - cb(err); - }); - readStream.pipe(sender); + // kill task + var killTask = function (data) { + if (data.TaskId === TaskId) { + readStream && readStream.isSdkCreated && readStream.close && readStream.close(); // 如果是 SDK 里从 FilePath 创建的读流,要主动取消 + sender && sender.abort && sender.abort(); + self.off('inner-kill-task', killTask); } - // pipe 输出 - if (params.outputStream) { - params.outputStream.on('error', function (err) { - sender && sender.abort && sender.abort(); - cb(err) + }; + TaskId && self.on('inner-kill-task', killTask); + + // 请求结束时,在 request 分配的 socket 上挂载 _lastBytesWritten 属性,记录该 socket 已经发送的字节数 + sender.once('end', function () { + markLastBytesWritten(); + }); + + // upload progress + if (params.onProgress && typeof params.onProgress === 'function') { + var contentLength = opt.headers['Content-Length']; + var time0 = Date.now(); + var size0 = 0; + sender.on('drain', function () { + var time1 = Date.now(); + var loaded = 0; + try { + // 已经上传的字节数 = socket当前累计发送的字节数 - 头部长度 - socket以前发送的字节数 + loaded = + sender.req.connection.bytesWritten - + sender.req._header.length - + (sender.req.connection._lastBytesWritten || 0); + } catch (e) {} + var total = contentLength; + var speed = parseInt(((loaded - size0) / ((time1 - time0) / 1000)) * 100) / 100 || 0; + var percent = parseInt((loaded / total) * 100) / 100 || 0; + time0 = time1; + size0 = loaded; + params.onProgress({ + loaded: loaded, + total: total, + speed: speed, + percent: percent, + }); + }); + } + // download progress + if (params.onDownloadProgress && typeof params.onDownloadProgress === 'function') { + var time0 = Date.now(); + var size0 = 0; + var loaded = 0; + var total = 0; + sender.on('response', function (res) { + total = res.headers['content-length']; + sender.on('data', function (chunk) { + loaded += chunk.length; + var time1 = Date.now(); + var speed = parseInt(((loaded - size0) / ((time1 - time0) / 1000)) * 100) / 100 || 0; + var percent = parseInt((loaded / total) * 100) / 100 || 0; + time0 = time1; + size0 = loaded; + params.onDownloadProgress({ + loaded: loaded, + total: total, + speed: speed, + percent: percent, }); - sender.pipe(params.outputStream); - } + }); + }); + } - return sender; + // pipe 输入 + if (readStream) { + readStream.on('error', function (err) { + sender && sender.abort && sender.abort(); + cb(err); + }); + readStream.pipe(sender); + } + // pipe 输出 + if (params.outputStream) { + params.outputStream.on('error', function (err) { + sender && sender.abort && sender.abort(); + cb(err); + }); + sender.pipe(params.outputStream); + } + return sender; } - var API_MAP = { - // Bucket 相关方法 - getService: getService, // Bucket - putBucket: putBucket, - headBucket: headBucket, // Bucket - getBucket: getBucket, - deleteBucket: deleteBucket, - putBucketAcl: putBucketAcl, // BucketACL - getBucketAcl: getBucketAcl, - putBucketCors: putBucketCors, // BucketCors - getBucketCors: getBucketCors, - deleteBucketCors: deleteBucketCors, - getBucketLocation: getBucketLocation, // BucketLocation - getBucketPolicy: getBucketPolicy, // BucketPolicy - putBucketPolicy: putBucketPolicy, - deleteBucketPolicy: deleteBucketPolicy, - putBucketTagging: putBucketTagging, // BucketTagging - getBucketTagging: getBucketTagging, - deleteBucketTagging: deleteBucketTagging, - putBucketLifecycle: putBucketLifecycle, // BucketLifecycle - getBucketLifecycle: getBucketLifecycle, - deleteBucketLifecycle: deleteBucketLifecycle, - putBucketVersioning: putBucketVersioning, // BucketVersioning - getBucketVersioning: getBucketVersioning, - putBucketReplication: putBucketReplication, // BucketReplication - getBucketReplication: getBucketReplication, - deleteBucketReplication: deleteBucketReplication, - putBucketWebsite: putBucketWebsite, // BucketWebsite - getBucketWebsite: getBucketWebsite, - deleteBucketWebsite: deleteBucketWebsite, - putBucketReferer: putBucketReferer, // BucketReferer - getBucketReferer: getBucketReferer, - putBucketDomain: putBucketDomain, // BucketDomain - getBucketDomain: getBucketDomain, - deleteBucketDomain: deleteBucketDomain, - putBucketOrigin: putBucketOrigin, // BucketOrigin - getBucketOrigin: getBucketOrigin, - deleteBucketOrigin: deleteBucketOrigin, - putBucketLogging: putBucketLogging, // BucketLogging - getBucketLogging: getBucketLogging, - putBucketInventory: putBucketInventory, // BucketInventory - getBucketInventory: getBucketInventory, - listBucketInventory: listBucketInventory, - deleteBucketInventory: deleteBucketInventory, - putBucketAccelerate: putBucketAccelerate, - getBucketAccelerate: getBucketAccelerate, - putBucketEncryption: putBucketEncryption, - getBucketEncryption: getBucketEncryption, - deleteBucketEncryption: deleteBucketEncryption, - - // Object 相关方法 - getObject: getObject, - getObjectStream: getObjectStream, - headObject: headObject, - listObjectVersions: listObjectVersions, - putObject: putObject, - deleteObject: deleteObject, - getObjectAcl: getObjectAcl, - putObjectAcl: putObjectAcl, - optionsObject: optionsObject, - putObjectCopy: putObjectCopy, - deleteMultipleObject: deleteMultipleObject, - restoreObject: restoreObject, - putObjectTagging: putObjectTagging, - getObjectTagging: getObjectTagging, - deleteObjectTagging: deleteObjectTagging, - selectObjectContent: selectObjectContent, - selectObjectContentStream: selectObjectContentStream, - appendObject: appendObject, - - // 分块上传相关方法 - uploadPartCopy: uploadPartCopy, - multipartInit: multipartInit, - multipartUpload: multipartUpload, - multipartComplete: multipartComplete, - multipartList: multipartList, - multipartListPart: multipartListPart, - multipartAbort: multipartAbort, - - // 工具方法 - request: request, - getObjectUrl: getObjectUrl, - getAuth: getAuth, - getV4Auth: getV4Auth, + // Bucket 相关方法 + getService: getService, // Bucket + putBucket: putBucket, + headBucket: headBucket, // Bucket + getBucket: getBucket, + deleteBucket: deleteBucket, + putBucketAcl: putBucketAcl, // BucketACL + getBucketAcl: getBucketAcl, + putBucketCors: putBucketCors, // BucketCors + getBucketCors: getBucketCors, + deleteBucketCors: deleteBucketCors, + getBucketLocation: getBucketLocation, // BucketLocation + getBucketPolicy: getBucketPolicy, // BucketPolicy + putBucketPolicy: putBucketPolicy, + deleteBucketPolicy: deleteBucketPolicy, + putBucketTagging: putBucketTagging, // BucketTagging + getBucketTagging: getBucketTagging, + deleteBucketTagging: deleteBucketTagging, + putBucketLifecycle: putBucketLifecycle, // BucketLifecycle + getBucketLifecycle: getBucketLifecycle, + deleteBucketLifecycle: deleteBucketLifecycle, + putBucketVersioning: putBucketVersioning, // BucketVersioning + getBucketVersioning: getBucketVersioning, + putBucketReplication: putBucketReplication, // BucketReplication + getBucketReplication: getBucketReplication, + deleteBucketReplication: deleteBucketReplication, + putBucketWebsite: putBucketWebsite, // BucketWebsite + getBucketWebsite: getBucketWebsite, + deleteBucketWebsite: deleteBucketWebsite, + putBucketReferer: putBucketReferer, // BucketReferer + getBucketReferer: getBucketReferer, + putBucketDomain: putBucketDomain, // BucketDomain + getBucketDomain: getBucketDomain, + deleteBucketDomain: deleteBucketDomain, + putBucketOrigin: putBucketOrigin, // BucketOrigin + getBucketOrigin: getBucketOrigin, + deleteBucketOrigin: deleteBucketOrigin, + putBucketLogging: putBucketLogging, // BucketLogging + getBucketLogging: getBucketLogging, + putBucketInventory: putBucketInventory, // BucketInventory + getBucketInventory: getBucketInventory, + listBucketInventory: listBucketInventory, + deleteBucketInventory: deleteBucketInventory, + putBucketAccelerate: putBucketAccelerate, + getBucketAccelerate: getBucketAccelerate, + putBucketEncryption: putBucketEncryption, + getBucketEncryption: getBucketEncryption, + deleteBucketEncryption: deleteBucketEncryption, + + // Object 相关方法 + getObject: getObject, + getObjectStream: getObjectStream, + headObject: headObject, + listObjectVersions: listObjectVersions, + putObject: putObject, + deleteObject: deleteObject, + getObjectAcl: getObjectAcl, + putObjectAcl: putObjectAcl, + optionsObject: optionsObject, + putObjectCopy: putObjectCopy, + deleteMultipleObject: deleteMultipleObject, + restoreObject: restoreObject, + putObjectTagging: putObjectTagging, + getObjectTagging: getObjectTagging, + deleteObjectTagging: deleteObjectTagging, + selectObjectContent: selectObjectContent, + selectObjectContentStream: selectObjectContentStream, + appendObject: appendObject, + + // 分块上传相关方法 + uploadPartCopy: uploadPartCopy, + multipartInit: multipartInit, + multipartUpload: multipartUpload, + multipartComplete: multipartComplete, + multipartList: multipartList, + multipartListPart: multipartListPart, + multipartAbort: multipartAbort, + + // 工具方法 + request: request, + getObjectUrl: getObjectUrl, + getAuth: getAuth, + getV4Auth: getV4Auth, }; function warnOldApi(apiName, fn, proto) { - util.each(['Cors', 'Acl'], function (suffix) { - if (apiName.slice(-suffix.length) === suffix) { - var oldName = apiName.slice(0, -suffix.length) + suffix.toUpperCase(); - var apiFn = util.apiWrapper(apiName, fn); - var warned = false; - proto[oldName] = function () { - !warned && console.warn('warning: cos.' + oldName + ' has been deprecated. Please Use cos.' + apiName + ' instead.'); - warned = true; - apiFn.apply(this, arguments); - }; - } - }); + util.each(['Cors', 'Acl'], function (suffix) { + if (apiName.slice(-suffix.length) === suffix) { + var oldName = apiName.slice(0, -suffix.length) + suffix.toUpperCase(); + var apiFn = util.apiWrapper(apiName, fn); + var warned = false; + proto[oldName] = function () { + !warned && + console.warn('warning: cos.' + oldName + ' has been deprecated. Please Use cos.' + apiName + ' instead.'); + warned = true; + apiFn.apply(this, arguments); + }; + } + }); } module.exports.init = function (COS, task) { - task.transferToTaskMethod(API_MAP, 'putObject'); - util.each(API_MAP, function (fn, apiName) { - COS.prototype[apiName] = util.apiWrapper(apiName, fn); - warnOldApi(apiName, fn, COS.prototype); - }); + task.transferToTaskMethod(API_MAP, 'putObject'); + util.each(API_MAP, function (fn, apiName) { + COS.prototype[apiName] = util.apiWrapper(apiName, fn); + warnOldApi(apiName, fn, COS.prototype); + }); }; diff --git a/sdk/cos.js b/sdk/cos.js index 04c7414..60fd9a4 100644 --- a/sdk/cos.js +++ b/sdk/cos.js @@ -8,47 +8,47 @@ var advance = require('./advance'); var pkg = require('../package.json'); var defaultOptions = { - AppId: '', // AppId 已废弃,请拼接到 Bucket 后传入,例如:test-1250000000 - SecretId: '', - SecretKey: '', - SecurityToken: '', // 使用临时密钥需要注意自行刷新 Token - ChunkRetryTimes: 2, - FileParallelLimit: 3, - ChunkParallelLimit: 3, - ChunkSize: 1024 * 1024, - SliceSize: 1024 * 1024, - CopyChunkParallelLimit: 20, - CopyChunkSize: 1024 * 1024 * 10, - CopySliceSize: 1024 * 1024 * 10, - MaxPartNumber: 10000, - ProgressInterval: 1000, - Domain: '', - ServiceDomain: '', - Protocol: '', - CompatibilityMode: false, - ForcePathStyle: false, - UseRawKey: false, - Timeout: 0, // 单位毫秒,0 代表不设置超时时间 - CorrectClockSkew: true, - SystemClockOffset: 0, // 单位毫秒,ms - UploadCheckContentMd5: false, - UploadQueueSize: 1000, - UploadIdCacheLimit: 500, - Proxy: '', - Tunnel: undefined, - Ip: '', - StrictSsl: true, - KeepAlive: true, - FollowRedirect: false, - UseAccelerate: false, - UserAgent: '', - ConfCwd: '', - ForceSignHost: true, // 默认将host加入签名计算,关闭后可能导致越权风险,建议保持为true - // 动态秘钥,优先级Credentials > SecretId/SecretKey。注意Cred内是小写的secretId、secretKey - Credentials: { - secretId: '', - secretKey: '', - }, + AppId: '', // AppId 已废弃,请拼接到 Bucket 后传入,例如:test-1250000000 + SecretId: '', + SecretKey: '', + SecurityToken: '', // 使用临时密钥需要注意自行刷新 Token + ChunkRetryTimes: 2, + FileParallelLimit: 3, + ChunkParallelLimit: 3, + ChunkSize: 1024 * 1024, + SliceSize: 1024 * 1024, + CopyChunkParallelLimit: 20, + CopyChunkSize: 1024 * 1024 * 10, + CopySliceSize: 1024 * 1024 * 10, + MaxPartNumber: 10000, + ProgressInterval: 1000, + Domain: '', + ServiceDomain: '', + Protocol: '', + CompatibilityMode: false, + ForcePathStyle: false, + UseRawKey: false, + Timeout: 0, // 单位毫秒,0 代表不设置超时时间 + CorrectClockSkew: true, + SystemClockOffset: 0, // 单位毫秒,ms + UploadCheckContentMd5: false, + UploadQueueSize: 1000, + UploadIdCacheLimit: 500, + Proxy: '', + Tunnel: undefined, + Ip: '', + StrictSsl: true, + KeepAlive: true, + FollowRedirect: false, + UseAccelerate: false, + UserAgent: '', + ConfCwd: '', + ForceSignHost: true, // 默认将host加入签名计算,关闭后可能导致越权风险,建议保持为true + // 动态秘钥,优先级Credentials > SecretId/SecretKey。注意Cred内是小写的secretId、secretKey + Credentials: { + secretId: '', + secretKey: '', + }, }; const watch = (obj, name, callback) => { @@ -60,69 +60,76 @@ const watch = (obj, name, callback) => { set(newValue) { value = newValue; callback(); - } + }, }); }; // 对外暴露的类 var COS = function (options) { - this.options = util.extend(util.clone(defaultOptions), options || {}); - this.options.FileParallelLimit = Math.max(1, this.options.FileParallelLimit); - this.options.ChunkParallelLimit = Math.max(1, this.options.ChunkParallelLimit); - this.options.ChunkRetryTimes = Math.max(0, this.options.ChunkRetryTimes); - this.options.ChunkSize = Math.max(1024 * 1024, this.options.ChunkSize); - this.options.CopyChunkParallelLimit = Math.max(1, this.options.CopyChunkParallelLimit); - this.options.CopyChunkSize = Math.max(1024 * 1024, this.options.CopyChunkSize); - this.options.CopySliceSize = Math.max(0, this.options.CopySliceSize); - this.options.MaxPartNumber = Math.max(1024, Math.min(10000, this.options.MaxPartNumber)); - this.options.Timeout = Math.max(0, this.options.Timeout); - if (this.options.AppId) { - console.warn('warning: AppId has been deprecated, Please put it at the end of parameter Bucket(E.g: "test-1250000000").'); - } - // 云API SDK 用小写密钥,这里兼容并 warning - if (this.options.secretId || this.options.secretKey) { - if (this.options.secretId && !this.options.SecretId) this.options.SecretId = this.options.secretId; - if (this.options.secretKey && !this.options.SecretKey) this.options.SecretKey = this.options.secretKey; - console.warn('warning: Please change options secretId/secretKey to SecretId/SecretKey.'); - } - // 支持外部传入Cred动态秘钥 - if (this.options.Credentials.secretId && this.options.Credentials.secretKey) { - this.options.SecretId = this.options.Credentials.secretId || ''; - this.options.SecretKey = this.options.Credentials.secretKey || ''; - } - if (this.options.SecretId && this.options.SecretId.indexOf(' ') > -1) { - console.error('error: SecretId格式错误,请检查'); - console.error('error: SecretId format is incorrect. Please check'); - } - if (this.options.SecretKey && this.options.SecretKey.indexOf(' ') > -1) { - console.error('error: SecretKey格式错误,请检查'); - console.error('error: SecretKey format is incorrect. Please check'); - } - if (util.isWeb()) { - console.warn('warning: cos-nodejs-sdk-v5 不支持浏览器使用,请改用 cos-js-sdk-v5,参考文档: https://cloud.tencent.com/document/product/436/11459'); - console.warn('warning: cos-nodejs-sdk-v5 does not support browsers. Please use cos-js-sdk-v5 instead, See: https://cloud.tencent.com/document/product/436/11459'); - } - event.init(this); - task.init(this); + this.options = util.extend(util.clone(defaultOptions), options || {}); + this.options.FileParallelLimit = Math.max(1, this.options.FileParallelLimit); + this.options.ChunkParallelLimit = Math.max(1, this.options.ChunkParallelLimit); + this.options.ChunkRetryTimes = Math.max(0, this.options.ChunkRetryTimes); + this.options.ChunkSize = Math.max(1024 * 1024, this.options.ChunkSize); + this.options.CopyChunkParallelLimit = Math.max(1, this.options.CopyChunkParallelLimit); + this.options.CopyChunkSize = Math.max(1024 * 1024, this.options.CopyChunkSize); + this.options.CopySliceSize = Math.max(0, this.options.CopySliceSize); + this.options.MaxPartNumber = Math.max(1024, Math.min(10000, this.options.MaxPartNumber)); + this.options.Timeout = Math.max(0, this.options.Timeout); + if (this.options.AppId) { + console.warn( + 'warning: AppId has been deprecated, Please put it at the end of parameter Bucket(E.g: "test-1250000000").', + ); + } + // 云API SDK 用小写密钥,这里兼容并 warning + if (this.options.secretId || this.options.secretKey) { + if (this.options.secretId && !this.options.SecretId) this.options.SecretId = this.options.secretId; + if (this.options.secretKey && !this.options.SecretKey) this.options.SecretKey = this.options.secretKey; + console.warn('warning: Please change options secretId/secretKey to SecretId/SecretKey.'); + } + // 支持外部传入Cred动态秘钥 + if (this.options.Credentials.secretId && this.options.Credentials.secretKey) { + this.options.SecretId = this.options.Credentials.secretId || ''; + this.options.SecretKey = this.options.Credentials.secretKey || ''; + } + if (this.options.SecretId && this.options.SecretId.indexOf(' ') > -1) { + console.error('error: SecretId格式错误,请检查'); + console.error('error: SecretId format is incorrect. Please check'); + } + if (this.options.SecretKey && this.options.SecretKey.indexOf(' ') > -1) { + console.error('error: SecretKey格式错误,请检查'); + console.error('error: SecretKey format is incorrect. Please check'); + } + if (util.isWeb()) { + console.warn( + 'warning: cos-nodejs-sdk-v5 不支持浏览器使用,请改用 cos-js-sdk-v5,参考文档: https://cloud.tencent.com/document/product/436/11459', + ); + console.warn( + 'warning: cos-nodejs-sdk-v5 does not support browsers. Please use cos-js-sdk-v5 instead, See: https://cloud.tencent.com/document/product/436/11459', + ); + } + event.init(this); + task.init(this); - // 支持动态秘钥,监听到cred里secretId、secretKey变化时,主动给cos替换秘钥 - watch(this.options.Credentials, 'secretId', () => { - console.log('Credentials secretId changed'); - this.options.SecretId = this.options.Credentials.secretId; - }); - watch(this.options.Credentials, 'secretKey', () => { - console.log('Credentials secretKey changed'); - this.options.SecretKey = this.options.Credentials.secretKey; - }); + // 支持动态秘钥,监听到cred里secretId、secretKey变化时,主动给cos替换秘钥 + watch(this.options.Credentials, 'secretId', () => { + console.log('Credentials secretId changed'); + this.options.SecretId = this.options.Credentials.secretId; + }); + watch(this.options.Credentials, 'secretKey', () => { + console.log('Credentials secretKey changed'); + this.options.SecretKey = this.options.Credentials.secretKey; + }); }; base.init(COS, task); advance.init(COS, task); COS.util = { - md5: util.md5, - xml2json: util.xml2json, - json2xml: util.json2xml, + md5: util.md5, + xml2json: util.xml2json, + json2xml: util.json2xml, + encodeBase64: util.encodeBase64, }; COS.getAuthorization = util.getAuth; COS.version = pkg.version; diff --git a/sdk/event.js b/sdk/event.js index 6f5765c..4cbdcc9 100644 --- a/sdk/event.js +++ b/sdk/event.js @@ -1,34 +1,34 @@ var initEvent = function (cos) { - var listeners = {}; - var getList = function (action) { - !listeners[action] && (listeners[action] = []); - return listeners[action]; - }; - cos.on = function (action, callback) { - if (action === 'task-list-update') { - console.warn('warning: Event "' + action + '" has been deprecated. Please use "list-update" instead.'); - } - getList(action).push(callback); - }; - cos.off = function (action, callback) { - var list = getList(action); - for (var i = list.length - 1; i >= 0; i--) { - callback === list[i] && list.splice(i, 1); - } - }; - cos.emit = function (action, data) { - var list = getList(action).map(function (cb) { - return cb; - }); - for (var i = 0; i < list.length; i++) { - list[i](data); - } - }; + var listeners = {}; + var getList = function (action) { + !listeners[action] && (listeners[action] = []); + return listeners[action]; + }; + cos.on = function (action, callback) { + if (action === 'task-list-update') { + console.warn('warning: Event "' + action + '" has been deprecated. Please use "list-update" instead.'); + } + getList(action).push(callback); + }; + cos.off = function (action, callback) { + var list = getList(action); + for (var i = list.length - 1; i >= 0; i--) { + callback === list[i] && list.splice(i, 1); + } + }; + cos.emit = function (action, data) { + var list = getList(action).map(function (cb) { + return cb; + }); + for (var i = 0; i < list.length; i++) { + list[i](data); + } + }; }; var EventProxy = function () { - initEvent(this); + initEvent(this); }; module.exports.init = initEvent; -module.exports.EventProxy = EventProxy; \ No newline at end of file +module.exports.EventProxy = EventProxy; diff --git a/sdk/select-stream.js b/sdk/select-stream.js index 182fa8c..9b89f16 100644 --- a/sdk/select-stream.js +++ b/sdk/select-stream.js @@ -3,176 +3,178 @@ var sysUtil = require('util'); var util = require('./util'); function SelectStream(options) { - if (!(this instanceof SelectStream)) return new SelectStream(options); - Transform.call(this, options); - Object.assign(this, { - totalLength: 0, // current message block's total length - headerLength: 0, // current message block's header length - payloadRestLength: 0, // current message block's rest payload length - header: null, // current message block's header - chunk: Buffer.alloc(0), // the data chunk being parsed - callback: null, // current _transform function's callback - }); + if (!(this instanceof SelectStream)) return new SelectStream(options); + Transform.call(this, options); + Object.assign(this, { + totalLength: 0, // current message block's total length + headerLength: 0, // current message block's header length + payloadRestLength: 0, // current message block's rest payload length + header: null, // current message block's header + chunk: Buffer.alloc(0), // the data chunk being parsed + callback: null, // current _transform function's callback + }); } SelectStream.prototype = { - /** - * process data chunk - * concat the last chunk and current chunk - * try to parse current message block's totalLength and headerLength - * try to parse current message block's header - * try to parse current message block's payload - */ - processChunk(chunk, encoding, callback) { - Object.assign(this, { - chunk: Buffer.concat([this.chunk, chunk], this.chunk.length + chunk.length), - encoding, - callback, - }); + /** + * process data chunk + * concat the last chunk and current chunk + * try to parse current message block's totalLength and headerLength + * try to parse current message block's header + * try to parse current message block's payload + */ + processChunk(chunk, encoding, callback) { + Object.assign(this, { + chunk: Buffer.concat([this.chunk, chunk], this.chunk.length + chunk.length), + encoding, + callback, + }); - this.parseLength(); - this.parseHeader(); - this.parsePayload(); - }, + this.parseLength(); + this.parseHeader(); + this.parsePayload(); + }, - /** - * try to parse current message block's totalLength and headerLength - */ - parseLength() { - if (!this.callback) { - return; - } + /** + * try to parse current message block's totalLength and headerLength + */ + parseLength() { + if (!this.callback) { + return; + } - if (this.totalLength && this.headerLength) { - return; - } + if (this.totalLength && this.headerLength) { + return; + } - if (this.chunk.length >= 12) { - this.totalLength = this.chunk.readInt32BE(0); - this.headerLength = this.chunk.readInt32BE(4); - this.payloadRestLength = this.totalLength - this.headerLength - 16; - this.chunk = this.chunk.slice(12); - } else { - this.callback(); - this.callback = null; - } - }, + if (this.chunk.length >= 12) { + this.totalLength = this.chunk.readInt32BE(0); + this.headerLength = this.chunk.readInt32BE(4); + this.payloadRestLength = this.totalLength - this.headerLength - 16; + this.chunk = this.chunk.slice(12); + } else { + this.callback(); + this.callback = null; + } + }, - /** - * try to parse current message block's header - * if header[':message-type'] is error, callback the error, emit error to next stream - */ - parseHeader() { - if (!this.callback) { - return; - } + /** + * try to parse current message block's header + * if header[':message-type'] is error, callback the error, emit error to next stream + */ + parseHeader() { + if (!this.callback) { + return; + } - if (!this.headerLength || this.header) { - return; - } + if (!this.headerLength || this.header) { + return; + } - if (this.chunk.length >= this.headerLength) { - var header = {}; - var offset = 0; - while (offset < this.headerLength) { - var headerNameLength = this.chunk[offset] * 1; - var headerName = this.chunk.toString('ascii', offset + 1, offset + 1 + headerNameLength); - var headerValueLength = this.chunk.readInt16BE(offset + headerNameLength + 2); - var headerValue = this.chunk.toString('ascii', offset + headerNameLength + 4, offset + headerNameLength + 4 + headerValueLength); - header[headerName] = headerValue; - offset += headerNameLength + 4 + headerValueLength; - } - this.header = header; - this.chunk = this.chunk.slice(this.headerLength); - this.checkErrorHeader(); - } else { - this.callback(); - this.callback = null; - } - }, + if (this.chunk.length >= this.headerLength) { + var header = {}; + var offset = 0; + while (offset < this.headerLength) { + var headerNameLength = this.chunk[offset] * 1; + var headerName = this.chunk.toString('ascii', offset + 1, offset + 1 + headerNameLength); + var headerValueLength = this.chunk.readInt16BE(offset + headerNameLength + 2); + var headerValue = this.chunk.toString( + 'ascii', + offset + headerNameLength + 4, + offset + headerNameLength + 4 + headerValueLength, + ); + header[headerName] = headerValue; + offset += headerNameLength + 4 + headerValueLength; + } + this.header = header; + this.chunk = this.chunk.slice(this.headerLength); + this.checkErrorHeader(); + } else { + this.callback(); + this.callback = null; + } + }, - /** - * try to parse current message block's payload - */ - parsePayload() { - var self = this; - if (!this.callback) { - return; - } + /** + * try to parse current message block's payload + */ + parsePayload() { + var self = this; + if (!this.callback) { + return; + } - if (this.chunk.length <= this.payloadRestLength) { - this.payloadRestLength -= this.chunk.length; - this.pushData(this.chunk); - this.chunk = Buffer.alloc(0); - } else if (this.chunk.length < this.payloadRestLength + 4) { - this.pushData(this.chunk.slice(0, this.payloadRestLength)); - this.chunk = this.chunk.slice(this.payloadRestLength); - this.payloadRestLength = 0; - } else { - this.pushData(this.chunk.slice(0, this.payloadRestLength)); - this.chunk = this.chunk.slice(this.payloadRestLength + 4); - this.totalLength = 0; - this.headerLength = 0; - this.payloadRestLength = 0; - this.header = null; - } + if (this.chunk.length <= this.payloadRestLength) { + this.payloadRestLength -= this.chunk.length; + this.pushData(this.chunk); + this.chunk = Buffer.alloc(0); + } else if (this.chunk.length < this.payloadRestLength + 4) { + this.pushData(this.chunk.slice(0, this.payloadRestLength)); + this.chunk = this.chunk.slice(this.payloadRestLength); + this.payloadRestLength = 0; + } else { + this.pushData(this.chunk.slice(0, this.payloadRestLength)); + this.chunk = this.chunk.slice(this.payloadRestLength + 4); + this.totalLength = 0; + this.headerLength = 0; + this.payloadRestLength = 0; + this.header = null; + } - if ( - this.chunk.length - && !(this.payloadRestLength === 0 && this.chunk.length < 4) - ) { - process.nextTick(function () { - self.processChunk(Buffer.alloc(0), self.encoding, self.callback); - }); - } else { - this.callback(); - this.callback = null; - } - }, + if (this.chunk.length && !(this.payloadRestLength === 0 && this.chunk.length < 4)) { + process.nextTick(function () { + self.processChunk(Buffer.alloc(0), self.encoding, self.callback); + }); + } else { + this.callback(); + this.callback = null; + } + }, - /** - * if header[':event-type'] is Records, pipe payload to next stream - */ - pushData(content) { - if (this.header[':event-type'] === 'Records') { - this.push(content); - this.emit('message:records', content); - } else if (this.header[':event-type'] === 'Progress') { - var progress = util.xml2json(content.toString()).Progress; - this.emit('message:progress', progress); - } else if (this.header[':event-type'] === 'Stats') { - var stats = util.xml2json(content.toString()).Stats; - this.emit('message:stats', stats); - } else if (this.header[':event-type'] === 'error') { - var errCode = this.header[':error-code']; - var errMessage = this.header[':error-message']; - var err = new Error(errMessage); - err.message = errMessage; - err.name = err.code = errCode; - this.emit('message:error', err); - } else { // 'Continuation', 'End' - this.emit('message:' + this.header[':event-type'].toLowerCase()); - } - }, + /** + * if header[':event-type'] is Records, pipe payload to next stream + */ + pushData(content) { + if (this.header[':event-type'] === 'Records') { + this.push(content); + this.emit('message:records', content); + } else if (this.header[':event-type'] === 'Progress') { + var progress = util.xml2json(content.toString()).Progress; + this.emit('message:progress', progress); + } else if (this.header[':event-type'] === 'Stats') { + var stats = util.xml2json(content.toString()).Stats; + this.emit('message:stats', stats); + } else if (this.header[':event-type'] === 'error') { + var errCode = this.header[':error-code']; + var errMessage = this.header[':error-message']; + var err = new Error(errMessage); + err.message = errMessage; + err.name = err.code = errCode; + this.emit('message:error', err); + } else { + // 'Continuation', 'End' + this.emit('message:' + this.header[':event-type'].toLowerCase()); + } + }, - /** - * if header[':message-type'] is error, callback the error, emit error to next stream - */ - checkErrorHeader() { - if (this.header[':message-type'] === 'error') { - this.callback(this.header); - this.callback = null; - } - }, + /** + * if header[':message-type'] is error, callback the error, emit error to next stream + */ + checkErrorHeader() { + if (this.header[':message-type'] === 'error') { + this.callback(this.header); + this.callback = null; + } + }, - /** - * Transform Stream's implementations - */ - _transform(chunk, encoding, callback) { - this.processChunk(chunk, encoding, callback); - }, - _flush(callback) { - this.processChunk(Buffer.alloc(0), this.encoding, callback); - }, + /** + * Transform Stream's implementations + */ + _transform(chunk, encoding, callback) { + this.processChunk(chunk, encoding, callback); + }, + _flush(callback) { + this.processChunk(Buffer.alloc(0), this.encoding, callback); + }, }; sysUtil.inherits(SelectStream, Transform); diff --git a/sdk/session.js b/sdk/session.js index 32f3f9a..53bd91d 100644 --- a/sdk/session.js +++ b/sdk/session.js @@ -7,116 +7,120 @@ var cache; var timer; var getCache = function () { - var val, opt = {configName: 'cos-nodejs-sdk-v5-storage'}; - if (this.options.ConfCwd) opt.cwd = this.options.ConfCwd; - try { - var Conf = require('conf'); - store = new Conf(opt); - val = store.get(cacheKey); - } catch (e) {} - if (!val || !(val instanceof Array)) val = []; - cache = val; + var val, + opt = { configName: 'cos-nodejs-sdk-v5-storage' }; + if (this.options.ConfCwd) opt.cwd = this.options.ConfCwd; + try { + var Conf = require('conf'); + store = new Conf(opt); + val = store.get(cacheKey); + } catch (e) {} + if (!val || !(val instanceof Array)) val = []; + cache = val; }; var setCache = function () { - try { - if (cache.length) store.set(cacheKey, cache); - else store.delete(cacheKey); - } catch (e) { - } + try { + if (cache.length) store.set(cacheKey, cache); + else store.delete(cacheKey); + } catch (e) {} }; var init = function () { - if (cache) return; - getCache.call(this); - // 清理太老旧的数据 - var changed = false; - var now = Math.round(Date.now() / 1000); - for (var i = cache.length - 1; i >= 0; i--) { - var mtime = cache[i][2]; - if (!mtime || mtime + expires < now) { - cache.splice(i, 1); - changed = true; - } + if (cache) return; + getCache.call(this); + // 清理太老旧的数据 + var changed = false; + var now = Math.round(Date.now() / 1000); + for (var i = cache.length - 1; i >= 0; i--) { + var mtime = cache[i][2]; + if (!mtime || mtime + expires < now) { + cache.splice(i, 1); + changed = true; } - changed && setCache(); + } + changed && setCache(); }; // 把缓存存到本地 var save = function () { - if (timer) return; - timer = setTimeout(function () { - setCache(); - timer = null; - }, 400); + if (timer) return; + timer = setTimeout(function () { + setCache(); + timer = null; + }, 400); }; var mod = { - using: {}, - // 标记 UploadId 正在使用 - setUsing: function (uuid) { - mod.using[uuid] = true; - }, - // 标记 UploadId 已经没在使用 - removeUsing: function (uuid) { - delete mod.using[uuid]; - }, - // 用上传参数生成哈希值 - getFileId: function (FileStat, ChunkSize, Bucket, Key) { - if (FileStat && FileStat.FilePath && FileStat.size && FileStat.ctime && FileStat.mtime && ChunkSize) { - return util.md5([FileStat.FilePath].join('::')) + '-' + util.md5([FileStat.size, FileStat.ctime, FileStat.mtime, ChunkSize, Bucket, Key].join('::')); - } else { - return null; - } - }, - // 用上传参数生成哈希值 - getCopyFileId: function (copySource, sourceHeaders, ChunkSize, Bucket, Key) { - var size = sourceHeaders['content-length']; - var etag = sourceHeaders.etag || ''; - var lastModified = sourceHeaders['last-modified']; - if (copySource && ChunkSize) { - return util.md5([copySource, size, etag, lastModified, ChunkSize, Bucket, Key].join('::')); - } else { - return null; - } - }, - // 获取文件对应的 UploadId 列表 - getUploadIdList: function (uuid) { - if (!uuid) return null; - init.call(this); - var list = []; - for (var i = 0; i < cache.length; i++) { - if (cache[i][0] === uuid) - list.push(cache[i][1]); - } - return list.length ? list : null; - }, - // 缓存 UploadId - saveUploadId: function (uuid, UploadId, limit) { - init.call(this); - if (!uuid) return; - // 清理没用的 UploadId - var part1 = uuid.substr(0, uuid.indexOf('-') + 1); - for (var i = cache.length - 1; i >= 0; i--) { - var item = cache[i]; - if (item[0] === uuid && item[1] === UploadId) { - cache.splice(i, 1); - } else if (uuid !== item[0] && item[0].indexOf(part1) === 0) { // 文件路径相同,但其他信息不同,说明文件改变了或上传参数(存储桶、路径、分片大小)变了,直接清理掉 - cache.splice(i, 1); - } - } - cache.unshift([uuid, UploadId, Math.round(Date.now() / 1000)]); - if (cache.length > limit) cache.splice(limit); - save(); - }, - // UploadId 已用完,移除掉 - removeUploadId: function (UploadId) { - init.call(this); - delete mod.using[UploadId]; - for (var i = cache.length - 1; i >= 0; i--) { - if (cache[i][1] === UploadId) cache.splice(i, 1) - } - save(); - }, + using: {}, + // 标记 UploadId 正在使用 + setUsing: function (uuid) { + mod.using[uuid] = true; + }, + // 标记 UploadId 已经没在使用 + removeUsing: function (uuid) { + delete mod.using[uuid]; + }, + // 用上传参数生成哈希值 + getFileId: function (FileStat, ChunkSize, Bucket, Key) { + if (FileStat && FileStat.FilePath && FileStat.size && FileStat.ctime && FileStat.mtime && ChunkSize) { + return ( + util.md5([FileStat.FilePath].join('::')) + + '-' + + util.md5([FileStat.size, FileStat.ctime, FileStat.mtime, ChunkSize, Bucket, Key].join('::')) + ); + } else { + return null; + } + }, + // 用上传参数生成哈希值 + getCopyFileId: function (copySource, sourceHeaders, ChunkSize, Bucket, Key) { + var size = sourceHeaders['content-length']; + var etag = sourceHeaders.etag || ''; + var lastModified = sourceHeaders['last-modified']; + if (copySource && ChunkSize) { + return util.md5([copySource, size, etag, lastModified, ChunkSize, Bucket, Key].join('::')); + } else { + return null; + } + }, + // 获取文件对应的 UploadId 列表 + getUploadIdList: function (uuid) { + if (!uuid) return null; + init.call(this); + var list = []; + for (var i = 0; i < cache.length; i++) { + if (cache[i][0] === uuid) list.push(cache[i][1]); + } + return list.length ? list : null; + }, + // 缓存 UploadId + saveUploadId: function (uuid, UploadId, limit) { + init.call(this); + if (!uuid) return; + // 清理没用的 UploadId + var part1 = uuid.substr(0, uuid.indexOf('-') + 1); + for (var i = cache.length - 1; i >= 0; i--) { + var item = cache[i]; + if (item[0] === uuid && item[1] === UploadId) { + cache.splice(i, 1); + } else if (uuid !== item[0] && item[0].indexOf(part1) === 0) { + // 文件路径相同,但其他信息不同,说明文件改变了或上传参数(存储桶、路径、分片大小)变了,直接清理掉 + cache.splice(i, 1); + } + } + cache.unshift([uuid, UploadId, Math.round(Date.now() / 1000)]); + if (cache.length > limit) cache.splice(limit); + save(); + }, + // UploadId 已用完,移除掉 + removeUploadId: function (UploadId) { + init.call(this); + delete mod.using[UploadId]; + for (var i = cache.length - 1; i >= 0; i--) { + if (cache[i][1] === UploadId) cache.splice(i, 1); + } + save(); + }, }; module.exports = mod; diff --git a/sdk/task.js b/sdk/task.js index 7e1ceb9..868ced3 100644 --- a/sdk/task.js +++ b/sdk/task.js @@ -3,250 +3,252 @@ var util = require('./util'); var originApiMap = {}; var transferToTaskMethod = function (apiMap, apiName) { - originApiMap[apiName] = apiMap[apiName]; - apiMap[apiName] = function (params, callback) { - if (params.SkipTask) { - originApiMap[apiName].call(this, params, callback); - } else { - this._addTask(apiName, params, callback); - } - }; + originApiMap[apiName] = apiMap[apiName]; + apiMap[apiName] = function (params, callback) { + if (params.SkipTask) { + originApiMap[apiName].call(this, params, callback); + } else { + this._addTask(apiName, params, callback); + } + }; }; var initTask = function (cos) { - - var queue = []; - var tasks = {}; - var uploadingFileCount = 0; - var nextUploadIndex = 0; - - // 接口返回简略的任务信息 - var formatTask = function (task) { - var t = { - id: task.id, - Bucket: task.Bucket, - Region: task.Region, - Key: task.Key, - FilePath: task.FilePath, - state: task.state, - loaded: task.loaded, - size: task.size, - speed: task.speed, - percent: task.percent, - hashPercent: task.hashPercent, - error: task.error, - }; - if (task.FilePath) t.FilePath = task.FilePath; - return t; - }; - - var emitListUpdate = (function () { - var timer; - var emit = function () { - timer = 0; - cos.emit('task-list-update', {list: util.map(queue, formatTask)}); - cos.emit('list-update', {list: util.map(queue, formatTask)}); - }; - return function () { - if (!timer) timer = setTimeout(emit); - } - })(); - - var clearQueue = function () { - if (queue.length <= cos.options.UploadQueueSize) return; - for (var i = 0; - i < nextUploadIndex && // 小于当前操作的 index 才清理 - i < queue.length && // 大于队列才清理 - queue.length > cos.options.UploadQueueSize // 如果还太多,才继续清理 - ;) { - var isActive = queue[i].state === 'waiting' || queue[i].state === 'checking' || queue[i].state === 'uploading'; - if (!queue[i] || !isActive) { - tasks[queue[i].id] && (delete tasks[queue[i].id]); - queue.splice(i, 1); - nextUploadIndex--; - } else { - i++; - } - } - emitListUpdate(); + var queue = []; + var tasks = {}; + var uploadingFileCount = 0; + var nextUploadIndex = 0; + + // 接口返回简略的任务信息 + var formatTask = function (task) { + var t = { + id: task.id, + Bucket: task.Bucket, + Region: task.Region, + Key: task.Key, + FilePath: task.FilePath, + state: task.state, + loaded: task.loaded, + size: task.size, + speed: task.speed, + percent: task.percent, + hashPercent: task.hashPercent, + error: task.error, }; - - var startNextTask = function () { - // 检查是否允许增加执行进程 - if (uploadingFileCount >= cos.options.FileParallelLimit) return; - // 跳过不可执行的任务 - while (queue[nextUploadIndex] && queue[nextUploadIndex].state !== 'waiting') nextUploadIndex++; - // 检查是否已遍历结束 - if (nextUploadIndex >= queue.length) return; - // 上传该遍历到的任务 - var task = queue[nextUploadIndex]; - nextUploadIndex++; - uploadingFileCount++; - task.state = 'checking'; - task.params.onTaskStart && task.params.onTaskStart(formatTask(task)); - !task.params.UploadData && (task.params.UploadData = {}); - var apiParams = util.formatParams(task.api, task.params); - originApiMap[task.api].call(cos, apiParams, function (err, data) { - if (!cos._isRunningTask(task.id)) return; - if (task.state === 'checking' || task.state === 'uploading') { - task.state = err ? 'error' : 'success'; - err && (task.error = err); - uploadingFileCount--; - emitListUpdate(); - startNextTask(); - task.callback && task.callback(err, data); - if (task.state === 'success') { - if (task.params) { - delete task.params.UploadData; - delete task.params.Body; - delete task.params; - } - delete task.callback; - } - } - clearQueue(); - }); - emitListUpdate(); - // 异步执行下一个任务 - setTimeout(startNextTask); + if (task.FilePath) t.FilePath = task.FilePath; + return t; + }; + + var emitListUpdate = (function () { + var timer; + var emit = function () { + timer = 0; + cos.emit('task-list-update', { list: util.map(queue, formatTask) }); + cos.emit('list-update', { list: util.map(queue, formatTask) }); }; - - var killTask = function (id, switchToState) { - var task = tasks[id]; - if (!task) return; - var waiting = task && task.state === 'waiting'; - var running = task && (task.state === 'checking' || task.state === 'uploading'); - if (switchToState === 'canceled' && task.state !== 'canceled' || - switchToState === 'paused' && waiting || - switchToState === 'paused' && running) { - if (switchToState === 'paused' && task.params.Body && typeof task.params.Body.pipe === 'function') { - console.error('stream not support pause'); - return; - } - task.state = switchToState; - cos.emit('inner-kill-task', {TaskId: id, toState: switchToState}); - try { - var UploadId = task && task.params && task.params.UploadData.UploadId - } catch(e) {} - if (switchToState === 'canceled' && UploadId) session.removeUsing(UploadId) - emitListUpdate(); - if (running) { - uploadingFileCount--; - startNextTask(); - } - if (switchToState === 'canceled') { - if (task.params) { - delete task.params.UploadData; - delete task.params.Body; - delete task.params; - } - delete task.callback; - } - } - clearQueue(); + return function () { + if (!timer) timer = setTimeout(emit); }; - - cos._addTasks = function (taskList) { - util.each(taskList, function (task) { - cos._addTask(task.api, task.params, task.callback, true); - }); + })(); + + var clearQueue = function () { + if (queue.length <= cos.options.UploadQueueSize) return; + for ( + var i = 0; + i < nextUploadIndex && // 小于当前操作的 index 才清理 + i < queue.length && // 大于队列才清理 + queue.length > cos.options.UploadQueueSize; // 如果还太多,才继续清理 + + ) { + var isActive = queue[i].state === 'waiting' || queue[i].state === 'checking' || queue[i].state === 'uploading'; + if (!queue[i] || !isActive) { + tasks[queue[i].id] && delete tasks[queue[i].id]; + queue.splice(i, 1); + nextUploadIndex--; + } else { + i++; + } + } + emitListUpdate(); + }; + + var startNextTask = function () { + // 检查是否允许增加执行进程 + if (uploadingFileCount >= cos.options.FileParallelLimit) return; + // 跳过不可执行的任务 + while (queue[nextUploadIndex] && queue[nextUploadIndex].state !== 'waiting') nextUploadIndex++; + // 检查是否已遍历结束 + if (nextUploadIndex >= queue.length) return; + // 上传该遍历到的任务 + var task = queue[nextUploadIndex]; + nextUploadIndex++; + uploadingFileCount++; + task.state = 'checking'; + task.params.onTaskStart && task.params.onTaskStart(formatTask(task)); + !task.params.UploadData && (task.params.UploadData = {}); + var apiParams = util.formatParams(task.api, task.params); + originApiMap[task.api].call(cos, apiParams, function (err, data) { + if (!cos._isRunningTask(task.id)) return; + if (task.state === 'checking' || task.state === 'uploading') { + task.state = err ? 'error' : 'success'; + err && (task.error = err); + uploadingFileCount--; emitListUpdate(); - }; - - var isTaskReadyWarning = true; - cos._addTask = function (api, params, callback, ignoreAddEvent) { - - // 复制参数对象 - params = util.formatParams(api, params); - - // 生成 id - var id = util.uuid(); - params.TaskId = id; - params.onTaskReady && params.onTaskReady(id); - if (params.TaskReady) { - params.TaskReady(id); - isTaskReadyWarning && console.warn('warning: Param "TaskReady" has been deprecated. Please use "onTaskReady" instead.'); - isTaskReadyWarning = false; + startNextTask(); + task.callback && task.callback(err, data); + if (task.state === 'success') { + if (task.params) { + delete task.params.UploadData; + delete task.params.Body; + delete task.params; + } + delete task.callback; } - - var task = { - // env - params: params, - callback: callback, - api: api, - index: queue.length, - // task - id: id, - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - FilePath: params.FilePath || '', - state: 'waiting', - loaded: 0, - size: 0, - speed: 0, - percent: 0, - hashPercent: 0, - error: null, - }; - var onHashProgress = params.onHashProgress; - params.onHashProgress = function (info) { - if (!cos._isRunningTask(task.id)) return; - task.hashPercent = info.percent; - onHashProgress && onHashProgress(info); - emitListUpdate(); - }; - var onProgress = params.onProgress; - params.onProgress = function (info) { - if (!cos._isRunningTask(task.id)) return; - task.state === 'checking' && (task.state = 'uploading'); - task.loaded = info.loaded; - task.speed = info.speed; - task.percent = info.percent; - onProgress && onProgress(info); - emitListUpdate(); - }; - - // 异步获取 filesize - util.getFileSize(api, params, function (err, size) { - // 开始处理上传 - if (err) return callback(util.error(err)); // 如果获取大小出错,不加入队列 - // 获取完文件大小再把任务加入队列 - tasks[id] = task; - queue.push(task); - task.size = size; - !ignoreAddEvent && emitListUpdate(); - startNextTask(); - clearQueue(); - }); - return id; - }; - cos._isRunningTask = function (id) { - var task = tasks[id]; - return !!(task && (task.state === 'checking' || task.state === 'uploading')); - }; - cos.getTaskList = function () { - return util.map(queue, formatTask); - }; - cos.cancelTask = function (id) { - killTask(id, 'canceled'); - }; - cos.pauseTask = function (id) { - killTask(id, 'paused'); - }; - cos.restartTask = function (id) { - var task = tasks[id]; - if (task && (task.state === 'paused' || task.state === 'error')) { - task.state = 'waiting'; - emitListUpdate(); - nextUploadIndex = Math.min(nextUploadIndex, task.index); - startNextTask(); + } + clearQueue(); + }); + emitListUpdate(); + // 异步执行下一个任务 + setTimeout(startNextTask); + }; + + var killTask = function (id, switchToState) { + var task = tasks[id]; + if (!task) return; + var waiting = task && task.state === 'waiting'; + var running = task && (task.state === 'checking' || task.state === 'uploading'); + if ( + (switchToState === 'canceled' && task.state !== 'canceled') || + (switchToState === 'paused' && waiting) || + (switchToState === 'paused' && running) + ) { + if (switchToState === 'paused' && task.params.Body && typeof task.params.Body.pipe === 'function') { + console.error('stream not support pause'); + return; + } + task.state = switchToState; + cos.emit('inner-kill-task', { TaskId: id, toState: switchToState }); + try { + var UploadId = task && task.params && task.params.UploadData.UploadId; + } catch (e) {} + if (switchToState === 'canceled' && UploadId) session.removeUsing(UploadId); + emitListUpdate(); + if (running) { + uploadingFileCount--; + startNextTask(); + } + if (switchToState === 'canceled') { + if (task.params) { + delete task.params.UploadData; + delete task.params.Body; + delete task.params; } + delete task.callback; + } + } + clearQueue(); + }; + + cos._addTasks = function (taskList) { + util.each(taskList, function (task) { + cos._addTask(task.api, task.params, task.callback, true); + }); + emitListUpdate(); + }; + + var isTaskReadyWarning = true; + cos._addTask = function (api, params, callback, ignoreAddEvent) { + // 复制参数对象 + params = util.formatParams(api, params); + + // 生成 id + var id = util.uuid(); + params.TaskId = id; + params.onTaskReady && params.onTaskReady(id); + if (params.TaskReady) { + params.TaskReady(id); + isTaskReadyWarning && + console.warn('warning: Param "TaskReady" has been deprecated. Please use "onTaskReady" instead.'); + isTaskReadyWarning = false; + } + + var task = { + // env + params: params, + callback: callback, + api: api, + index: queue.length, + // task + id: id, + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + FilePath: params.FilePath || '', + state: 'waiting', + loaded: 0, + size: 0, + speed: 0, + percent: 0, + hashPercent: 0, + error: null, + }; + var onHashProgress = params.onHashProgress; + params.onHashProgress = function (info) { + if (!cos._isRunningTask(task.id)) return; + task.hashPercent = info.percent; + onHashProgress && onHashProgress(info); + emitListUpdate(); }; - cos.isUploadRunning = function () { - return uploadingFileCount || nextUploadIndex < queue.length; + var onProgress = params.onProgress; + params.onProgress = function (info) { + if (!cos._isRunningTask(task.id)) return; + task.state === 'checking' && (task.state = 'uploading'); + task.loaded = info.loaded; + task.speed = info.speed; + task.percent = info.percent; + onProgress && onProgress(info); + emitListUpdate(); }; + // 异步获取 filesize + util.getFileSize(api, params, function (err, size) { + // 开始处理上传 + if (err) return callback(util.error(err)); // 如果获取大小出错,不加入队列 + // 获取完文件大小再把任务加入队列 + tasks[id] = task; + queue.push(task); + task.size = size; + !ignoreAddEvent && emitListUpdate(); + startNextTask(); + clearQueue(); + }); + return id; + }; + cos._isRunningTask = function (id) { + var task = tasks[id]; + return !!(task && (task.state === 'checking' || task.state === 'uploading')); + }; + cos.getTaskList = function () { + return util.map(queue, formatTask); + }; + cos.cancelTask = function (id) { + killTask(id, 'canceled'); + }; + cos.pauseTask = function (id) { + killTask(id, 'paused'); + }; + cos.restartTask = function (id) { + var task = tasks[id]; + if (task && (task.state === 'paused' || task.state === 'error')) { + task.state = 'waiting'; + emitListUpdate(); + nextUploadIndex = Math.min(nextUploadIndex, task.index); + startNextTask(); + } + }; + cos.isUploadRunning = function () { + return uploadingFileCount || nextUploadIndex < queue.length; + }; }; module.exports.transferToTaskMethod = transferToTaskMethod; diff --git a/sdk/util.js b/sdk/util.js index 7dce856..3b557c9 100644 --- a/sdk/util.js +++ b/sdk/util.js @@ -11,26 +11,26 @@ var xmlParser = new XMLParser({ var xmlBuilder = new XMLBuilder(); function camSafeUrlEncode(str) { - return encodeURIComponent(str) - .replace(/!/g, '%21') - .replace(/'/g, '%27') - .replace(/\(/g, '%28') - .replace(/\)/g, '%29') - .replace(/\*/g, '%2A'); + return encodeURIComponent(str) + .replace(/!/g, '%21') + .replace(/'/g, '%27') + .replace(/\(/g, '%28') + .replace(/\)/g, '%29') + .replace(/\*/g, '%2A'); } var getObjectKeys = function (obj, forKey) { - var list = []; - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - list.push(forKey ? camSafeUrlEncode(key).toLowerCase() : key); - } + var list = []; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + list.push(forKey ? camSafeUrlEncode(key).toLowerCase() : key); } - return list.sort(function (a, b) { - a = a.toLowerCase(); - b = b.toLowerCase(); - return a === b ? 0 : (a > b ? 1 : -1); - }); + } + return list.sort(function (a, b) { + a = a.toLowerCase(); + b = b.toLowerCase(); + return a === b ? 0 : a > b ? 1 : -1; + }); }; /** @@ -40,688 +40,736 @@ var getObjectKeys = function (obj, forKey) { * @return {String} data 返回字符串 */ var obj2str = function (obj, lowerCaseKey) { - var i, key, val; - var list = []; - var keyList = getObjectKeys(obj); - for (i = 0; i < keyList.length; i++) { - key = keyList[i]; - val = (obj[key] === undefined || obj[key] === null) ? '' : ('' + obj[key]); - key = lowerCaseKey? camSafeUrlEncode(key).toLowerCase() : camSafeUrlEncode(key); - val = camSafeUrlEncode(val) || ''; - list.push(key + '=' + val) - } - return list.join('&'); + var i, key, val; + var list = []; + var keyList = getObjectKeys(obj); + for (i = 0; i < keyList.length; i++) { + key = keyList[i]; + val = obj[key] === undefined || obj[key] === null ? '' : '' + obj[key]; + key = lowerCaseKey ? camSafeUrlEncode(key).toLowerCase() : camSafeUrlEncode(key); + val = camSafeUrlEncode(val) || ''; + list.push(key + '=' + val); + } + return list.join('&'); }; // 可以签入签名的headers -var signHeaders = ['content-disposition', 'content-encoding', 'content-length', 'content-md5', - 'expect', 'expires', 'host', 'if-match', 'if-modified-since', 'if-none-match', 'if-unmodified-since', - 'origin', 'range', 'transfer-encoding']; +var signHeaders = [ + 'content-disposition', + 'content-encoding', + 'content-length', + 'content-md5', + 'expect', + 'expires', + 'host', + 'if-match', + 'if-modified-since', + 'if-none-match', + 'if-unmodified-since', + 'origin', + 'range', + 'transfer-encoding', +]; var getSignHeaderObj = function (headers) { - var signHeaderObj = {}; - for (var i in headers) { - var key = i.toLowerCase(); - if (key.indexOf('x-cos-') > -1 || signHeaders.indexOf(key) > -1) { - signHeaderObj[i] = headers[i]; - } + var signHeaderObj = {}; + for (var i in headers) { + var key = i.toLowerCase(); + if (key.indexOf('x-cos-') > -1 || signHeaders.indexOf(key) > -1) { + signHeaderObj[i] = headers[i]; } - return signHeaderObj; -} + } + return signHeaderObj; +}; //测试用的key后面可以去掉 var getAuth = function (opt) { - opt = opt || {}; - - var SecretId = opt.SecretId; - var SecretKey = opt.SecretKey; - var KeyTime = opt.KeyTime; - var method = (opt.method || opt.Method || 'get').toLowerCase(); - var queryParams = clone(opt.Query || opt.params || {}); - var headers = getSignHeaderObj(clone(opt.Headers || opt.headers || {})); - - var Key = opt.Key || ''; - var pathname; - if (opt.UseRawKey) { - pathname = opt.Pathname || opt.pathname || '/' + Key; - } else { - pathname = opt.Pathname || opt.pathname || Key; - pathname.indexOf('/') !== 0 && (pathname = '/' + pathname); - } - - // ForceSignHost明确传入false才不加入host签名 - var forceSignHost = opt.ForceSignHost === false ? false : true; - - // 如果有传入存储桶,那么签名默认加 Host 参与计算,避免跨桶访问 - if (!headers.Host && !headers.host && opt.Bucket && opt.Region && forceSignHost) headers.Host = opt.Bucket + '.cos.' + opt.Region + '.myqcloud.com'; - - if (!SecretId) throw new Error('missing param SecretId'); - if (!SecretKey) throw new Error('missing param SecretKey'); - - // 签名有效起止时间 - var now = Math.round(getSkewTime(opt.SystemClockOffset) / 1000) - 1; - var exp = now; - - var Expires = opt.Expires || opt.expires; - if (Expires === undefined) { - exp += 900; // 签名过期时间为当前 + 900s - } else { - exp += (Expires * 1) || 0; - } - - // 要用到的 Authorization 参数列表 - var qSignAlgorithm = 'sha1'; - var qAk = SecretId; - var qSignTime = KeyTime || now + ';' + exp; - var qKeyTime = KeyTime || now + ';' + exp; - var qHeaderList = getObjectKeys(headers, true).join(';').toLowerCase(); - var qUrlParamList = getObjectKeys(queryParams, true).join(';').toLowerCase(); - - // 签名算法说明文档:https://www.qcloud.com/document/product/436/7778 - // 步骤一:计算 SignKey - var signKey = crypto.createHmac('sha1', SecretKey).update(qKeyTime).digest('hex'); - - // 步骤二:构成 FormatString - var formatString = [method, pathname, obj2str(queryParams, true), obj2str(headers, true), ''].join('\n'); - formatString = Buffer.from(formatString, 'utf8'); - - // 步骤三:计算 StringToSign - var res = crypto.createHash('sha1').update(formatString).digest('hex'); - var stringToSign = ['sha1', qSignTime, res, ''].join('\n'); - - // 步骤四:计算 Signature - var qSignature = crypto.createHmac('sha1', signKey).update(stringToSign).digest('hex'); - - // 步骤五:构造 Authorization - var authorization = [ - 'q-sign-algorithm=' + qSignAlgorithm, - 'q-ak=' + qAk, - 'q-sign-time=' + qSignTime, - 'q-key-time=' + qKeyTime, - 'q-header-list=' + qHeaderList, - 'q-url-param-list=' + qUrlParamList, - 'q-signature=' + qSignature - ].join('&'); - - return authorization; - + opt = opt || {}; + + var SecretId = opt.SecretId; + var SecretKey = opt.SecretKey; + var KeyTime = opt.KeyTime; + var method = (opt.method || opt.Method || 'get').toLowerCase(); + var queryParams = clone(opt.Query || opt.params || {}); + var headers = getSignHeaderObj(clone(opt.Headers || opt.headers || {})); + + var Key = opt.Key || ''; + var pathname; + if (opt.UseRawKey) { + pathname = opt.Pathname || opt.pathname || '/' + Key; + } else { + pathname = opt.Pathname || opt.pathname || Key; + pathname.indexOf('/') !== 0 && (pathname = '/' + pathname); + } + + // ForceSignHost明确传入false才不加入host签名 + var forceSignHost = opt.ForceSignHost === false ? false : true; + + // 如果有传入存储桶,那么签名默认加 Host 参与计算,避免跨桶访问 + if (!headers.Host && !headers.host && opt.Bucket && opt.Region && forceSignHost) + headers.Host = opt.Bucket + '.cos.' + opt.Region + '.myqcloud.com'; + + if (!SecretId) throw new Error('missing param SecretId'); + if (!SecretKey) throw new Error('missing param SecretKey'); + + // 签名有效起止时间 + var now = Math.round(getSkewTime(opt.SystemClockOffset) / 1000) - 1; + var exp = now; + + var Expires = opt.Expires || opt.expires; + if (Expires === undefined) { + exp += 900; // 签名过期时间为当前 + 900s + } else { + exp += Expires * 1 || 0; + } + + // 要用到的 Authorization 参数列表 + var qSignAlgorithm = 'sha1'; + var qAk = SecretId; + var qSignTime = KeyTime || now + ';' + exp; + var qKeyTime = KeyTime || now + ';' + exp; + var qHeaderList = getObjectKeys(headers, true).join(';').toLowerCase(); + var qUrlParamList = getObjectKeys(queryParams, true).join(';').toLowerCase(); + + // 签名算法说明文档:https://www.qcloud.com/document/product/436/7778 + // 步骤一:计算 SignKey + var signKey = crypto.createHmac('sha1', SecretKey).update(qKeyTime).digest('hex'); + + // 步骤二:构成 FormatString + var formatString = [method, pathname, obj2str(queryParams, true), obj2str(headers, true), ''].join('\n'); + formatString = Buffer.from(formatString, 'utf8'); + + // 步骤三:计算 StringToSign + var res = crypto.createHash('sha1').update(formatString).digest('hex'); + var stringToSign = ['sha1', qSignTime, res, ''].join('\n'); + + // 步骤四:计算 Signature + var qSignature = crypto.createHmac('sha1', signKey).update(stringToSign).digest('hex'); + + // 步骤五:构造 Authorization + var authorization = [ + 'q-sign-algorithm=' + qSignAlgorithm, + 'q-ak=' + qAk, + 'q-sign-time=' + qSignTime, + 'q-key-time=' + qKeyTime, + 'q-header-list=' + qHeaderList, + 'q-url-param-list=' + qUrlParamList, + 'q-signature=' + qSignature, + ].join('&'); + + return authorization; }; var getV4Auth = function (opt) { - - if (!opt.SecretId) return console.error('missing param SecretId'); - if (!opt.SecretKey) return console.error('missing param SecretKey'); - if (!opt.Bucket) return console.error('missing param Bucket'); - - var longBucket = opt.Bucket; - var ShortBucket = longBucket.substr(0, longBucket.lastIndexOf('-')); - var AppId = longBucket.substr(longBucket.lastIndexOf('-') + 1); - var random = Math.round(Math.random() * Math.pow(2, 32)); - var now = Math.round(Date.now() / 1000); - var e = now + (opt.Expires === undefined ? 900 : opt.Expires); - var path = '/' + AppId + '/' + ShortBucket + '/' + encodeURIComponent((opt.Key || '').replace(/(^\/*)/g, '')).replace(/%2F/g, '/'); - var plainText = 'a=' + AppId + '&b=' + ShortBucket + '&k=' + opt.SecretId + '&t=' + now + '&e=' + e + '&r=' + random + '&f=' + path; - var signKey = crypto.createHmac("sha1", opt.SecretKey).update(plainText).digest(); - var sign = Buffer.concat([signKey, Buffer.from(plainText)]).toString("base64"); - return sign; + if (!opt.SecretId) return console.error('missing param SecretId'); + if (!opt.SecretKey) return console.error('missing param SecretKey'); + if (!opt.Bucket) return console.error('missing param Bucket'); + + var longBucket = opt.Bucket; + var ShortBucket = longBucket.substr(0, longBucket.lastIndexOf('-')); + var AppId = longBucket.substr(longBucket.lastIndexOf('-') + 1); + var random = Math.round(Math.random() * Math.pow(2, 32)); + var now = Math.round(Date.now() / 1000); + var e = now + (opt.Expires === undefined ? 900 : opt.Expires); + var path = + '/' + + AppId + + '/' + + ShortBucket + + '/' + + encodeURIComponent((opt.Key || '').replace(/(^\/*)/g, '')).replace(/%2F/g, '/'); + var plainText = + 'a=' + AppId + '&b=' + ShortBucket + '&k=' + opt.SecretId + '&t=' + now + '&e=' + e + '&r=' + random + '&f=' + path; + var signKey = crypto.createHmac('sha1', opt.SecretKey).update(plainText).digest(); + var sign = Buffer.concat([signKey, Buffer.from(plainText)]).toString('base64'); + return sign; }; var getSourceParams = function (source) { - var parser = this.options.CopySourceParser; - if (parser) return parser(source); - var m = source.match(/^([^.]+-\d+)\.cos(v6|-cdc|-internal)?\.([^.]+)\.((myqcloud\.com)|(tencentcos\.cn))\/(.+)$/); - if (!m) return null; - return { Bucket: m[1], Region: m[3], Key: m[7] }; + var parser = this.options.CopySourceParser; + if (parser) return parser(source); + var m = source.match(/^([^.]+-\d+)\.cos(v6|-cdc|-internal)?\.([^.]+)\.((myqcloud\.com)|(tencentcos\.cn))\/(.+)$/); + if (!m) return null; + return { Bucket: m[1], Region: m[3], Key: m[7] }; }; -var noop = function () { - -}; +var noop = function () {}; // 清除对象里值为的 undefined 或 null 的属性 var clearKey = function (obj) { - var retObj = {}; - for (var key in obj) { - if (obj.hasOwnProperty(key) && obj[key] !== undefined && obj[key] !== null) { - retObj[key] = obj[key]; - } + var retObj = {}; + for (var key in obj) { + if (obj.hasOwnProperty(key) && obj[key] !== undefined && obj[key] !== null) { + retObj[key] = obj[key]; } - return retObj; + } + return retObj; }; // XML 对象转 JSON 对象 var xml2json = function (bodyStr) { - var d = xmlParser.parse(bodyStr); + var d = xmlParser.parse(bodyStr); - return d; + return d; }; // JSON 对象转 XML 对象 var json2xml = function (json) { - var xml = xmlBuilder.build(json); - return xml; + var xml = xmlBuilder.build(json); + return xml; }; // 计算 MD5 var md5 = function (str, encoding) { - return crypto.createHash('md5').update(str).digest(encoding || 'hex'); + return crypto + .createHash('md5') + .update(str) + .digest(encoding || 'hex'); }; // 获取文件分片 var fileSlice = function (FilePath, start, end, callback) { - if (FilePath) { - try { - var readStream = fs.createReadStream(FilePath, {start: start, end: end - 1}); - readStream.isSdkCreated = true; - callback(readStream); - } catch(e) { - } - } else { - callback(null); - } + if (FilePath) { + try { + var readStream = fs.createReadStream(FilePath, { start: start, end: end - 1 }); + readStream.isSdkCreated = true; + callback(readStream); + } catch (e) {} + } else { + callback(null); + } }; // 获取文件内容的 MD5 var getBodyMd5 = function (UploadCheckContentMd5, Body, callback) { - callback = callback || noop; - if (UploadCheckContentMd5) { - if (Body instanceof Buffer || typeof Body === 'string') { - callback(util.md5(Body)); - } else { - callback(); - } + callback = callback || noop; + if (UploadCheckContentMd5) { + if (Body instanceof Buffer || typeof Body === 'string') { + callback(util.md5(Body)); } else { - callback(); + callback(); } + } else { + callback(); + } }; // 获取文件 md5 值 var getFileMd5 = function (readStream, callback) { - var md5 = crypto.createHash('md5'); - readStream.on('data', function (chunk) { - md5.update(chunk); - }); - readStream.on('error', function (err) { - callback(util.error(err)); - }); - readStream.on('end', function () { - var hash = md5.digest('hex'); - callback(null, hash); - }); + var md5 = crypto.createHash('md5'); + readStream.on('data', function (chunk) { + md5.update(chunk); + }); + readStream.on('error', function (err) { + callback(util.error(err)); + }); + readStream.on('end', function () { + var hash = md5.digest('hex'); + callback(null, hash); + }); }; function clone(obj) { - return map(obj, function (v) { - return typeof v === 'object' && v !== null ? clone(v) : v; - }); + return map(obj, function (v) { + return typeof v === 'object' && v !== null ? clone(v) : v; + }); } function attr(obj, name, defaultValue) { - return obj && name in obj ? obj[name] : defaultValue; + return obj && name in obj ? obj[name] : defaultValue; } function extend(target, source) { - each(source, function (val, key) { - target[key] = source[key]; - }); - return target; + each(source, function (val, key) { + target[key] = source[key]; + }); + return target; } function isArray(arr) { - return arr instanceof Array; + return arr instanceof Array; } function isInArray(arr, item) { - var flag = false; - for (var i = 0; i < arr.length; i++) { - if (item === arr[i]) { - flag = true; - break; - } + var flag = false; + for (var i = 0; i < arr.length; i++) { + if (item === arr[i]) { + flag = true; + break; } - return flag; + } + return flag; } function makeArray(arr) { - return isArray(arr) ? arr : [arr]; + return isArray(arr) ? arr : [arr]; } function each(obj, fn) { - for (var i in obj) { - if (obj.hasOwnProperty(i)) { - fn(obj[i], i); - } + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + fn(obj[i], i); } + } } function map(obj, fn) { - var o = isArray(obj) ? [] : {}; - for (var i in obj) { - if (obj.hasOwnProperty(i)) { - o[i] = fn(obj[i], i); - } + var o = isArray(obj) ? [] : {}; + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + o[i] = fn(obj[i], i); } - return o; + } + return o; } function filter(obj, fn) { - var iaArr = isArray(obj); - var o = iaArr ? [] : {}; - for (var i in obj) { - if (obj.hasOwnProperty(i)) { - if (fn(obj[i], i)) { - if (iaArr) { - o.push(obj[i]); - } else { - o[i] = obj[i]; - } - } + var iaArr = isArray(obj); + var o = iaArr ? [] : {}; + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + if (fn(obj[i], i)) { + if (iaArr) { + o.push(obj[i]); + } else { + o[i] = obj[i]; } + } } - return o; + } + return o; } var binaryBase64 = function (str) { - var i, len, char, arr = []; - for (i = 0, len = str.length / 2; i < len; i++) { - char = parseInt(str[i * 2] + str[i * 2 + 1], 16); - arr.push(char); - } - return Buffer.from(arr).toString('base64'); + var i, + len, + char, + arr = []; + for (i = 0, len = str.length / 2; i < len; i++) { + char = parseInt(str[i * 2] + str[i * 2 + 1], 16); + arr.push(char); + } + return Buffer.from(arr).toString('base64'); }; var uuid = function () { - var S4 = function () { - return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); - }; - return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4()); + var S4 = function () { + return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); + }; + return S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4(); }; var hasMissingParams = function (apiName, params) { - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - if (apiName.indexOf('Bucket') > -1 || apiName === 'deleteMultipleObject' || apiName === 'multipartList' || apiName === 'listObjectVersions') { - if (!Bucket) return 'Bucket'; - if (!Region) return 'Region'; - } else if (apiName.indexOf('Object') > -1 || apiName.indexOf('multipart') > -1 || apiName === 'sliceUploadFile' || apiName === 'abortUploadTask') { - if (!Bucket) return 'Bucket'; - if (!Region) return 'Region'; - if (!Key) return 'Key'; - } - return false; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + if ( + apiName.indexOf('Bucket') > -1 || + apiName === 'deleteMultipleObject' || + apiName === 'multipartList' || + apiName === 'listObjectVersions' + ) { + if (!Bucket) return 'Bucket'; + if (!Region) return 'Region'; + } else if ( + apiName.indexOf('Object') > -1 || + apiName.indexOf('multipart') > -1 || + apiName === 'sliceUploadFile' || + apiName === 'abortUploadTask' + ) { + if (!Bucket) return 'Bucket'; + if (!Region) return 'Region'; + if (!Key) return 'Key'; + } + return false; }; var formatParams = function (apiName, params) { - - // 复制参数对象 - params = extend({}, params); - - // 统一处理 Headers - if (apiName !== 'getAuth' && apiName !== 'getV4Auth' && apiName !== 'getObjectUrl') { - var Headers = params.Headers || {}; - if (params && typeof params === 'object') { - (function () { - for (var key in params) { - if (params.hasOwnProperty(key) && key.indexOf('x-cos-') > -1) { - Headers[key] = params[key]; - } - } - })(); - - var headerMap = { - // params headers - 'x-cos-mfa': 'MFA', - 'Content-MD5': 'ContentMD5', - 'Content-Length': 'ContentLength', - 'Content-Type': 'ContentType', - 'Expect': 'Expect', - 'Expires': 'Expires', - 'Cache-Control': 'CacheControl', - 'Content-Disposition': 'ContentDisposition', - 'Content-Encoding': 'ContentEncoding', - 'Range': 'Range', - 'If-Modified-Since': 'IfModifiedSince', - 'If-Unmodified-Since': 'IfUnmodifiedSince', - 'If-Match': 'IfMatch', - 'If-None-Match': 'IfNoneMatch', - 'x-cos-copy-source': 'CopySource', - 'x-cos-copy-source-Range': 'CopySourceRange', - 'x-cos-metadata-directive': 'MetadataDirective', - 'x-cos-copy-source-If-Modified-Since': 'CopySourceIfModifiedSince', - 'x-cos-copy-source-If-Unmodified-Since': 'CopySourceIfUnmodifiedSince', - 'x-cos-copy-source-If-Match': 'CopySourceIfMatch', - 'x-cos-copy-source-If-None-Match': 'CopySourceIfNoneMatch', - 'x-cos-acl': 'ACL', - 'x-cos-grant-read': 'GrantRead', - 'x-cos-grant-write': 'GrantWrite', - 'x-cos-grant-full-control': 'GrantFullControl', - 'x-cos-grant-read-acp': 'GrantReadAcp', - 'x-cos-grant-write-acp': 'GrantWriteAcp', - 'x-cos-storage-class': 'StorageClass', - 'x-cos-traffic-limit': 'TrafficLimit', - 'x-cos-mime-limit': 'MimeLimit', - // SSE-C - 'x-cos-server-side-encryption-customer-algorithm': 'SSECustomerAlgorithm', - 'x-cos-server-side-encryption-customer-key': 'SSECustomerKey', - 'x-cos-server-side-encryption-customer-key-MD5': 'SSECustomerKeyMD5', - // SSE-COS、SSE-KMS - 'x-cos-server-side-encryption': 'ServerSideEncryption', - 'x-cos-server-side-encryption-cos-kms-key-id': 'SSEKMSKeyId', - 'x-cos-server-side-encryption-context': 'SSEContext', - }; - util.each(headerMap, function (paramKey, headerKey) { - if (params[paramKey] !== undefined) { - Headers[headerKey] = params[paramKey]; - } - }); - - params.Headers = clearKey(Headers); + // 复制参数对象 + params = extend({}, params); + + // 统一处理 Headers + if (apiName !== 'getAuth' && apiName !== 'getV4Auth' && apiName !== 'getObjectUrl') { + var Headers = params.Headers || {}; + if (params && typeof params === 'object') { + (function () { + for (var key in params) { + if (params.hasOwnProperty(key) && key.indexOf('x-cos-') > -1) { + Headers[key] = params[key]; + } + } + })(); + + var headerMap = { + // params headers + 'x-cos-mfa': 'MFA', + 'Content-MD5': 'ContentMD5', + 'Content-Length': 'ContentLength', + 'Content-Type': 'ContentType', + Expect: 'Expect', + Expires: 'Expires', + 'Cache-Control': 'CacheControl', + 'Content-Disposition': 'ContentDisposition', + 'Content-Encoding': 'ContentEncoding', + Range: 'Range', + 'If-Modified-Since': 'IfModifiedSince', + 'If-Unmodified-Since': 'IfUnmodifiedSince', + 'If-Match': 'IfMatch', + 'If-None-Match': 'IfNoneMatch', + 'x-cos-copy-source': 'CopySource', + 'x-cos-copy-source-Range': 'CopySourceRange', + 'x-cos-metadata-directive': 'MetadataDirective', + 'x-cos-copy-source-If-Modified-Since': 'CopySourceIfModifiedSince', + 'x-cos-copy-source-If-Unmodified-Since': 'CopySourceIfUnmodifiedSince', + 'x-cos-copy-source-If-Match': 'CopySourceIfMatch', + 'x-cos-copy-source-If-None-Match': 'CopySourceIfNoneMatch', + 'x-cos-acl': 'ACL', + 'x-cos-grant-read': 'GrantRead', + 'x-cos-grant-write': 'GrantWrite', + 'x-cos-grant-full-control': 'GrantFullControl', + 'x-cos-grant-read-acp': 'GrantReadAcp', + 'x-cos-grant-write-acp': 'GrantWriteAcp', + 'x-cos-storage-class': 'StorageClass', + 'x-cos-traffic-limit': 'TrafficLimit', + 'x-cos-mime-limit': 'MimeLimit', + // SSE-C + 'x-cos-server-side-encryption-customer-algorithm': 'SSECustomerAlgorithm', + 'x-cos-server-side-encryption-customer-key': 'SSECustomerKey', + 'x-cos-server-side-encryption-customer-key-MD5': 'SSECustomerKeyMD5', + // SSE-COS、SSE-KMS + 'x-cos-server-side-encryption': 'ServerSideEncryption', + 'x-cos-server-side-encryption-cos-kms-key-id': 'SSEKMSKeyId', + 'x-cos-server-side-encryption-context': 'SSEContext', + }; + util.each(headerMap, function (paramKey, headerKey) { + if (params[paramKey] !== undefined) { + Headers[headerKey] = params[paramKey]; } + }); + + params.Headers = clearKey(Headers); } + } - return params; + return params; }; var apiWrapper = function (apiName, apiFn) { - return function (params, callback) { - - var self = this; + return function (params, callback) { + var self = this; - // 处理参数 - if (typeof params === 'function') { - callback = params; - params = {}; - } + // 处理参数 + if (typeof params === 'function') { + callback = params; + params = {}; + } - // 整理参数格式 - params = formatParams(apiName, params); + // 整理参数格式 + params = formatParams(apiName, params); + + // 代理回调函数 + var formatResult = function (result) { + if (result && result.headers) { + result.headers['x-cos-request-id'] && (result.RequestId = result.headers['x-cos-request-id']); + result.headers['x-ci-request-id'] && (result.RequestId = result.headers['x-ci-request-id']); + result.headers['x-cos-version-id'] && (result.VersionId = result.headers['x-cos-version-id']); + result.headers['x-cos-delete-marker'] && (result.DeleteMarker = result.headers['x-cos-delete-marker']); + } + return result; + }; + var _callback = function (err, data) { + callback && callback(formatResult(err), formatResult(data)); + }; - // 代理回调函数 - var formatResult = function (result) { - if (result && result.headers) { - result.headers['x-cos-request-id'] && (result.RequestId = result.headers['x-cos-request-id']); - result.headers['x-ci-request-id'] && (result.RequestId = result.headers['x-ci-request-id']); - result.headers['x-cos-version-id'] && (result.VersionId = result.headers['x-cos-version-id']); - result.headers['x-cos-delete-marker'] && (result.DeleteMarker = result.headers['x-cos-delete-marker']); + var checkParams = function () { + if (apiName !== 'getService' && apiName !== 'abortUploadTask') { + // 判断参数是否完整 + var missingResult = hasMissingParams(apiName, params); + if (missingResult) { + return 'missing param ' + missingResult; + } + // 判断 region 格式 + if (params.Region) { + if (params.Region.indexOf('cos.') > -1) { + return 'param Region should not be start with "cos."'; + } else if (!/^([a-z\d-]+)$/.test(params.Region)) { + return 'Region format error.'; + } + // 判断 region 格式 + if ( + !self.options.CompatibilityMode && + params.Region.indexOf('-') === -1 && + params.Region !== 'yfb' && + params.Region !== 'default' && + params.Region !== 'accelerate' + ) { + console.warn( + 'warning: param Region format error, find help here: https://cloud.tencent.com/document/product/436/6224', + ); + } + } + // 兼容不带 AppId 的 Bucket + if (params.Bucket) { + if (!/^([a-z\d-]+)-(\d+)$/.test(params.Bucket)) { + if (params.AppId) { + params.Bucket = params.Bucket + '-' + params.AppId; + } else if (self.options.AppId) { + params.Bucket = params.Bucket + '-' + self.options.AppId; + } else { + return 'Bucket should format as "test-1250000000".'; } - return result; - }; - var _callback = function (err, data) { - callback && callback(formatResult(err), formatResult(data)); - }; + } + if (params.AppId) { + console.warn( + 'warning: AppId has been deprecated, Please put it at the end of parameter Bucket(E.g Bucket:"test-1250000000" ).', + ); + delete params.AppId; + } + } + // 如果 Key 是 / 开头,强制去掉第一个 / + if (!self.options.UseRawKey && params.Key && params.Key.substr(0, 1) === '/') { + params.Key = params.Key.substr(1); + } + } + }; - var checkParams = function () { - if (apiName !== 'getService' && apiName !== 'abortUploadTask') { - // 判断参数是否完整 - var missingResult = hasMissingParams(apiName, params) - if (missingResult) { - return 'missing param ' + missingResult; - } - // 判断 region 格式 - if (params.Region) { - if (params.Region.indexOf('cos.') > -1) { - return 'param Region should not be start with "cos."'; - } else if (!/^([a-z\d-]+)$/.test(params.Region)) { - return 'Region format error.'; - } - // 判断 region 格式 - if (!self.options.CompatibilityMode - && params.Region.indexOf('-') === -1 - && params.Region !== 'yfb' - && params.Region !== 'default' - && params.Region !== 'accelerate') { - console.warn('warning: param Region format error, find help here: https://cloud.tencent.com/document/product/436/6224'); - } - } - // 兼容不带 AppId 的 Bucket - if (params.Bucket) { - if (!/^([a-z\d-]+)-(\d+)$/.test(params.Bucket)) { - if (params.AppId) { - params.Bucket = params.Bucket + '-' + params.AppId; - } else if (self.options.AppId) { - params.Bucket = params.Bucket + '-' + self.options.AppId; - } else { - return 'Bucket should format as "test-1250000000".'; - } - } - if (params.AppId) { - console.warn('warning: AppId has been deprecated, Please put it at the end of parameter Bucket(E.g Bucket:"test-1250000000" ).'); - delete params.AppId; - } - } - // 如果 Key 是 / 开头,强制去掉第一个 / - if (!self.options.UseRawKey && params.Key && params.Key.substr(0, 1) === '/') { - params.Key = params.Key.substr(1); - } - } + var errMsg = checkParams(); + var isSync = ['getAuth', 'getV4Auth', 'getObjectUrl'].includes(apiName) || apiName.indexOf('Stream') > -1; + if (Promise && !isSync && !callback) { + return new Promise(function (resolve, reject) { + callback = function (err, data) { + err ? reject(err) : resolve(data); }; - - var errMsg = checkParams(); - var isSync = ['getAuth', 'getV4Auth', 'getObjectUrl'].includes(apiName) || apiName.indexOf('Stream') > -1; - if (Promise && !isSync && !callback) { - return new Promise(function (resolve, reject) { - callback = function (err, data) { - err ? reject(err) : resolve(data); - }; - if (errMsg) return _callback(util.error(new Error(errMsg))); - apiFn.call(self, params, _callback); - }); - } else { - if (errMsg) return _callback(util.error(new Error(errMsg))); - var res = apiFn.call(self, params, _callback); - if (isSync) return res; - } + if (errMsg) return _callback(util.error(new Error(errMsg))); + apiFn.call(self, params, _callback); + }); + } else { + if (errMsg) return _callback(util.error(new Error(errMsg))); + var res = apiFn.call(self, params, _callback); + if (isSync) return res; } + }; }; var throttleOnProgress = function (total, onProgress) { - var self = this; - var size0 = 0; - var size1 = 0; - var time0 = Date.now(); - var time1; - var timer; - - function update() { - timer = 0; - if (onProgress && (typeof onProgress === 'function')) { - time1 = Date.now(); - var speed = Math.max(0, Math.round((size1 - size0) / ((time1 - time0) / 1000) * 100) / 100) || 0; - var percent; - if (size1 === 0 && total === 0) { - percent = 1; - } else { - percent = Math.floor(size1 / total * 100) / 100 || 0; - } - time0 = time1; - size0 = size1; - try { - onProgress({loaded: size1, total: total, speed: speed, percent: percent}); - } catch (e) { - } - } + var self = this; + var size0 = 0; + var size1 = 0; + var time0 = Date.now(); + var time1; + var timer; + + function update() { + timer = 0; + if (onProgress && typeof onProgress === 'function') { + time1 = Date.now(); + var speed = Math.max(0, Math.round(((size1 - size0) / ((time1 - time0) / 1000)) * 100) / 100) || 0; + var percent; + if (size1 === 0 && total === 0) { + percent = 1; + } else { + percent = Math.floor((size1 / total) * 100) / 100 || 0; + } + time0 = time1; + size0 = size1; + try { + onProgress({ loaded: size1, total: total, speed: speed, percent: percent }); + } catch (e) {} } + } - return function (info, immediately) { - if (info) { - size1 = info.loaded; - total = info.total; - } - if (immediately) { - clearTimeout(timer); - update(); - } else { - if (timer) return; - timer = setTimeout(update, self.options.ProgressInterval); - } - }; + return function (info, immediately) { + if (info) { + size1 = info.loaded; + total = info.total; + } + if (immediately) { + clearTimeout(timer); + update(); + } else { + if (timer) return; + timer = setTimeout(update, self.options.ProgressInterval); + } + }; }; var getFileSize = function (api, params, callback) { - var size; - if (api === 'sliceUploadFile') { - if (params.FilePath) { - fs.stat(params.FilePath, function (err, fileStats) { - if (err) { - if (params.ContentLength !== undefined) { - size = params.ContentLength; - } else { - return callback(err); - } - } else { - params.FileStat = fileStats; - params.FileStat.FilePath = params.FilePath; - size = fileStats.isDirectory() ? 0 : fileStats.size; - } - params.ContentLength = size = size || 0; - callback(null, size); - }); - return; + var size; + if (api === 'sliceUploadFile') { + if (params.FilePath) { + fs.stat(params.FilePath, function (err, fileStats) { + if (err) { + if (params.ContentLength !== undefined) { + size = params.ContentLength; + } else { + return callback(err); + } } else { - callback(util.error(new Error('missing param FilePath'))); - return; + params.FileStat = fileStats; + params.FileStat.FilePath = params.FilePath; + size = fileStats.isDirectory() ? 0 : fileStats.size; } + params.ContentLength = size = size || 0; + callback(null, size); + }); + return; } else { - if (params.Body !== undefined) { - if (typeof params.Body === 'string') { - params.Body = global.Buffer.from(params.Body); - } - if (params.Body instanceof global.Buffer) { - size = params.Body.length; - } else if (typeof params.Body.pipe === 'function') { - if (params.ContentLength === undefined) { - size = undefined; - } else { - size = params.ContentLength; - } - } else { - callback(util.error(new Error('params Body format error, Only allow Buffer|Stream|String.'))); - return; - } + callback(util.error(new Error('missing param FilePath'))); + return; + } + } else { + if (params.Body !== undefined) { + if (typeof params.Body === 'string') { + params.Body = global.Buffer.from(params.Body); + } + if (params.Body instanceof global.Buffer) { + size = params.Body.length; + } else if (typeof params.Body.pipe === 'function') { + if (params.ContentLength === undefined) { + size = undefined; } else { - callback(util.error(new Error('missing param Body'))); - return; + size = params.ContentLength; } + } else { + callback(util.error(new Error('params Body format error, Only allow Buffer|Stream|String.'))); + return; + } + } else { + callback(util.error(new Error('missing param Body'))); + return; } - params.ContentLength = size; - callback(null, size); + } + params.ContentLength = size; + callback(null, size); }; // 获取调正的时间戳 var getSkewTime = function (offset) { - return Date.now() + (offset || 0); + return Date.now() + (offset || 0); }; // 重写 callback,等待流结束后才 callback var callbackAfterStreamFinish = function (stream, callback) { - if (!stream) return callback; - var err, data, count = 2, loaded = false; - var cb = function (e, d) { - if (loaded) return; - // 如果有数据,且没有错误,清理 设置错误 - if (d && !data || e || err) { - data = d; - } - if (e && !err) { - err = e; - data = null; - } - if (err || --count === 0) { - loaded = true; - callback(err, data); - } - }; - stream.on('error', function (err) { - cb(err); - }); - stream.on('finish', function () { - cb(); - }); - return cb; -}; - -var error = function (err, opt) { - var sourceErr = err; - err.message = err.message || null; - - if (typeof opt === 'string') { - err.error = opt; - err.message = opt; - } else if (typeof opt === 'object' && opt !== null) { - extend(err, opt); - if (opt.code || opt.name) err.code = opt.code || opt.name; - if (opt.message) err.message = opt.message; - if (opt.stack) err.stack = opt.stack; + if (!stream) return callback; + var err, + data, + count = 2, + loaded = false; + var cb = function (e, d) { + if (loaded) return; + // 如果有数据,且没有错误,清理 设置错误 + if ((d && !data) || e || err) { + data = d; } - - if (typeof Object.defineProperty === 'function') { - Object.defineProperty(err, 'name', {writable: true, enumerable: false}); - Object.defineProperty(err, 'message', {enumerable: true}); + if (e && !err) { + err = e; + data = null; + } + if (err || --count === 0) { + loaded = true; + callback(err, data); } + }; + stream.on('error', function (err) { + cb(err); + }); + stream.on('finish', function () { + cb(); + }); + return cb; +}; - err.name = opt && opt.name || err.name || err.code || 'Error'; - if (!err.code) err.code = err.name; - - if (!err.error) { - var objectType = Object.prototype.toString.call(err); - if (objectType === '[object Object]') { - // 兼容老的错误格式 - err.error = clone(sourceErr); - } else if (objectType === '[object Error]') { - // 有环境报出[object Error]对象的情况,兼容处理一下 - err = { - code: err.code || err.name || 'Error', - name: err.name || err.code || 'Error', - message: err.reason || err.message || 'Error', - }; - } +var error = function (err, opt) { + var sourceErr = err; + err.message = err.message || null; + + if (typeof opt === 'string') { + err.error = opt; + err.message = opt; + } else if (typeof opt === 'object' && opt !== null) { + extend(err, opt); + if (opt.code || opt.name) err.code = opt.code || opt.name; + if (opt.message) err.message = opt.message; + if (opt.stack) err.stack = opt.stack; + } + + if (typeof Object.defineProperty === 'function') { + Object.defineProperty(err, 'name', { writable: true, enumerable: false }); + Object.defineProperty(err, 'message', { enumerable: true }); + } + + err.name = (opt && opt.name) || err.name || err.code || 'Error'; + if (!err.code) err.code = err.name; + + if (!err.error) { + var objectType = Object.prototype.toString.call(err); + if (objectType === '[object Object]') { + // 兼容老的错误格式 + err.error = clone(sourceErr); + } else if (objectType === '[object Error]') { + // 有环境报出[object Error]对象的情况,兼容处理一下 + err = { + code: err.code || err.name || 'Error', + name: err.name || err.code || 'Error', + message: err.reason || err.message || 'Error', + }; } - return err; -} + } + return err; +}; var isWeb = function () { - return typeof window === 'object'; -} + return typeof window === 'object'; +}; -var isCIHost = function(url) { +var isCIHost = function (url) { return /^https?:\/\/([^/]+\.)?ci\.[^/]+/.test(url); -} +}; + +var encodeBase64 = function (str, safe) { + let base64Str = Buffer.from(str).toString('base64'); + // 万象使用的安全base64格式需要特殊处理 + if (safe) { + base64Str = base64Str.replaceAll('+', '-').replaceAll('/', '_').replaceAll('=', ''); + } + return base64Str; +}; var util = { - noop: noop, - formatParams: formatParams, - apiWrapper: apiWrapper, - xml2json: xml2json, - json2xml: json2xml, - md5: md5, - clearKey: clearKey, - fileSlice: fileSlice, - getBodyMd5: getBodyMd5, - getFileMd5: getFileMd5, - binaryBase64: binaryBase64, - extend: extend, - isArray: isArray, - isInArray: isInArray, - makeArray: makeArray, - each: each, - map: map, - filter: filter, - clone: clone, - attr: attr, - uuid: uuid, - camSafeUrlEncode: camSafeUrlEncode, - throttleOnProgress: throttleOnProgress, - getFileSize: getFileSize, - getSkewTime: getSkewTime, - error: error, - getAuth: getAuth, - callbackAfterStreamFinish: callbackAfterStreamFinish, - getV4Auth: getV4Auth, - isBrowser: false, - obj2str: obj2str, - isWeb: isWeb, - isCIHost: isCIHost, - getSourceParams: getSourceParams, + noop: noop, + formatParams: formatParams, + apiWrapper: apiWrapper, + xml2json: xml2json, + json2xml: json2xml, + md5: md5, + clearKey: clearKey, + fileSlice: fileSlice, + getBodyMd5: getBodyMd5, + getFileMd5: getFileMd5, + binaryBase64: binaryBase64, + extend: extend, + isArray: isArray, + isInArray: isInArray, + makeArray: makeArray, + each: each, + map: map, + filter: filter, + clone: clone, + attr: attr, + uuid: uuid, + camSafeUrlEncode: camSafeUrlEncode, + throttleOnProgress: throttleOnProgress, + getFileSize: getFileSize, + getSkewTime: getSkewTime, + error: error, + getAuth: getAuth, + callbackAfterStreamFinish: callbackAfterStreamFinish, + getV4Auth: getV4Auth, + isBrowser: false, + obj2str: obj2str, + isWeb: isWeb, + isCIHost: isCIHost, + getSourceParams: getSourceParams, + encodeBase64: encodeBase64, }; module.exports = util; diff --git a/test/test.js b/test/test.js index 78333cd..4d963cf 100644 --- a/test/test.js +++ b/test/test.js @@ -6,14 +6,13 @@ var util = require('../demo/util'); var config = require('../demo/config'); var Stream = require('stream'); - // 先删除测试文件zip const dir = path.resolve(__dirname); fs.readdir(dir, (error, data) => { if (error) { console.log('readdir error', error); } else { - data.forEach(filename => { + data.forEach((filename) => { if (filename.endsWith('.zip')) { fs.rmSync(path.resolve(__dirname, filename)); } @@ -24,56 +23,56 @@ fs.readdir(dir, (error, data) => { var Writable = Stream.Writable; var dataURItoUploadBody = function (dataURI) { - return Buffer.from(dataURI.split(',')[1], 'base64'); + return Buffer.from(dataURI.split(',')[1], 'base64'); }; var createFileSync = function (filePath, size) { - if (!fs.existsSync(filePath) || fs.statSync(filePath).size !== size) { - fs.writeFileSync(filePath, Buffer.from(Array(size).fill(0))); - } - return filePath; + if (!fs.existsSync(filePath) || fs.statSync(filePath).size !== size) { + fs.writeFileSync(filePath, Buffer.from(Array(size).fill(0))); + } + return filePath; }; function camSafeUrlEncode(str) { - return encodeURIComponent(str) - .replace(/!/g, '%21') - .replace(/'/g, '%27') - .replace(/\(/g, '%28') - .replace(/\)/g, '%29') - .replace(/\*/g, '%2A'); + return encodeURIComponent(str) + .replace(/!/g, '%21') + .replace(/'/g, '%27') + .replace(/\(/g, '%28') + .replace(/\)/g, '%29') + .replace(/\*/g, '%2A'); } -var assert = require("assert"); +var assert = require('assert'); assert.ok = assert; var test = function (name, fn) { - it(name, function (done) { - fn(done, assert); - }); + it(name, function (done) { + fn(done, assert); + }); }; var group = function (name, fn) { - describe(name, function () { - this.timeout(120000); - fn.apply(this, arguments); - }); + describe(name, function () { + this.timeout(120000); + fn.apply(this, arguments); + }); }; var proxy = ''; -if(!config.SecretId || !config.SecretKey || !config.Bucket || !config.Region || !config.Uin) { +if (!config.SecretId || !config.SecretKey || !config.Bucket || !config.Region || !config.Uin) { console.log('Please check for complete configuration information in demo/config.js'); console.log('请检查demo/config.js是否有完整的配置信息'); return; } var cos = new COS({ - SecretId: config.SecretId, - SecretKey: config.SecretKey, - Proxy: proxy, - // 可选参数 - FileParallelLimit: 6, // 控制文件上传并发数 - ChunkParallelLimit: 3, // 控制单个文件下分片上传并发数 - ChunkSize: 1024 * 1024, // 控制分片大小,单位 B - ProgressInterval: 1, // 控制 onProgress 回调的间隔 - ChunkRetryTimes: 3, // 控制文件切片后单片上传失败后重试次数 - UploadCheckContentMd5: true, // 上传过程计算 Content-MD5 - ServiceDomain: 'service.cos.myqcloud.com/', + SecretId: config.SecretId, + SecretKey: config.SecretKey, + Proxy: proxy, + // 可选参数 + FileParallelLimit: 6, // 控制文件上传并发数 + ChunkParallelLimit: 3, // 控制单个文件下分片上传并发数 + ChunkSize: 1024 * 1024, // 控制分片大小,单位 B + ProgressInterval: 1, // 控制 onProgress 回调的间隔 + ChunkRetryTimes: 3, // 控制文件切片后单片上传失败后重试次数 + UploadCheckContentMd5: true, // 上传过程计算 Content-MD5 + ServiceDomain: 'service.cos.myqcloud.com/', }); var AppId; @@ -84,99 +83,114 @@ var TaskId; var match = config.Bucket.match(/^(.+)-(\d+)$/); if (match) { - BucketLongName = config.Bucket; - BucketShortName = match[1]; - AppId = match[2]; + BucketLongName = config.Bucket; + BucketShortName = match[1]; + AppId = match[2]; } function comparePlainObject(a, b) { - if (Object.keys(a).length !== Object.keys(b).length) { + if (Object.keys(a).length !== Object.keys(b).length) { + return false; + } + for (var key in a) { + if (typeof a[key] === 'object' && typeof b[key] === 'object') { + if (!comparePlainObject(a[key], b[key])) { return false; + } + } else if (a[key] != b[key]) { + return false; } - for (var key in a) { - if (typeof a[key] === 'object' && typeof b[key] === 'object') { - if (!comparePlainObject(a[key], b[key])) { - return false; - } - } else if (a[key] != b[key]) { - return false; - } - } - return true; + } + return true; } function prepareBigObject() { - return new Promise(function (resolve, reject) { - // 创建测试文件 - var filename = 'bigger.zip'; - var content = Buffer.from(Array(1024 * 1024 * 10).fill(0)); - var put = function () { - // 调用方法 - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - Body: content, - ContentLength: content.length, - }, function (err, data) { - err ? reject(err) : resolve() - }); - }; - put(); - }); + return new Promise(function (resolve, reject) { + // 创建测试文件 + var filename = 'bigger.zip'; + var content = Buffer.from(Array(1024 * 1024 * 10).fill(0)); + var put = function () { + // 调用方法 + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + Body: content, + ContentLength: content.length, + }, + function (err, data) { + err ? reject(err) : resolve(); + }, + ); + }; + put(); + }); } function prepareBucket() { - return new Promise(function (resolve, reject) { - cos.putBucket({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - resolve(); - }); - }); + return new Promise(function (resolve, reject) { + cos.putBucket( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + resolve(); + }, + ); + }); } function prepareObject(key = '1.txt') { return new Promise(function (resolve, reject) { - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: key, - Body: '123456', - }, function (err, data) { + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + Body: '123456', + }, + function (err, data) { err ? reject(err) : resolve(data); - }); + }, + ); }); } function deleteObjectBefore(Key) { return new Promise(function (resolve, reject) { - cos.deleteObject({ - Bucket: config.Bucket, - Region: config.Region, - Key, - }, function (err, data) { - err ? reject(err) : resolve(data); - }); + cos.deleteObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key, + }, + function (err, data) { + err ? reject(err) : resolve(data); + }, + ); }); } -group('init cos', function() { - const putFile = function(cosIns, done, assert, canSuccess = true) { +group('init cos', function () { + const putFile = function (cosIns, done, assert, canSuccess = true) { var key = '1.txt'; var content = Date.now().toString(); - cosIns.putObject({ + cosIns.putObject( + { Bucket: config.Bucket, Region: config.Region, Key: key, Body: content, - }, function (err, data) { - assert.ok(canSuccess ? !err : err); - done(); - }); - } - test('使用AppId', function(done, assert) { + }, + function (err, data) { + assert.ok(canSuccess ? !err : err); + done(); + }, + ); + }; + test('使用AppId', function (done, assert) { var initCos = new COS({ SecretId: config.SecretId, SecretKey: config.SecretKey, @@ -185,14 +199,14 @@ group('init cos', function() { assert.ok(initCos.options.AppId); done(); }); - test('使用了小写ak sk', function(done, assert) { + test('使用了小写ak sk', function (done, assert) { var initCos = new COS({ secretId: config.SecretId, secretKey: config.SecretKey, }); putFile(initCos, done, assert, true); }); - test('SecretId格式错误', function(done, assert) { + test('SecretId格式错误', function (done, assert) { var initCos = new COS({ SecretId: config.SecretId + ' ', SecretKey: config.SecretKey, @@ -201,255 +215,330 @@ group('init cos', function() { var content = Date.now().toString(); putFile(initCos, done, assert, false); }); - test('SecretKey格式错误', function(done, assert) { - var initCos = new COS({ - SecretId: config.SecretId, - SecretKey: config.SecretKey + ' ', - }); - putFile(initCos, done, assert, false); - }); - test('StrictSsl=false', function(done, assert) { - var initCos = new COS({ - SecretId: config.SecretId, - SecretKey: config.SecretKey, - StrictSsl: false, - }); - putFile(initCos, done, assert, true); + test('SecretKey格式错误', function (done, assert) { + var initCos = new COS({ + SecretId: config.SecretId, + SecretKey: config.SecretKey + ' ', }); - test('Tunnel=false', function(done, assert) { - var initCos = new COS({ - SecretId: config.SecretId, - SecretKey: config.SecretKey, - Tunnel: false, - }); - putFile(initCos, done, assert, true); + putFile(initCos, done, assert, false); + }); + test('StrictSsl=false', function (done, assert) { + var initCos = new COS({ + SecretId: config.SecretId, + SecretKey: config.SecretKey, + StrictSsl: false, }); - test('Timeout=6000', function(done, assert) { - var initCos = new COS({ - SecretId: config.SecretId, - SecretKey: config.SecretKey, - Timeout: 6000, - }); - putFile(initCos, done, assert, true); + putFile(initCos, done, assert, true); + }); + test('Tunnel=false', function (done, assert) { + var initCos = new COS({ + SecretId: config.SecretId, + SecretKey: config.SecretKey, + Tunnel: false, }); - test('ForcePathStyle', function(done, assert) { - var initCos = new COS({ - SecretId: config.SecretId, - SecretKey: config.SecretKey, - ForcePathStyle: true, - }); - putFile(initCos, done, assert, true); + putFile(initCos, done, assert, true); + }); + test('Timeout=6000', function (done, assert) { + var initCos = new COS({ + SecretId: config.SecretId, + SecretKey: config.SecretKey, + Timeout: 6000, }); - test('模拟sms init', function(done, assert) { - var Credentials = { - secretId: config.SecretId, - secretKey: config.SecretKey, - }; - var initCos = new COS({ Credentials }); - setTimeout(() => { - Credentials.secretId = '123456'; - Credentials.secretKey = 'abcdefg'; - }, 1000); - putFile(initCos, done, assert, true); + putFile(initCos, done, assert, true); + }); + test('ForcePathStyle', function (done, assert) { + var initCos = new COS({ + SecretId: config.SecretId, + SecretKey: config.SecretKey, + ForcePathStyle: true, }); - test('getAuthorization error tmpSecretId', function(done, assert) { - var initCos = new COS({ - getAuthorization: function (options, callback) { - callback({ - tmpSecretId: config.SecretId, - TmpSecretKey: config.SecretKey, + putFile(initCos, done, assert, true); + }); + test('模拟sms init', function (done, assert) { + var Credentials = { + secretId: config.SecretId, + secretKey: config.SecretKey, + }; + var initCos = new COS({ Credentials }); + setTimeout(() => { + Credentials.secretId = '123456'; + Credentials.secretKey = 'abcdefg'; + }, 1000); + putFile(initCos, done, assert, true); + }); + test('getAuthorization error tmpSecretId', function (done, assert) { + var initCos = new COS({ + getAuthorization: function (options, callback) { + callback({ + tmpSecretId: config.SecretId, + TmpSecretKey: config.SecretKey, }); - } - }); - putFile(initCos, done, assert, false); + }, }); - test('getAuthorization error tmpSecretKey', function(done, assert) { + putFile(initCos, done, assert, false); + }); + test('getAuthorization error tmpSecretKey', function (done, assert) { var initCos = new COS({ getAuthorization: function (options, callback) { callback({ TmpSecretId: config.SecretId, tmpSecretKey: config.SecretKey, - }); - } + }); + }, }); putFile(initCos, done, assert, false); }); - test('getAuthorization error', function(done, assert) { + test('getAuthorization error', function (done, assert) { var initCos = new COS({ getAuthorization: function (options, callback) { callback({ TmpSecretId: config.SecretId, TmpSecretKey: config.SecretKey, - }); - } + }); + }, }); putFile(initCos, done, assert, false); }); - test('getAuthorization', function(done, assert) { + test('getAuthorization', function (done, assert) { var initCos = new COS({ getAuthorization: function (options, callback) { var AuthData = cos.getAuth({ Method: 'put', - Key: '1.txt' + Key: '1.txt', }); callback({ - Authorization: AuthData + Authorization: AuthData, }); - } + }, }); putFile(initCos, done, assert); }); }); group('getService()', function () { - test('getService 老用法', function (done, assert) { - prepareBucket().then(function () { - cos.getService(function (err, data) { - assert.ok(!err); - done(); - }); - }); - }); - test('getService 传Region', function (done, assert) { - var cos = new COS({ - SecretId: config.SecretId, - SecretKey: config.SecretKey, - }); - prepareBucket().then(function () { - cos.getService({ - Region: config.Region, - }, function (err, data) { - var hasBucket = false; - data.Buckets && data.Buckets.forEach(function (item) { - if (item.Name === BucketLongName && (item.Location === config.Region || !item.Location)) { - hasBucket = true; - } - }); - assert.ok(hasBucket); - done(); - }); - }).catch(function () { + test('getService 老用法', function (done, assert) { + prepareBucket().then(function () { + cos.getService(function (err, data) { + assert.ok(!err); + done(); }); }); - test('getService 不传Region和Domain', function (done, assert) { - var cos = new COS({ - SecretId: config.SecretId, - SecretKey: config.SecretKey, - }); - prepareBucket().then(function () { - cos.getService({}, function (err, data) { - var hasBucket = false; - data.Buckets && data.Buckets.forEach(function (item) { - if (item.Name === BucketLongName && (item.Location === config.Region || !item.Location)) { - hasBucket = true; - } + }); + test('getService 传Region', function (done, assert) { + var cos = new COS({ + SecretId: config.SecretId, + SecretKey: config.SecretKey, + }); + prepareBucket() + .then(function () { + cos.getService( + { + Region: config.Region, + }, + function (err, data) { + var hasBucket = false; + data.Buckets && + data.Buckets.forEach(function (item) { + if (item.Name === BucketLongName && (item.Location === config.Region || !item.Location)) { + hasBucket = true; + } }); - assert.ok(hasBucket); - done(); - }); - }).catch(function () { - }); + assert.ok(hasBucket); + done(); + }, + ); + }) + .catch(function () {}); + }); + test('getService 不传Region和Domain', function (done, assert) { + var cos = new COS({ + SecretId: config.SecretId, + SecretKey: config.SecretKey, }); - test('能正常列出 Bucket', function (done, assert) { - prepareBucket().then(function () { - cos.getService({ - Region: config.Region, - }, function (err, data) { - var hasBucket = false; - data.Buckets && data.Buckets.forEach(function (item) { - if (item.Name === BucketLongName && (item.Location === config.Region || !item.Location)) { - hasBucket = true; - } - }); - assert.ok(hasBucket); - done(); + prepareBucket() + .then(function () { + cos.getService({}, function (err, data) { + var hasBucket = false; + data.Buckets && + data.Buckets.forEach(function (item) { + if (item.Name === BucketLongName && (item.Location === config.Region || !item.Location)) { + hasBucket = true; + } }); - }).catch(function () { + assert.ok(hasBucket); + done(); }); - }); + }) + .catch(function () {}); + }); + test('能正常列出 Bucket', function (done, assert) { + prepareBucket() + .then(function () { + cos.getService( + { + Region: config.Region, + }, + function (err, data) { + var hasBucket = false; + data.Buckets && + data.Buckets.forEach(function (item) { + if (item.Name === BucketLongName && (item.Location === config.Region || !item.Location)) { + hasBucket = true; + } + }); + assert.ok(hasBucket); + done(); + }, + ); + }) + .catch(function () {}); + }); }); group('putBucket()', function () { - var NewBucket = 'test' + Date.now().toString(36) + '-' + AppId; - test('正常创建 bucket', function (done, assert) { - cos.putBucket({ + var NewBucket = 'test' + Date.now().toString(36) + '-' + AppId; + test('正常创建 bucket', function (done, assert) { + cos.putBucket( + { + Bucket: NewBucket, + Region: config.Region, + }, + function (err, data) { + var location1 = NewBucket + '.cos.' + config.Region + '.myqcloud.com'; + var location2 = NewBucket + '.cos.' + config.Region + '.myqcloud.com/'; + assert.ok(location1 === data.Location || location2 === data.Location); + cos.headBucket( + { Bucket: NewBucket, - Region: config.Region - }, function (err, data) { - var location1 = NewBucket + '.cos.' + config.Region + '.myqcloud.com'; - var location2 = NewBucket + '.cos.' + config.Region + '.myqcloud.com/'; - assert.ok(location1 === data.Location || location2 === data.Location); - cos.headBucket({ + Region: config.Region, + }, + function (err, data) { + assert.ok(data); + cos.deleteBucket( + { Bucket: NewBucket, - Region: config.Region - }, function (err, data) { - assert.ok(data); - cos.deleteBucket({ - Bucket: NewBucket, - Region: config.Region - }, function (err, data) { - done(); - }); - }); - }); - }); + Region: config.Region, + }, + function (err, data) { + done(); + }, + ); + }, + ); + }, + ); + }); }); group('getAuth();getV4Auth()', function () { - test('getAuth()', function (done, assert) { - var content = Date.now().toString(); - var key = '1.txt'; - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: key, - Body: content, - }, function (err, data) { - var AuthData = cos.getAuth({ - Method: 'get', - Key: key - }); - if (typeof AuthData === 'string') { - AuthData = {Authorization: AuthData}; - } - var link = 'http://' + config.Bucket + '.cos.' + config.Region + '.myqcloud.com' + '/' + - camSafeUrlEncode(key).replace(/%2F/g, '/') + '?' + AuthData.Authorization + - (AuthData.XCosSecurityToken ? '&x-cos-security-token=' + AuthData.XCosSecurityToken : ''); - request({ - url: link, - proxy: proxy, - }, function (err, response, body) { - assert.ok(response.statusCode === 200); - assert.ok(body === content); - done(); - }); + test('getAuth()', function (done, assert) { + var content = Date.now().toString(); + var key = '1.txt'; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + Body: content, + }, + function (err, data) { + var AuthData = cos.getAuth({ + Method: 'get', + Key: key, }); - }); - test('getV4Auth()', function (done, assert) { - var content = Date.now().toString(); - var key = '1.txt'; - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: key, - Body: content, - }, function (err, data) { - var sign = cos.getV4Auth({ - Bucket: config.Bucket, - Key: key - }); - var link = 'http://' + config.Bucket + '.cos.' + config.Region + '.myqcloud.com' + '/' + - camSafeUrlEncode(key).replace(/%2F/g, '/') + '?sign=' + encodeURIComponent(sign); - request({ - url: link, - proxy: proxy, - }, function (err, response, body) { - assert.ok(response.statusCode === 200); - assert.ok(body === content); - done(); - }); + if (typeof AuthData === 'string') { + AuthData = { Authorization: AuthData }; + } + var link = + 'http://' + + config.Bucket + + '.cos.' + + config.Region + + '.myqcloud.com' + + '/' + + camSafeUrlEncode(key).replace(/%2F/g, '/') + + '?' + + AuthData.Authorization + + (AuthData.XCosSecurityToken ? '&x-cos-security-token=' + AuthData.XCosSecurityToken : ''); + request( + { + url: link, + proxy: proxy, + }, + function (err, response, body) { + assert.ok(response.statusCode === 200); + assert.ok(body === content); + done(); + }, + ); + }, + ); + }); + test('getV4Auth()', function (done, assert) { + var content = Date.now().toString(); + var key = '1.txt'; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + Body: content, + }, + function (err, data) { + var sign = cos.getV4Auth({ + Bucket: config.Bucket, + Key: key, }); - }); + var link = + 'http://' + + config.Bucket + + '.cos.' + + config.Region + + '.myqcloud.com' + + '/' + + camSafeUrlEncode(key).replace(/%2F/g, '/') + + '?sign=' + + encodeURIComponent(sign); + request( + { + url: link, + proxy: proxy, + }, + function (err, response, body) { + assert.ok(response.statusCode === 200); + assert.ok(body === content); + done(); + }, + ); + }, + ); + }); +}); + +group('putObject() 兼容老参数AppId', function () { + test('putObject()', function (done, assert) { + const sp = config.Bucket.split('-'); + const len = sp.length; + const appId = sp[len - 1]; + sp.pop(); + const bucketShortName = sp.join('-'); + cos.putObject( + { + Bucket: bucketShortName, + Region: config.Region, + AppId: appId, + Key: '12345.txt', + Body: '12345', + Headers: { + 'x-cos-test': 1, + }, + }, + function (err, data) { + assert.ok(!err); + done(); + }, + ); + }); }); group('putObject() 兼容老参数AppId', function () { @@ -476,211 +565,260 @@ group('putObject() 兼容老参数AppId', function () { }); group('getObjectUrl()', function () { - test('getObjectUrl()', function (done, assert) { - var content = Date.now().toString(); - var key = '1.txt'; - cos.putObject({ + test('getObjectUrl()', function (done, assert) { + var content = Date.now().toString(); + var key = '1.txt'; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + Body: content, + }, + function (err, data) { + cos.getObjectUrl( + { Bucket: config.Bucket, Region: config.Region, Key: key, - Body: content, - }, function (err, data) { - cos.getObjectUrl({ - Bucket: config.Bucket, - Region: config.Region, - Key: key, - }, function (err, data) { - request({ - url: data.Url, - proxy: proxy, - }, function (err, response, body) { - assert.ok(!err); - done(); - }); - }); - }); - }); - test('getObjectUrl() Query', function (done, assert) { - var key = '1.txt'; - var content = '12345'; - cos.putObject({ + }, + function (err, data) { + request( + { + url: data.Url, + proxy: proxy, + }, + function (err, response, body) { + assert.ok(!err); + done(); + }, + ); + }, + ); + }, + ); + }); + test('getObjectUrl() Query', function (done, assert) { + var key = '1.txt'; + var content = '12345'; + cos.putObject( + { Bucket: config.Bucket, Region: config.Region, Key: key, Body: content, - }, function (err, data) { - cos.getObjectUrl({ - Bucket: config.Bucket, - Region: config.Region, - Key: key, - Query: { - a: 1, + }, + function (err, data) { + cos.getObjectUrl( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + Query: { + a: 1, + }, + Sign: true, }, - Sign: true, - }, function (err, data) { - request({ + function (err, data) { + request( + { url: data.Url, proxy: proxy, - }, function (err, response, body) { + }, + function (err, response, body) { assert.ok(!err, '文件获取出错'); assert.ok(response.statusCode === 200, '获取文件 200'); assert.ok(body.toString() === content, '通过获取签名能正常获取文件'); done(); - }); - }); - }); - }); - test('getObjectUrl() QueryString', function (done, assert) { - var key = '1.txt'; - cos.getObjectUrl({ + }, + ); + }, + ); + }, + ); + }); + test('getObjectUrl() QueryString', function (done, assert) { + var key = '1.txt'; + cos.getObjectUrl( + { Bucket: config.Bucket, Region: config.Region, Key: key, QueryString: 'a=1', Sign: true, - }, function (err, data) { - request({ - url: data.Url, - proxy: proxy, - }, function (err, response, body) { - assert.ok(!err, '文件获取出错'); - assert.ok(response.statusCode === 200, '获取文件 200'); - done(); - }); - }); - }); - test('getObjectUrl() sign=false', function (done, assert) { - var key = '1.txt'; - cos.getObjectUrl({ + }, + function (err, data) { + request( + { + url: data.Url, + proxy: proxy, + }, + function (err, response, body) { + assert.ok(!err, '文件获取出错'); + assert.ok(response.statusCode === 200, '获取文件 200'); + done(); + }, + ); + }, + ); + }); + test('getObjectUrl() sign=false', function (done, assert) { + var key = '1.txt'; + cos.getObjectUrl( + { Bucket: config.Bucket, Region: config.Region, Key: key, QueryString: 'a=1', Sign: false, - }, function (err, data) { - request({ - url: data.Url, - proxy: proxy, - }, function (err, response, body) { - assert.ok(response.statusCode === 403, '获取文件 403'); - done(); - }); - }); - }); + }, + function (err, data) { + request( + { + url: data.Url, + proxy: proxy, + }, + function (err, response, body) { + assert.ok(response.statusCode === 403, '获取文件 403'); + done(); + }, + ); + }, + ); + }); }); group('auth check', function () { - test('auth check', function (done, assert) { - cos.getBucket({ - Bucket: config.Bucket, - Region: config.Region, - Prefix: 'aksjhdlash sajlhj!@#$%^&*()_+=-[]{}\';:"/.<>?.,??sadasd#/.,/~`', - Headers: { - 'x-cos-test': 'aksjhdlash sajlhj!@#$%^&*()_+=-[]{}\';:\"/.<>?.,??sadasd#/.,/~`', - }, - }, function (err, data) { - assert.ok(!err); - done(); - }); - }); + test('auth check', function (done, assert) { + cos.getBucket( + { + Bucket: config.Bucket, + Region: config.Region, + Prefix: 'aksjhdlash sajlhj!@#$%^&*()_+=-[]{}\';:"/.<>?.,??sadasd#/.,/~`', + Headers: { + 'x-cos-test': 'aksjhdlash sajlhj!@#$%^&*()_+=-[]{}\';:"/.<>?.,??sadasd#/.,/~`', + }, + }, + function (err, data) { + assert.ok(!err); + done(); + }, + ); + }); }); group('getBucket(),listObjectVersions', function () { - test('正常获取 bucket 里的文件列表', function (done, assert) { - prepareBucket().then(function () { - cos.getBucket({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(data.Name === BucketLongName); - assert.ok(data.Contents.constructor, Array); - done(); - }); - }).catch(function () { - assert.ok(false); + test('正常获取 bucket 里的文件列表', function (done, assert) { + prepareBucket() + .then(function () { + cos.getBucket( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(data.Name === BucketLongName); + assert.ok(data.Contents.constructor, Array); done(); - }); - }); - test('正常获取 bucket 里的文件版本列表', function (done, assert) { - prepareBucket().then(function () { - cos.listObjectVersions({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(data.Name === BucketLongName); - assert.ok(data.Versions.constructor === Array); - done(); - }); - }).catch(function () { - assert.ok(false); + }, + ); + }) + .catch(function () { + assert.ok(false); + done(); + }); + }); + test('正常获取 bucket 里的文件版本列表', function (done, assert) { + prepareBucket() + .then(function () { + cos.listObjectVersions( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(data.Name === BucketLongName); + assert.ok(data.Versions.constructor === Array); done(); - }); - }); + }, + ); + }) + .catch(function () { + assert.ok(false); + done(); + }); + }); }); group('putObject(),cancelTask()', function () { - test('putObject(),cancelTask()', function (done, assert) { - var filename = '10m.zip'; - var alive = false; - var canceled = false; - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - Body: Buffer.from(Array(1024 * 1024 * 10).fill(0)), - onTaskReady: function (taskId) { - TaskId = taskId; - }, - onProgress: function (info) { - alive = true; - if (!canceled) { - cos.cancelTask(TaskId); - alive = false; - canceled = true; - setTimeout(function () { - assert.ok(!alive, '取消上传已经生效'); - done(); - }, 1200); - } - } - }, function (err, data) { - alive = true; - }); - }); - test('putObject(),update-list()', function (done, assert) { - var filename = '10m.zip'; - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - Body: Buffer.from(Array(1024 * 1024 * 10).fill(0)), - }, function (err, data) { + test('putObject(),cancelTask()', function (done, assert) { + var filename = '10m.zip'; + var alive = false; + var canceled = false; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + Body: Buffer.from(Array(1024 * 1024 * 10).fill(0)), + onTaskReady: function (taskId) { + TaskId = taskId; + }, + onProgress: function (info) { + alive = true; + if (!canceled) { + cos.cancelTask(TaskId); + alive = false; + canceled = true; + setTimeout(function () { + assert.ok(!alive, '取消上传已经生效'); + done(); + }, 1200); + } + }, + }, + function (err, data) { + alive = true; + }, + ); + }); + test('putObject(),update-list()', function (done, assert) { + var filename = '10m.zip'; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + Body: Buffer.from(Array(1024 * 1024 * 10).fill(0)), + }, + function (err, data) { assert(!err); done(); - }); - cos.on('task-list-update', function() { - - }) - }); + }, + ); + cos.on('task-list-update', function () {}); + }); }); group('task 队列', function () { test('putObject() 批量上传', function (done, assert) { - var upload = function() { + var upload = function () { var filename = '10m.zip'; var taskId; - cos.putObject({ + cos.putObject( + { Bucket: config.Bucket, Region: config.Region, Key: filename, Body: Buffer.from(Array(1024 * 1024 * 1).fill(0)), - TaskReady: function(id) { + TaskReady: function (id) { taskId = id; - } - }, function (err, data) { - }); - } - for(var i = 0; i < 1200; i ++) { + }, + }, + function (err, data) {}, + ); + }; + for (var i = 0; i < 1200; i++) { upload(); } var taskList = cos.getTaskList(); @@ -691,869 +829,1117 @@ group('task 队列', function () { }); group('sliceUploadFile() 完整上传文件', function () { - test('sliceUploadFile() 完整上传文件', function (done, assert) { - var lastPercent; - var filename = '3m.zip'; - var fileSize = 1024 * 1024 * 3; - var filePath = createFileSync(path.resolve(__dirname, filename), fileSize) - cos.abortUploadTask({ + test('sliceUploadFile() 完整上传文件', function (done, assert) { + var lastPercent; + var filename = '3m.zip'; + var fileSize = 1024 * 1024 * 3; + var filePath = createFileSync(path.resolve(__dirname, filename), fileSize); + cos.abortUploadTask( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + Level: 'file', + }, + function (err, data) { + cos.sliceUploadFile( + { Bucket: config.Bucket, Region: config.Region, Key: filename, - Level: 'file', - }, function (err, data) { - cos.sliceUploadFile({ + FilePath: filePath, + onTaskReady: function (taskId) { + TaskId = taskId; + }, + onProgress: function (info) { + lastPercent = info.percent; + }, + }, + function (err, data) { + assert.ok(data.ETag.length > 0); + fs.unlinkSync(filePath); + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: filename, - FilePath: filePath, - onTaskReady: function (taskId) { - TaskId = taskId; - }, - onProgress: function (info) { - lastPercent = info.percent; - } - }, function (err, data) { - assert.ok(data.ETag.length > 0); - fs.unlinkSync(filePath); - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - }, function (err, data) { - assert.ok(data && data.headers && data.headers.etag && data.headers.etag.length > 0, '文件已上传成功'); - assert.ok(data && data.headers && parseInt(data.headers['content-length'] || 0) === fileSize, '文件大小一致'); - done(); - }); - }); - }); - }); - test('sliceUploadFile(),pauseTask(),restartTask()', function (done, assert) { - var filename = '10m.zip'; - var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 10); - var paused = false; - var restarted = false; - cos.abortUploadTask({ + }, + function (err, data) { + assert.ok(data && data.headers && data.headers.etag && data.headers.etag.length > 0, '文件已上传成功'); + assert.ok( + data && data.headers && parseInt(data.headers['content-length'] || 0) === fileSize, + '文件大小一致', + ); + done(); + }, + ); + }, + ); + }, + ); + }); + test('sliceUploadFile(),pauseTask(),restartTask()', function (done, assert) { + var filename = '10m.zip'; + var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 10); + var paused = false; + var restarted = false; + cos.abortUploadTask( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + Level: 'file', + }, + function (err, data) { + var TaskId; + cos.sliceUploadFile( + { Bucket: config.Bucket, Region: config.Region, Key: filename, - Level: 'file', - }, function (err, data) { - var TaskId; - cos.sliceUploadFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - FilePath: filePath, - onTaskReady: function (taskId) { - TaskId = taskId; - }, - onProgress: function (info) { - if (!paused && info.percent > 0.6) { - cos.pauseTask(TaskId); - paused = true; - setTimeout(function () { - restarted = true; - cos.restartTask(TaskId); - }, 1000); - } - if (paused && restarted) { - if (info.percent === 0) return; - assert.ok(info.percent > 0.3, '暂停和重试成功'); - cos.cancelTask(TaskId); - fs.unlinkSync(filePath); - done(); - } - } - }, function (err, data) { + FilePath: filePath, + onTaskReady: function (taskId) { + TaskId = taskId; + }, + onProgress: function (info) { + if (!paused && info.percent > 0.6) { + cos.pauseTask(TaskId); paused = true; - }); - }); - }); - test('sliceUploadFile(),cancelTask(),restartTask()', function (done, assert) { - var filename = '10m.zip'; - var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 10); - var paused = false; - cos.abortUploadTask({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - Level: 'file', - }, function (err, data) { - var TaskId; - cos.sliceUploadFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - FilePath: filePath, - onTaskReady: function (taskId) { - TaskId = taskId; - }, - onProgress: function (info) { - if (!paused && info.percent > 0.6) { - cos.cancelTask(TaskId); - setTimeout(function () { - cos.sliceUploadFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - FilePath: filePath, - }, function (err, data) { - assert.ok(!err); - fs.unlinkSync(filePath); - done(); - }); - }, 10); - } - } - }, function (err, data) { - }); - }); - }); - test('sliceUploadFile(),cancelTask()', function (done, assert) { - var filename = '3m.zip'; - var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 3) - var alive = false; - var canceled = false; - cos.sliceUploadFile({ + setTimeout(function () { + restarted = true; + cos.restartTask(TaskId); + }, 1000); + } + if (paused && restarted) { + if (info.percent === 0) return; + assert.ok(info.percent > 0.3, '暂停和重试成功'); + cos.cancelTask(TaskId); + fs.unlinkSync(filePath); + done(); + } + }, + }, + function (err, data) { + paused = true; + }, + ); + }, + ); + }); + test('sliceUploadFile(),cancelTask(),restartTask()', function (done, assert) { + var filename = '10m.zip'; + var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 10); + var paused = false; + cos.abortUploadTask( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + Level: 'file', + }, + function (err, data) { + var TaskId; + cos.sliceUploadFile( + { Bucket: config.Bucket, Region: config.Region, Key: filename, FilePath: filePath, onTaskReady: function (taskId) { - TaskId = taskId; + TaskId = taskId; }, onProgress: function (info) { - alive = true; - if (!canceled) { - cos.cancelTask(TaskId); - alive = false; - canceled = true; - fs.unlinkSync(filePath); - setTimeout(function () { - assert.ok(!alive, '取消上传已经生效'); - done(); - }, 1200); - } - } - }, function (err, data) { - alive = true; - }); - }); - test('sliceUploadFile() fileSize = 0', function (done, assert) { - var filename = '0b.zip'; - var filePath = createFileSync(path.resolve(__dirname, filename), 0); - cos.sliceUploadFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - FilePath: filePath, - Headers: { - 'x-cos-test': 'test', - 'x-cos-meta-test': 'meta', - 'x-cos-traffic-limit': 819200 + if (!paused && info.percent > 0.6) { + cos.cancelTask(TaskId); + setTimeout(function () { + cos.sliceUploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + FilePath: filePath, + }, + function (err, data) { + assert.ok(!err); + fs.unlinkSync(filePath); + done(); + }, + ); + }, 10); + } + }, }, - }, function (err, data) { - assert(!err); - done(); - }); - }); - test('sliceUploadFile() 上传过程中删除本地文件', function (done, assert) { - var filename = '30mb.zip'; - var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 30); - cos.sliceUploadFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - FilePath: filePath, - }, function (err, data) { - assert(err); - done(); - }); - setTimeout(() => { - fs.rmSync(filePath); - }, 1000); - }); - test('sliceUploadFile() 上传过程中本地文件修改', function (done, assert) { - var filename = '30mb.zip'; - var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 30); - var taskId; - cos.sliceUploadFile({ + function (err, data) {}, + ); + }, + ); + }); + test('sliceUploadFile(),cancelTask()', function (done, assert) { + var filename = '3m.zip'; + var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 3); + var alive = false; + var canceled = false; + cos.sliceUploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + FilePath: filePath, + onTaskReady: function (taskId) { + TaskId = taskId; + }, + onProgress: function (info) { + alive = true; + if (!canceled) { + cos.cancelTask(TaskId); + alive = false; + canceled = true; + fs.unlinkSync(filePath); + setTimeout(function () { + assert.ok(!alive, '取消上传已经生效'); + done(); + }, 1200); + } + }, + }, + function (err, data) { + alive = true; + }, + ); + }); + test('sliceUploadFile() fileSize = 0', function (done, assert) { + var filename = '0b.zip'; + var filePath = createFileSync(path.resolve(__dirname, filename), 0); + cos.sliceUploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + FilePath: filePath, + Headers: { + 'x-cos-test': 'test', + 'x-cos-meta-test': 'meta', + 'x-cos-traffic-limit': 819200, + }, + }, + function (err, data) { + assert(!err); + done(); + }, + ); + }); + test('sliceUploadFile() 上传过程中删除本地文件', function (done, assert) { + var filename = '30mb.zip'; + var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 30); + cos.sliceUploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + FilePath: filePath, + }, + function (err, data) { + assert(err); + done(); + }, + ); + setTimeout(() => { + fs.rmSync(filePath); + }, 1000); + }); + test('sliceUploadFile() 上传过程中本地文件修改', function (done, assert) { + var filename = '30mb.zip'; + var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 30); + var taskId; + cos.sliceUploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + FilePath: filePath, + onTaskReady: function (id) { + taskId = id; + }, + }, + function (err, data) { + assert(err); + done(); + }, + ); + setTimeout(() => { + // 先暂停任务 + cos.pauseTask(taskId); + // 重新上传 + cos.sliceUploadFile( + { Bucket: config.Bucket, Region: config.Region, Key: filename, FilePath: filePath, - onTaskReady: function(id) { - taskId = id; - } - }, function (err, data) { - assert(err); - done(); - }); - setTimeout(() => { - // 先暂停任务 - cos.pauseTask(taskId); - // 重新上传 - cos.sliceUploadFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - FilePath: filePath, - }, function (err, data) { + }, + function (err, data) { assert(err); done(); - }); - // 1秒后修改文件内容 - setTimeout(() => { - const fd = fs.openSync(filePath, "r+"); - fs.writeSync(fd, 'test', 10240, 'utf8'); - }, 1000); + }, + ); + // 1秒后修改文件内容 + setTimeout(() => { + const fd = fs.openSync(filePath, 'r+'); + fs.writeSync(fd, 'test', 10240, 'utf8'); }, 1000); - }); + }, 1000); + }); }); group('abortUploadTask()', function () { - test('abortUploadTask(),Level=task', function (done, assert) { - var filename = '1m.zip'; - cos.multipartInit({ + test('abortUploadTask(),Level=task', function (done, assert) { + var filename = '1m.zip'; + cos.multipartInit( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + }, + function (err, data) { + cos.abortUploadTask( + { Bucket: config.Bucket, Region: config.Region, Key: filename, - }, function (err, data) { - cos.abortUploadTask({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - Level: 'task', - UploadId: data.UploadId, - }, function (err, data) { - var nameExist = false; - data.successList.forEach(function (item) { - if (filename === item.Key) { - nameExist = true; - } - }); - assert.ok(data.successList.length >= 1, '成功取消单个分片任务'); - assert.ok(nameExist, '成功取消单个分片任务'); - done(); + Level: 'task', + UploadId: data.UploadId, + }, + function (err, data) { + var nameExist = false; + data.successList.forEach(function (item) { + if (filename === item.Key) { + nameExist = true; + } }); - }); - }); - test('abortUploadTask(),Level=file', function (done, assert) { - var filename = '1m.zip'; - var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024) - cos.sliceUploadFile({ + assert.ok(data.successList.length >= 1, '成功取消单个分片任务'); + assert.ok(nameExist, '成功取消单个分片任务'); + done(); + }, + ); + }, + ); + }); + test('abortUploadTask(),Level=file', function (done, assert) { + var filename = '1m.zip'; + var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024); + cos.sliceUploadFile({ + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + FilePath: filePath, + onTaskReady: function (taskId) { + TaskId = taskId; + }, + onProgress: function (info) { + cos.cancelTask(TaskId); + cos.abortUploadTask( + { Bucket: config.Bucket, Region: config.Region, + Level: 'file', Key: filename, - FilePath: filePath, - onTaskReady: function (taskId) { - TaskId = taskId; - }, - onProgress: function (info) { - cos.cancelTask(TaskId); - cos.abortUploadTask({ - Bucket: config.Bucket, - Region: config.Region, - Level: 'file', - Key: filename, - }, function (err, data) { - assert.ok(data.successList.length >= 1, '成功舍弃单个文件下的所有分片任务'); - assert.ok(data.successList[0] && data.successList[0].Key === filename, '成功舍弃单个文件的所有分片任务'); - done(); - }); - } - }); + }, + function (err, data) { + assert.ok(data.successList.length >= 1, '成功舍弃单个文件下的所有分片任务'); + assert.ok(data.successList[0] && data.successList[0].Key === filename, '成功舍弃单个文件的所有分片任务'); + done(); + }, + ); + }, }); + }); - test('abortUploadTask(),Level=bucket', function (done, assert) { - var filename = '1m.zip'; - var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024) - cos.sliceUploadFile({ - Bucket: config.Bucket, + test('abortUploadTask(),Level=bucket', function (done, assert) { + var filename = '1m.zip'; + var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024); + cos.sliceUploadFile({ + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + FilePath: filePath, + onTaskReady: function (taskId) { + TaskId = taskId; + }, + onProgress: function (info) { + cos.cancelTask(TaskId); + fs.unlinkSync(filePath); + cos.abortUploadTask( + { + Bucket: config.Bucket, Region: config.Region, - Key: filename, - FilePath: filePath, - onTaskReady: function (taskId) { - TaskId = taskId; - }, - onProgress: function (info) { - cos.cancelTask(TaskId); - fs.unlinkSync(filePath); - cos.abortUploadTask({ - Bucket: config.Bucket, - Region: config.Region, - Level: 'bucket', - }, function (err, data) { - var nameExist = false; - data.successList.forEach(function (item) { - if (filename === item.Key) { - nameExist = true; - } - }); - assert.ok(data.successList.length >= 1, '成功舍弃Bucket下所有分片任务'); - assert.ok(nameExist, '成功舍弃Bucket下所有分片任务'); - done(); - }); - } - }); + Level: 'bucket', + }, + function (err, data) { + var nameExist = false; + data.successList.forEach(function (item) { + if (filename === item.Key) { + nameExist = true; + } + }); + assert.ok(data.successList.length >= 1, '成功舍弃Bucket下所有分片任务'); + assert.ok(nameExist, '成功舍弃Bucket下所有分片任务'); + done(); + }, + ); + }, }); + }); }); group('headBucket()', function () { - test('headBucket()', function (done, assert) { - cos.headBucket({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(data, '正常获取 head bucket'); - done(); - }); - }); + test('headBucket()', function (done, assert) { + cos.headBucket( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(data, '正常获取 head bucket'); + done(); + }, + ); + }); - test('headBucket() bucket not exist', function (done, assert) { - cos.headBucket({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(err, 'bucket 不存在'); - done(); - }); - }); + test('headBucket() bucket not exist', function (done, assert) { + cos.headBucket( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(err, 'bucket 不存在'); + done(); + }, + ); + }); - test('deleteBucket()', function (done, assert) { - cos.deleteBucket({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(err, 'deleteBucket 不存在'); - done(); - }); - }); + test('deleteBucket()', function (done, assert) { + cos.deleteBucket( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(err, 'deleteBucket 不存在'); + done(); + }, + ); + }); - test('getBucket()', function (done, assert) { - cos.getBucket({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(data.Name === BucketLongName, '能列出 bucket'); - assert.ok(data.Contents.constructor === Array, '正常获取 bucket 里的文件列表'); - done(); - }); - }); + test('getBucket()', function (done, assert) { + cos.getBucket( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(data.Name === BucketLongName, '能列出 bucket'); + assert.ok(data.Contents.constructor === Array, '正常获取 bucket 里的文件列表'); + done(); + }, + ); + }); }); group('putObject()', function () { - var filename = '1.txt'; - var filePath = path.resolve(__dirname, filename); - var getObjectContent = function (callback) { - var objectContent = Buffer.from([]); - var outputStream = new Writable({ - write: function (chunk, encoding, callback) { - objectContent = Buffer.concat([objectContent, chunk]); - callback(); - } + var filename = '1.txt'; + var filePath = path.resolve(__dirname, filename); + var getObjectContent = function (callback) { + var objectContent = Buffer.from([]); + var outputStream = new Writable({ + write: function (chunk, encoding, callback) { + objectContent = Buffer.concat([objectContent, chunk]); + callback(); + }, + }); + setTimeout(function () { + cos.getObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + onProgress: function (info) {}, + Output: outputStream, + }, + function (err, data) { + var content = objectContent.toString(); + callback(content); + }, + ); + }, 2000); + }; + test('fs.createReadStream 创建 object', function (done, assert) { + var content = Date.now().toString(); + fs.writeFileSync(filePath, content); + var lastPercent = 0; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + Body: fs.createReadStream(filePath), + ContentLength: fs.statSync(filePath).size, + onTaskReady(id) { + // 暂停任务 + cos.pauseTask(id); + }, + onProgress: function (info) { + lastPercent = info.percent; + }, + }, + function (err, data) { + if (err) throw err; + assert.ok(data.ETag.length > 0); + fs.unlinkSync(filePath); + getObjectContent(function (objectContent) { + assert.ok(objectContent === content); + done(); }); - setTimeout(function () { - cos.getObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - onProgress: function (info) { - }, - Output: outputStream - }, function (err, data) { - var content = objectContent.toString(); - callback(content); - }); - }, 2000); + }, + ); + }); + test('fs.readFileSync 创建 object', function (done, assert) { + var content = Date.now().toString(); + fs.writeFileSync(filePath, content); + var lastPercent = 0; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + Body: fs.readFileSync(filePath), + onProgress: function (info) { + lastPercent = info.percent; + }, + }, + function (err, data) { + if (err) throw err; + assert.ok(data.ETag.length > 0); + fs.unlinkSync(filePath); + getObjectContent(function (objectContent) { + assert.ok(objectContent === content); + done(); + }); + }, + ); + }); + test('捕获输入流异常', function (done, assert) { + var filename = 'big.zip'; + var filePath = path.resolve(__dirname, filename); + var put = function () { + var Body = fs.createReadStream(filePath); + setTimeout(function () { + Body.emit('error', new Error('some error')); + }, 1000); + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + Body: Body, + ContentLength: fs.statSync(filePath).size, + }, + function (err, data) { + fs.unlinkSync(filePath); + done(); + }, + ); }; - test('fs.createReadStream 创建 object', function (done, assert) { - var content = Date.now().toString(); - fs.writeFileSync(filePath, content); - var lastPercent = 0; - cos.putObject({ + if (fs.existsSync(filePath)) { + put(); + } else { + util.createFile(filePath, 5 << 20, put); + } + }); + test('putObject(),buffer', function (done, assert) { + var content = Buffer.from('中文_' + Date.now()); + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1.txt', + Body: content, + }, + function (err, data) { + var ETag = data.ETag; + assert.ok(!err && ETag); + cos.getObject( + { Bucket: config.Bucket, Region: config.Region, Key: filename, - Body: fs.createReadStream(filePath), - ContentLength: fs.statSync(filePath).size, - onTaskReady(id) { - // 暂停任务 - cos.pauseTask(id); - }, - onProgress: function (info) { - lastPercent = info.percent; - }, - }, function (err, data) { - if (err) throw err; - assert.ok(data.ETag.length > 0); - fs.unlinkSync(filePath); - getObjectContent(function (objectContent) { - assert.ok(objectContent === content); - done(); - }); - }); - }); - test('fs.readFileSync 创建 object', function (done, assert) { - var content = Date.now().toString(); - fs.writeFileSync(filePath, content); - var lastPercent = 0; - cos.putObject({ + }, + function (err, data) { + assert.ok( + data.Body && data.Body.toString() === content.toString() && (data.headers && data.headers.etag) === ETag, + ); + done(); + }, + ); + }, + ); + }); + test('putObject(),buffer,empty', function (done, assert) { + var content = Buffer.from(''); + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1.txt', + Body: content, + }, + function (err, data) { + var ETag = data.ETag; + assert.ok(!err && ETag); + cos.getObject( + { Bucket: config.Bucket, Region: config.Region, Key: filename, - Body: fs.readFileSync(filePath), - onProgress: function (info) { - lastPercent = info.percent; - }, - }, function (err, data) { - if (err) throw err; - assert.ok(data.ETag.length > 0); - fs.unlinkSync(filePath); - getObjectContent(function (objectContent) { - assert.ok(objectContent === content); - done(); - }); - }); - }); - test('捕获输入流异常', function (done, assert) { - var filename = 'big.zip'; - var filePath = path.resolve(__dirname, filename); - var put = function () { - var Body = fs.createReadStream(filePath); - setTimeout(function () { - Body.emit('error', new Error('some error')) - }, 1000); - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - Body: Body, - ContentLength: fs.statSync(filePath).size, - }, function (err, data) { - fs.unlinkSync(filePath); - done(); - }); - }; - if (fs.existsSync(filePath)) { - put(); - } else { - util.createFile(filePath, 5 << 20, put); - } - }); - test('putObject(),buffer', function (done, assert) { - var content = Buffer.from('中文_' + Date.now()); - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.txt', - Body: content, - }, function (err, data) { - var ETag = data.ETag; - assert.ok(!err && ETag); - cos.getObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename - }, function (err, data) { - assert.ok(data.Body && data.Body.toString() === content.toString() && (data.headers && data.headers.etag) === ETag); - done(); - }); - }); - }); - test('putObject(),buffer,empty', function (done, assert) { - var content = Buffer.from(''); - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.txt', - Body: content, - }, function (err, data) { - var ETag = data.ETag; - assert.ok(!err && ETag); - cos.getObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename - }, function (err, data) { - assert.ok(data.Body && data.Body.toString() === content.toString() && (data.headers && data.headers.etag) === ETag); - done(); - }); - }); - }); - test('putObject()', function (done, assert) { - var filename = '1.txt'; - var getObjectETag = function (callback) { - setTimeout(function () { - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - }, function (err, data) { - callback(data && data.headers && data.headers.etag); - }); - }, 2000); - }; - var content = Date.now().toString(); - var lastPercent = 0; - cos.putObject({ + }, + function (err, data) { + assert.ok( + data.Body && data.Body.toString() === content.toString() && (data.headers && data.headers.etag) === ETag, + ); + done(); + }, + ); + }, + ); + }); + test('putObject()', function (done, assert) { + var filename = '1.txt'; + var getObjectETag = function (callback) { + setTimeout(function () { + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: filename, - Body: content, - onProgress: function (info) { - lastPercent = info.percent; - }, - }, function (err, data) { - if (err) throw err; - assert.ok(data && data.ETag, 'putObject 有返回 ETag'); - getObjectETag(function (ETag) { - assert.ok(data.ETag === ETag, 'Blob 创建 object'); - done(); - }); + }, + function (err, data) { + callback(data && data.headers && data.headers.etag); + }, + ); + }, 2000); + }; + var content = Date.now().toString(); + var lastPercent = 0; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + Body: content, + onProgress: function (info) { + lastPercent = info.percent; + }, + }, + function (err, data) { + if (err) throw err; + assert.ok(data && data.ETag, 'putObject 有返回 ETag'); + getObjectETag(function (ETag) { + assert.ok(data.ETag === ETag, 'Blob 创建 object'); + done(); }); - }); + }, + ); + }); - test('putObject(),string', function (done, assert) { - var filename = '1.txt'; - var content = '中文_' + Date.now().toString(36); - var lastPercent = 0; - cos.putObject({ + test('putObject(),string', function (done, assert) { + var filename = '1.txt'; + var content = '中文_' + Date.now().toString(36); + var lastPercent = 0; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + Body: content, + onProgress: function (info) { + lastPercent = info.percent; + }, + }, + function (err, data) { + if (err) throw err; + var ETag = data && data.ETag; + assert.ok(ETag, 'putObject 有返回 ETag'); + cos.getObject( + { Bucket: config.Bucket, Region: config.Region, Key: filename, - Body: content, - onProgress: function (info) { - lastPercent = info.percent; - }, - }, function (err, data) { - if (err) throw err; - var ETag = data && data.ETag; - assert.ok(ETag, 'putObject 有返回 ETag'); - cos.getObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - }, function (err, data) { - assert.ok(data.Body && data.Body.toString() === content.toString() && (data.headers && data.headers.etag) === ETag); - done(); - }); - }); - }); - test('putObject(),string,empty', function (done, assert) { - var content = ''; - var lastPercent = 0; - var Key = '1.txt'; - cos.putObject({ + }, + function (err, data) { + assert.ok( + data.Body && data.Body.toString() === content.toString() && (data.headers && data.headers.etag) === ETag, + ); + done(); + }, + ); + }, + ); + }); + test('putObject(),string,empty', function (done, assert) { + var content = ''; + var lastPercent = 0; + var Key = '1.txt'; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + Body: content, + onProgress: function (info) { + lastPercent = info.percent; + }, + }, + function (err, data) { + if (err) throw err; + var ETag = data && data.ETag; + assert.ok(ETag, 'putObject 有返回 ETag'); + cos.getObject( + { Bucket: config.Bucket, Region: config.Region, Key: Key, - Body: content, - onProgress: function (info) { - lastPercent = info.percent; - }, - }, function (err, data) { - if (err) throw err; - var ETag = data && data.ETag; - assert.ok(ETag, 'putObject 有返回 ETag'); - cos.getObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: Key, - }, function (err, data) { - assert.ok(data.Body && data.Body.toString() === content && (data.headers && data.headers.etag) === ETag); - done(); - }); - }); - }); + }, + function (err, data) { + assert.ok(data.Body && data.Body.toString() === content && (data.headers && data.headers.etag) === ETag); + done(); + }, + ); + }, + ); + }); }); group('getObject(),getObjectStream()', function () { - test('getObject() body', function (done, assert) { - var key = '1.txt'; - var content = Date.now().toString(); - cos.putObject({ + test('getObject() body', function (done, assert) { + var key = '1.txt'; + var content = Date.now().toString(); + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + Body: content, + }, + function (err, data) { + cos.getObject( + { Bucket: config.Bucket, Region: config.Region, Key: key, - Body: content, - }, function (err, data) { - cos.getObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: key - }, function (err, data) { - if (err) throw err; - var objectContent = data.Body.toString(); - assert.ok(data.headers['content-length'] === '' + content.length); - assert.ok(objectContent === content); - done(); - }); - }); - }); + }, + function (err, data) { + if (err) throw err; + var objectContent = data.Body.toString(); + assert.ok(data.headers['content-length'] === '' + content.length); + assert.ok(objectContent === content); + done(); + }, + ); + }, + ); + }); - test('getObject() stream', function (done, assert) { - var key = '1.txt'; - var objectContent = Buffer.from([]); - var outputStream = new Writable({ - write: function (chunk, encoding, callback) { - objectContent = Buffer.concat([objectContent, chunk]); - callback(); - } - }); - var content = Date.now().toString(36); - cos.putObject({ + test('getObject() stream', function (done, assert) { + var key = '1.txt'; + var objectContent = Buffer.from([]); + var outputStream = new Writable({ + write: function (chunk, encoding, callback) { + objectContent = Buffer.concat([objectContent, chunk]); + callback(); + }, + }); + var content = Date.now().toString(36); + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + Body: Buffer.from(content), + }, + function (err, data) { + cos.getObject( + { Bucket: config.Bucket, Region: config.Region, Key: key, - Body: Buffer.from(content) - }, function (err, data) { - cos.getObject({ + Output: outputStream, + }, + function (err, data) { + if (err) throw err; + objectContent = objectContent.toString(); + assert.ok(data.headers['content-length'] === '' + content.length); + assert.ok(objectContent === content); + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: key, - Output: outputStream - }, function (err, data) { - if (err) throw err; - objectContent = objectContent.toString(); - assert.ok(data.headers['content-length'] === '' + content.length); - assert.ok(objectContent === content); - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: key - }, function (err, data) { - assert.ok(!err); - done(); - }); - }); - }); - }); - test('getObject() stream2', function (done, assert) { - var key = '1.txt'; - var objectContent = Buffer.from([]); - var outputStream = new Writable({ - write: function (chunk, encoding, callback) { - objectContent = Buffer.concat([objectContent, chunk]); - callback(); - } - }); - var content = Date.now().toString(36); - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: key, - Body: Buffer.from(content) - }, function (err, data) { - cos.getObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: key, - Output: './1.txt' - }, function (err, data) { - if (err) throw err; - objectContent = objectContent.toString(); - assert.ok(data.headers['content-length'] === '' + content.length); - assert.ok(objectContent !== content); - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: key - }, function (err, data) { - assert.ok(!err); - done(); - }); - }); - }); - }); - test('getObjectStream', function (done, assert) { - var content = Date.now().toString(); - var key = '1.json'; - cos.putObject({ + }, + function (err, data) { + assert.ok(!err); + done(); + }, + ); + }, + ); + }, + ); + }); + test('getObject() stream2', function (done, assert) { + var key = '1.txt'; + var objectContent = Buffer.from([]); + var outputStream = new Writable({ + write: function (chunk, encoding, callback) { + objectContent = Buffer.concat([objectContent, chunk]); + callback(); + }, + }); + var content = Date.now().toString(36); + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + Body: Buffer.from(content), + }, + function (err, data) { + cos.getObject( + { Bucket: config.Bucket, Region: config.Region, Key: key, - Body: content, - }, function (err, data) { - var bufList = []; - var writeStream = new Writable({ - write: function (chunk, encoding, callback) { - bufList.push(chunk); - callback(); - }, - }); - cos.getObjectStream({ + Output: './1.txt', + }, + function (err, data) { + if (err) throw err; + objectContent = objectContent.toString(); + assert.ok(data.headers['content-length'] === '' + content.length); + assert.ok(objectContent !== content); + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: key, - }, function (err, data) { - assert.ok(Buffer.concat(bufList).toString() === content); + }, + function (err, data) { + assert.ok(!err); done(); - }).pipe(writeStream); + }, + ); + }, + ); + }, + ); + }); + test('getObjectStream', function (done, assert) { + var content = Date.now().toString(); + var key = '1.json'; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + Body: content, + }, + function (err, data) { + var bufList = []; + var writeStream = new Writable({ + write: function (chunk, encoding, callback) { + bufList.push(chunk); + callback(); + }, }); - }); - test('getObject Output', function (done, assert) { - var content = Date.now().toString(); - var key = '1.json'; - cos.putObject({ + cos + .getObjectStream( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + }, + function (err, data) { + assert.ok(Buffer.concat(bufList).toString() === content); + done(); + }, + ) + .pipe(writeStream); + }, + ); + }); + test('getObject Output', function (done, assert) { + var content = Date.now().toString(); + var key = '1.json'; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + Body: content, + }, + function (err, data) { + var bufList = []; + var writeStream = new Writable({ + write: function (chunk, encoding, callback) { + bufList.push(chunk); + callback(); + }, + }); + cos.getObject( + { Bucket: config.Bucket, Region: config.Region, Key: key, - Body: content, - }, function (err, data) { - var bufList = []; - var writeStream = new Writable({ - write: function (chunk, encoding, callback) { - bufList.push(chunk); - callback(); - }, - }); - cos.getObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: key, - Output: writeStream, - }, function (err, data) { - assert.ok(Buffer.concat(bufList).toString() === content); - done(); - }); - }); - }); + Output: writeStream, + }, + function (err, data) { + assert.ok(Buffer.concat(bufList).toString() === content); + done(); + }, + ); + }, + ); + }); }); group('deleteObject() 404', function () { - test('deleteObject() 404', function (done, assert) { - cos.deleteObject({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region, - Key: '123abc' + Date.now().toString(36), - }, function (err, data) { - assert.ok(data.statusCode === 404); - done(); - }); - }); + test('deleteObject() 404', function (done, assert) { + cos.deleteObject( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + Key: '123abc' + Date.now().toString(36), + }, + function (err, data) { + assert.ok(data.statusCode === 404); + done(); + }, + ); + }); }); group('Key 特殊字符', function () { - test('Key 特殊字符', function (done, assert) { - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '(!\'*) "#$%&+,-./0123456789:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~', - Body: Date.now().toString() - }, function (err, data) { - assert.ok(data, 'putObject 特殊字符的 Key 能通过'); - done(); - }); - }); + test('Key 特殊字符', function (done, assert) { + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '(!\'*) "#$%&+,-./0123456789:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~', + Body: Date.now().toString(), + }, + function (err, data) { + assert.ok(data, 'putObject 特殊字符的 Key 能通过'); + done(); + }, + ); + }); }); group('putObjectCopy() 1', function () { - test('putObjectCopy() 1', function (done, assert) { - var content = Date.now().toString(36); - cos.putObject({ + test('putObjectCopy() 1', function (done, assert) { + var content = Date.now().toString(36); + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1.txt', + Body: content, + }, + function (err, data) { + var ETag = data.ETag; + cos.deleteObject( + { Bucket: config.Bucket, Region: config.Region, - Key: '1.txt', - Body: content, - }, function (err, data) { - var ETag = data.ETag; - cos.deleteObject({ + Key: '1.copy.txt', + }, + function (err, data) { + cos.putObjectCopy( + { Bucket: config.Bucket, Region: config.Region, Key: '1.copy.txt', - }, function (err, data) { - cos.putObjectCopy({ + CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/1.txt', + }, + function (err, data) { + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: '1.copy.txt', - CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/1.txt', - }, function (err, data) { - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.copy.txt', - }, function (err, data) { - assert.ok(data.headers && data.headers.etag === ETag, '成功复制文件'); - done(); - }); - }); - }); - }); - }); + }, + function (err, data) { + assert.ok(data.headers && data.headers.etag === ETag, '成功复制文件'); + done(); + }, + ); + }, + ); + }, + ); + }, + ); + }); }); group('putObjectCopy()', function () { - var filename = '1.txt'; - test('正常复制 object', function (done, assert) { - prepareObject(filename).then(() => { - cos.putObjectCopy({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.copy.txt', - CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + filename, - }, function (err, data) { - assert.ok(!err); - assert.ok(data.ETag.length > 0); - done(); - }); - }); + var filename = '1.txt'; + test('正常复制 object', function (done, assert) { + prepareObject(filename).then(() => { + cos.putObjectCopy( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1.copy.txt', + CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + filename, + }, + function (err, data) { + assert.ok(!err); + assert.ok(data.ETag.length > 0); + done(); + }, + ); }); - test('捕获 object 异常', function (done, assert) { - var errFileName = '12345.txt' + Date.now().toString(36); - cos.putObjectCopy({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.copy.txt', - CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + errFileName, - }, function (err, data) { - assert.ok(err); - done(); - }); - }); - test('putObjectCopy error source', function (done, assert) { - var errFileName = '12345.txt'; - cos.putObjectCopy({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.copy.txt', - CopySource: 'www.qq.com' + errFileName, - }, function (err, data) { - assert.ok(err); - done(); - }); - }); + }); + test('捕获 object 异常', function (done, assert) { + var errFileName = '12345.txt' + Date.now().toString(36); + cos.putObjectCopy( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1.copy.txt', + CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + errFileName, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); + test('putObjectCopy error source', function (done, assert) { + var errFileName = '12345.txt'; + cos.putObjectCopy( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1.copy.txt', + CopySource: 'www.qq.com' + errFileName, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); }); group('sliceCopyFile()', function () { - var filename = 'bigger.zip'; - var Key = 'bigger.copy.zip'; - test('正常分片复制 object', function (done, assert) { - prepareBigObject(true).then(function () { - cos.headObject({ + var filename = 'bigger.zip'; + var Key = 'bigger.copy.zip'; + test('正常分片复制 object', function (done, assert) { + prepareBigObject(true) + .then(function () { + cos.headObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + }, + function (err, data1) { + if (err) throw err; + cos.sliceCopyFile( + { Bucket: config.Bucket, Region: config.Region, - Key: filename, - }, function (err, data1) { + Key: Key, + CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + filename, + CopySliceSize: 5 * 1024 * 1024, + Headers: { + 'x-cos-metadata-directive': 'Replaced', + }, + }, + function (err, data) { if (err) throw err; - cos.sliceCopyFile({ + assert.ok(data.ETag.length > 0); + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: Key, - CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/'+ filename, - CopySliceSize: 5 * 1024 * 1024, - Headers: { - 'x-cos-metadata-directive': 'Replaced', - }, - },function (err, data) { + }, + function (err, data2) { if (err) throw err; - assert.ok(data.ETag.length > 0); - cos.headObject({ + delete data1.VersionId; + delete data2.VersionId; + delete data1.headers['x-cos-request-id']; + delete data2.headers['x-cos-request-id']; + delete data1.headers['x-cos-version-id']; + delete data2.headers['x-cos-version-id']; + delete data1.headers['x-cos-replication-status']; + delete data2.headers['x-cos-replication-status']; + delete data1.headers['last-modified']; + delete data2.headers['last-modified']; + delete data1.headers['date']; + delete data2.headers['date']; + delete data1.headers['etag']; + delete data2.headers['etag']; + delete data1.ETag; + delete data2.ETag; + delete data1.RequestId; + delete data2.RequestId; + assert.ok(comparePlainObject(data1, data2)); + done(); + }, + ); + }, + ); + }, + ); + }) + .catch(function () { + assert.ok(false); + done(); + }); + }); + test('单片复制 object', function (done, assert) { + setTimeout(function () { + prepareBigObject(true) + .then(function () { + cos.headObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + }, + function (err, data1) { + if (err) throw err; + cos.sliceCopyFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + filename, + SliceSize: 10 * 1024 * 1024, + }, + function (err, data) { + if (err) throw err; + assert.ok(data.ETag.length > 0); + setTimeout(function () { + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: Key, - }, function (err, data2) { + }, + function (err, data2) { if (err) throw err; delete data1.VersionId; delete data2.VersionId; @@ -1567,3322 +1953,4096 @@ group('sliceCopyFile()', function () { delete data2.headers['last-modified']; delete data1.headers['date']; delete data2.headers['date']; - delete data1.headers['etag']; - delete data2.headers['etag']; delete data1.ETag; delete data2.ETag; delete data1.RequestId; delete data2.RequestId; assert.ok(comparePlainObject(data1, data2)); done(); - }); - }); - }); - }).catch(function () { - assert.ok(false); - done(); - }); - }); - test('单片复制 object', function (done, assert) { - setTimeout(function () { - prepareBigObject(true).then(function () { - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - }, function (err, data1) { - if (err) throw err; - cos.sliceCopyFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: Key, - CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + filename, - SliceSize: 10 * 1024 * 1024, - }, function (err, data) { - if (err) throw err; - assert.ok(data.ETag.length > 0); - setTimeout(function () { - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: Key, - }, function (err, data2) { - if (err) throw err; - delete data1.VersionId; - delete data2.VersionId; - delete data1.headers['x-cos-request-id']; - delete data2.headers['x-cos-request-id']; - delete data1.headers['x-cos-version-id']; - delete data2.headers['x-cos-version-id']; - delete data1.headers['x-cos-replication-status']; - delete data2.headers['x-cos-replication-status']; - delete data1.headers['last-modified']; - delete data2.headers['last-modified']; - delete data1.headers['date']; - delete data2.headers['date']; - delete data1.ETag; - delete data2.ETag; - delete data1.RequestId; - delete data2.RequestId; - assert.ok(comparePlainObject(data1, data2)); - done(); - }); - }, 2000); - }); - }); - }).catch(function () { - assert.ok(false); - done(); - }); - }, 2000); - }); - test('CopySource error source', function (done, assert) { - cos.sliceCopyFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: Key, - CopySource: 'www.123.com/1.txt', - }, function (err, data) { - assert.ok(err); + }, + ); + }, 2000); + }, + ); + }, + ); + }) + .catch(function () { + assert.ok(false); done(); - }); - }); - test('CopySource() fileSize=0', function (done, assert) { - var Key = '0b.zip'; - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: Key, - Body: '', - Headers: { - 'x-cos-meta-test': 'test' - }, - }, function(err, data){ - cos.sliceCopyFile({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + Key, - }, function (err, data) { - assert.ok(err); - done(); - }); }); - }); - test('CopySource not found', function (done, assert) { - cos.sliceCopyFile({ - Bucket: config.Bucket, + }, 2000); + }); + test('CopySource error source', function (done, assert) { + cos.sliceCopyFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + CopySource: 'www.123.com/1.txt', + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); + test('CopySource() fileSize=0', function (done, assert) { + var Key = '0b.zip'; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + Body: '', + Headers: { + 'x-cos-meta-test': 'test', + }, + }, + function (err, data) { + cos.sliceCopyFile( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 Region: config.Region, - Key: Key, - CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + Date.now(), - }, function (err, data) { + CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + Key, + }, + function (err, data) { assert.ok(err); done(); - }); - }); - test('复制归档文件', function (done, assert) { - var sourceKey = 'archive'; - var targetKey = 'archive-target'; - var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 30); - cos.sliceUploadFile({ + }, + ); + }, + ); + }); + test('CopySource not found', function (done, assert) { + cos.sliceCopyFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + Date.now(), + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); + test('复制归档文件', function (done, assert) { + var sourceKey = 'archive'; + var targetKey = 'archive-target'; + var filePath = createFileSync(path.resolve(__dirname, filename), 1024 * 1024 * 30); + cos.sliceUploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: sourceKey, + FilePath: filePath, + StorageClass: 'ARCHIVE', + }, + function () { + cos.sliceCopyFile( + { Bucket: config.Bucket, Region: config.Region, - Key: sourceKey, - FilePath: filePath, - StorageClass: 'ARCHIVE', - }, function () { - cos.sliceCopyFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: targetKey, - CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + sourceKey, - }, function (err, data) { - assert.ok(err); - done(); - }); - }); - }); + Key: targetKey, + CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + sourceKey, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }, + ); + }); }); group('deleteMultipleObject', function () { - test('deleteMultipleObject()', function (done, assert) { - var content = Date.now().toString(36); - cos.putObject({ + test('deleteMultipleObject()', function (done, assert) { + var content = Date.now().toString(36); + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1.txt', + Body: content, + }, + function (err, data) { + cos.putObject( + { Bucket: config.Bucket, Region: config.Region, - Key: '1.txt', + Key: '2.txt', Body: content, - }, function (err, data) { - cos.putObject({ + }, + function (err, data) { + cos.deleteMultipleObject( + { Bucket: config.Bucket, Region: config.Region, - Key: '2.txt', - Body: content, - }, function (err, data) { - cos.deleteMultipleObject({ + Objects: [{ Key: '1.txt' }, { Key: '2.txt' }], + }, + function (err, data) { + assert.ok(data.Deleted.length === 2); + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, - Objects: [ - {Key: '1.txt'}, - {Key: '2.txt'}, - ], - }, function (err, data) { - assert.ok(data.Deleted.length === 2); - cos.headObject({ + Key: '1.txt', + }, + function (err, data) { + assert.ok(err.statusCode === 404, '1.txt 删除成功'); + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, - Key: '1.txt', - }, function (err, data) { - assert.ok(err.statusCode === 404, '1.txt 删除成功'); - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '2.txt', - }, function (err, data) { - assert.ok(err.statusCode === 404, '2.txt 删除成功'); - done(); - }); - }); - }); - }); - }); - }); + Key: '2.txt', + }, + function (err, data) { + assert.ok(err.statusCode === 404, '2.txt 删除成功'); + done(); + }, + ); + }, + ); + }, + ); + }, + ); + }, + ); + }); }); group('BucketAcl', function () { - var AccessControlPolicy = { - "Owner": { - "ID": 'qcs::cam::uin/10001:uin/10001' // 10001 是 QQ 号 - }, - "Grants": [{ - "Grantee": { - "ID": "qcs::cam::uin/10002:uin/10002", // 10002 是 QQ 号 - }, - "Permission": "READ" - }] - }; - var AccessControlPolicy2 = { - "Owner": { - "ID": 'qcs::cam::uin/10001:uin/10001' // 10001 是 QQ 号 + var AccessControlPolicy = { + Owner: { + ID: 'qcs::cam::uin/10001:uin/10001', // 10001 是 QQ 号 + }, + Grants: [ + { + Grantee: { + ID: 'qcs::cam::uin/10002:uin/10002', // 10002 是 QQ 号 }, - "Grant": { - "Grantee": { - "ID": "qcs::cam::uin/10002:uin/10002", // 10002 是 QQ 号 - }, - "Permission": "READ" - } - }; - test('putBucketAcl() header ACL:private', function (done, assert) { - cos.putBucketAcl({ + Permission: 'READ', + }, + ], + }; + var AccessControlPolicy2 = { + Owner: { + ID: 'qcs::cam::uin/10001:uin/10001', // 10001 是 QQ 号 + }, + Grant: { + Grantee: { + ID: 'qcs::cam::uin/10002:uin/10002', // 10002 是 QQ 号 + }, + Permission: 'READ', + }, + }; + test('putBucketAcl() header ACL:private', function (done, assert) { + cos.putBucketAcl( + { + Bucket: config.Bucket, + Region: config.Region, + ACL: 'private', + }, + function (err, data) { + assert.ok(!err, 'putBucketAcl 成功'); + cos.getBucketAcl( + { Bucket: config.Bucket, Region: config.Region, - ACL: 'private' - }, function (err, data) { - assert.ok(!err, 'putBucketAcl 成功'); - cos.getBucketAcl({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - AccessControlPolicy.Owner.ID = data.Owner.ID; - AccessControlPolicy2.Owner.ID = data.Owner.ID; - assert.ok(data.ACL === 'private' || data.ACL === 'default'); - done(); - }); + }, + function (err, data) { + AccessControlPolicy.Owner.ID = data.Owner.ID; + AccessControlPolicy2.Owner.ID = data.Owner.ID; + assert.ok(data.ACL === 'private' || data.ACL === 'default'); + done(); + }, + ); + }, + ); + }); + test('putBucketAcl() header ACL:public-read', function (done, assert) { + cos.putBucketAcl( + { + Bucket: config.Bucket, + Region: config.Region, + ACL: 'public-read', + }, + function (err, data) { + assert.ok(!err, 'putBucketAcl 成功'); + cos.getBucketAcl({ Bucket: config.Bucket, Region: config.Region }, function (err, data) { + assert.ok(data.ACL === 'public-read'); + done(); }); - }); - test('putBucketAcl() header ACL:public-read', function (done, assert) { - cos.putBucketAcl({ - Bucket: config.Bucket, - Region: config.Region, - ACL: 'public-read', - }, function (err, data) { - assert.ok(!err, 'putBucketAcl 成功'); - cos.getBucketAcl({Bucket: config.Bucket, Region: config.Region}, function (err, data) { - assert.ok(data.ACL === 'public-read'); - done(); - }); + }, + ); + }); + test('putBucketAcl() header ACL:public-read-write', function (done, assert) { + cos.putBucketAcl( + { + Bucket: config.Bucket, + Region: config.Region, + ACL: 'public-read-write', + }, + function (err, data) { + assert.ok(!err, 'putBucketAcl 成功'); + cos.getBucketAcl({ Bucket: config.Bucket, Region: config.Region }, function (err, data) { + assert.ok(data.ACL === 'public-read-write'); + done(); }); - }); - test('putBucketAcl() header ACL:public-read-write', function (done, assert) { - cos.putBucketAcl({ - Bucket: config.Bucket, - Region: config.Region, - ACL: 'public-read-write', - }, function (err, data) { - assert.ok(!err, 'putBucketAcl 成功'); - cos.getBucketAcl({Bucket: config.Bucket, Region: config.Region}, function (err, data) { - assert.ok(data.ACL === 'public-read-write'); - done(); - }); + }, + ); + }); + test('putBucketAcl() header GrantRead:1001,1002', function (done, assert) { + var GrantRead = 'id="qcs::cam::uin/1001:uin/1001", id="qcs::cam::uin/1002:uin/1002"'; + cos.putBucketAcl( + { + Bucket: config.Bucket, + Region: config.Region, + GrantRead: GrantRead, + }, + function (err, data) { + assert.ok(!err, 'putBucketAcl 成功'); + cos.getBucketAcl({ Bucket: config.Bucket, Region: config.Region }, function (err, data) { + assert.ok((data.GrantRead = GrantRead)); + done(); }); - }); - test('putBucketAcl() header GrantRead:1001,1002', function (done, assert) { - var GrantRead = 'id="qcs::cam::uin/1001:uin/1001", id="qcs::cam::uin/1002:uin/1002"'; - cos.putBucketAcl({ - Bucket: config.Bucket, - Region: config.Region, - GrantRead: GrantRead, - }, function (err, data) { - assert.ok(!err, 'putBucketAcl 成功'); - cos.getBucketAcl({Bucket: config.Bucket, Region: config.Region}, function (err, data) { - assert.ok(data.GrantRead = GrantRead); - done(); - }); + }, + ); + }); + test('putBucketAcl() header GrantWrite:1001,1002', function (done, assert) { + var GrantWrite = 'id="qcs::cam::uin/1001:uin/1001", id="qcs::cam::uin/1002:uin/1002"'; + cos.putBucketAcl( + { + Bucket: config.Bucket, + Region: config.Region, + GrantWrite: GrantWrite, + }, + function (err, data) { + assert.ok(!err, 'putBucketAcl 成功'); + cos.getBucketAcl({ Bucket: config.Bucket, Region: config.Region }, function (err, data) { + assert.ok((data.GrantWrite = GrantWrite)); + done(); }); - }); - test('putBucketAcl() header GrantWrite:1001,1002', function (done, assert) { - var GrantWrite = 'id="qcs::cam::uin/1001:uin/1001", id="qcs::cam::uin/1002:uin/1002"'; - cos.putBucketAcl({ - Bucket: config.Bucket, - Region: config.Region, - GrantWrite: GrantWrite, - }, function (err, data) { - assert.ok(!err, 'putBucketAcl 成功'); - cos.getBucketAcl({Bucket: config.Bucket, Region: config.Region}, function (err, data) { - assert.ok(data.GrantWrite = GrantWrite); - done(); - }); + }, + ); + }); + test('putBucketAcl() header GrantFullControl:1001,1002', function (done, assert) { + var GrantFullControl = 'id="qcs::cam::uin/1001:uin/1001", id="qcs::cam::uin/1002:uin/1002"'; + cos.putBucketAcl( + { + Bucket: config.Bucket, + Region: config.Region, + GrantFullControl: GrantFullControl, + }, + function (err, data) { + assert.ok(!err, 'putBucketAcl 成功'); + cos.getBucketAcl({ Bucket: config.Bucket, Region: config.Region }, function (err, data) { + assert.ok((data.GrantFullControl = GrantFullControl)); + done(); }); - }); - test('putBucketAcl() header GrantFullControl:1001,1002', function (done, assert) { - var GrantFullControl = 'id="qcs::cam::uin/1001:uin/1001", id="qcs::cam::uin/1002:uin/1002"'; - cos.putBucketAcl({ - Bucket: config.Bucket, - Region: config.Region, - GrantFullControl: GrantFullControl, - }, function (err, data) { - assert.ok(!err, 'putBucketAcl 成功'); - cos.getBucketAcl({Bucket: config.Bucket, Region: config.Region}, function (err, data) { - assert.ok(data.GrantFullControl = GrantFullControl); - done(); - }); + }, + ); + }); + test('putBucketAcl() header ACL:public-read, GrantFullControl:1001,1002', function (done, assert) { + var GrantFullControl = 'id="qcs::cam::uin/1001:uin/1001", id="qcs::cam::uin/1002:uin/1002"'; + cos.putBucketAcl( + { + Bucket: config.Bucket, + Region: config.Region, + GrantFullControl: GrantFullControl, + ACL: 'public-read', + }, + function (err, data) { + assert.ok(!err, 'putBucketAcl 成功'); + cos.getBucketAcl({ Bucket: config.Bucket, Region: config.Region }, function (err, data) { + assert.ok((data.GrantFullControl = GrantFullControl)); + assert.ok(data.ACL === 'public-read'); + done(); }); - }); - test('putBucketAcl() header ACL:public-read, GrantFullControl:1001,1002', function (done, assert) { - var GrantFullControl = 'id="qcs::cam::uin/1001:uin/1001", id="qcs::cam::uin/1002:uin/1002"'; - cos.putBucketAcl({ - Bucket: config.Bucket, - Region: config.Region, - GrantFullControl: GrantFullControl, - ACL: 'public-read', - }, function (err, data) { - assert.ok(!err, 'putBucketAcl 成功'); - cos.getBucketAcl({Bucket: config.Bucket, Region: config.Region}, function (err, data) { - assert.ok(data.GrantFullControl = GrantFullControl); - assert.ok(data.ACL === 'public-read'); - done(); - }); + }, + ); + }); + test('putBucketAcl() xml', function (done, assert) { + cos.putBucketAcl( + { + Bucket: config.Bucket, + Region: config.Region, + AccessControlPolicy: AccessControlPolicy, + }, + function (err, data) { + assert.ok(!err, 'putBucketAcl 成功'); + cos.getBucketAcl({ Bucket: config.Bucket, Region: config.Region }, function (err, data) { + assert.ok(data.Grants.length === 1); + assert.ok( + data.Grants[0] && data.Grants[0].Grantee.ID === 'qcs::cam::uin/10002:uin/10002', + '设置 AccessControlPolicy ID 正确', + ); + assert.ok(data.Grants[0] && data.Grants[0].Permission === 'READ', '设置 AccessControlPolicy Permission 正确'); + done(); }); - }); - test('putBucketAcl() xml', function (done, assert) { - cos.putBucketAcl({ - Bucket: config.Bucket, - Region: config.Region, - AccessControlPolicy: AccessControlPolicy - }, function (err, data) { - assert.ok(!err, 'putBucketAcl 成功'); - cos.getBucketAcl({Bucket: config.Bucket, Region: config.Region}, function (err, data) { - assert.ok(data.Grants.length === 1); - assert.ok(data.Grants[0] && data.Grants[0].Grantee.ID === 'qcs::cam::uin/10002:uin/10002', '设置 AccessControlPolicy ID 正确'); - assert.ok(data.Grants[0] && data.Grants[0].Permission === 'READ', '设置 AccessControlPolicy Permission 正确'); - done(); - }); + }, + ); + }); + test('putBucketAcl() xml2', function (done, assert) { + cos.putBucketAcl( + { + Bucket: config.Bucket, + Region: config.Region, + AccessControlPolicy: AccessControlPolicy2, + }, + function (err, data) { + assert.ok(!err, 'putBucketAcl 成功'); + cos.getBucketAcl({ Bucket: config.Bucket, Region: config.Region }, function (err, data) { + assert.ok(data.Grants.length === 1); + assert.ok(data.Grants[0] && data.Grants[0].Grantee.ID === 'qcs::cam::uin/10002:uin/10002'); + assert.ok(data.Grants[0] && data.Grants[0].Permission === 'READ'); + done(); }); - }); - test('putBucketAcl() xml2', function (done, assert) { - cos.putBucketAcl({ + }, + ); + }); + test('putBucketAcl() decodeAcl', function (done, assert) { + cos.getBucketAcl( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + cos.putBucketAcl( + { Bucket: config.Bucket, Region: config.Region, - AccessControlPolicy: AccessControlPolicy2, - }, function (err, data) { - assert.ok(!err, 'putBucketAcl 成功'); - cos.getBucketAcl({Bucket: config.Bucket, Region: config.Region}, function (err, data) { - assert.ok(data.Grants.length === 1); - assert.ok(data.Grants[0] && data.Grants[0].Grantee.ID === 'qcs::cam::uin/10002:uin/10002'); - assert.ok(data.Grants[0] && data.Grants[0].Permission === 'READ'); - done(); - }); - }); - }); - test('putBucketAcl() decodeAcl', function (done, assert) { - cos.getBucketAcl({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - cos.putBucketAcl({ - Bucket: config.Bucket, - Region: config.Region, - GrantFullControl: data.GrantFullControl, - GrantWrite: data.GrantWrite, - GrantRead: data.GrantRead, - ACL: data.ACL, - }, function (err, data) { - assert.ok(data); - done(); - }); - }); - }); + GrantFullControl: data.GrantFullControl, + GrantWrite: data.GrantWrite, + GrantRead: data.GrantRead, + ACL: data.ACL, + }, + function (err, data) { + assert.ok(data); + done(); + }, + ); + }, + ); + }); }); group('ObjectAcl', function () { - var AccessControlPolicy = { - "Owner": { - "ID": 'qcs::cam::uin/10001:uin/10001' // 10001 是 QQ 号 - }, - "Grants": [{ - "Grantee": { - "ID": "qcs::cam::uin/10002:uin/10002", // 10002 是 QQ 号 - }, - "Permission": "READ" - }] - }; - var AccessControlPolicy2 = { - "Owner": { - "ID": 'qcs::cam::uin/10001:uin/10001' // 10001 是 QQ 号 + var AccessControlPolicy = { + Owner: { + ID: 'qcs::cam::uin/10001:uin/10001', // 10001 是 QQ 号 + }, + Grants: [ + { + Grantee: { + ID: 'qcs::cam::uin/10002:uin/10002', // 10002 是 QQ 号 }, - "Grant": { - "Grantee": { - "ID": "qcs::cam::uin/10002:uin/10002", // 10002 是 QQ 号 - }, - "Permission": "READ" - } - }; - test('putObjectAcl() header ACL:private', function (done, assert) { - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.txt', - Body: 'hello!', - }, function (err, data) { - assert.ok(!err); - cos.putObjectAcl({ - Bucket: config.Bucket, - Region: config.Region, - ACL: 'private', - Key: '1.txt', - }, function (err, data) { - assert.ok(!err, 'putObjectAcl 成功'); - cos.getObjectAcl({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.txt' - }, function (err, data) { - assert.ok(data.ACL = 'private'); - AccessControlPolicy.Owner.ID = data.Owner.ID; - AccessControlPolicy2.Owner.ID = data.Owner.ID; - assert.ok(data.Grants.length === 1); - done(); - }); - }); - }); - }); - test('putObjectAcl() header ACL:default', function (done, assert) { - cos.putObjectAcl({ + Permission: 'READ', + }, + ], + }; + var AccessControlPolicy2 = { + Owner: { + ID: 'qcs::cam::uin/10001:uin/10001', // 10001 是 QQ 号 + }, + Grant: { + Grantee: { + ID: 'qcs::cam::uin/10002:uin/10002', // 10002 是 QQ 号 + }, + Permission: 'READ', + }, + }; + test('putObjectAcl() header ACL:private', function (done, assert) { + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1.txt', + Body: 'hello!', + }, + function (err, data) { + assert.ok(!err); + cos.putObjectAcl( + { Bucket: config.Bucket, Region: config.Region, - ACL: 'default', + ACL: 'private', Key: '1.txt', - }, function (err, data) { + }, + function (err, data) { assert.ok(!err, 'putObjectAcl 成功'); - cos.getObjectAcl({ + cos.getObjectAcl( + { Bucket: config.Bucket, Region: config.Region, - Key: '1.txt' - }, function (err, data) { - assert.ok(data.ACL = 'default'); + Key: '1.txt', + }, + function (err, data) { + assert.ok((data.ACL = 'private')); + AccessControlPolicy.Owner.ID = data.Owner.ID; + AccessControlPolicy2.Owner.ID = data.Owner.ID; + assert.ok(data.Grants.length === 1); done(); - }); - }); - }); - test('putObjectAcl() header ACL:public-read', function (done, assert) { - cos.putObjectAcl({ + }, + ); + }, + ); + }, + ); + }); + test('putObjectAcl() header ACL:default', function (done, assert) { + cos.putObjectAcl( + { + Bucket: config.Bucket, + Region: config.Region, + ACL: 'default', + Key: '1.txt', + }, + function (err, data) { + assert.ok(!err, 'putObjectAcl 成功'); + cos.getObjectAcl( + { Bucket: config.Bucket, Region: config.Region, - ACL: 'public-read', Key: '1.txt', - }, function (err, data) { - assert.ok(!err, 'putObjectAcl 成功'); - cos.getObjectAcl({Bucket: config.Bucket, Region: config.Region, Key: '1.txt'}, function (err, data) { - assert.ok(data.ACL = 'public-read'); - done(); - }); + }, + function (err, data) { + assert.ok((data.ACL = 'default')); + done(); + }, + ); + }, + ); + }); + test('putObjectAcl() header ACL:public-read', function (done, assert) { + cos.putObjectAcl( + { + Bucket: config.Bucket, + Region: config.Region, + ACL: 'public-read', + Key: '1.txt', + }, + function (err, data) { + assert.ok(!err, 'putObjectAcl 成功'); + cos.getObjectAcl({ Bucket: config.Bucket, Region: config.Region, Key: '1.txt' }, function (err, data) { + assert.ok((data.ACL = 'public-read')); + done(); }); - }); - // Object 不再支持修改写权限 - // test('putObjectAcl() header ACL:public-read-write', function (done, assert) { - // cos.putObjectAcl({ - // Bucket: config.Bucket, - // Region: config.Region, - // ACL: 'public-read-write', - // Key: '1.txt', - // }, function (err, data) { - // assert.ok(!err, 'putObjectAcl 成功'); - // cos.getObjectAcl({Bucket: config.Bucket, Region: config.Region, Key: '1.txt'}, function (err, data) { - // assert.ok(data.ACL = 'public-read-write'); - // done(); - // }); - // }); - // }); - test('putObjectAcl() header GrantRead:1001,1002', function (done, assert) { - var GrantRead = 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"'; - cos.putObjectAcl({ - Bucket: config.Bucket, - Region: config.Region, - GrantRead: GrantRead, - Key: '1.txt', - }, function (err, data) { - assert.ok(!err, 'putObjectAcl 成功'); - cos.getObjectAcl({Bucket: config.Bucket, Region: config.Region, Key: '1.txt'}, function (err, data) { - assert.ok(data.GrantRead = GrantRead); - done(); - }); + }, + ); + }); + // Object 不再支持修改写权限 + // test('putObjectAcl() header ACL:public-read-write', function (done, assert) { + // cos.putObjectAcl({ + // Bucket: config.Bucket, + // Region: config.Region, + // ACL: 'public-read-write', + // Key: '1.txt', + // }, function (err, data) { + // assert.ok(!err, 'putObjectAcl 成功'); + // cos.getObjectAcl({Bucket: config.Bucket, Region: config.Region, Key: '1.txt'}, function (err, data) { + // assert.ok(data.ACL = 'public-read-write'); + // done(); + // }); + // }); + // }); + test('putObjectAcl() header GrantRead:1001,1002', function (done, assert) { + var GrantRead = 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"'; + cos.putObjectAcl( + { + Bucket: config.Bucket, + Region: config.Region, + GrantRead: GrantRead, + Key: '1.txt', + }, + function (err, data) { + assert.ok(!err, 'putObjectAcl 成功'); + cos.getObjectAcl({ Bucket: config.Bucket, Region: config.Region, Key: '1.txt' }, function (err, data) { + assert.ok((data.GrantRead = GrantRead)); + done(); }); - }); - // Object 不再支持修改写权限 - // test('putObjectAcl() header GrantWrite:1001,1002', function (done, assert) { - // var GrantWrite = 'id="qcs::cam::uin/1001:uin/1001", id="qcs::cam::uin/1002:uin/1002"'; - // cos.putObjectAcl({ - // Bucket: config.Bucket, - // Region: config.Region, - // GrantWrite: GrantWrite, - // Key: '1.txt', - // }, function (err, data) { - // assert.ok(!err, 'putObjectAcl 成功'); - // cos.getObjectAcl({Bucket: config.Bucket, Region: config.Region, Key: '1.txt'}, function (err, data) { - // assert.ok(data.GrantWrite = GrantWrite); - // done(); - // }); - // }); - // }); - test('putObjectAcl() header GrantFullControl:1001,1002', function (done, assert) { - var GrantFullControl = 'id="qcs::cam::uin/1001:uin/1001", id="qcs::cam::uin/1002:uin/1002"'; - cos.putObjectAcl({ - Bucket: config.Bucket, - Region: config.Region, - GrantFullControl: GrantFullControl, - Key: '1.txt', - }, function (err, data) { - assert.ok(!err, 'putObjectAcl 成功'); - cos.getObjectAcl({Bucket: config.Bucket, Region: config.Region, Key: '1.txt'}, function (err, data) { - assert.ok(data.GrantFullControl = GrantFullControl); - done(); - }); + }, + ); + }); + // Object 不再支持修改写权限 + // test('putObjectAcl() header GrantWrite:1001,1002', function (done, assert) { + // var GrantWrite = 'id="qcs::cam::uin/1001:uin/1001", id="qcs::cam::uin/1002:uin/1002"'; + // cos.putObjectAcl({ + // Bucket: config.Bucket, + // Region: config.Region, + // GrantWrite: GrantWrite, + // Key: '1.txt', + // }, function (err, data) { + // assert.ok(!err, 'putObjectAcl 成功'); + // cos.getObjectAcl({Bucket: config.Bucket, Region: config.Region, Key: '1.txt'}, function (err, data) { + // assert.ok(data.GrantWrite = GrantWrite); + // done(); + // }); + // }); + // }); + test('putObjectAcl() header GrantFullControl:1001,1002', function (done, assert) { + var GrantFullControl = 'id="qcs::cam::uin/1001:uin/1001", id="qcs::cam::uin/1002:uin/1002"'; + cos.putObjectAcl( + { + Bucket: config.Bucket, + Region: config.Region, + GrantFullControl: GrantFullControl, + Key: '1.txt', + }, + function (err, data) { + assert.ok(!err, 'putObjectAcl 成功'); + cos.getObjectAcl({ Bucket: config.Bucket, Region: config.Region, Key: '1.txt' }, function (err, data) { + assert.ok((data.GrantFullControl = GrantFullControl)); + done(); }); - }); - test('putObjectAcl() header ACL:public-read, GrantRead:1001,1002', function (done, assert) { - var GrantFullControl = 'id="qcs::cam::uin/1001:uin/1001", id="qcs::cam::uin/1002:uin/1002"'; - cos.putObjectAcl({ - Bucket: config.Bucket, - Region: config.Region, - GrantFullControl: GrantFullControl, - ACL: 'public-read', - Key: '1.txt', - }, function (err, data) { - assert.ok(!err, 'putObjectAcl 成功'); - cos.getObjectAcl({Bucket: config.Bucket, Region: config.Region, Key: '1.txt'}, function (err, data) { - assert.ok(data.GrantFullControl = GrantFullControl); - assert.ok(data.ACL = 'public-read'); - done(); - }); + }, + ); + }); + test('putObjectAcl() header ACL:public-read, GrantRead:1001,1002', function (done, assert) { + var GrantFullControl = 'id="qcs::cam::uin/1001:uin/1001", id="qcs::cam::uin/1002:uin/1002"'; + cos.putObjectAcl( + { + Bucket: config.Bucket, + Region: config.Region, + GrantFullControl: GrantFullControl, + ACL: 'public-read', + Key: '1.txt', + }, + function (err, data) { + assert.ok(!err, 'putObjectAcl 成功'); + cos.getObjectAcl({ Bucket: config.Bucket, Region: config.Region, Key: '1.txt' }, function (err, data) { + assert.ok((data.GrantFullControl = GrantFullControl)); + assert.ok((data.ACL = 'public-read')); + done(); }); - }); - test('putObjectAcl() xml', function (done, assert) { - cos.putObjectAcl({ - Bucket: config.Bucket, - Region: config.Region, - AccessControlPolicy: AccessControlPolicy, - Key: '1.txt', - }, function (err, data) { - assert.ok(!err, 'putObjectAcl 成功'); - cos.getBucketAcl({Bucket: config.Bucket, Region: config.Region, Key: '1.txt'}, function (err, data) { - assert.ok(data.Grants.length === 1); - assert.ok(data.Grants[0] && data.Grants[0].Grantee.ID === 'qcs::cam::uin/10002:uin/10002', '设置 AccessControlPolicy ID 正确'); - assert.ok(data.Grants[0] && data.Grants[0].Permission === 'READ', '设置 AccessControlPolicy Permission 正确'); - done(); - }); + }, + ); + }); + test('putObjectAcl() xml', function (done, assert) { + cos.putObjectAcl( + { + Bucket: config.Bucket, + Region: config.Region, + AccessControlPolicy: AccessControlPolicy, + Key: '1.txt', + }, + function (err, data) { + assert.ok(!err, 'putObjectAcl 成功'); + cos.getBucketAcl({ Bucket: config.Bucket, Region: config.Region, Key: '1.txt' }, function (err, data) { + assert.ok(data.Grants.length === 1); + assert.ok( + data.Grants[0] && data.Grants[0].Grantee.ID === 'qcs::cam::uin/10002:uin/10002', + '设置 AccessControlPolicy ID 正确', + ); + assert.ok(data.Grants[0] && data.Grants[0].Permission === 'READ', '设置 AccessControlPolicy Permission 正确'); + done(); }); - }); - test('putObjectAcl() xml2', function (done, assert) { - cos.putObjectAcl({ + }, + ); + }); + test('putObjectAcl() xml2', function (done, assert) { + cos.putObjectAcl( + { + Bucket: config.Bucket, + Region: config.Region, + AccessControlPolicy: AccessControlPolicy2, + Key: '1.txt', + }, + function (err, data) { + assert.ok(!err, 'putObjectAcl 成功'); + cos.getObjectAcl( + { Bucket: config.Bucket, Region: config.Region, - AccessControlPolicy: AccessControlPolicy2, Key: '1.txt', - }, function (err, data) { - assert.ok(!err, 'putObjectAcl 成功'); - cos.getObjectAcl({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.txt' - }, function (err, data) { - assert.ok(data.Grants.length === 1); - assert.ok(data.Grants[0] && data.Grants[0].Grantee.ID === 'qcs::cam::uin/10002:uin/10002', 'ID 正确'); - assert.ok(data.Grants[0] && data.Grants[0].Permission === 'READ', 'Permission 正确'); - done(); - }); - }); - }); - test('putObjectAcl() decodeAcl', function (done, assert) { - cos.getObjectAcl({ + }, + function (err, data) { + assert.ok(data.Grants.length === 1); + assert.ok(data.Grants[0] && data.Grants[0].Grantee.ID === 'qcs::cam::uin/10002:uin/10002', 'ID 正确'); + assert.ok(data.Grants[0] && data.Grants[0].Permission === 'READ', 'Permission 正确'); + done(); + }, + ); + }, + ); + }); + test('putObjectAcl() decodeAcl', function (done, assert) { + cos.getObjectAcl( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1.txt', + }, + function (err, data) { + cos.putObjectAcl( + { Bucket: config.Bucket, Region: config.Region, - Key: '1.txt' - }, function (err, data) { - cos.putObjectAcl({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.txt', - GrantFullControl: data.GrantFullControl, - GrantWrite: data.GrantWrite, - GrantRead: data.GrantRead, - ACL: data.ACL, - }, function (err, data) { - assert.ok(data); - done(); - }); - }); - }); + Key: '1.txt', + GrantFullControl: data.GrantFullControl, + GrantWrite: data.GrantWrite, + GrantRead: data.GrantRead, + ACL: data.ACL, + }, + function (err, data) { + assert.ok(data); + done(); + }, + ); + }, + ); + }); }); group('optionsObject()', function () { - test('optionsObject()', function (done, assert) { - cos.putBucketCors({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - CORSRules: [{ - "AllowedOrigins": ["*"], - "AllowedMethods": ["GET", "POST", "PUT", "DELETE", "HEAD"], - "AllowedHeaders": ["*", 'test-' + Date.now().toString(36)], - "ExposeHeaders": ['etag'], - "MaxAgeSeconds": "5" - }], - }, function (err, data) { - cos.optionsObject({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Key: '1.jpg', - Origin: 'https://qq.com', - 'AccessControlRequestMethod': 'PUT', - 'AccessControlRequestHeaders': 'Authorization,x-cos-security-token', - }, function (err, data) { - assert.ok(data && data.statusCode === 200); - done(); - }); - }); - }); - test('delete cors, optionsObject()', function (done, assert) { - cos.deleteBucketCors({ + test('optionsObject()', function (done, assert) { + cos.putBucketCors( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + CORSRules: [ + { + AllowedOrigins: ['*'], + AllowedMethods: ['GET', 'POST', 'PUT', 'DELETE', 'HEAD'], + AllowedHeaders: ['*', 'test-' + Date.now().toString(36)], + ExposeHeaders: ['etag'], + MaxAgeSeconds: '5', + }, + ], + }, + function (err, data) { + cos.optionsObject( + { Bucket: config.Bucket, // Bucket 格式:test-1250000000 Region: config.Region, - }, function (err, data) { - cos.optionsObject({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Key: '1.jpg', - Headers: { - Origin: 'https://qq.com', - 'Access-Control-Request-Method': 'PUT', - 'Access-Control-Request-Headers': 'Authorization,x-cos-security-token', - }, - }, function (err, data) { - assert.ok(err); - done(); - }); - }); - }); + Key: '1.jpg', + Origin: 'https://qq.com', + AccessControlRequestMethod: 'PUT', + AccessControlRequestHeaders: 'Authorization,x-cos-security-token', + }, + function (err, data) { + assert.ok(data && data.statusCode === 200); + done(); + }, + ); + }, + ); + }); + test('delete cors, optionsObject()', function (done, assert) { + cos.deleteBucketCors( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + }, + function (err, data) { + cos.optionsObject( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: '1.jpg', + Headers: { + Origin: 'https://qq.com', + 'Access-Control-Request-Method': 'PUT', + 'Access-Control-Request-Headers': 'Authorization,x-cos-security-token', + }, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }, + ); + }); }); group('BucketCors', function () { - var CORSRules = [{ - "AllowedOrigins": ["*"], - "AllowedMethods": ["GET", "POST", "PUT", "DELETE", "HEAD"], - "AllowedHeaders": ["*", 'test-' + Date.now().toString(36)], - "ExposeHeaders": [ - 'etag', - 'date', - 'content-length', - 'expires', - 'cache-control', - 'content-disposition', - 'content-encoding', - 'x-cos-acl', - 'x-cos-version-id', - 'x-cos-request-id', - 'x-cos-delete-marker', - 'x-cos-server-side-encryption', - 'x-cos-storage-class', - 'x-cos-acl', - 'x-cos-meta-test', - 'x-cos-tagging-count', - ], - "MaxAgeSeconds": "5" - }]; - var CORSRulesMulti = [{ - "AllowedOrigins": ["*"], - "AllowedMethods": ["GET", "POST", "PUT", "DELETE", "HEAD"], - "AllowedHeaders": ["*"], - "ExposeHeaders": ["ETag", "Date", "Content-Length", "x-cos-acl", "x-cos-version-id", "x-cos-request-id", "x-cos-delete-marker", "x-cos-server-side-encryption"], - "MaxAgeSeconds": "5" - }, { - "AllowedOrigins": ["http://qq.com", "http://qcloud.com"], - "AllowedMethods": ["GET", "POST", "PUT", "DELETE", "HEAD"], - "AllowedHeaders": ["*"], - "ExposeHeaders": ["ETag", "Date", "Content-Length", "x-cos-acl", "x-cos-version-id", "x-cos-request-id", "x-cos-delete-marker", "x-cos-server-side-encryption"], - "MaxAgeSeconds": "5" - }]; - test('deleteBucketCors()', function (done, assert) { - cos.deleteBucketCors({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(!err); - cos.getBucketCors({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(comparePlainObject([], data.CORSRules)); - done(); - }); - }); - }); - test('deleteBucketCors() bucket not exist', function (done, assert) { - cos.deleteBucketCors({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(err); - done(); - }); - }); - test('putBucketCors() old CORSConfiguration', function (done, assert) { - CORSRules[0].AllowedHeaders[1] = 'test-' + Date.now().toString(36); - cos.putBucketCors({ - Bucket: config.Bucket, - Region: config.Region, - CORSConfiguration: { - CORSRules: CORSRules - } - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getBucketCors({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(comparePlainObject(CORSRules, data.CORSRules)); - done(); - }); - }, 2000); - }); - }); - test('putBucketCors() multi', function (done, assert) { - cos.putBucketCors({ - Bucket: config.Bucket, - Region: config.Region, - CORSConfiguration: { - CORSRules: CORSRulesMulti - } - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getBucketCors({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(comparePlainObject(CORSRulesMulti, data.CORSRules)); - done(); - }); - }, 2000); - }); - }); - test('putBucketCors() old CORSRules', function (done, assert) { - CORSRules[0].AllowedHeaders[1] = 'test-' + Date.now().toString(36); - cos.putBucketCors({ - Bucket: config.Bucket, - Region: config.Region, - CORSRules: CORSRules - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getBucketCors({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(comparePlainObject(CORSRules, data.CORSRules)); - done(); - }); - }, 2000); - }); - }); - test('putBucketCors(),getBucketCors()', function (done, assert) { - CORSRules[0].AllowedHeaders = ['*']; - cos.putBucketCors({ + var CORSRules = [ + { + AllowedOrigins: ['*'], + AllowedMethods: ['GET', 'POST', 'PUT', 'DELETE', 'HEAD'], + AllowedHeaders: ['*', 'test-' + Date.now().toString(36)], + ExposeHeaders: [ + 'etag', + 'date', + 'content-length', + 'expires', + 'cache-control', + 'content-disposition', + 'content-encoding', + 'x-cos-acl', + 'x-cos-version-id', + 'x-cos-request-id', + 'x-cos-delete-marker', + 'x-cos-server-side-encryption', + 'x-cos-storage-class', + 'x-cos-acl', + 'x-cos-meta-test', + 'x-cos-tagging-count', + ], + MaxAgeSeconds: '5', + }, + ]; + var CORSRulesMulti = [ + { + AllowedOrigins: ['*'], + AllowedMethods: ['GET', 'POST', 'PUT', 'DELETE', 'HEAD'], + AllowedHeaders: ['*'], + ExposeHeaders: [ + 'ETag', + 'Date', + 'Content-Length', + 'x-cos-acl', + 'x-cos-version-id', + 'x-cos-request-id', + 'x-cos-delete-marker', + 'x-cos-server-side-encryption', + ], + MaxAgeSeconds: '5', + }, + { + AllowedOrigins: ['http://qq.com', 'http://qcloud.com'], + AllowedMethods: ['GET', 'POST', 'PUT', 'DELETE', 'HEAD'], + AllowedHeaders: ['*'], + ExposeHeaders: [ + 'ETag', + 'Date', + 'Content-Length', + 'x-cos-acl', + 'x-cos-version-id', + 'x-cos-request-id', + 'x-cos-delete-marker', + 'x-cos-server-side-encryption', + ], + MaxAgeSeconds: '5', + }, + ]; + test('deleteBucketCors()', function (done, assert) { + cos.deleteBucketCors( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(!err); + cos.getBucketCors( + { Bucket: config.Bucket, Region: config.Region, - CORSConfiguration: { - CORSRules: CORSRules - } - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getBucketCors({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(comparePlainObject(CORSRules, data.CORSRules)); - done(); - }); - }, 2000); - }); - }); + }, + function (err, data) { + assert.ok(comparePlainObject([], data.CORSRules)); + done(); + }, + ); + }, + ); + }); + test('deleteBucketCors() bucket not exist', function (done, assert) { + cos.deleteBucketCors( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); + test('putBucketCors() old CORSConfiguration', function (done, assert) { + CORSRules[0].AllowedHeaders[1] = 'test-' + Date.now().toString(36); + cos.putBucketCors( + { + Bucket: config.Bucket, + Region: config.Region, + CORSConfiguration: { + CORSRules: CORSRules, + }, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getBucketCors( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(comparePlainObject(CORSRules, data.CORSRules)); + done(); + }, + ); + }, 2000); + }, + ); + }); + test('putBucketCors() multi', function (done, assert) { + cos.putBucketCors( + { + Bucket: config.Bucket, + Region: config.Region, + CORSConfiguration: { + CORSRules: CORSRulesMulti, + }, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getBucketCors( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(comparePlainObject(CORSRulesMulti, data.CORSRules)); + done(); + }, + ); + }, 2000); + }, + ); + }); + test('putBucketCors() old CORSRules', function (done, assert) { + CORSRules[0].AllowedHeaders[1] = 'test-' + Date.now().toString(36); + cos.putBucketCors( + { + Bucket: config.Bucket, + Region: config.Region, + CORSRules: CORSRules, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getBucketCors( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(comparePlainObject(CORSRules, data.CORSRules)); + done(); + }, + ); + }, 2000); + }, + ); + }); + test('putBucketCors(),getBucketCors()', function (done, assert) { + CORSRules[0].AllowedHeaders = ['*']; + cos.putBucketCors( + { + Bucket: config.Bucket, + Region: config.Region, + CORSConfiguration: { + CORSRules: CORSRules, + }, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getBucketCors( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(comparePlainObject(CORSRules, data.CORSRules)); + done(); + }, + ); + }, 2000); + }, + ); + }); }); group('BucketTagging', function () { - var Tags = [ - {Key: "k1", Value: "v1"} - ]; - var TagsMulti = [ - {Key: "k1", Value: "v1"}, - {Key: "k2", Value: "v2"}, - ]; - test('putBucketTagging(),getBucketTagging()', function (done, assert) { - Tags[0].Value = Date.now().toString(36); - cos.putBucketTagging({ - Bucket: config.Bucket, - Region: config.Region, - Tagging: { - Tags: Tags - } - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getBucketTagging({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(comparePlainObject(Tags, data.Tags)); - done(); - }); - }, 1000); - }); - }); - test('putBucketTagging() bucket not exist', function (done, assert) { - cos.putBucketTagging({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region, - Tagging: { - Tags: Tags - } - }, function (err, data) { - assert.ok(err); - done(); - }); - }); - test('deleteBucketTagging()', function (done, assert) { - cos.deleteBucketTagging({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getBucketTagging({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(comparePlainObject([], data.Tags)); - done(); - }); - }, 1000); - }); - }); - test('deleteBucketTagging() bucket not exist', function (done, assert) { - cos.deleteBucketTagging({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(err); - done(); - }); + var Tags = [{ Key: 'k1', Value: 'v1' }]; + var TagsMulti = [ + { Key: 'k1', Value: 'v1' }, + { Key: 'k2', Value: 'v2' }, + ]; + test('putBucketTagging(),getBucketTagging()', function (done, assert) { + Tags[0].Value = Date.now().toString(36); + cos.putBucketTagging( + { + Bucket: config.Bucket, + Region: config.Region, + Tagging: { + Tags: Tags, + }, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getBucketTagging( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(comparePlainObject(Tags, data.Tags)); + done(); + }, + ); + }, 1000); + }, + ); + }); + test('putBucketTagging() bucket not exist', function (done, assert) { + cos.putBucketTagging( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + Tagging: { + Tags: Tags, + }, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); + test('deleteBucketTagging()', function (done, assert) { + cos.deleteBucketTagging( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getBucketTagging( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(comparePlainObject([], data.Tags)); + done(); + }, + ); + }, 1000); + }, + ); + }); + test('deleteBucketTagging() bucket not exist', function (done, assert) { + cos.deleteBucketTagging( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); + test('putBucketTagging() multi', function (done, assert) { + Tags[0].Value = Date.now().toString(36); + cos.putBucketTagging( + { + Bucket: config.Bucket, + Region: config.Region, + Tagging: { + Tags: TagsMulti, + }, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getBucketTagging( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(comparePlainObject(TagsMulti, data.Tags)); + done(); + }, + ); + }, 1000); + }, + ); }); - test('putBucketTagging() multi', function (done, assert) { - Tags[0].Value = Date.now().toString(36); - cos.putBucketTagging({ - Bucket: config.Bucket, - Region: config.Region, - Tagging: { - Tags: TagsMulti - } - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getBucketTagging({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(comparePlainObject(TagsMulti, data.Tags)); - done(); - }); - }, 1000); - }); - }); }); group('BucketPolicy', function () { - var Prefix = Date.now().toString(36); - var Policy = { - "version": "2.0", - "principal": {"qcs": ["qcs::cam::uin/10001:uin/10001"]}, // 这里的 10001 是 QQ 号 - "statement": [{ - "effect": "allow", - "action": [ - "name/cos:GetBucket", - "name/cos:PutObject", - "name/cos:PostObject", - "name/cos:PutObjectCopy", - "name/cos:InitiateMultipartUpload", - "name/cos:UploadPart", - "name/cos:UploadPartCopy", - "name/cos:CompleteMultipartUpload", - "name/cos:AbortMultipartUpload", - "name/cos:AppendObject" - ], - "resource": ["qcs::cos:" + config.Region + ":uid/" + AppId + ":" + BucketLongName + "//" + AppId + "/" + BucketShortName + "/" + Prefix + "/*"] // 1250000000 是 appid - }] - }; - var getRes = function (s) { - var t = s && s[0]; - var res = t && t.resource && t.resource[0]; - return res; - }; - test('putBucketPolicy(),getBucketPolicy()', function (done, assert) { - cos.putBucketPolicy({ + var Prefix = Date.now().toString(36); + var Policy = { + version: '2.0', + principal: { qcs: ['qcs::cam::uin/10001:uin/10001'] }, // 这里的 10001 是 QQ 号 + statement: [ + { + effect: 'allow', + action: [ + 'name/cos:GetBucket', + 'name/cos:PutObject', + 'name/cos:PostObject', + 'name/cos:PutObjectCopy', + 'name/cos:InitiateMultipartUpload', + 'name/cos:UploadPart', + 'name/cos:UploadPartCopy', + 'name/cos:CompleteMultipartUpload', + 'name/cos:AbortMultipartUpload', + 'name/cos:AppendObject', + ], + resource: [ + 'qcs::cos:' + + config.Region + + ':uid/' + + AppId + + ':' + + BucketLongName + + '//' + + AppId + + '/' + + BucketShortName + + '/' + + Prefix + + '/*', + ], // 1250000000 是 appid + }, + ], + }; + var getRes = function (s) { + var t = s && s[0]; + var res = t && t.resource && t.resource[0]; + return res; + }; + test('putBucketPolicy(),getBucketPolicy()', function (done, assert) { + cos.putBucketPolicy( + { + Bucket: config.Bucket, + Region: config.Region, + Policy: Policy, + }, + function (err, data) { + assert.ok(!err); + cos.getBucketPolicy( + { Bucket: config.Bucket, Region: config.Region, - Policy: Policy - }, function (err, data) { - assert.ok(!err); - cos.getBucketPolicy({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(getRes(Policy.statement) === getRes(data.Policy.Statement)); - done(); - }); - }); - }); - test('putBucketPolicy() bucket not exist', function (done, assert) { - cos.putBucketPolicy({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region, - Policy: JSON.stringify(Policy) - }, function (err, data) { - assert.ok(err); + }, + function (err, data) { + assert.ok(getRes(Policy.statement) === getRes(data.Policy.Statement)); done(); - }); - }); - test('putBucketPolicy() s3', function (done, assert) { - cos.putBucketPolicy({ - Bucket: config.Bucket, - Region: config.Region, - Policy: JSON.stringify(Policy) - }, function (err, data) { - assert.ok(!err); - done(); - }); - }); - test('deleteBucketPolicy() bucket not exist', function (done, assert) { - cos.deleteBucketPolicy({ - Bucket: Date.now().toString(36) + config.Bucket, + }, + ); + }, + ); + }); + test('putBucketPolicy() bucket not exist', function (done, assert) { + cos.putBucketPolicy( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + Policy: JSON.stringify(Policy), + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); + test('putBucketPolicy() s3', function (done, assert) { + cos.putBucketPolicy( + { + Bucket: config.Bucket, + Region: config.Region, + Policy: JSON.stringify(Policy), + }, + function (err, data) { + assert.ok(!err); + done(); + }, + ); + }); + test('deleteBucketPolicy() bucket not exist', function (done, assert) { + cos.deleteBucketPolicy( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + Policy: JSON.stringify(Policy), + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); + test('deleteBucketPolicy()', function (done, assert) { + cos.deleteBucketPolicy( + { + Bucket: config.Bucket, + Region: config.Region, + Policy: JSON.stringify(Policy), + }, + function (err, data) { + assert.ok(!err); + cos.getBucketPolicy( + { + Bucket: config.Bucket, Region: config.Region, - Policy: JSON.stringify(Policy) - }, function (err, data) { - assert.ok(err); + }, + function (err, data) { + assert.ok(err.ErrorStatus === 'Policy Not Found'); done(); - }); - }); - test('deleteBucketPolicy()', function (done, assert) { - cos.deleteBucketPolicy({ - Bucket: config.Bucket, - Region: config.Region, - Policy: JSON.stringify(Policy) - }, function (err, data) { - assert.ok(!err); - cos.getBucketPolicy({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(err.ErrorStatus === 'Policy Not Found'); - done(); - }); - }); - }); + }, + ); + }, + ); + }); }); group('BucketLocation', function () { - test('getBucketLocation()', function (done, assert) { - cos.getBucketLocation({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - var map1 = { - 'tianjin': 'ap-beijing-1', - 'cn-south-2': 'ap-guangzhou-2', - 'cn-south': 'ap-guangzhou', - 'cn-east': 'ap-shanghai', - 'cn-southwest': 'ap-chengdu', - }; - var map2 = { - 'ap-beijing-1': 'tianjin', - 'ap-guangzhou-2': 'cn-south-2', - 'ap-guangzhou': 'cn-south', - 'ap-shanghai': 'cn-east', - 'ap-chengdu': 'cn-southwest', - }; - assert.ok(data.LocationConstraint === config.Region || data.LocationConstraint === map1[config.Region] || - data.LocationConstraint === map2[config.Region]); - done(); - }); - }); + test('getBucketLocation()', function (done, assert) { + cos.getBucketLocation( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + var map1 = { + tianjin: 'ap-beijing-1', + 'cn-south-2': 'ap-guangzhou-2', + 'cn-south': 'ap-guangzhou', + 'cn-east': 'ap-shanghai', + 'cn-southwest': 'ap-chengdu', + }; + var map2 = { + 'ap-beijing-1': 'tianjin', + 'ap-guangzhou-2': 'cn-south-2', + 'ap-guangzhou': 'cn-south', + 'ap-shanghai': 'cn-east', + 'ap-chengdu': 'cn-southwest', + }; + assert.ok( + data.LocationConstraint === config.Region || + data.LocationConstraint === map1[config.Region] || + data.LocationConstraint === map2[config.Region], + ); + done(); + }, + ); + }); }); group('BucketLifecycle', function () { - var Rules = [{ - 'ID': '1', - 'Filter': { - 'Prefix': 'test_' + Date.now().toString(36), - }, - 'Status': 'Enabled', - 'Transition': { - 'Date': '2018-07-29T16:00:00.000Z', - 'StorageClass': 'STANDARD_IA' - } - }]; - var RulesMulti = [{ - 'ID': '1', - 'Filter': { - 'Prefix': 'test1_' + Date.now().toString(36), - }, - 'Status': 'Enabled', - 'Transition': { - 'Date': '2018-07-29T16:00:00.000Z', - 'StorageClass': 'STANDARD_IA' - } - }, { - 'ID': '2', - 'Filter': { - 'Prefix': 'test2_' + Date.now().toString(36), - }, - 'Status': 'Enabled', - 'Transition': { - 'Date': '2018-07-29T16:00:00.000Z', - 'StorageClass': 'STANDARD_IA' - } - }]; - test('deleteBucketLifecycle()', function (done, assert) { - cos.deleteBucketLifecycle({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - cos.getBucketLifecycle({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(comparePlainObject([], data.Rules)); - done(); - }); - }); - }); - test('deleteBucketLifecycle() bucket not exist', function (done, assert) { - cos.deleteBucketLifecycle({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(err); - done(); - }); - }); - test('putBucketLifecycle(),getBucketLifecycle()', function (done, assert) { - Rules[0].Filter.Prefix = 'test_' + Date.now().toString(36); - cos.putBucketLifecycle({ + var Rules = [ + { + ID: '1', + Filter: { + Prefix: 'test_' + Date.now().toString(36), + }, + Status: 'Enabled', + Transition: { + Date: '2018-07-29T16:00:00.000Z', + StorageClass: 'STANDARD_IA', + }, + }, + ]; + var RulesMulti = [ + { + ID: '1', + Filter: { + Prefix: 'test1_' + Date.now().toString(36), + }, + Status: 'Enabled', + Transition: { + Date: '2018-07-29T16:00:00.000Z', + StorageClass: 'STANDARD_IA', + }, + }, + { + ID: '2', + Filter: { + Prefix: 'test2_' + Date.now().toString(36), + }, + Status: 'Enabled', + Transition: { + Date: '2018-07-29T16:00:00.000Z', + StorageClass: 'STANDARD_IA', + }, + }, + ]; + test('deleteBucketLifecycle()', function (done, assert) { + cos.deleteBucketLifecycle( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + cos.getBucketLifecycle( + { Bucket: config.Bucket, Region: config.Region, - LifecycleConfiguration: { - Rules: Rules - } - }, function (err, data) { - cos.getBucketLifecycle({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(comparePlainObject(Rules, data && data.Rules)); - done(); - }); - }); - }); - test('putBucketLifecycle() multi', function (done, assert) { - Rules[0].Filter.Prefix = 'test_' + Date.now().toString(36); - cos.putBucketLifecycle({ + }, + function (err, data) { + assert.ok(comparePlainObject([], data.Rules)); + done(); + }, + ); + }, + ); + }); + test('deleteBucketLifecycle() bucket not exist', function (done, assert) { + cos.deleteBucketLifecycle( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); + test('putBucketLifecycle(),getBucketLifecycle()', function (done, assert) { + Rules[0].Filter.Prefix = 'test_' + Date.now().toString(36); + cos.putBucketLifecycle( + { + Bucket: config.Bucket, + Region: config.Region, + LifecycleConfiguration: { + Rules: Rules, + }, + }, + function (err, data) { + cos.getBucketLifecycle( + { Bucket: config.Bucket, Region: config.Region, - LifecycleConfiguration: { - Rules: RulesMulti - } - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getBucketLifecycle({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(comparePlainObject(RulesMulti, data.Rules)); - done(); - }); - }, 2000); - }); - }); - test('putBucketLifecycle() bucket not exist', function (done, assert) { - cos.putBucketLifecycle({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region, - LifecycleConfiguration: { - Rules: RulesMulti - } - }, function (err, data) { - assert.ok(err); - done(); - }); - }); + }, + function (err, data) { + assert.ok(comparePlainObject(Rules, data && data.Rules)); + done(); + }, + ); + }, + ); + }); + test('putBucketLifecycle() multi', function (done, assert) { + Rules[0].Filter.Prefix = 'test_' + Date.now().toString(36); + cos.putBucketLifecycle( + { + Bucket: config.Bucket, + Region: config.Region, + LifecycleConfiguration: { + Rules: RulesMulti, + }, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getBucketLifecycle( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(comparePlainObject(RulesMulti, data.Rules)); + done(); + }, + ); + }, 2000); + }, + ); + }); + test('putBucketLifecycle() bucket not exist', function (done, assert) { + cos.putBucketLifecycle( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + LifecycleConfiguration: { + Rules: RulesMulti, + }, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); }); group('BucketWebsite', function () { - var RoutingRules = [{ - Condition: { - HttpErrorCodeReturnedEquals: "404" - }, - Redirect: { - Protocol: "https", - ReplaceKeyWith: "404.html" - } - }, { - Condition: { - KeyPrefixEquals: "docs/" - }, - Redirect: { - Protocol: "https", - ReplaceKeyPrefixWith: "documents/" - } - }, { - Condition: { - KeyPrefixEquals: "img/" - }, - Redirect: { - Protocol: "https", - ReplaceKeyWith: "picture.jpg" - } - }]; - var WebsiteConfiguration = { - IndexDocument: { - Suffix: "index.html" - }, - RedirectAllRequestsTo: { - Protocol: "https" - }, - ErrorDocument: { - Key: "error.html" - }, - }; - test('putBucketWebsite() no WebsiteConfiguration', function (done, assert) { - cos.putBucketWebsite({ - Bucket: config.Bucket, - Region: config.Region, - }, function (err, data) { - assert.ok(err); - done(); - }); - }); - test('putBucketWebsite() bucket not exist', function (done, assert) { - cos.putBucketWebsite({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region, - }, function (err, data) { - assert.ok(err); - done(); - }); - }); - test('putBucketWebsite(),getBucketWebsite()', function (done, assert) { - cos.putBucketWebsite({ - Bucket: config.Bucket, - Region: config.Region, - WebsiteConfiguration: WebsiteConfiguration - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getBucketWebsite({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(comparePlainObject(WebsiteConfiguration, data.WebsiteConfiguration)); - done(); - }); - }, 2000); - }); - }); - test('putBucketWebsite() multi RoutingRules', function (done, assert) { - WebsiteConfiguration.RoutingRules = RoutingRules; - cos.putBucketWebsite({ + var RoutingRules = [ + { + Condition: { + HttpErrorCodeReturnedEquals: '404', + }, + Redirect: { + Protocol: 'https', + ReplaceKeyWith: '404.html', + }, + }, + { + Condition: { + KeyPrefixEquals: 'docs/', + }, + Redirect: { + Protocol: 'https', + ReplaceKeyPrefixWith: 'documents/', + }, + }, + { + Condition: { + KeyPrefixEquals: 'img/', + }, + Redirect: { + Protocol: 'https', + ReplaceKeyWith: 'picture.jpg', + }, + }, + ]; + var WebsiteConfiguration = { + IndexDocument: { + Suffix: 'index.html', + }, + RedirectAllRequestsTo: { + Protocol: 'https', + }, + ErrorDocument: { + Key: 'error.html', + }, + }; + test('putBucketWebsite() no WebsiteConfiguration', function (done, assert) { + cos.putBucketWebsite( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); + test('putBucketWebsite() bucket not exist', function (done, assert) { + cos.putBucketWebsite( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); + test('putBucketWebsite(),getBucketWebsite()', function (done, assert) { + cos.putBucketWebsite( + { + Bucket: config.Bucket, + Region: config.Region, + WebsiteConfiguration: WebsiteConfiguration, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getBucketWebsite( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(comparePlainObject(WebsiteConfiguration, data.WebsiteConfiguration)); + done(); + }, + ); + }, 2000); + }, + ); + }); + test('putBucketWebsite() multi RoutingRules', function (done, assert) { + WebsiteConfiguration.RoutingRules = RoutingRules; + cos.putBucketWebsite( + { + Bucket: config.Bucket, + Region: config.Region, + WebsiteConfiguration: WebsiteConfiguration, + }, + function (err, data) { + assert.ok(!err); + cos.getBucketWebsite( + { Bucket: config.Bucket, Region: config.Region, - WebsiteConfiguration: WebsiteConfiguration - }, function (err, data) { - assert.ok(!err); - cos.getBucketWebsite({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(comparePlainObject(WebsiteConfiguration, data.WebsiteConfiguration)); - done(); - }); - }); - }); - test('deleteBucketWebsite()', function (done, assert) { - cos.deleteBucketWebsite({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getBucketWebsite({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(comparePlainObject({}, data.WebsiteConfiguration)); - done(); - }); - }, 2000); - }); - }); - test('deleteBucketWebsite() bucket not exist', function (done, assert) { - cos.deleteBucketWebsite({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(err); - done(); - }); - }); + }, + function (err, data) { + assert.ok(comparePlainObject(WebsiteConfiguration, data.WebsiteConfiguration)); + done(); + }, + ); + }, + ); + }); + test('deleteBucketWebsite()', function (done, assert) { + cos.deleteBucketWebsite( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getBucketWebsite( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(comparePlainObject({}, data.WebsiteConfiguration)); + done(); + }, + ); + }, 2000); + }, + ); + }); + test('deleteBucketWebsite() bucket not exist', function (done, assert) { + cos.deleteBucketWebsite( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); }); group('BucketDomain', function () { - var DomainRule = [{ - Status: "DISABLED", - Name: "www.testDomain1.com", - Type: "REST" + var DomainRule = [ + { + Status: 'DISABLED', + Name: 'www.testDomain1.com', + Type: 'REST', }, { - Status: "DISABLED", - Name: "www.testDomain2.com", - Type: "WEBSITE" - }]; - test('putBucketDomain(),getBucketDomain()', function (done, assert) { - cos.putBucketDomain({ - Bucket: config.Bucket, - Region: config.Region, - DomainRule: DomainRule - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getBucketDomain({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(comparePlainObject(DomainRule, data.DomainRule)); - done(); - }); - }, 2000); - }); - }); - test('putBucketDomain() bucket not exist', function (done, assert) { - cos.putBucketDomain({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region, - DomainRule: DomainRule - }, function (err, data) { - assert.ok(err); - done(); - }); - }); - // test('putBucketDomain() multi', function (done, assert) { - // cos.putBucketDomain({ - // Bucket: config.Bucket, - // Region: config.Region, - // DomainRule: DomainRuleMulti - // }, function (err, data) { - // assert.ok(!err); - // setTimeout(function () { - // cos.getBucketDomain({ - // Bucket: config.Bucket, - // Region: config.Region - // }, function (err, data) { - // assert.ok(comparePlainObject(DomainRuleMulti, data.DomainRule)); - // done(); - // }); - // }, 2000); - // }); - // }); - test('deleteBucketDomain()', function (done, assert) { - cos.deleteBucketDomain({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getBucketDomain({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - if (err) { - done(); - } else { - assert.ok(comparePlainObject([], data.DomainRule)); - done(); - } - }); - }, 2000); - }); - }); - test('deleteBucketDomain() bucket not exist', function (done, assert) { - cos.deleteBucketDomain({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region, - DomainRule: DomainRule - }, function (err, data) { - assert.ok(err); - done(); - }); + Status: 'DISABLED', + Name: 'www.testDomain2.com', + Type: 'WEBSITE', + }, + ]; + test('putBucketDomain(),getBucketDomain()', function (done, assert) { + cos.putBucketDomain( + { + Bucket: config.Bucket, + Region: config.Region, + DomainRule: DomainRule, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getBucketDomain( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(comparePlainObject(DomainRule, data.DomainRule)); + done(); + }, + ); + }, 2000); + }, + ); + }); + test('putBucketDomain() bucket not exist', function (done, assert) { + cos.putBucketDomain( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + DomainRule: DomainRule, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); + // test('putBucketDomain() multi', function (done, assert) { + // cos.putBucketDomain({ + // Bucket: config.Bucket, + // Region: config.Region, + // DomainRule: DomainRuleMulti + // }, function (err, data) { + // assert.ok(!err); + // setTimeout(function () { + // cos.getBucketDomain({ + // Bucket: config.Bucket, + // Region: config.Region + // }, function (err, data) { + // assert.ok(comparePlainObject(DomainRuleMulti, data.DomainRule)); + // done(); + // }); + // }, 2000); + // }); + // }); + test('deleteBucketDomain()', function (done, assert) { + cos.deleteBucketDomain( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getBucketDomain( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + if (err) { + done(); + } else { + assert.ok(comparePlainObject([], data.DomainRule)); + done(); + } + }, + ); + }, 2000); + }, + ); + }); + test('deleteBucketDomain() bucket not exist', function (done, assert) { + cos.deleteBucketDomain( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + DomainRule: DomainRule, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); }); }); group('params check Region', function () { - test('params check', function (done, assert) { - cos.headBucket({ - Bucket: config.Bucket, - Region: 'cos.ap-guangzhou' - }, function (err, data) { - assert.ok(err.message === 'param Region should not be start with "cos."'); - done(); - }); - }); - test('params check Region', function (done, assert) { - cos.headBucket({ - Bucket: config.Bucket, - Region: 'gz' - }, function (err, data) { - assert.ok(err); - done(); - }); - }); + test('params check', function (done, assert) { + cos.headBucket( + { + Bucket: config.Bucket, + Region: 'cos.ap-guangzhou', + }, + function (err, data) { + assert.ok(err.message === 'param Region should not be start with "cos."'); + done(); + }, + ); + }); + test('params check Region', function (done, assert) { + cos.headBucket( + { + Bucket: config.Bucket, + Region: 'gz', + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); }); group('Key 特殊字符处理', function () { - test('Key 特殊字符处理', function (done, assert) { - var Key = '中文→↓←→↖↗↙↘! $&\'()+,-.0123456789=@ABCDEFGHIJKLMNOPQRSTUV?WXYZ[]^_`abcdefghijklmnopqrstuvwxyz{}~.jpg'; - cos.putObject({ + test('Key 特殊字符处理', function (done, assert) { + var Key = + "中文→↓←→↖↗↙↘! $&'()+,-.0123456789=@ABCDEFGHIJKLMNOPQRSTUV?WXYZ[]^_`abcdefghijklmnopqrstuvwxyz{}~.jpg"; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + Body: 'hello', + }, + function (err, data) { + assert.ok(!err); + cos.deleteObject( + { Bucket: config.Bucket, Region: config.Region, Key: Key, Body: 'hello', - }, function (err, data) { + }, + function (err, data) { assert.ok(!err); - cos.deleteObject({ + cos.deleteMultipleObject( + { Bucket: config.Bucket, Region: config.Region, - Key: Key, - Body: 'hello', - }, function (err, data) { + Objects: { + Key: Key, + }, + }, + function (err, data) { assert.ok(!err); - cos.deleteMultipleObject({ - Bucket: config.Bucket, - Region: config.Region, - Objects: { - Key: Key, - }, - }, function (err, data) { - assert.ok(!err); - done(); - }); - }); - }); - }); + done(); + }, + ); + }, + ); + }, + ); + }); }); group('Bucket 格式有误', function () { - test('Bucket 带有中文', function (done, assert) { - cos.headBucket({ - Bucket: '中文-1250000000', - Region: config.Region, - }, function (err, data) { - assert.ok(err && err.message === 'Bucket should format as "test-1250000000".'); - done(); - }); - }); - test('Bucket 带有 /', function (done, assert) { - cos.headBucket({ - Bucket: 'te/st-1250000000', - Region: config.Region, - }, function (err, data) { - assert.ok(err && err.message === 'Bucket should format as "test-1250000000".'); - done(); - }); - }); - test('Bucket 带有 .', function (done, assert) { - cos.headBucket({ - Bucket: 'te.st-1250000000', - Region: config.Region, - }, function (err, data) { - assert.ok(err && err.message === 'Bucket should format as "test-1250000000".'); - done(); - }); - }); - test('Bucket 带有 :', function (done, assert) { - cos.headBucket({ - Bucket: 'te:st-1250000000', - Region: config.Region, - }, function (err, data) { - assert.ok(err && err.message === 'Bucket should format as "test-1250000000".'); - done(); - }); - }); + test('Bucket 带有中文', function (done, assert) { + cos.headBucket( + { + Bucket: '中文-1250000000', + Region: config.Region, + }, + function (err, data) { + assert.ok(err && err.message === 'Bucket should format as "test-1250000000".'); + done(); + }, + ); + }); + test('Bucket 带有 /', function (done, assert) { + cos.headBucket( + { + Bucket: 'te/st-1250000000', + Region: config.Region, + }, + function (err, data) { + assert.ok(err && err.message === 'Bucket should format as "test-1250000000".'); + done(); + }, + ); + }); + test('Bucket 带有 .', function (done, assert) { + cos.headBucket( + { + Bucket: 'te.st-1250000000', + Region: config.Region, + }, + function (err, data) { + assert.ok(err && err.message === 'Bucket should format as "test-1250000000".'); + done(); + }, + ); + }); + test('Bucket 带有 :', function (done, assert) { + cos.headBucket( + { + Bucket: 'te:st-1250000000', + Region: config.Region, + }, + function (err, data) { + assert.ok(err && err.message === 'Bucket should format as "test-1250000000".'); + done(); + }, + ); + }); }); group('Region 格式有误', function () { - test('Region 带有中文', function (done, assert) { - cos.headBucket({ - Bucket: 'test-1250000000', - Region: '中文', - }, function (err, data) { - assert.ok(err && err.message === 'Region format error.'); - done(); - }); - }); - test('Region 带有 /', function (done, assert) { - cos.headBucket({ - Bucket: 'test-1250000000', - Region: 'test/', - }, function (err, data) { - assert.ok(err && err.message === 'Region format error.'); - done(); - }); - }); - test('Region 带有 :', function (done, assert) { - cos.headBucket({ - Bucket: 'test-1250000000', - Region: 'test:', - }, function (err, data) { - assert.ok(err && err.message === 'Region format error.'); - done(); - }); - }); + test('Region 带有中文', function (done, assert) { + cos.headBucket( + { + Bucket: 'test-1250000000', + Region: '中文', + }, + function (err, data) { + assert.ok(err && err.message === 'Region format error.'); + done(); + }, + ); + }); + test('Region 带有 /', function (done, assert) { + cos.headBucket( + { + Bucket: 'test-1250000000', + Region: 'test/', + }, + function (err, data) { + assert.ok(err && err.message === 'Region format error.'); + done(); + }, + ); + }); + test('Region 带有 :', function (done, assert) { + cos.headBucket( + { + Bucket: 'test-1250000000', + Region: 'test:', + }, + function (err, data) { + assert.ok(err && err.message === 'Region format error.'); + done(); + }, + ); + }); }); group('复制文件', function () { - var filename = '10m.zip'; - var filePath = path.resolve(__dirname, filename); - test('sliceCopyFile() 正常分片复制', function (done, assert) { - createFileSync(filePath, 1024 * 1024 * 10); - var Key = '10mb.copy.zip'; - var lastPercent; - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - Body: fs.createReadStream(filePath), - }, function (err, data) { - fs.unlinkSync(filePath); - cos.sliceCopyFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: Key, - CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + filename, - SliceSize: 5 * 1024 * 1024, - onProgress: function (info) { - lastPercent = info.percent; - } - }, function (err, data) { - assert.ok(data && data.ETag, '成功进行分片复制'); - done(); - }); - }); - }); - - test('sliceCopyFile() 单片复制', function (done, assert) { - var filename = '10m.zip'; - var Key = '10mb.copy.zip'; - cos.sliceCopyFile({ + var filename = '10m.zip'; + var filePath = path.resolve(__dirname, filename); + test('sliceCopyFile() 正常分片复制', function (done, assert) { + createFileSync(filePath, 1024 * 1024 * 10); + var Key = '10mb.copy.zip'; + var lastPercent; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + Body: fs.createReadStream(filePath), + }, + function (err, data) { + fs.unlinkSync(filePath); + cos.sliceCopyFile( + { Bucket: config.Bucket, Region: config.Region, Key: Key, CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + filename, - SliceSize: 10 * 1024 * 1024, - }, function (err, data) { - if (err) throw err; - assert.ok(data && data.ETag, '成功进行单片复制'); + SliceSize: 5 * 1024 * 1024, + onProgress: function (info) { + lastPercent = info.percent; + }, + }, + function (err, data) { + assert.ok(data && data.ETag, '成功进行分片复制'); done(); - }); - }); + }, + ); + }, + ); + }); + + test('sliceCopyFile() 单片复制', function (done, assert) { + var filename = '10m.zip'; + var Key = '10mb.copy.zip'; + cos.sliceCopyFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + filename, + SliceSize: 10 * 1024 * 1024, + }, + function (err, data) { + if (err) throw err; + assert.ok(data && data.ETag, '成功进行单片复制'); + done(); + }, + ); + }); }); group('putObject 中文 Content-MD5', function () { - var fileBlob = dataURItoUploadBody('data:text/plain;base64,5Lit5paH'); - // 这里两个用户正式测试的时候需要给 putObject 计算并加上 Content-MD5 字段 - test('putObject 中文文件内容 带 Content-MD5', function (done, assert) { - var Key = '中文.txt'; - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: Key, - Body: fileBlob, - }, function (err, data) { - assert.ok(data && data.ETag, '成功进行上传'); - done(); - }); - }); - test('putObject 中文字符串 带 Content-MD5', function (done, assert) { - var Key = '中文.txt'; - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: Key, - Body: '中文', - }, function (err, data) { - assert.ok(data && data.ETag, '成功进行上传'); - done(); - }); - }); + var fileBlob = dataURItoUploadBody('data:text/plain;base64,5Lit5paH'); + // 这里两个用户正式测试的时候需要给 putObject 计算并加上 Content-MD5 字段 + test('putObject 中文文件内容 带 Content-MD5', function (done, assert) { + var Key = '中文.txt'; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + Body: fileBlob, + }, + function (err, data) { + assert.ok(data && data.ETag, '成功进行上传'); + done(); + }, + ); + }); + test('putObject 中文字符串 带 Content-MD5', function (done, assert) { + var Key = '中文.txt'; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + Body: '中文', + }, + function (err, data) { + assert.ok(data && data.ETag, '成功进行上传'); + done(); + }, + ); + }); }); group('deleteMultipleObject Key 带中文字符', function () { - test('deleteMultipleObject Key 带中文字符', function (done, assert) { - cos.deleteMultipleObject({ - Bucket: config.Bucket, - Region: config.Region, - Objects: [ - {Key: '中文/中文.txt'}, - {Key: '中文/中文.zip', VersionId: 'MTg0NDY3NDI1MzM4NzM0ODA2MTI'}, - {Key: unescape(encodeURIComponent('中文'))}, - {Key: unescape('%e8%af%b4%2e%70%72%70%72')}, - ] - }, function (err, data) { - assert.ok(!err, '成功进行批量删除'); - done(); - }); - }); + test('deleteMultipleObject Key 带中文字符', function (done, assert) { + cos.deleteMultipleObject( + { + Bucket: config.Bucket, + Region: config.Region, + Objects: [ + { Key: '中文/中文.txt' }, + { Key: '中文/中文.zip', VersionId: 'MTg0NDY3NDI1MzM4NzM0ODA2MTI' }, + { Key: unescape(encodeURIComponent('中文')) }, + { Key: unescape('%e8%af%b4%2e%70%72%70%72') }, + ], + }, + function (err, data) { + assert.ok(!err, '成功进行批量删除'); + done(); + }, + ); + }); }); group('upload Content-Type', function () { - var filename = Date.now() + '.zip'; - var filePath = path.resolve(__dirname, filename); - createFileSync(filePath, 1); - // putObject - test('putObject empty string Content-Type null -> application/octet-stream', function (done, assert) { - cos.putObject({ + var filename = Date.now() + '.zip'; + var filePath = path.resolve(__dirname, filename); + createFileSync(filePath, 1); + // putObject + test('putObject empty string Content-Type null -> application/octet-stream', function (done, assert) { + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1', + Body: '', + }, + function (err, data) { + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: '1', - Body: '', - }, function (err, data) { - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1', - }, function (err, data) { - console.log(data.headers['content-type']); - assert.ok(data.headers['content-type'] === 'application/octet-stream', 'Content-Type 正确'); - done(); - }); - }); - }); - test('putObject stream Content-Type null -> application/zip', function (done, assert) { - cos.putObject({ + }, + function (err, data) { + console.log(data.headers['content-type']); + assert.ok(data.headers['content-type'] === 'application/octet-stream', 'Content-Type 正确'); + done(); + }, + ); + }, + ); + }); + test('putObject stream Content-Type null -> application/zip', function (done, assert) { + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1.txt', + Body: fs.createReadStream(filePath), + }, + function (err, data) { + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: '1.txt', - Body: fs.createReadStream(filePath), - }, function (err, data) { - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.txt', - }, function (err, data) { - assert.ok(data.headers['content-type'] === 'application/zip', 'Content-Type 正确'); - done(); - }); - }); - }); - test('putObject string Content-Type null -> application/zip', function (done, assert) { - cos.putObject({ + }, + function (err, data) { + assert.ok(data.headers['content-type'] === 'application/zip', 'Content-Type 正确'); + done(); + }, + ); + }, + ); + }); + test('putObject string Content-Type null -> application/zip', function (done, assert) { + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1.zip', + Body: '12345', + }, + function (err, data) { + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: '1.zip', - Body: '12345', - }, function (err, data) { - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.zip', - }, function (err, data) { - assert.ok(data.headers['content-type'] === 'application/zip', 'Content-Type 正确'); - done(); - }); - }); - }); - // putObject 不支持 FilePath - // test('putObject file Content-Type null -> application/zip', function (done, assert) { - // cos.putObject({ - // Bucket: config.Bucket, - // Region: config.Region, - // Key: '1.txt', - // ContentType: 'text/xml', - // FilePath: filePath, - // }, function (err, data) { - // cos.headObject({ - // Bucket: config.Bucket, - // Region: config.Region, - // Key: '1.txt', - // }, function (err, data) { - // assert.ok(data.headers['content-type'] === 'text/xml', 'Content-Type 正确'); - // done(); - // }); - // }); - // }); - // test('putObject stream Content-Type null -> application/zip', function (done, assert) { - // cos.putObject({ - // Bucket: config.Bucket, - // Region: config.Region, - // Key: '1.txt', - // ContentType: 'text/xml', - // Body: fs.createReadStream(filePath), - // }, function (err, data) { - // cos.headObject({ - // Bucket: config.Bucket, - // Region: config.Region, - // Key: '1.txt', - // }, function (err, data) { - // assert.ok(data.headers['content-type'] === 'text/xml', 'Content-Type 正确'); - // done(); - // }); - // }); - // }); - // test('putObject file Content-Type null -> text/plain', function (done, assert) { - // cos.putObject({ - // Bucket: config.Bucket, - // Region: config.Region, - // Key: '1.txt', - // FilePath: filePath, - // }, function (err, data) { - // cos.headObject({ - // Bucket: config.Bucket, - // Region: config.Region, - // Key: '1.txt', - // }, function (err, data) { - // console.log(data.headers['content-type']); - // assert.ok(data.headers['content-type'] === 'text/plain', 'Content-Type 正确'); - // done(); - // }); - // }); - // }); - // sliceUploadFile - test('sliceUploadFile string Content-Type text/xml -> text/xml', function (done, assert) { - cos.sliceUploadFile({ + }, + function (err, data) { + assert.ok(data.headers['content-type'] === 'application/zip', 'Content-Type 正确'); + done(); + }, + ); + }, + ); + }); + // putObject 不支持 FilePath + // test('putObject file Content-Type null -> application/zip', function (done, assert) { + // cos.putObject({ + // Bucket: config.Bucket, + // Region: config.Region, + // Key: '1.txt', + // ContentType: 'text/xml', + // FilePath: filePath, + // }, function (err, data) { + // cos.headObject({ + // Bucket: config.Bucket, + // Region: config.Region, + // Key: '1.txt', + // }, function (err, data) { + // assert.ok(data.headers['content-type'] === 'text/xml', 'Content-Type 正确'); + // done(); + // }); + // }); + // }); + // test('putObject stream Content-Type null -> application/zip', function (done, assert) { + // cos.putObject({ + // Bucket: config.Bucket, + // Region: config.Region, + // Key: '1.txt', + // ContentType: 'text/xml', + // Body: fs.createReadStream(filePath), + // }, function (err, data) { + // cos.headObject({ + // Bucket: config.Bucket, + // Region: config.Region, + // Key: '1.txt', + // }, function (err, data) { + // assert.ok(data.headers['content-type'] === 'text/xml', 'Content-Type 正确'); + // done(); + // }); + // }); + // }); + // test('putObject file Content-Type null -> text/plain', function (done, assert) { + // cos.putObject({ + // Bucket: config.Bucket, + // Region: config.Region, + // Key: '1.txt', + // FilePath: filePath, + // }, function (err, data) { + // cos.headObject({ + // Bucket: config.Bucket, + // Region: config.Region, + // Key: '1.txt', + // }, function (err, data) { + // console.log(data.headers['content-type']); + // assert.ok(data.headers['content-type'] === 'text/plain', 'Content-Type 正确'); + // done(); + // }); + // }); + // }); + // sliceUploadFile + test('sliceUploadFile string Content-Type text/xml -> text/xml', function (done, assert) { + cos.sliceUploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1.txt', + FilePath: filePath, + }, + function (err, data) { + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: '1.txt', - FilePath: filePath, - }, function (err, data) { - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.txt', - }, function (err, data) { - assert.ok(data.headers['content-type'] === 'text/plain', 'Content-Type 正确'); - done(); - }); - }); - }); - test('sliceUploadFile string Content-Type text/xml -> text/xml', function (done, assert) { - cos.sliceUploadFile({ + }, + function (err, data) { + assert.ok(data.headers['content-type'] === 'text/plain', 'Content-Type 正确'); + done(); + }, + ); + }, + ); + }); + test('sliceUploadFile string Content-Type text/xml -> text/xml', function (done, assert) { + cos.sliceUploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1.txt', + ContentType: 'text/xml', + FilePath: filePath, + }, + function (err, data) { + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: '1.txt', - ContentType: 'text/xml', - FilePath: filePath, - }, function (err, data) { - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.txt', - }, function (err, data) { - assert.ok(data.headers['content-type'] === 'text/xml', 'Content-Type 正确'); - fs.unlinkSync(filePath); - done(); - }); - }); - }); + }, + function (err, data) { + assert.ok(data.headers['content-type'] === 'text/xml', 'Content-Type 正确'); + fs.unlinkSync(filePath); + done(); + }, + ); + }, + ); + }); }); group('Cache-Control', function () { - var filename = Date.now() + '.zip'; - var filePath = path.resolve(__dirname, filename); - createFileSync(filePath, 1); - // putObject - test('putObject Cache-Control: null -> Cache-Control: null or max-age=259200', function (done, assert) { - cos.putObject({ + var filename = Date.now() + '.zip'; + var filePath = path.resolve(__dirname, filename); + createFileSync(filePath, 1); + // putObject + test('putObject Cache-Control: null -> Cache-Control: null or max-age=259200', function (done, assert) { + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1mb.zip', + Body: '', + }, + function (err, data) { + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: '1mb.zip', - Body: '', - }, function (err, data) { - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1mb.zip', - }, function (err, data) { - assert.ok(data.headers['cache-control'] === undefined || data.headers['cache-control'] === 'max-age=259200', 'cache-control 正确'); - done(); - }); - }); - }); - test('putObject Cache-Control: max-age=7200 -> Cache-Control: max-age=7200', function (done, assert) { - cos.putObject({ + }, + function (err, data) { + assert.ok( + data.headers['cache-control'] === undefined || data.headers['cache-control'] === 'max-age=259200', + 'cache-control 正确', + ); + done(); + }, + ); + }, + ); + }); + test('putObject Cache-Control: max-age=7200 -> Cache-Control: max-age=7200', function (done, assert) { + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1mb.zip', + Body: '', + CacheControl: 'max-age=7200', + }, + function (err, data) { + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: '1mb.zip', - Body: '', - CacheControl: 'max-age=7200', - }, function (err, data) { - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1mb.zip', - }, function (err, data) { - assert.ok(data.headers['cache-control'] === 'max-age=7200', 'cache-control 正确'); - done(); - }); - }); - }); - test('putObject Cache-Control: no-cache -> Cache-Control: no-cache', function (done, assert) { - cos.putObject({ + }, + function (err, data) { + assert.ok(data.headers['cache-control'] === 'max-age=7200', 'cache-control 正确'); + done(); + }, + ); + }, + ); + }); + test('putObject Cache-Control: no-cache -> Cache-Control: no-cache', function (done, assert) { + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1mb.zip', + Body: '', + CacheControl: 'no-cache', + }, + function (err, data) { + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: '1mb.zip', - Body: '', - CacheControl: 'no-cache', - }, function (err, data) { - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1mb.zip', - }, function (err, data) { - assert.ok(data.headers['cache-control'] === 'no-cache' || data.headers['cache-control'] === 'no-cache, max-age=259200', 'cache-control 正确'); - done(); - }); - }); - }); - // sliceUploadFile - test('sliceUploadFile Cache-Control: null -> Cache-Control: null or max-age=259200', function (done, assert) { - cos.sliceUploadFile({ + }, + function (err, data) { + assert.ok( + data.headers['cache-control'] === 'no-cache' || + data.headers['cache-control'] === 'no-cache, max-age=259200', + 'cache-control 正确', + ); + done(); + }, + ); + }, + ); + }); + // sliceUploadFile + test('sliceUploadFile Cache-Control: null -> Cache-Control: null or max-age=259200', function (done, assert) { + cos.sliceUploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1mb.zip', + FilePath: filePath, + }, + function (err, data) { + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: '1mb.zip', - FilePath: filePath, - }, function (err, data) { - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1mb.zip', - }, function (err, data) { - assert.ok(data.headers['cache-control'] === undefined || data.headers['cache-control'] === 'max-age=259200', 'cache-control 正确'); - done(); - }); - }); - }); - test('sliceUploadFile Cache-Control: max-age=7200 -> Cache-Control: max-age=7200', function (done, assert) { - cos.sliceUploadFile({ + }, + function (err, data) { + assert.ok( + data.headers['cache-control'] === undefined || data.headers['cache-control'] === 'max-age=259200', + 'cache-control 正确', + ); + done(); + }, + ); + }, + ); + }); + test('sliceUploadFile Cache-Control: max-age=7200 -> Cache-Control: max-age=7200', function (done, assert) { + cos.sliceUploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1mb.zip', + FilePath: filePath, + CacheControl: 'max-age=7200', + }, + function (err, data) { + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: '1mb.zip', - FilePath: filePath, - CacheControl: 'max-age=7200', - }, function (err, data) { - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1mb.zip', - }, function (err, data) { - assert.ok(data.headers['cache-control'] === 'max-age=7200', 'cache-control 正确'); - done(); - }); - }); - }); - test('sliceUploadFile Cache-Control: no-cache -> Cache-Control: no-cache', function (done, assert) { - cos.sliceUploadFile({ + }, + function (err, data) { + assert.ok(data.headers['cache-control'] === 'max-age=7200', 'cache-control 正确'); + done(); + }, + ); + }, + ); + }); + test('sliceUploadFile Cache-Control: no-cache -> Cache-Control: no-cache', function (done, assert) { + cos.sliceUploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1mb.zip', + FilePath: filePath, + CacheControl: 'no-cache', + }, + function (err, data) { + cos.headObject( + { Bucket: config.Bucket, Region: config.Region, Key: '1mb.zip', - FilePath: filePath, - CacheControl: 'no-cache', - }, function (err, data) { - cos.headObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1mb.zip', - }, function (err, data) { - assert.ok(data.headers['cache-control'] === 'no-cache' || data.headers['cache-control'] === 'no-cache, max-age=259200', 'cache-control 正确'); - fs.unlinkSync(filePath); - done(); - }); - }); - }); + }, + function (err, data) { + assert.ok( + data.headers['cache-control'] === 'no-cache' || + data.headers['cache-control'] === 'no-cache, max-age=259200', + 'cache-control 正确', + ); + fs.unlinkSync(filePath); + done(); + }, + ); + }, + ); + }); }); group('BucketLogging', function () { - var TargetBucket = config.Bucket; - var TargetPrefix = 'bucket-logging-prefix' + Date.now().toString(36) + '/'; - var BucketLoggingStatus = { - LoggingEnabled: { - TargetBucket: TargetBucket, - TargetPrefix: TargetPrefix - } - }; + var TargetBucket = config.Bucket; + var TargetPrefix = 'bucket-logging-prefix' + Date.now().toString(36) + '/'; + var BucketLoggingStatus = { + LoggingEnabled: { + TargetBucket: TargetBucket, + TargetPrefix: TargetPrefix, + }, + }; - test('putBucketLogging(), getBucketLogging()', function (done, assert) { - cos.putBucketLogging({ + test('putBucketLogging(), getBucketLogging()', function (done, assert) { + cos.putBucketLogging( + { + Bucket: config.Bucket, + Region: config.Region, + BucketLoggingStatus: BucketLoggingStatus, + }, + function (err, data) { + assert.ok(!err); + cos.getBucketLogging( + { Bucket: config.Bucket, Region: config.Region, - BucketLoggingStatus: BucketLoggingStatus - }, function (err, data) { - assert.ok(!err); - cos.getBucketLogging({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(comparePlainObject(BucketLoggingStatus, data.BucketLoggingStatus)); - done(); - }); - }); - }); + }, + function (err, data) { + assert.ok(comparePlainObject(BucketLoggingStatus, data.BucketLoggingStatus)); + done(); + }, + ); + }, + ); + }); - test('putBucketLogging() 删除 logging 配置', function (done, assert) { - cos.putBucketLogging({ + test('putBucketLogging() 删除 logging 配置', function (done, assert) { + cos.putBucketLogging( + { + Bucket: config.Bucket, + Region: config.Region, + BucketLoggingStatus: '', + }, + function (err, data) { + cos.getBucketLogging( + { Bucket: config.Bucket, Region: config.Region, - BucketLoggingStatus: '' - }, function (err, data) { - cos.getBucketLogging({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(data.BucketLoggingStatus === ''); - done(); - }); - }); - }); - - test('putBucketLogging() bucket not exist', function (done, assert) { - cos.putBucketLogging({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region, - BucketLoggingStatus: BucketLoggingStatus - }, function (err, data) { - assert.ok(err); - done(); - }); - }); + }, + function (err, data) { + assert.ok(data.BucketLoggingStatus === ''); + done(); + }, + ); + }, + ); + }); - test('getBucketLogging() bucket not exist', function (done, assert) { - cos.getBucketLogging({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region, - }, function (err, data) { - assert.ok(err); - done(); - }); - }); + test('putBucketLogging() bucket not exist', function (done, assert) { + cos.putBucketLogging( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + BucketLoggingStatus: BucketLoggingStatus, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); + test('getBucketLogging() bucket not exist', function (done, assert) { + cos.getBucketLogging( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); }); group('BucketInventory', function () { - var TargetBucket = 'bucket-inventory' + Date.now().toString(36) + '-' + AppId; + var TargetBucket = 'bucket-inventory' + Date.now().toString(36) + '-' + AppId; - // 创建新 Bucket - before(function (done) { - cos.putBucket({ - Bucket: TargetBucket, - Region: config.Region - }, done); - }); + // 创建新 Bucket + before(function (done) { + cos.putBucket( + { + Bucket: TargetBucket, + Region: config.Region, + }, + done, + ); + }); - // 删除新 Bucket - after(function (done) { - cos.deleteBucket({ - Bucket: TargetBucket, - Region: config.Region - }, done); - }); + // 删除新 Bucket + after(function (done) { + cos.deleteBucket( + { + Bucket: TargetBucket, + Region: config.Region, + }, + done, + ); + }); - var InventoryConfiguration = { - Id: 'inventory_test', - IsEnabled: 'true', - Destination: { - COSBucketDestination: { - Format: 'CSV', - AccountId: config.Uin, - Bucket: 'qcs::cos:' + config.Region + '::' + TargetBucket, - Prefix: 'inventory_prefix_1', - Encryption: { - SSECOS: '' - } - } - }, - Schedule: { - Frequency: 'Daily' + var InventoryConfiguration = { + Id: 'inventory_test', + IsEnabled: 'true', + Destination: { + COSBucketDestination: { + Format: 'CSV', + AccountId: config.Uin, + Bucket: 'qcs::cos:' + config.Region + '::' + TargetBucket, + Prefix: 'inventory_prefix_1', + Encryption: { + SSECOS: '', }, - Filter: { - Prefix: 'myPrefix' - }, - IncludedObjectVersions: 'All', - OptionalFields: [ - 'Size' - ] - }; + }, + }, + Schedule: { + Frequency: 'Daily', + }, + Filter: { + Prefix: 'myPrefix', + }, + IncludedObjectVersions: 'All', + OptionalFields: ['Size'], + }; - var InventoryConfigurationNoEncryption = { - Id: 'inventory_test', - IsEnabled: 'true', - Destination: { - COSBucketDestination: { - Format: 'CSV', - AccountId: config.Uin, - Bucket: 'qcs::cos:' + config.Region + '::' + TargetBucket, - Prefix: 'inventory_prefix_1' - } - }, - Schedule: { - Frequency: 'Daily' - }, - Filter: { - Prefix: 'myPrefix' - }, - IncludedObjectVersions: 'All', - OptionalFields: [ - 'Size' - ] - }; + var InventoryConfigurationNoEncryption = { + Id: 'inventory_test', + IsEnabled: 'true', + Destination: { + COSBucketDestination: { + Format: 'CSV', + AccountId: config.Uin, + Bucket: 'qcs::cos:' + config.Region + '::' + TargetBucket, + Prefix: 'inventory_prefix_1', + }, + }, + Schedule: { + Frequency: 'Daily', + }, + Filter: { + Prefix: 'myPrefix', + }, + IncludedObjectVersions: 'All', + OptionalFields: ['Size'], + }; - test('putBucketInventory(), getBucketInventory()', function (done, assert) { - cos.putBucketInventory({ + test('putBucketInventory(), getBucketInventory()', function (done, assert) { + cos.putBucketInventory( + { + Bucket: config.Bucket, + Region: config.Region, + Id: InventoryConfiguration.Id, + InventoryConfiguration: InventoryConfiguration, + }, + function (err, data) { + cos.getBucketInventory( + { Bucket: config.Bucket, Region: config.Region, Id: InventoryConfiguration.Id, - InventoryConfiguration: InventoryConfiguration - }, function (err, data) { - cos.getBucketInventory({ - Bucket: config.Bucket, - Region: config.Region, - Id: InventoryConfiguration.Id - }, function (err, data) { - assert.ok(comparePlainObject(InventoryConfiguration, data.InventoryConfiguration)); - done(); - }); - }); - }); - - test('listBucketInventory()', function (done, assert) { - cos.listBucketInventory({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - var targetInventory; - data.InventoryConfigurations.forEach(function (item) { - if (item.Id === InventoryConfiguration.Id) { - targetInventory = item; - } - }); - assert.ok(comparePlainObject(InventoryConfiguration, targetInventory)); - assert.ok(data.IsTruncated === 'false' || data.IsTruncated === 'true'); + }, + function (err, data) { + assert.ok(comparePlainObject(InventoryConfiguration, data.InventoryConfiguration)); done(); + }, + ); + }, + ); + }); + + test('listBucketInventory()', function (done, assert) { + cos.listBucketInventory( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + var targetInventory; + data.InventoryConfigurations.forEach(function (item) { + if (item.Id === InventoryConfiguration.Id) { + targetInventory = item; + } }); - }); + assert.ok(comparePlainObject(InventoryConfiguration, targetInventory)); + assert.ok(data.IsTruncated === 'false' || data.IsTruncated === 'true'); + done(); + }, + ); + }); - test('putBucketInventory() 不设置 SSECOS', function (done, assert) { - cos.putBucketInventory({ + test('putBucketInventory() 不设置 SSECOS', function (done, assert) { + cos.putBucketInventory( + { + Bucket: config.Bucket, + Region: config.Region, + Id: InventoryConfigurationNoEncryption.Id, + InventoryConfiguration: InventoryConfigurationNoEncryption, + }, + function (err, data) { + cos.getBucketInventory( + { Bucket: config.Bucket, Region: config.Region, Id: InventoryConfigurationNoEncryption.Id, - InventoryConfiguration: InventoryConfigurationNoEncryption - }, function (err, data) { - cos.getBucketInventory({ - Bucket: config.Bucket, - Region: config.Region, - Id: InventoryConfigurationNoEncryption.Id - }, function (err, data) { - assert.ok(comparePlainObject(InventoryConfigurationNoEncryption, data.InventoryConfiguration)); - done(); - }); - }); - }); + }, + function (err, data) { + assert.ok(comparePlainObject(InventoryConfigurationNoEncryption, data.InventoryConfiguration)); + done(); + }, + ); + }, + ); + }); - test('deleteBucketInventory()', function (done, assert) { - cos.deleteBucketInventory({ + test('deleteBucketInventory()', function (done, assert) { + cos.deleteBucketInventory( + { + Bucket: config.Bucket, + Region: config.Region, + Id: InventoryConfiguration.Id, + }, + function (err, data) { + assert.ok(!err); + cos.getBucketInventory( + { Bucket: config.Bucket, Region: config.Region, - Id: InventoryConfiguration.Id - }, function (err, data) { - assert.ok(!err); - cos.getBucketInventory({ - Bucket: config.Bucket, - Region: config.Region, - Id: InventoryConfiguration.Id - }, function (err, data) { - assert.ok(err && err.statusCode === 404); - done(); - }); - }); - }); + Id: InventoryConfiguration.Id, + }, + function (err, data) { + assert.ok(err && err.statusCode === 404); + done(); + }, + ); + }, + ); + }); - test('putBucketInventory() bucket not exist', function (done, assert) { - cos.putBucketInventory({ + test('putBucketInventory() bucket not exist', function (done, assert) { + cos.putBucketInventory( + { Bucket: Date.now().toString(36) + config.Bucket, Region: config.Region, Id: InventoryConfigurationNoEncryption.Id, - InventoryConfiguration: InventoryConfigurationNoEncryption - }, function (err, data) { - assert.ok(err); - done(); - }); - }); - - test('getBucketInventory() bucket not exist', function (done, assert) { - cos.getBucketInventory({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region, - Id: InventoryConfiguration.Id - }, function (err, data) { - assert.ok(err); - done(); - }); - }); + InventoryConfiguration: InventoryConfigurationNoEncryption, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); - test('deleteBucketInventory() bucket not exist', function (done, assert) { - cos.deleteBucketInventory({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region, - Id: InventoryConfiguration.Id - }, function (err, data) { - assert.ok(err); - done(); - }); - }); + test('getBucketInventory() bucket not exist', function (done, assert) { + cos.getBucketInventory( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + Id: InventoryConfiguration.Id, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); + test('deleteBucketInventory() bucket not exist', function (done, assert) { + cos.deleteBucketInventory( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + Id: InventoryConfiguration.Id, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); }); group('Content-Type: false Bug', function () { - test('fs.createReadStream 1', function (done, assert) { - var filename = '1'; - var filepath = path.resolve(__dirname, filename); - util.createFile(filepath, 1, function (err) { - // 调用方法 - cos.putObject({ - Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 - Region: config.Region, - Key: filename, - Body: fs.createReadStream(filepath), - }, function (err1, data1) { - cos.headObject({ - Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 - Region: config.Region, - Key: filename, - }, function (err, data) { - var contentType = data && data.headers['content-type']; - assert.ok(contentType === 'application/octet-stream', '返回了 Content-Type: ' + contentType); - fs.unlinkSync(filepath); - done(); - }); - }); - }); + test('fs.createReadStream 1', function (done, assert) { + var filename = '1'; + var filepath = path.resolve(__dirname, filename); + util.createFile(filepath, 1, function (err) { + // 调用方法 + cos.putObject( + { + Bucket: config.Bucket /* 必须 */, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: filename, + Body: fs.createReadStream(filepath), + }, + function (err1, data1) { + cos.headObject( + { + Bucket: config.Bucket /* 必须 */, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: filename, + }, + function (err, data) { + var contentType = data && data.headers['content-type']; + assert.ok(contentType === 'application/octet-stream', '返回了 Content-Type: ' + contentType); + fs.unlinkSync(filepath); + done(); + }, + ); + }, + ); }); - test('text 2', function (done, assert) { - // 调用方法 - cos.putObject({ - Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 + }); + test('text 2', function (done, assert) { + // 调用方法 + cos.putObject( + { + Bucket: config.Bucket /* 必须 */, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: '2', + Body: 'hello!', + }, + function (err1, data1) { + cos.headObject( + { + Bucket: config.Bucket /* 必须 */, // Bucket 格式:test-1250000000 Region: config.Region, Key: '2', - Body: 'hello!', - }, function (err1, data1) { - cos.headObject({ - Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 - Region: config.Region, - Key: '2', - }, function (err, data) { - var contentType = data && data.headers['content-type']; - assert.ok(contentType === 'application/octet-stream', '返回了 Content-Type: ' + contentType); - done(); - }); - }); - }); - test('text 1.zip', function (done, assert) { - // 调用方法 - cos.putObject({ - Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 + }, + function (err, data) { + var contentType = data && data.headers['content-type']; + assert.ok(contentType === 'application/octet-stream', '返回了 Content-Type: ' + contentType); + done(); + }, + ); + }, + ); + }); + test('text 1.zip', function (done, assert) { + // 调用方法 + cos.putObject( + { + Bucket: config.Bucket /* 必须 */, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: '2.zip', + Body: 'hello!', + }, + function (err1, data1) { + cos.headObject( + { + Bucket: config.Bucket /* 必须 */, // Bucket 格式:test-1250000000 Region: config.Region, Key: '2.zip', - Body: 'hello!', - }, function (err1, data1) { - cos.headObject({ - Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 - Region: config.Region, - Key: '2.zip', - }, function (err, data) { - var contentType = data && data.headers['content-type']; - assert.ok(contentType === 'application/zip', '返回了 Content-Type: ' + contentType); - done(); - }); - }); - }); - test('Buffer 3', function (done, assert) { - // 调用方法 - cos.putObject({ - Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 + }, + function (err, data) { + var contentType = data && data.headers['content-type']; + assert.ok(contentType === 'application/zip', '返回了 Content-Type: ' + contentType); + done(); + }, + ); + }, + ); + }); + test('Buffer 3', function (done, assert) { + // 调用方法 + cos.putObject( + { + Bucket: config.Bucket /* 必须 */, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: '3', + Body: Buffer.from('hello!'), + }, + function (err1, data1) { + cos.headObject( + { + Bucket: config.Bucket /* 必须 */, // Bucket 格式:test-1250000000 Region: config.Region, Key: '3', - Body: Buffer.from('hello!'), - }, function (err1, data1) { - cos.headObject({ - Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 - Region: config.Region, - Key: '3', - }, function (err, data) { - var contentType = data && data.headers['content-type']; - assert.ok(contentType === 'application/octet-stream', '返回了 Content-Type: ' + contentType); - done(); - }); - }); - }); + }, + function (err, data) { + var contentType = data && data.headers['content-type']; + assert.ok(contentType === 'application/octet-stream', '返回了 Content-Type: ' + contentType); + done(); + }, + ); + }, + ); + }); }); var tagging2str = function (obj) { - var arr = []; - obj.forEach(function (v) { - arr.push(v.Key + '=' + encodeURIComponent(v.Value)); - }) - return arr.join('&'); -} + var arr = []; + obj.forEach(function (v) { + arr.push(v.Key + '=' + encodeURIComponent(v.Value)); + }); + return arr.join('&'); +}; group('上传带 tagging', function () { - var Tags = [ - {Key: "k1", Value: "v1"}, - {Key: "k2", Value: "v2"}, - ]; - var key = '1.txt'; + var Tags = [ + { Key: 'k1', Value: 'v1' }, + { Key: 'k2', Value: 'v2' }, + ]; + var key = '1.txt'; - test('putObject 带 x-cos-tagging', function (done, assert) { - Tags[0].Value = Date.now().toString(36); - var tagStr = tagging2str(Tags); - // 调用方法 - cos.putObject({ - Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 + test('putObject 带 x-cos-tagging', function (done, assert) { + Tags[0].Value = Date.now().toString(36); + var tagStr = tagging2str(Tags); + // 调用方法 + cos.putObject( + { + Bucket: config.Bucket /* 必须 */, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: key, + Body: 'hello!', + Headers: { + 'x-cos-tagging': tagStr, + }, + }, + function (err1, data1) { + cos.headObject( + { + Bucket: config.Bucket /* 必须 */, // Bucket 格式:test-1250000000 Region: config.Region, Key: key, - Body: 'hello!', - Headers: { - 'x-cos-tagging': tagStr, - }, - }, function (err1, data1) { - cos.headObject({ - Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 + }, + function (err2, data2) { + var taggingCount = data2 && data2.headers['x-cos-tagging-count']; + assert.ok(taggingCount === '2', '返回 x-cos-tagging-count: ' + taggingCount); + cos.getObjectTagging( + { + Bucket: config.Bucket /* 必须 */, // Bucket 格式:test-1250000000 Region: config.Region, Key: key, - }, function (err2, data2) { - var taggingCount = data2 && data2.headers['x-cos-tagging-count']; - assert.ok(taggingCount === '2', '返回 x-cos-tagging-count: ' + taggingCount); - cos.getObjectTagging({ - Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 - Region: config.Region, - Key: key, - }, function (err3, data3) { - assert.ok(comparePlainObject(Tags, data3.Tags)); - done(); - }); - }); - }); - }); + }, + function (err3, data3) { + assert.ok(comparePlainObject(Tags, data3.Tags)); + done(); + }, + ); + }, + ); + }, + ); + }); - // test('sliceUploadFile 带 x-cos-tagging', function (done, assert) { - // Tags[0].Value = Date.now().toString(36); - // var tagStr = tagging2str(Tags); - // // 调用方法 - // cos.sliceUploadFile({ - // Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 - // Region: config.Region, - // Key: key, - // Body: 'hello!', - // Headers: { - // 'x-cos-tagging': tagStr, - // }, - // }, function (err1, data1) { - // cos.headObject({ - // Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 - // Region: config.Region, - // Key: key, - // }, function (err2, data2) { - // var taggingCount = data2 && data2.headers['x-cos-tagging-count']; - // assert.ok(taggingCount === '1', '返回 x-cos-tagging-count: ' + taggingCount); - // cos.getObjectTagging({ - // Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 - // Region: config.Region, - // Key: key, - // }, function (err3, data3) { - // assert.ok(data3 && data3.Tags && comparePlainObject(Tags, data3.Tags)); - // done(); - // }); - // }); - // }); - // }); + // test('sliceUploadFile 带 x-cos-tagging', function (done, assert) { + // Tags[0].Value = Date.now().toString(36); + // var tagStr = tagging2str(Tags); + // // 调用方法 + // cos.sliceUploadFile({ + // Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 + // Region: config.Region, + // Key: key, + // Body: 'hello!', + // Headers: { + // 'x-cos-tagging': tagStr, + // }, + // }, function (err1, data1) { + // cos.headObject({ + // Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 + // Region: config.Region, + // Key: key, + // }, function (err2, data2) { + // var taggingCount = data2 && data2.headers['x-cos-tagging-count']; + // assert.ok(taggingCount === '1', '返回 x-cos-tagging-count: ' + taggingCount); + // cos.getObjectTagging({ + // Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000 + // Region: config.Region, + // Key: key, + // }, function (err3, data3) { + // assert.ok(data3 && data3.Tags && comparePlainObject(Tags, data3.Tags)); + // done(); + // }); + // }); + // }); + // }); }); group('ObjectTagging', function () { - var key = '1.txt'; - var Tags = [ - {Key: "k1", Value: "v1"}, - {Key: "k2", Value: "v2"}, - ]; - test('putObjectTagging(),getObjectTagging()', function (done, assert) { - Tags[0].Value = Date.now().toString(36); - cos.putObjectTagging({ - Bucket: config.Bucket, - Region: config.Region, - Key: key, - Tagging: { - Tags: Tags + var key = '1.txt'; + var Tags = [ + { Key: 'k1', Value: 'v1' }, + { Key: 'k2', Value: 'v2' }, + ]; + test('putObjectTagging(),getObjectTagging()', function (done, assert) { + Tags[0].Value = Date.now().toString(36); + cos.putObjectTagging( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + Tagging: { + Tags: Tags, + }, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getObjectTagging( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, }, - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getObjectTagging({ - Bucket: config.Bucket, - Region: config.Region, - Key: key, - }, function (err, data) { - assert.ok(comparePlainObject(Tags, data.Tags)); - done(); - }); - }, 1000); - }); - }); - test('putObjectTagging() object not exist', function (done, assert) { - cos.putObjectTagging({ - Bucket: config.Bucket, - Region: config.Region, - Key: Date.now().toString(36) + key, - Tagging: { - Tags: Tags - }, - }, function (err, data) { + function (err, data) { + assert.ok(comparePlainObject(Tags, data.Tags)); + done(); + }, + ); + }, 1000); + }, + ); + }); + test('putObjectTagging() object not exist', function (done, assert) { + cos.putObjectTagging( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Date.now().toString(36) + key, + Tagging: { + Tags: Tags, + }, + }, + function (err, data) { assert.ok(err); done(); - }); + }, + ); }); - test('getObjectTagging() object not exist', function (done, assert) { - cos.getObjectTagging({ - Bucket: config.Bucket, - Region: config.Region, - Key: Date.now().toString(36) + key, - }, function (err, data) { - assert.ok(err); - done(); - }); - }); - test('deleteObjectTagging()', function (done, assert) { - cos.deleteObjectTagging({ - Bucket: config.Bucket, - Region: config.Region, - Key: key, - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getObjectTagging({ - Bucket: config.Bucket, - Region: config.Region, - Key: key, - }, function (err, data) { - assert.ok(comparePlainObject([], data.Tags)); - done(); - }); - }, 1000); - }); - }); - test('deleteObjectTagging() object not exist', function (done, assert) { - cos.deleteObjectTagging({ - Bucket: config.Bucket, - Region: config.Region, - Key: Date.now().toString(36) + key, - }, function (err, data) { - assert.ok(err); - done(); - }); + test('getObjectTagging() object not exist', function (done, assert) { + cos.getObjectTagging( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Date.now().toString(36) + key, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); + test('deleteObjectTagging()', function (done, assert) { + cos.deleteObjectTagging( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getObjectTagging( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + }, + function (err, data) { + assert.ok(comparePlainObject([], data.Tags)); + done(); + }, + ); + }, 1000); + }, + ); + }); + test('deleteObjectTagging() object not exist', function (done, assert) { + cos.deleteObjectTagging( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Date.now().toString(36) + key, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); }); }); group('getBucketAccelerate', function () { test('putBucketAccelerate() no AccelerateConfiguration', function (done, assert) { - cos.putBucketAccelerate({ + cos.putBucketAccelerate( + { Bucket: config.Bucket, Region: config.Region, - }, function (err, data) { + }, + function (err, data) { assert.ok(err); done(); - }); -}); - test('putBucketAccelerate(),getBucketAccelerate() Enabled', function (done, assert) { - cos.putBucketAccelerate({ - Bucket: config.Bucket, - Region: config.Region, - AccelerateConfiguration: { - Status: 'Enabled', // Suspended、Enabled + }, + ); + }); + test('putBucketAccelerate(),getBucketAccelerate() Enabled', function (done, assert) { + cos.putBucketAccelerate( + { + Bucket: config.Bucket, + Region: config.Region, + AccelerateConfiguration: { + Status: 'Enabled', // Suspended、Enabled + }, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getBucketAccelerate( + { + Bucket: config.Bucket, + Region: config.Region, }, - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getBucketAccelerate({ - Bucket: config.Bucket, - Region: config.Region, - }, function (err2, data2) { - assert.ok(data2 && data2.AccelerateConfiguration && data2.AccelerateConfiguration.Status === 'Enabled'); - done(); - }); - }, 2000); - }); - }); + function (err2, data2) { + assert.ok(data2 && data2.AccelerateConfiguration && data2.AccelerateConfiguration.Status === 'Enabled'); + done(); + }, + ); + }, 2000); + }, + ); + }); - test('putBucketAccelerate(),getBucketAccelerate() Suspended', function (done, assert) { - cos.putBucketAccelerate({ - Bucket: config.Bucket, - Region: config.Region, - AccelerateConfiguration: { - Status: 'Suspended', // Suspended、Enabled + test('putBucketAccelerate(),getBucketAccelerate() Suspended', function (done, assert) { + cos.putBucketAccelerate( + { + Bucket: config.Bucket, + Region: config.Region, + AccelerateConfiguration: { + Status: 'Suspended', // Suspended、Enabled + }, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getBucketAccelerate( + { + Bucket: config.Bucket, + Region: config.Region, }, - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getBucketAccelerate({ - Bucket: config.Bucket, - Region: config.Region, - }, function (err2, data2) { - assert.ok(data2 && data2.AccelerateConfiguration && data2.AccelerateConfiguration.Status === 'Suspended'); - done(); - }); - }, 1000); - }); - }); + function (err2, data2) { + assert.ok(data2 && data2.AccelerateConfiguration && data2.AccelerateConfiguration.Status === 'Suspended'); + done(); + }, + ); + }, 1000); + }, + ); + }); }); -group('putBucketEncryption getBucketEncryption', function() { - test('putBucketEncryption empty', function(done, assert) { - cos.putBucketEncryption({ +group('putBucketEncryption getBucketEncryption', function () { + test('putBucketEncryption empty', function (done, assert) { + cos.putBucketEncryption( + { Bucket: config.Bucket, Region: config.Region, - }, function(err, data) { - cos.getBucketEncryption({ + }, + function (err, data) { + cos.getBucketEncryption( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(data.EncryptionConfiguration.Rules.length === 0); + done(); + }, + ); + }, + ); + }); + test('putBucketEncryption', function (done, assert) { + cos.putBucketEncryption( + { Bucket: config.Bucket, Region: config.Region, - }, function(err, data) { - assert.ok(data.EncryptionConfiguration.Rules.length === 0); - done(); - }); - }); -}); - test('putBucketEncryption', function(done, assert) { - cos.putBucketEncryption({ - Bucket: config.Bucket, - Region: config.Region, - ServerSideEncryptionConfiguration: { - Rule: [{ - ApplySideEncryptionConfiguration: { - SSEAlgorithm: 'AES256', - }, - }], - }, - }, function(err, data) { + ServerSideEncryptionConfiguration: { + Rule: [ + { + ApplySideEncryptionConfiguration: { + SSEAlgorithm: 'AES256', + }, + }, + ], + }, + }, + function (err, data) { assert.ok(!err); done(); - }); + }, + ); }); - test('getBucketEncryption', function(done, assert) { - cos.getBucketEncryption({ + test('getBucketEncryption', function (done, assert) { + cos.getBucketEncryption( + { Bucket: config.Bucket, Region: config.Region, - }, function(err, data) { - assert.ok(!err); - done(); - }); + }, + function (err, data) { + assert.ok(!err); + done(); + }, + ); }); - test('deleteBucketEncryption', function(done, assert) { - cos.deleteBucketEncryption({ + test('deleteBucketEncryption', function (done, assert) { + cos.deleteBucketEncryption( + { Bucket: config.Bucket, Region: config.Region, - }, function(err, data) { - assert.ok(!err); - done(); - }); + }, + function (err, data) { + assert.ok(!err); + done(); + }, + ); }); - test('putBucketEncryption bucket not exist', function(done, assert) { - cos.putBucketEncryption({ + test('putBucketEncryption bucket not exist', function (done, assert) { + cos.putBucketEncryption( + { Bucket: Date.now().toString(36) + config.Bucket, Region: config.Region, ServerSideEncryptionConfiguration: { - Rule: [{ - ApplySideEncryptionConfiguration: { - SSEAlgorithm: 'AES256', - }, - }], + Rule: [ + { + ApplySideEncryptionConfiguration: { + SSEAlgorithm: 'AES256', + }, + }, + ], }, - }, function(err, data) { + }, + function (err, data) { assert.ok(err); done(); - }); - }); - test('getBucketEncryption bucket not exist', function(done, assert) { - cos.getBucketEncryption({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region, - }, function(err, data) { + }, + ); + }); + test('getBucketEncryption bucket not exist', function (done, assert) { + cos.getBucketEncryption( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + }, + function (err, data) { assert.ok(err); done(); - }); - }); - test('deleteBucketEncryption bucket not exist', function(done, assert) { - cos.deleteBucketEncryption({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region, - }, function(err, data) { + }, + ); + }); + test('deleteBucketEncryption bucket not exist', function (done, assert) { + cos.deleteBucketEncryption( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + }, + function (err, data) { assert.ok(err); done(); - }); - }); - + }, + ); + }); }); group('Promise', function () { + test('Promise() getService', function (done, assert) { + cos + .getService() + .then(function (data) { + assert.ok(data); + done(); + }) + .catch(function (err) { + assert.ok(false); + done(); + }); + }); - test('Promise() getService', function (done, assert) { - cos.getService().then(function (data) { - assert.ok(data); - done(); - }).catch(function (err) { - assert.ok(false); - done(); - }); - }); + test('Promise() getService region', function (done, assert) { + cos + .getService({ + Region: config.Region, + }) + .then(function (data) { + assert.ok(data); + done(); + }) + .catch(function (err) { + assert.ok(false); + done(); + }); + }); - test('Promise() getService region', function (done, assert) { - cos.getService({ - Region: config.Region, - }).then(function (data) { - assert.ok(data); - done(); - }).catch(function (err) { - assert.ok(false); - done(); - }); - }); + test('headBucket callback', function (done, assert) { + var res = cos.headBucket( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(!err && data); + done(); + }, + ); + assert.ok(!res); + }); - test('headBucket callback', function (done, assert) { - var res = cos.headBucket({ - Bucket: config.Bucket, - Region: config.Region, - }, function (err, data) { - assert.ok(!err && data); - done(); - }); - assert.ok(!res); + test('Promise() getObjectUrl', function (done, assert) { + var res = cos.getObjectUrl({ + Bucket: config.Bucket, + Region: config.Region, + Key: '123.txt', + Expires: 900, }); + assert.ok(!res.then); + done(); + }); - test('Promise() getObjectUrl', function (done, assert) { - var res = cos.getObjectUrl({ - Bucket: config.Bucket, - Region: config.Region, - Key: '123.txt', - Expires: 900, - }); - assert.ok(!res.then); + test('Promise() headBucket', function (done, assert) { + cos + .headBucket({ + Bucket: config.Bucket, + Region: config.Region, + }) + .then(function (data) { + assert.ok(data); done(); - }); - - test('Promise() headBucket', function (done, assert) { - cos.headBucket({ - Bucket: config.Bucket, - Region: config.Region, - }).then(function (data) { - assert.ok(data); - done(); - }).catch(function () { - assert.ok(false); - done(); - }); - }); + }) + .catch(function () { + assert.ok(false); + done(); + }); + }); - test('headBucket callback', function (done, assert) { - var res = cos.headBucket({ - Bucket: config.Bucket, - Region: config.Region, - }, function (err, data) { - assert.ok(!err && data); - done(); - }); - assert.ok(!res); - }); + test('headBucket callback', function (done, assert) { + var res = cos.headBucket( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(!err && data); + done(); + }, + ); + assert.ok(!res); + }); - test('Promise() headBucket error', function (done, assert) { - cos.headBucket({ - Bucket: config.Bucket, - Region: config.Region + '/', - }).then(function (data) { - assert.ok(!data); - done(); - }).catch(function (err) { - assert.ok(err && err.message === 'Region format error.'); - done(); - }); - }); + test('Promise() headBucket error', function (done, assert) { + cos + .headBucket({ + Bucket: config.Bucket, + Region: config.Region + '/', + }) + .then(function (data) { + assert.ok(!data); + done(); + }) + .catch(function (err) { + assert.ok(err && err.message === 'Region format error.'); + done(); + }); + }); }); group('Query 的键值带有特殊字符', function () { - test('getAuth() 特殊字符', function (done, assert) { - var content = Date.now().toString(); - var key = '1.txt'; - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: key, - Body: content, - }, function (err, data) { - var str = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM,./;\'[]\\-=0987654321`~!@#$%^&*()_+{}|":>?<'; - var qs = {}; - qs[str] = str; - var AuthData = cos.getAuth({ - Method: 'GET', - Key: key, - Query: qs, - }); - if (typeof AuthData === 'string') { - AuthData = {Authorization: AuthData}; - } - var link = 'http://' + config.Bucket + '.cos.' + config.Region + '.myqcloud.com' + '/' + - camSafeUrlEncode(key).replace(/%2F/g, '/') + - '?sign=' + camSafeUrlEncode(AuthData.Authorization) + - (AuthData.XCosSecurityToken ? '&x-cos-security-token=' + AuthData.XCosSecurityToken : '') + - '&' + camSafeUrlEncode(str) + '=' + camSafeUrlEncode(str); - request({ - method: 'GET', - url: link, - }, function (err, response, body) { - assert.ok(response.statusCode === 200); - assert.ok(body === content); - done(); - }); + test('getAuth() 特殊字符', function (done, assert) { + var content = Date.now().toString(); + var key = '1.txt'; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + Body: content, + }, + function (err, data) { + var str = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM,./;\'[]\\-=0987654321`~!@#$%^&*()_+{}|":>?<'; + var qs = {}; + qs[str] = str; + var AuthData = cos.getAuth({ + Method: 'GET', + Key: key, + Query: qs, }); - }); + if (typeof AuthData === 'string') { + AuthData = { Authorization: AuthData }; + } + var link = + 'http://' + + config.Bucket + + '.cos.' + + config.Region + + '.myqcloud.com' + + '/' + + camSafeUrlEncode(key).replace(/%2F/g, '/') + + '?sign=' + + camSafeUrlEncode(AuthData.Authorization) + + (AuthData.XCosSecurityToken ? '&x-cos-security-token=' + AuthData.XCosSecurityToken : '') + + '&' + + camSafeUrlEncode(str) + + '=' + + camSafeUrlEncode(str); + request( + { + method: 'GET', + url: link, + }, + function (err, response, body) { + assert.ok(response.statusCode === 200); + assert.ok(body === content); + done(); + }, + ); + }, + ); + }); }); group('selectObjectContent(),selectObjectContentStream()', function () { - var key = '1.json'; - var selectJsonOpt = { + var key = '1.json'; + var selectJsonOpt = { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + SelectType: 2, + SelectRequest: { + Expression: 'Select * from COSObject', + ExpressionType: 'SQL', + InputSerialization: { JSON: { Type: 'DOCUMENT' } }, + OutputSerialization: { JSON: { RecordDelimiter: '\n' } }, + RequestProgress: { Enabled: 'FALSE' }, + }, + onProgress: function (info) { + console.log(info); + }, + }; + test('selectObjectContent', function (done, assert) { + var time = Date.now(); + var content = `{"a":123,"b":"${time}","c":{"d":456}}`; + cos.putObject( + { Bucket: config.Bucket, Region: config.Region, Key: key, - SelectType: 2, - SelectRequest: { - Expression: "Select * from COSObject", - ExpressionType: "SQL", - InputSerialization: {JSON: {Type: "DOCUMENT",},}, - OutputSerialization: {JSON: {RecordDelimiter: "\n"},}, - RequestProgress: {Enabled: "FALSE"} - }, - onProgress: function(info) { - console.log(info); - } - }; - test('selectObjectContent', function (done, assert) { - var time = Date.now(); - var content = `{"a":123,"b":"${time}","c":{"d":456}}`; - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: key, - Body: content, - }, function (err, data) { - var bufList = []; - var writeStream = new Writable({ - write: function (chunk, encoding, callback) { - bufList.push(chunk); - callback(); - }, - }); - cos.selectObjectContent(selectJsonOpt, function (err, data) { - assert.ok(data.Payload.toString() === content + '\n'); - done(); - }); + Body: content, + }, + function (err, data) { + var bufList = []; + var writeStream = new Writable({ + write: function (chunk, encoding, callback) { + bufList.push(chunk); + callback(); + }, }); - }); - test('selectObjectContent', function (done, assert) { - var time = Date.now(); - var content = `{"a":123,"b":"${time}","c":{"d":456}`; - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: key, - Body: content, - }, function (err, data) { - var bufList = []; - cos.selectObjectContent(selectJsonOpt, function (err, data) { - assert.ok(err); - done(); - }); + cos.selectObjectContent(selectJsonOpt, function (err, data) { + assert.ok(data.Payload.toString() === content + '\n'); + done(); }); - }); - test('selectObjectContentStream', function (done, assert) { - var time = Date.now(); - var content = `{"a":123,"b":"${time}","c":{"d":456}}`; - cos.putObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: key, - Body: content, - }, function (err, data) { - var bufList = []; - var writeStream = new Writable({ - write: function (chunk, encoding, callback) { - bufList.push(chunk); - callback(); - }, - }); - cos.selectObjectContentStream(selectJsonOpt, function (err, data) { - assert.ok(Buffer.concat(bufList).toString() === content + '\n'); - done(); - }).pipe(writeStream); + }, + ); + }); + test('selectObjectContent', function (done, assert) { + var time = Date.now(); + var content = `{"a":123,"b":"${time}","c":{"d":456}`; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + Body: content, + }, + function (err, data) { + var bufList = []; + cos.selectObjectContent(selectJsonOpt, function (err, data) { + assert.ok(err); + done(); }); - }); + }, + ); + }); + test('selectObjectContentStream', function (done, assert) { + var time = Date.now(); + var content = `{"a":123,"b":"${time}","c":{"d":456}}`; + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: key, + Body: content, + }, + function (err, data) { + var bufList = []; + var writeStream = new Writable({ + write: function (chunk, encoding, callback) { + bufList.push(chunk); + callback(); + }, + }); + cos + .selectObjectContentStream(selectJsonOpt, function (err, data) { + assert.ok(Buffer.concat(bufList).toString() === content + '\n'); + done(); + }) + .pipe(writeStream); + }, + ); + }); }); group('BucketReplication', function () { - var prepared = false; - var repBucket = config.Bucket.replace(/^(.*)(-\d+)$/, '$1-replication$2') - var repBucketName = repBucket.replace(/(-\d+)$/, '') - var repRegion = 'ap-chengdu'; - var prepareBucket = function (callback) { - cos.putBucket({ - Bucket: repBucket, - Region: repRegion, - }, function (err, data) { - cos.putBucketVersioning({ - Bucket: config.Bucket, - Region: config.Region, - VersioningConfiguration: { - Status: 'Enabled' - } - }, function (err, data) { - cos.putBucketVersioning({ - Bucket: repBucket, - Region: repRegion, - VersioningConfiguration: { - Status: 'Enabled' - } - }, function (err, data) { - prepared = true - callback(); - }); - }); - }); - }; - test('putBucketReplication();getBucketReplication()', function (done, assert) { - var ruleId = Date.now().toString(36); - prepareBucket(function () { - cos.putBucketReplication({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - ReplicationConfiguration: { - Role: "qcs::cam::uin/" + config.Uin + ":uin/" + config.Uin, - Rules: [{ - ID: ruleId, - Status: "Enabled", - Prefix: "sync/", - Destination: { - Bucket: `qcs::cos:${repRegion}::${repBucket}`, - } - }] - } - }, function (err, data) { - assert.ok(!err); - cos.getBucketReplication({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - }, function (err, data) { - assert.ok(data.ReplicationConfiguration.Rules[0].ID === ruleId); - done(); - }); - }); - }); - }); - test('deleteBucketReplication()', function (done, assert) { - cos.deleteBucketReplication({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 + var prepared = false; + var repBucket = config.Bucket.replace(/^(.*)(-\d+)$/, '$1-replication$2'); + var repBucketName = repBucket.replace(/(-\d+)$/, ''); + var repRegion = 'ap-chengdu'; + var prepareBucket = function (callback) { + cos.putBucket( + { + Bucket: repBucket, + Region: repRegion, + }, + function (err, data) { + cos.putBucketVersioning( + { + Bucket: config.Bucket, Region: config.Region, VersioningConfiguration: { - Status: 'Suspended' - } - }, function (err, data) { - setTimeout(function () { - cos.getBucketReplication({ - Bucket: config.Bucket, - Region: config.Region, - }, function (err, data) { - assert.ok(err && err.statusCode === 404); - done(); - }); - }, 2000); - }); - }); - test('deleteBucketReplication() bucket not exist', function (done, assert) { - cos.deleteBucketReplication({ - Bucket: Date.now().toString(36) + config.Bucket, // Bucket 格式:test-1250000000 + Status: 'Enabled', + }, + }, + function (err, data) { + cos.putBucketVersioning( + { + Bucket: repBucket, + Region: repRegion, + VersioningConfiguration: { + Status: 'Enabled', + }, + }, + function (err, data) { + prepared = true; + callback(); + }, + ); + }, + ); + }, + ); + }; + test('putBucketReplication();getBucketReplication()', function (done, assert) { + var ruleId = Date.now().toString(36); + prepareBucket(function () { + cos.putBucketReplication( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 Region: config.Region, - VersioningConfiguration: { - Status: 'Suspended' - } - }, function (err, data) { + ReplicationConfiguration: { + Role: 'qcs::cam::uin/' + config.Uin + ':uin/' + config.Uin, + Rules: [ + { + ID: ruleId, + Status: 'Enabled', + Prefix: 'sync/', + Destination: { + Bucket: `qcs::cos:${repRegion}::${repBucket}`, + }, + }, + ], + }, + }, + function (err, data) { + assert.ok(!err); + cos.getBucketReplication( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + }, + function (err, data) { + assert.ok(data.ReplicationConfiguration.Rules[0].ID === ruleId); + done(); + }, + ); + }, + ); + }); + }); + test('deleteBucketReplication()', function (done, assert) { + cos.deleteBucketReplication( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + VersioningConfiguration: { + Status: 'Suspended', + }, + }, + function (err, data) { + setTimeout(function () { + cos.getBucketReplication( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(err && err.statusCode === 404); + done(); + }, + ); + }, 2000); + }, + ); + }); + test('deleteBucketReplication() bucket not exist', function (done, assert) { + cos.deleteBucketReplication( + { + Bucket: Date.now().toString(36) + config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + VersioningConfiguration: { + Status: 'Suspended', + }, + }, + function (err, data) { assert.ok(err); done(); - }); - }); + }, + ); + }); }); group('putBucketVersioning(),getBucketVersioning()', function () { - test('putBucketVersioning no VersioningConfiguration', function(done, assert) { - cos.putBucketVersioning({ + test('putBucketVersioning no VersioningConfiguration', function (done, assert) { + cos.putBucketVersioning( + { Bucket: config.Bucket, // Bucket 格式:test-1250000000 Region: config.Region, - }, function (err, data) { + }, + function (err, data) { assert.ok(err); done(); - }); - }); - test('Enabled', function (done, assert) { - cos.deleteBucketReplication({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - VersioningConfiguration: { - Status: "Enabled" - } - }, function (err, data) { - cos.putBucketVersioning({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - VersioningConfiguration: { - Status: "Enabled" - } - }, function (err, data) { - setTimeout(function () { - cos.getBucketVersioning({ - Bucket: config.Bucket, - Region: config.Region, - }, function (err, data) { - assert.ok(data.VersioningConfiguration.Status === 'Enabled'); - done(); - }); - }, 2000); - }); - }); - }); - test('Suspended', function (done, assert) { - cos.putBucketVersioning({ + }, + ); + }); + test('Enabled', function (done, assert) { + cos.deleteBucketReplication( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + VersioningConfiguration: { + Status: 'Enabled', + }, + }, + function (err, data) { + cos.putBucketVersioning( + { Bucket: config.Bucket, // Bucket 格式:test-1250000000 Region: config.Region, VersioningConfiguration: { - Status: 'Suspended' - } - }, function (err, data) { + Status: 'Enabled', + }, + }, + function (err, data) { setTimeout(function () { - cos.getBucketVersioning({ - Bucket: config.Bucket, - Region: config.Region, - }, function (err, data) { - console.log(data.VersioningConfiguration.Status); - assert.ok(data.VersioningConfiguration.Status === 'Suspended'); - done(); - }); + cos.getBucketVersioning( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(data.VersioningConfiguration.Status === 'Enabled'); + done(); + }, + ); }, 2000); - }); - }); + }, + ); + }, + ); + }); + test('Suspended', function (done, assert) { + cos.putBucketVersioning( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + VersioningConfiguration: { + Status: 'Suspended', + }, + }, + function (err, data) { + setTimeout(function () { + cos.getBucketVersioning( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + console.log(data.VersioningConfiguration.Status); + assert.ok(data.VersioningConfiguration.Status === 'Suspended'); + done(); + }, + ); + }, 2000); + }, + ); + }); }); group('BucketOrigin', function () { - test('putBucketOrigin(),getBucketOrigin()', function (done, assert) { - var prefix = Date.now().toString(36) + '/'; - cos.putBucketOrigin({ + test('putBucketOrigin(),getBucketOrigin()', function (done, assert) { + var prefix = Date.now().toString(36) + '/'; + cos.putBucketOrigin( + { + Bucket: config.Bucket, + Region: config.Region, + OriginRule: [ + { + OriginType: 'Mirror', + OriginCondition: { HTTPStatusCode: 404, Prefix: '' }, + OriginParameter: { + Protocol: 'HTTP', + FollowQueryString: 'true', + HttpHeader: { + NewHttpHeader: { + Header: [ + { + Key: 'a', + Value: 'a', + }, + ], + }, + }, + FollowRedirection: 'true', + HttpRedirectCode: ['301', '302'], + }, + OriginInfo: { + HostInfo: { HostName: 'qq.com' }, + FileInfo: { + PrefixConfiguration: { Prefix: prefix }, + SuffixConfiguration: { Suffix: '.jpg' }, + }, + }, + RulePriority: 1, + }, + ], + }, + function (err, data) { + assert.ok(!err); + cos.getBucketOrigin( + { Bucket: config.Bucket, Region: config.Region, - OriginRule: [{ - OriginType: 'Mirror', - OriginCondition: {HTTPStatusCode: 404, Prefix: ''}, - OriginParameter: { - Protocol: 'HTTP', - FollowQueryString: 'true', - HttpHeader: { - NewHttpHeader: { - Header: [{ - Key: 'a', - Value: 'a' - }] - } + }, + function (err, data) { + assert.ok(data.OriginRule[0].OriginInfo.FileInfo.PrefixConfiguration.Prefix === prefix); + done(); + }, + ); + }, + ); + }); + test('putBucketOrigin() bucket not exist', function (done, assert) { + var prefix = Date.now().toString(36) + '/'; + cos.putBucketOrigin( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + OriginRule: [ + { + OriginType: 'Mirror', + OriginCondition: { HTTPStatusCode: 404, Prefix: '' }, + OriginParameter: { + Protocol: 'HTTP', + FollowQueryString: 'true', + HttpHeader: { + NewHttpHeader: { + Header: [ + { + Key: 'a', + Value: 'a', }, - FollowRedirection: 'true', - HttpRedirectCode: ['301', '302'] + ], }, - OriginInfo: { - HostInfo: {HostName: 'qq.com'}, - FileInfo: { - PrefixConfiguration: {Prefix: prefix}, - SuffixConfiguration: {Suffix: '.jpg'} - } - }, - RulePriority: 1 - }] - }, function (err, data) { - assert.ok(!err); - cos.getBucketOrigin({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(data.OriginRule[0].OriginInfo.FileInfo.PrefixConfiguration.Prefix === prefix); - done(); - }); - }); - }); - test('putBucketOrigin() bucket not exist', function (done, assert) { - var prefix = Date.now().toString(36) + '/'; - cos.putBucketOrigin({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region, - OriginRule: [{ - OriginType: 'Mirror', - OriginCondition: {HTTPStatusCode: 404, Prefix: ''}, - OriginParameter: { - Protocol: 'HTTP', - FollowQueryString: 'true', - HttpHeader: { - NewHttpHeader: { - Header: [{ - Key: 'a', - Value: 'a' - }] - } - }, - FollowRedirection: 'true', - HttpRedirectCode: ['301', '302'] }, - OriginInfo: { - HostInfo: {HostName: 'qq.com'}, - FileInfo: { - PrefixConfiguration: {Prefix: prefix}, - SuffixConfiguration: {Suffix: '.jpg'} - } + FollowRedirection: 'true', + HttpRedirectCode: ['301', '302'], + }, + OriginInfo: { + HostInfo: { HostName: 'qq.com' }, + FileInfo: { + PrefixConfiguration: { Prefix: prefix }, + SuffixConfiguration: { Suffix: '.jpg' }, }, - RulePriority: 1 - }] - }, function (err, data) { - assert.ok(err); - done(); - }); - }); - test('deleteBucketOrigin()', function (done, assert) { - cos.deleteBucketOrigin({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getBucketOrigin({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - assert.ok(err); - done(); - }); - }, 2000); - }); - }); - test('deleteBucketOrigin() bucket not exist', function (done, assert) { - cos.deleteBucketOrigin({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region - }, function (err, data) { + }, + RulePriority: 1, + }, + ], + }, + function (err, data) { assert.ok(err); done(); - }); - }); + }, + ); + }); + test('deleteBucketOrigin()', function (done, assert) { + cos.deleteBucketOrigin( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getBucketOrigin( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }, 2000); + }, + ); + }); + test('deleteBucketOrigin() bucket not exist', function (done, assert) { + cos.deleteBucketOrigin( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }); }); group('BucketReferer', function () { test('putBucketReferer() no RefererConfiguration', function (done, assert) { - cos.putBucketReferer({ + cos.putBucketReferer( + { Bucket: config.Bucket, Region: config.Region, - }, function (err, data) { + }, + function (err, data) { setTimeout(function () { - cos.getBucketReferer({ + cos.getBucketReferer( + { Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { + Region: config.Region, + }, + function (err, data) { assert.ok(!err); done(); - }); - }, 2000); - }); - }); - test('putBucketReferer(),getBucketReferer()', function (done, assert) { - var conf = { - Status: 'Enabled', - RefererType: 'White-List', - DomainList: { - Domains: [ - Date.now().toString(36) + '.qq.com', - '*.qcloud.com', - ] }, - EmptyReferConfiguration: 'Allow', - }; - cos.putBucketReferer({ - Bucket: config.Bucket, - Region: config.Region, - RefererConfiguration: conf - }, function (err, data) { - assert.ok(!err); - setTimeout(function () { - cos.getBucketReferer({ - Bucket: config.Bucket, - Region: config.Region - }, function (err, data) { - // todo VerifySignatureURL全量后再支持单测 - delete data.RefererConfiguration['VerifySignatureURL']; - assert.ok(comparePlainObject(conf, data.RefererConfiguration)); - done(); - }); - }, 2000); - }); - }); - test('putBucketReferer() bucket not exist', function (done, assert) { - cos.putBucketReferer({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region, - }, function (err, data) { + ); + }, 2000); + }, + ); + }); + test('putBucketReferer(),getBucketReferer()', function (done, assert) { + var conf = { + Status: 'Enabled', + RefererType: 'White-List', + DomainList: { + Domains: [Date.now().toString(36) + '.qq.com', '*.qcloud.com'], + }, + EmptyReferConfiguration: 'Allow', + }; + cos.putBucketReferer( + { + Bucket: config.Bucket, + Region: config.Region, + RefererConfiguration: conf, + }, + function (err, data) { + assert.ok(!err); + setTimeout(function () { + cos.getBucketReferer( + { + Bucket: config.Bucket, + Region: config.Region, + }, + function (err, data) { + // todo VerifySignatureURL全量后再支持单测 + delete data.RefererConfiguration['VerifySignatureURL']; + assert.ok(comparePlainObject(conf, data.RefererConfiguration)); + done(); + }, + ); + }, 2000); + }, + ); + }); + test('putBucketReferer() bucket not exist', function (done, assert) { + cos.putBucketReferer( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + }, + function (err, data) { assert.ok(err); done(); - }); - }); - test('getBucketReferer() bucket not exist', function (done, assert) { - cos.getBucketReferer({ - Bucket: Date.now().toString(36) + config.Bucket, - Region: config.Region, - }, function (err, data) { + }, + ); + }); + test('getBucketReferer() bucket not exist', function (done, assert) { + cos.getBucketReferer( + { + Bucket: Date.now().toString(36) + config.Bucket, + Region: config.Region, + }, + function (err, data) { assert.ok(err); done(); - }); - }); + }, + ); + }); }); group('restoreObject()', function () { - test('restoreObject no RestoreRequest', function(done, assert) { - cos.restoreObject({ + test('restoreObject no RestoreRequest', function (done, assert) { + cos.restoreObject( + { Bucket: config.Bucket, Region: config.Region, Key: '1.jpg', - }, function (err, data) { + }, + function (err, data) { assert.ok(err); done(); - }); - }); - test('restoreObject()', function (done, assert) { - cos.putObject({ + }, + ); + }); + test('restoreObject()', function (done, assert) { + cos.putObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1.jpg', + Body: '123', + StorageClass: 'ARCHIVE', + }, + function (err, data) { + assert.ok(!err); + cos.restoreObject( + { Bucket: config.Bucket, Region: config.Region, Key: '1.jpg', - Body: '123', - StorageClass: 'ARCHIVE' - }, function (err, data) { - assert.ok(!err); - cos.restoreObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.jpg', - RestoreRequest: { - Days: 1, - CASJobParameters: { - Tier: 'Expedited' - } - }, - }, function (err, data) { - assert.ok(data && Math.floor(data.statusCode / 100) === 2); - done(); - }); - }); - }); + RestoreRequest: { + Days: 1, + CASJobParameters: { + Tier: 'Expedited', + }, + }, + }, + function (err, data) { + assert.ok(data && Math.floor(data.statusCode / 100) === 2); + done(); + }, + ); + }, + ); + }); }); group('uploadFile()', function () { - test('uploadFile() 高级上传', function (done, assert) { - var filename = '3mb.zip'; - var filepath = path.resolve(__dirname, filename); - util.createFile(filepath, 1024 * 1024 * 3, function (err) { - cos.uploadFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - FilePath: filepath, - }, function (err, data) { - assert.ok(!err); - fs.unlinkSync(filepath); - done(); - }); - }); + test('uploadFile() 高级上传', function (done, assert) { + var filename = '3mb.zip'; + var filepath = path.resolve(__dirname, filename); + util.createFile(filepath, 1024 * 1024 * 3, function (err) { + cos.uploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + FilePath: filepath, + }, + function (err, data) { + assert.ok(!err); + fs.unlinkSync(filepath); + done(); + }, + ); }); - test('uploadFile() 高级上传目录', function (done, assert) { - var filename = '3mb/'; - var filepath = path.resolve(__dirname, filename); - util.createFile(filepath, 1024 * 1024 * 3, function (err) { - cos.uploadFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - FilePath: filepath, - }, function (err, data) { - assert.ok(!err); - fs.unlinkSync(filepath); - done(); - }); - }); + }); + test('uploadFile() 高级上传目录', function (done, assert) { + var filename = '3mb/'; + var filepath = path.resolve(__dirname, filename); + util.createFile(filepath, 1024 * 1024 * 3, function (err) { + cos.uploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + FilePath: filepath, + }, + function (err, data) { + assert.ok(!err); + fs.unlinkSync(filepath); + done(); + }, + ); }); - test('uploadFile() 高级上传 大于5mb则分块上传', function (done, assert) { - var filename = '3mb.zip'; - var filepath = path.resolve(__dirname, filename); - util.createFile(filepath, 1024 * 1024 * 3, function (err) { - cos.uploadFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - FilePath: filepath, - SliceSize: 1024 * 1024 * 5, - }, function (err, data) { - assert.ok(!err); - fs.unlinkSync(filepath); - done(); - }); - }); + }); + test('uploadFile() 高级上传 大于5mb则分块上传', function (done, assert) { + var filename = '3mb.zip'; + var filepath = path.resolve(__dirname, filename); + util.createFile(filepath, 1024 * 1024 * 3, function (err) { + cos.uploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + FilePath: filepath, + SliceSize: 1024 * 1024 * 5, + }, + function (err, data) { + assert.ok(!err); + fs.unlinkSync(filepath); + done(); + }, + ); }); + }); }); group('uploadFiles()', function () { - test('uploadFiles()', function (done, assert) { - var filename = '1.zip'; - var filepath = path.resolve(__dirname, filename); - util.createFile(filepath, 1, function (err) { - cos.uploadFiles({ - files: [{ - Bucket: config.Bucket, - Region: config.Region, - Key: filename, - FilePath: filepath, - }], - }, function (err, data) { - assert.ok(!data.files.error); - fs.unlinkSync(filepath); - done(); - }); - }); + test('uploadFiles()', function (done, assert) { + var filename = '1.zip'; + var filepath = path.resolve(__dirname, filename); + util.createFile(filepath, 1, function (err) { + cos.uploadFiles( + { + files: [ + { + Bucket: config.Bucket, + Region: config.Region, + Key: filename, + FilePath: filepath, + }, + ], + }, + function (err, data) { + assert.ok(!data.files.error); + fs.unlinkSync(filepath); + done(); + }, + ); }); + }); }); group('multipartAbort()', function () { - test('multipartAbort()', function (done, assert) { - var Key = '1.jpg' - cos.multipartInit({ + test('multipartAbort()', function (done, assert) { + var Key = '1.jpg'; + cos.multipartInit( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + }, + function (err, data) { + assert.ok(!err); + var UploadId = data.UploadId; + cos.multipartAbort( + { Bucket: config.Bucket, Region: config.Region, Key: Key, - }, function (err, data) { + UploadId: UploadId, + }, + function (err, data) { assert.ok(!err); - var UploadId = data.UploadId; - cos.multipartAbort({ + cos.multipartListPart( + { Bucket: config.Bucket, Region: config.Region, Key: Key, UploadId: UploadId, - }, function (err, data) { - assert.ok(!err); - cos.multipartListPart({ - Bucket: config.Bucket, - Region: config.Region, - Key: Key, - UploadId: UploadId, - }, function (err, data) { - assert.ok(err); - done(); - }); - }); - }); - }); + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); + }, + ); + }, + ); + }); }); group('sliceUploadFile() 续传', function () { - test('multipartAbort()', function (done, assert) { - var Key = '3.zip' - var filepath = path.resolve(__dirname, Key); - createFileSync(filepath, 1024 * 1024 * 3); - cos.multipartInit({ + test('multipartAbort()', function (done, assert) { + var Key = '3.zip'; + var filepath = path.resolve(__dirname, Key); + createFileSync(filepath, 1024 * 1024 * 3); + cos.multipartInit( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + }, + function (err, data) { + assert.ok(!err); + var UploadId = data.UploadId; + cos.multipartUpload( + { Bucket: config.Bucket, Region: config.Region, Key: Key, - }, function (err, data) { + UploadId: UploadId, + PartNumber: 1, + Body: Buffer.from(Array(0, 1024 * 1024)), + }, + function (err, data) { assert.ok(!err); - var UploadId = data.UploadId; - cos.multipartUpload({ + cos.sliceUploadFile( + { Bucket: config.Bucket, Region: config.Region, Key: Key, - UploadId: UploadId, - PartNumber: 1, - Body: Buffer.from(Array(0, 1024 * 1024)), - }, function (err, data) { - assert.ok(!err); - cos.sliceUploadFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: Key, - FilePath: filepath, - ChunkSize: 1024 * 1024, - }, function (err, data) { - assert.ok(data); - fs.unlinkSync(filepath); - done(); - }); - }); - }); - }); + FilePath: filepath, + ChunkSize: 1024 * 1024, + }, + function (err, data) { + assert.ok(data); + fs.unlinkSync(filepath); + done(); + }, + ); + }, + ); + }, + ); + }); }); group('getStream() 流式下载 ECONNREFUSED 错误', function () { - test('getStream() 流式下载 ECONNREFUSED 错误', function (done, assert) { - cos.options.Domain = '127.0.0.1:12345'; - cos.getObject({ - Bucket: config.Bucket, - Region: config.Region, - Key: '1.jpg', - }, function (err, data) { - assert.ok(err.code === 'ECONNREFUSED'); - cos.options.Domain = ''; - done(); - }); - }); + test('getStream() 流式下载 ECONNREFUSED 错误', function (done, assert) { + cos.options.Domain = '127.0.0.1:12345'; + cos.getObject( + { + Bucket: config.Bucket, + Region: config.Region, + Key: '1.jpg', + }, + function (err, data) { + assert.ok(err.code === 'ECONNREFUSED'); + cos.options.Domain = ''; + done(); + }, + ); + }); }); group('appendObject', function () { - test('appendObject()', function (done, assert) { - deleteObjectBefore('append.txt').then(() => { - cos.appendObject({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Key: 'append.txt', /* 必须 */ - Body: '12345', - Position: 0, - }, function(err, data) { - cos.headObject({ + test('appendObject()', function (done, assert) { + deleteObjectBefore('append.txt').then(() => { + cos.appendObject( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: 'append.txt' /* 必须 */, + Body: '12345', + Position: 0, + }, + function (err, data) { + cos.headObject( + { Bucket: config.Bucket, // Bucket 格式:test-1250000000 Region: config.Region, - Key: 'append.txt', /* 必须 */ - }, function(err, data) { - if (err) return console.log(err); - // 首先取到要追加的文件当前长度,即需要上送的Position - var position = data.headers['content-length']; - cos.appendObject({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Key: 'append.txt', /* 必须 */ - Body: '66666', - Position: position, - Headers: { - 'x-cos-test': 'test' - }, + Key: 'append.txt' /* 必须 */, + }, + function (err, data) { + if (err) return console.log(err); + // 首先取到要追加的文件当前长度,即需要上送的Position + var position = data.headers['content-length']; + cos.appendObject( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: 'append.txt' /* 必须 */, + Body: '66666', + Position: position, + Headers: { + 'x-cos-test': 'test', + }, }, - function(err, data) { - assert.ok(!err); - done(); - }) - }); - }); - }); + function (err, data) { + assert.ok(!err); + done(); + }, + ); + }, + ); + }, + ); }); + }); }); group('downloadFile', function () { test('downloadFile() file not found', function (done, assert) { - var Key = '101mb.zip'; - cos.downloadFile({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Key: Key, - FilePath: './' + Key, // 本地保存路径 - ChunkSize: 1024 * 1024 * 8, // 分块大小 - ParallelLimit: 5, // 分块并发数 - RetryTimes: 3, // 分块失败重试次数 - TaskId: '123', // 可以自己生成TaskId,用于取消下载 - }, function (err, data) { - assert.ok(err); - done(); - }); + var Key = '101mb.zip'; + cos.downloadFile( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: Key, + FilePath: './' + Key, // 本地保存路径 + ChunkSize: 1024 * 1024 * 8, // 分块大小 + ParallelLimit: 5, // 分块并发数 + RetryTimes: 3, // 分块失败重试次数 + TaskId: '123', // 可以自己生成TaskId,用于取消下载 + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); }); test('downloadFile() fileSize=0', function (done, assert) { - var Key = '0b.zip'; - cos.downloadFile({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Key: Key, - FilePath: './' + Key, // 本地保存路径 - ChunkSize: 1024 * 1024 * 8, // 分块大小 - ParallelLimit: 5, // 分块并发数 - RetryTimes: 3, // 分块失败重试次数 - TaskId: '123', // 可以自己生成TaskId,用于取消下载 - }, function (err, data) { - assert.ok(err); - done(); - }); + var Key = '0b.zip'; + cos.downloadFile( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: Key, + FilePath: './' + Key, // 本地保存路径 + ChunkSize: 1024 * 1024 * 8, // 分块大小 + ParallelLimit: 5, // 分块并发数 + RetryTimes: 3, // 分块失败重试次数 + TaskId: '123', // 可以自己生成TaskId,用于取消下载 + }, + function (err, data) { + assert.ok(err); + done(); + }, + ); }); test('downloadFile() 小文件简单下载', function (done, assert) { - var Key = '1mb.zip'; - var fileSize = 1024 * 1024 * 3; - var filePath = createFileSync(path.resolve(__dirname, Key), fileSize); - cos.sliceUploadFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: Key, - FilePath: filePath, - TrafficLimit: 819200, - }, function (err, data) { + var Key = '1mb.zip'; + var fileSize = 1024 * 1024 * 3; + var filePath = createFileSync(path.resolve(__dirname, Key), fileSize); + cos.sliceUploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + FilePath: filePath, + TrafficLimit: 819200, + }, + function (err, data) { if (!err) { - cos.downloadFile({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Key: Key, - FilePath: './' + Key, // 本地保存路径 - ChunkSize: 1024 * 1024 * 8, // 分块大小 - ParallelLimit: 5, // 分块并发数 - RetryTimes: 3, // 分块失败重试次数 - TaskId: '123', // 可以自己生成TaskId,用于取消下载 - }, function (err, data) { + cos.downloadFile( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: Key, + FilePath: './' + Key, // 本地保存路径 + ChunkSize: 1024 * 1024 * 8, // 分块大小 + ParallelLimit: 5, // 分块并发数 + RetryTimes: 3, // 分块失败重试次数 + TaskId: '123', // 可以自己生成TaskId,用于取消下载 + }, + function (err, data) { assert.ok(!err); done(); - }); + }, + ); } else { done(); } - }); + }, + ); }); test('downloadFile() 大文件分块下载', function (done, assert) { - var Key = '50mb.zip'; - var fileSize = 1024 * 1024 * 50; - var filePath = createFileSync(path.resolve(__dirname, Key), fileSize); - cos.sliceUploadFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: Key, - FilePath: filePath, - Headers: { - 'x-cos-traffic-limit': 81920000, - }, - }, function (err, data) { + var Key = '50mb.zip'; + var fileSize = 1024 * 1024 * 50; + var filePath = createFileSync(path.resolve(__dirname, Key), fileSize); + cos.sliceUploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + FilePath: filePath, + Headers: { + 'x-cos-traffic-limit': 81920000, + }, + }, + function (err, data) { if (err) { done(); } else { - cos.downloadFile({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Key: Key, - FilePath: './' + Key, // 本地保存路径 - ChunkSize: 1024 * 1024 * 8, // 分块大小 - ParallelLimit: 5, // 分块并发数 - RetryTimes: 3, // 分块失败重试次数 - TaskId: '123', // 可以自己生成TaskId,用于取消下载 - }, function (err, data) { + cos.downloadFile( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: Key, + FilePath: './' + Key, // 本地保存路径 + ChunkSize: 1024 * 1024 * 8, // 分块大小 + ParallelLimit: 5, // 分块并发数 + RetryTimes: 3, // 分块失败重试次数 + TaskId: '123', // 可以自己生成TaskId,用于取消下载 + }, + function (err, data) { assert.ok(!err); done(); - }); + }, + ); } - }); + }, + ); }); test('downloadFile() 文件续传时远端文件已修改', function (done, assert) { - var Key = '50mb.zip'; - var fileSize = 1024 * 1024 * 50; - var filePath = createFileSync(path.resolve(__dirname, Key), fileSize); - cos.sliceUploadFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: Key, - FilePath: filePath, - TrafficLimit: 819200, - }, function (err, data) { + var Key = '50mb.zip'; + var fileSize = 1024 * 1024 * 50; + var filePath = createFileSync(path.resolve(__dirname, Key), fileSize); + cos.sliceUploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + FilePath: filePath, + TrafficLimit: 819200, + }, + function (err, data) { if (err) { done(); } else { - cos.downloadFile({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Key: Key, - FilePath: './' + Key, // 本地保存路径 - ChunkSize: 1024 * 1024 * 8, // 分块大小 - ParallelLimit: 5, // 分块并发数 - RetryTimes: 3, // 分块失败重试次数 - TaskId: '123', // 可以自己生成TaskId,用于取消下载 - }, function (err, data) { + cos.downloadFile( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: Key, + FilePath: './' + Key, // 本地保存路径 + ChunkSize: 1024 * 1024 * 8, // 分块大小 + ParallelLimit: 5, // 分块并发数 + RetryTimes: 3, // 分块失败重试次数 + TaskId: '123', // 可以自己生成TaskId,用于取消下载 + }, + function (err, data) { assert.ok(!err); done(); - }); + }, + ); } - }); + }, + ); }); test('downloadFile() 下载归档文件', function (done, assert) { - var Key = '10mb.zip'; - var fileSize = 1024 * 1024 * 10; - var filePath = createFileSync(path.resolve(__dirname, Key), fileSize); - cos.sliceUploadFile({ - Bucket: config.Bucket, - Region: config.Region, - Key: Key, - FilePath: filePath, - StorageClass: 'ARCHIVE', - }, function (err, data) { + var Key = '10mb.zip'; + var fileSize = 1024 * 1024 * 10; + var filePath = createFileSync(path.resolve(__dirname, Key), fileSize); + cos.sliceUploadFile( + { + Bucket: config.Bucket, + Region: config.Region, + Key: Key, + FilePath: filePath, + StorageClass: 'ARCHIVE', + }, + function (err, data) { if (err) { done(); } else { - cos.downloadFile({ - Bucket: config.Bucket, // Bucket 格式:test-1250000000 - Region: config.Region, - Key: Key, - FilePath: './' + Key, // 本地保存路径 - ChunkSize: 1024 * 1024 * 8, // 分块大小 - ParallelLimit: 5, // 分块并发数 - RetryTimes: 3, // 分块失败重试次数 - TaskId: '123', // 可以自己生成TaskId,用于取消下载 - }, function (err, data) { + cos.downloadFile( + { + Bucket: config.Bucket, // Bucket 格式:test-1250000000 + Region: config.Region, + Key: Key, + FilePath: './' + Key, // 本地保存路径 + ChunkSize: 1024 * 1024 * 8, // 分块大小 + ParallelLimit: 5, // 分块并发数 + RetryTimes: 3, // 分块失败重试次数 + TaskId: '123', // 可以自己生成TaskId,用于取消下载 + }, + function (err, data) { assert.ok(err); done(); - }); + }, + ); } - }); + }, + ); }); });