From 3f06e2e8d7f054f83114734b49c7ca1a88ac302d Mon Sep 17 00:00:00 2001 From: lwvjhm Date: Wed, 20 Nov 2024 18:01:44 +0800 Subject: [PATCH] feat(cos): Add new data source `tencentcloud_cos_object_signed_url` --- .changelog/2967.txt | 3 + go.mod | 2 +- go.sum | 3 + tencentcloud/provider.go | 1 + tencentcloud/provider.md | 1 + .../data_source_tc_cos_object_signed_url.go | 126 +++ .../data_source_tc_cos_object_signed_url.md | 10 + ...ta_source_tc_cos_object_signed_url_test.go | 41 + .../services/cos/resource_tc_cos_bucket.go | 17 +- .../services/cos/service_tencentcloud_cos.go | 4 +- .../tencentyun/cos-go-sdk-v5/.gitignore | 8 +- .../tencentyun/cos-go-sdk-v5/CHANGELOG.md | 403 +++++++- .../tencentyun/cos-go-sdk-v5/auth.go | 224 +++- .../tencentyun/cos-go-sdk-v5/bucket.go | 155 +++ .../tencentyun/cos-go-sdk-v5/bucket_acl.go | 13 +- .../tencentyun/cos-go-sdk-v5/bucket_cors.go | 10 +- .../tencentyun/cos-go-sdk-v5/bucket_domain.go | 36 +- .../cos-go-sdk-v5/bucket_encryption.go | 2 +- .../bucket_intelligenttiering.go | 96 +- .../cos-go-sdk-v5/bucket_inventory.go | 2 +- .../cos-go-sdk-v5/bucket_lifecycle.go | 24 +- .../cos-go-sdk-v5/bucket_location.go | 2 +- .../cos-go-sdk-v5/bucket_object_lock.go | 18 + .../tencentyun/cos-go-sdk-v5/bucket_origin.go | 111 +- .../tencentyun/cos-go-sdk-v5/bucket_part.go | 26 +- .../tencentyun/cos-go-sdk-v5/bucket_policy.go | 1 + .../cos-go-sdk-v5/bucket_referer.go | 18 + .../cos-go-sdk-v5/bucket_replication.go | 3 +- .../cos-go-sdk-v5/bucket_website.go | 8 +- .../github.com/tencentyun/cos-go-sdk-v5/ci.go | 453 +++++++- .../tencentyun/cos-go-sdk-v5/ci_doc.go | 51 + .../cos-go-sdk-v5/ci_fileprocess.go | 66 +- .../tencentyun/cos-go-sdk-v5/ci_media.go | 963 ++++++++++++++++-- .../cos-go-sdk-v5/ci_metainsight.go | 609 +++++++++++ .../tencentyun/cos-go-sdk-v5/cos.go | 256 ++++- .../tencentyun/cos-go-sdk-v5/error.go | 16 + .../tencentyun/cos-go-sdk-v5/helper.go | 88 +- .../tencentyun/cos-go-sdk-v5/object.go | 420 +++++++- .../tencentyun/cos-go-sdk-v5/object_part.go | 191 +++- .../tencentyun/cos-go-sdk-v5/service.go | 3 +- vendor/modules.txt | 2 +- .../d/cos_object_signed_url.html.markdown | 41 + website/tencentcloud.erb | 3 + 43 files changed, 4154 insertions(+), 376 deletions(-) create mode 100644 .changelog/2967.txt create mode 100644 tencentcloud/services/cos/data_source_tc_cos_object_signed_url.go create mode 100644 tencentcloud/services/cos/data_source_tc_cos_object_signed_url.md create mode 100644 tencentcloud/services/cos/data_source_tc_cos_object_signed_url_test.go create mode 100644 vendor/github.com/tencentyun/cos-go-sdk-v5/ci_metainsight.go create mode 100644 website/docs/d/cos_object_signed_url.html.markdown diff --git a/.changelog/2967.txt b/.changelog/2967.txt new file mode 100644 index 0000000000..9ea34d35f2 --- /dev/null +++ b/.changelog/2967.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +tencentcloud_cos_object_signed_url +``` diff --git a/go.mod b/go.mod index b0a49929c0..56b907cbe2 100644 --- a/go.mod +++ b/go.mod @@ -100,7 +100,7 @@ require ( github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/waf v1.0.1037 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/wedata v1.0.792 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/wss v1.0.199 - github.com/tencentyun/cos-go-sdk-v5 v0.7.42-0.20230629101357-7edd77448a0f + github.com/tencentyun/cos-go-sdk-v5 v0.7.58 github.com/yangwenmai/ratelimit v0.0.0-20180104140304-44221c2292e1 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index cfad42a86e..9ed823de25 100644 --- a/go.sum +++ b/go.sum @@ -277,6 +277,7 @@ github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14j github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -1064,6 +1065,8 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/wss v1.0.199 h1:hMBLtiJ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/wss v1.0.199/go.mod h1:nnY91/H3j/Gu7V/oCA6Zeg8T5D3q36EUdBh4EjmHwqY= github.com/tencentyun/cos-go-sdk-v5 v0.7.42-0.20230629101357-7edd77448a0f h1:yTMDoBvFuXjZat10d98DIKbPnN9FQG+drt1SbNfMW5U= github.com/tencentyun/cos-go-sdk-v5 v0.7.42-0.20230629101357-7edd77448a0f/go.mod h1:LUFnaqRmGk6pEHOaRmdn2dCZR2j0cSsM5xowWFPTPao= +github.com/tencentyun/cos-go-sdk-v5 v0.7.58 h1:YoZTqaRUcv75P4GSvyam93aEtdgOZWGUJWzXzyCV5EM= +github.com/tencentyun/cos-go-sdk-v5 v0.7.58/go.mod h1:8+hG+mQMuRP/OIS9d83syAvXvrMj9HhkND6Q1fLghw0= github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA= github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= diff --git a/tencentcloud/provider.go b/tencentcloud/provider.go index eaa04bdb48..51a229172b 100644 --- a/tencentcloud/provider.go +++ b/tencentcloud/provider.go @@ -511,6 +511,7 @@ func Provider() *schema.Provider { "tencentcloud_cos_batchs": cos.DataSourceTencentCloudCosBatchs(), "tencentcloud_cos_bucket_inventorys": cos.DataSourceTencentCloudCosBucketInventorys(), "tencentcloud_cos_bucket_multipart_uploads": cos.DataSourceTencentCloudCosBucketMultipartUploads(), + "tencentcloud_cos_object_signed_url": cos.DataSourceTencentCloudCosObjectSignedUrl(), "tencentcloud_cfs_file_systems": cfs.DataSourceTencentCloudCfsFileSystems(), "tencentcloud_cfs_access_groups": cfs.DataSourceTencentCloudCfsAccessGroups(), "tencentcloud_cfs_access_rules": cfs.DataSourceTencentCloudCfsAccessRules(), diff --git a/tencentcloud/provider.md b/tencentcloud/provider.md index f4330e30b0..a60eb1e0f5 100644 --- a/tencentcloud/provider.md +++ b/tencentcloud/provider.md @@ -412,6 +412,7 @@ Cloud Object Storage(COS) tencentcloud_cos_batchs tencentcloud_cos_bucket_inventorys tencentcloud_cos_bucket_multipart_uploads + tencentcloud_cos_object_signed_url Resource tencentcloud_cos_bucket diff --git a/tencentcloud/services/cos/data_source_tc_cos_object_signed_url.go b/tencentcloud/services/cos/data_source_tc_cos_object_signed_url.go new file mode 100644 index 0000000000..0d02340444 --- /dev/null +++ b/tencentcloud/services/cos/data_source_tc_cos_object_signed_url.go @@ -0,0 +1,126 @@ +package cos + +import ( + "context" + "time" + + tccommon "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/common" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/tencentyun/cos-go-sdk-v5" + + "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/internal/helper" +) + +func DataSourceTencentCloudCosObjectSignedUrl() *schema.Resource { + return &schema.Resource{ + Read: DataSourceTencentCloudCosObjectSignedUrlRead, + + Schema: map[string]*schema.Schema{ + "bucket": { + Type: schema.TypeString, + Required: true, + Description: "Name of the bucket.", + }, + "path": { + Type: schema.TypeString, + Required: true, + Description: "The full path to the object inside the bucket.", + }, + "method": { + Type: schema.TypeString, + Optional: true, + Default: "GET", + ValidateFunc: validation.StringInSlice([]string{"GET", "PUT"}, true), + Description: "Method, GET or PUT. Default value is GET.", + }, + "duration": { + Type: schema.TypeString, + Optional: true, + Default: "1m", + Description: "Duration of signed url. Default value is 1m.", + }, + "headers": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Request headers.", + }, + "queries": { + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Description: "Request query parameters.", + }, + "signed_url": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Signed URL.", + }, + "result_output_file": { + Type: schema.TypeString, + Optional: true, + Description: "Used to save results.", + }, + }, + } +} + +func DataSourceTencentCloudCosObjectSignedUrlRead(d *schema.ResourceData, meta interface{}) error { + defer tccommon.LogElapsed("data_source.tencentcloud_cos_object_signed_url.read")() + + logId := tccommon.GetLogId(tccommon.ContextNil) + ctx := context.WithValue(context.TODO(), tccommon.LogIdKey, logId) + + bucket := d.Get("bucket").(string) + path := d.Get("path").(string) + method := "GET" + durationString := "1m" + opt := &cos.PresignedURLOptions{} + signHost := true + + if v, ok := d.GetOk("method"); ok { + method = v.(string) + } + + if v, ok := d.GetOk("duration"); ok { + durationString = v.(string) + } + + duration, err := time.ParseDuration(durationString) + if err != nil { + return err + } + + if v, ok := d.GetOk("headers"); ok { + for key, value := range v.(map[string]string) { + opt.Header.Set(key, value) + } + } + + if v, ok := d.GetOk("queries"); ok { + for key, value := range v.(map[string]string) { + opt.Query.Set(key, value) + } + } + + result, err := meta.(tccommon.ProviderMeta).GetAPIV3Conn().UseTencentCosClient(bucket).Object.GetPresignedURL2(ctx, method, path, duration, opt, signHost) + if err != nil { + return err + } + + signedUrl := result.String() + + d.SetId(helper.DataResourceIdHash(path)) + _ = d.Set("signed_url", signedUrl) + output, ok := d.GetOk("result_output_file") + if ok && output.(string) != "" { + if err := tccommon.WriteToFile(output.(string), signedUrl); err != nil { + return err + } + } + + return nil +} diff --git a/tencentcloud/services/cos/data_source_tc_cos_object_signed_url.md b/tencentcloud/services/cos/data_source_tc_cos_object_signed_url.md new file mode 100644 index 0000000000..4ab58303d7 --- /dev/null +++ b/tencentcloud/services/cos/data_source_tc_cos_object_signed_url.md @@ -0,0 +1,10 @@ +Use this data source to query the signed url of the COS object. + +Example Usage + +```hcl +data "tencentcloud_cos_object_signed_url" "cos_object_signed_url" { + bucket = "xxxxxx" + path = "path/to/file" +} +``` diff --git a/tencentcloud/services/cos/data_source_tc_cos_object_signed_url_test.go b/tencentcloud/services/cos/data_source_tc_cos_object_signed_url_test.go new file mode 100644 index 0000000000..d27813b99e --- /dev/null +++ b/tencentcloud/services/cos/data_source_tc_cos_object_signed_url_test.go @@ -0,0 +1,41 @@ +package cos_test + +import ( + "testing" + + tcacctest "github.com/tencentcloudstack/terraform-provider-tencentcloud/tencentcloud/acctest" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccTencentCloudCosObjectSignedUrlDataSource_basic(t *testing.T) { + t.Parallel() + resource.Test(t, resource.TestCase{ + PreCheck: func() { + tcacctest.AccPreCheck(t) + }, + Providers: tcacctest.AccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCosObjectSignedUrlDataSource, + Check: resource.ComposeTestCheckFunc( + tcacctest.AccCheckTencentCloudDataSourceID("data.tencentcloud_cos_object_signed_url.cos_object_signed_url"), + resource.TestCheckResourceAttrSet("data.tencentcloud_cos_object_signed_url.cos_object_signed_url", "signed_url"), + ), + }, + }, + }) +} + +const testAccCosObjectSignedUrlDataSource = ` +data "tencentcloud_cos_object_signed_url" "cos_object_signed_url" { + bucket = "keep-test-1308919341" + path = "path/to/file" + headers = { + Content-Type = "text/plain" + } + queries = { + prefix = "xxx" + } +} +` diff --git a/tencentcloud/services/cos/resource_tc_cos_bucket.go b/tencentcloud/services/cos/resource_tc_cos_bucket.go index 1b6764c133..bd2c89af85 100644 --- a/tencentcloud/services/cos/resource_tc_cos_bucket.go +++ b/tencentcloud/services/cos/resource_tc_cos_bucket.go @@ -1582,11 +1582,6 @@ func resourceTencentCloudCosBucketOriginPullUpdate(ctx context.Context, service CopyOriginData: true, HttpHeader: &cos.BucketOriginHttpHeader{}, }, - OriginInfo: &cos.BucketOriginInfo{ - FileInfo: &cos.BucketOriginFileInfo{ - PrefixDirective: false, - }, - }, } ) @@ -1606,7 +1601,7 @@ func resourceTencentCloudCosBucketOriginPullUpdate(ctx context.Context, service item.OriginParameter.Protocol = v.(string) } if v, ok := dMap["host"]; ok { - item.OriginInfo.HostInfo = v.(string) + item.OriginInfo.HostInfo.HostName = v.(string) } if v, ok := dMap["follow_query_string"]; ok { item.OriginParameter.FollowQueryString = v.(bool) @@ -1619,17 +1614,11 @@ func resourceTencentCloudCosBucketOriginPullUpdate(ctx context.Context, service //} if v, ok := dMap["redirect_prefix"]; ok { value := v.(string) - if value != "" { - item.OriginInfo.FileInfo.PrefixDirective = true - } - item.OriginInfo.FileInfo.Prefix = value + item.OriginInfo.FileInfo.PrefixConfiguration.Prefix = value } if v, ok := dMap["redirect_suffix"]; ok { value := v.(string) - if value != "" { - item.OriginInfo.FileInfo.PrefixDirective = true - } - item.OriginInfo.FileInfo.Suffix = value + item.OriginInfo.FileInfo.SuffixConfiguration.Suffix = value } if v, ok := dMap["custom_http_headers"]; ok { var customHeaders []cos.OriginHttpHeader diff --git a/tencentcloud/services/cos/service_tencentcloud_cos.go b/tencentcloud/services/cos/service_tencentcloud_cos.go index dd8cacc9ec..c07a316065 100644 --- a/tencentcloud/services/cos/service_tencentcloud_cos.go +++ b/tencentcloud/services/cos/service_tencentcloud_cos.go @@ -1272,7 +1272,7 @@ func (me *CosService) GetBucketPullOrigin(ctx context.Context, bucket string) (r for _, rule := range originConfig.Rule { item := make(map[string]interface{}) item["priority"] = helper.Int(rule.RulePriority) - item["host"] = helper.String(rule.OriginInfo.HostInfo) + item["host"] = helper.String(rule.OriginInfo.HostInfo.HostName) if rule.OriginCondition != nil { item["prefix"] = helper.String(rule.OriginCondition.Prefix) @@ -1311,7 +1311,7 @@ func (me *CosService) GetBucketPullOrigin(ctx context.Context, bucket string) (r } if rule.OriginInfo.FileInfo != nil { - item["host"] = helper.String(rule.OriginInfo.HostInfo) + item["host"] = helper.String(rule.OriginInfo.HostInfo.HostName) //item["redirect_prefix"] = helper.String(rule.OriginInfo.FileInfo.Prefix) //item["redirect_suffix"] = helper.String(rule.OriginInfo.FileInfo.Suffix) } diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/.gitignore b/vendor/github.com/tencentyun/cos-go-sdk-v5/.gitignore index 9b0647f96e..5dbdb7424c 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/.gitignore +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/.gitignore @@ -29,5 +29,11 @@ cover.html cover.out covprofile coverage.html -example/CI/media_process/media_process +example/CI/media_process/test* +example/CI/workflow_and_job/test* +example/CI/metainsight/test* +example/CI/ai_recognition/test* +example/CI/image_process/test* +example/CI/doc_preview/test* +example/CI/content_auditing/test* .vscode diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/CHANGELOG.md b/vendor/github.com/tencentyun/cos-go-sdk-v5/CHANGELOG.md index 35cb1ad14e..7b7e1f1eb6 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/CHANGELOG.md +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/CHANGELOG.md @@ -7,6 +7,375 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +## [v0.7.57](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.56...v0.7.57) - 2024-11-04 + +COS ServiceURL和BatchURL检验兼容Bucket格式,GetPresignedURL3兼容path全urlencode + +### Merged + +- 更新GetPresignedURL3, 兼容trpc-go url格式 [`#284`](https://github.com/tencentyun/cos-go-sdk-v5/pull/284) + +### Commits + +- Updated CHANGELOG.md [`43fbd84`](https://github.com/tencentyun/cos-go-sdk-v5/commit/43fbd84ff1e729589191d1894fdf660ebb910503) + +## [v0.7.56](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.55...v0.7.56) - 2024-11-01 + +1、COS 3xx默认不跟随,COS域名会检验BaseURL格式。 +2、CI 新增边转边播多任务创建接口,播放列表任务批量接口 + +### Merged + +- Feature jojoliang b8918773 [`#283`](https://github.com/tencentyun/cos-go-sdk-v5/pull/283) +- Feature jojoliang 1a086920 [`#282`](https://github.com/tencentyun/cos-go-sdk-v5/pull/282) + +### Commits + +- 默认不跟随,检验URL [`2a003a6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2a003a69bd7c0f5321384b828f69a70b60fa78fe) +- 支持边转边播播放列表任务批量接口 [`1f64e94`](https://github.com/tencentyun/cos-go-sdk-v5/commit/1f64e947b9d79f428e5f56062e7270cef09b8aac) +- 新增边转边播多任务创建接口 [`b335033`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b335033a313cbc736e4f5102895d6bfa3c2979af) +- Updated CHANGELOG.md [`08b4159`](https://github.com/tencentyun/cos-go-sdk-v5/commit/08b415932672abe067aee56666e614183c7612db) +- fix ci test [`9677c2b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9677c2b34dcb41f57313abcec1b399cb89187730) + +## [v0.7.55](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.54...v0.7.55) - 2024-09-12 + +1、COS增加DeleteReferer方法,PutSymlink内部对SymlinkTarget做urlencode,更新demo规范,更加GetMeta接口和intelligent-tiering v2接口。 +2、CI 支持多合一ai识别接口,metainsight增加mode字段,更新VideoTargetRec,支持盲水印3.0和极智压缩,支持kafka回调通知能力,解决jwt库版本安全问题。 + +### Merged + +- Feature jojoliang 2e155105 [`#280`](https://github.com/tencentyun/cos-go-sdk-v5/pull/280) +- Feature jojoliang 0aa53fe3 [`#279`](https://github.com/tencentyun/cos-go-sdk-v5/pull/279) +- Feature jojoliang 8dfdf213 [`#278`](https://github.com/tencentyun/cos-go-sdk-v5/pull/278) +- Feature jojoliang 3f696cf3 [`#277`](https://github.com/tencentyun/cos-go-sdk-v5/pull/277) +- fix FileProcessJobsDetail [`#276`](https://github.com/tencentyun/cos-go-sdk-v5/pull/276) +- Feature jojoliang b4436de4 [`#275`](https://github.com/tencentyun/cos-go-sdk-v5/pull/275) +- 增加domain header [`#274`](https://github.com/tencentyun/cos-go-sdk-v5/pull/274) +- 更新 demo [`#273`](https://github.com/tencentyun/cos-go-sdk-v5/pull/273) +- update bucket referer [`#271`](https://github.com/tencentyun/cos-go-sdk-v5/pull/271) + +### Commits + +- 增加GetMeta接口,增加intelligent-tiering v2接口 [`b3a9f08`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b3a9f08a223c83ebf985ddf816895ccb014fe217) +- 更新demo [`8ce4837`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8ce483740aadf37b0bd05a3681e8bcb88a52298f) +- 支持盲水印3.0和极智压缩 [`ae68c1f`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ae68c1f8d835e5aa6e2773c1811f340634016481) +- 支持多合一ai识别接口 [`ce30d02`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ce30d02fc9f5cf2ccd2202e7c125ef5e186df1a8) +- 支持kafka回调通知能力 [`debfcd1`](https://github.com/tencentyun/cos-go-sdk-v5/commit/debfcd14317f4ed401794aa4600d59ae9a0bdbf2) +- 解决jwt库的版本安全问题 [`26d3550`](https://github.com/tencentyun/cos-go-sdk-v5/commit/26d3550b9c425e2f3ff3a019d8d5f2906f2e2bfe) +- update VideoTargetRec [`8670f9c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8670f9cbfaf628e28b8ab42d82f8cb51f28b1045) +- update presignedurl demo [`4257d33`](https://github.com/tencentyun/cos-go-sdk-v5/commit/4257d33afb6b106145d2ab1b7443b180cc516355) +- 修复demo中问题 [`41bf4a3`](https://github.com/tencentyun/cos-go-sdk-v5/commit/41bf4a34ed41bd1ae97afa63f6ef2491829b282d) +- Updated CHANGELOG.md [`6468769`](https://github.com/tencentyun/cos-go-sdk-v5/commit/64687693995512ca14bfd8796596032937fdbe7e) +- update go.mod [`74f414d`](https://github.com/tencentyun/cos-go-sdk-v5/commit/74f414d5126bb8d25d349288ae260ac2e1551055) +- metainsight add mode [`b002c8b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b002c8b0ff1e81fdfacf9e7e5d80e8133f02d28e) +- 支持极智压缩状态参数 [`38b6730`](https://github.com/tencentyun/cos-go-sdk-v5/commit/38b6730e503ac6aa826dab2a3cc52cc3064f3b0b) +- x-cos-symlink-target内部做urlencode [`66ce357`](https://github.com/tencentyun/cos-go-sdk-v5/commit/66ce3574c92d8d649d51d055e72edc4b44320d36) + +## [v0.7.54](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.53...v0.7.54) - 2024-07-11 + +1、COS download方法允许分块可以超过10000, +2、增加sts签名方式并自动更新临时密钥 + +### Merged + +- download分块可以超过10000, 增加sts签名方式 [`#270`](https://github.com/tencentyun/cos-go-sdk-v5/pull/270) + +### Commits + +- Updated CHANGELOG.md [`7b3b630`](https://github.com/tencentyun/cos-go-sdk-v5/commit/7b3b630a1d9fab65f66804aec8f3b2c43893c06b) + +## [v0.7.53](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.52...v0.7.53) - 2024-07-11 + +1、COS upload接口透传参数到compelete,upload part支持上传0字节,设置软链接x-cos-symlink-target头部做urlencode。 +2、CI 增加人像抠图接口。 + +### Merged + +- x-cos-symlink-target内部做urlencode [`#269`](https://github.com/tencentyun/cos-go-sdk-v5/pull/269) +- Feature jojoliang 9ca80bb5 [`#268`](https://github.com/tencentyun/cos-go-sdk-v5/pull/268) +- upload part 支持上传0字节 [`#267`](https://github.com/tencentyun/cos-go-sdk-v5/pull/267) +- Feature jojoliang c9b129da [`#266`](https://github.com/tencentyun/cos-go-sdk-v5/pull/266) + +### Commits + +- 支持人像抠图和通用抠图接口 [`0f45101`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0f45101e8f9af144ebc77bebb512aa26ff4a07ad) +- sdk update [`055592b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/055592be590c940af040d35c3f4a30b8791daeea) +- Updated CHANGELOG.md [`3e334a4`](https://github.com/tencentyun/cos-go-sdk-v5/commit/3e334a46a4f30228ac3667fe14ce6260c13e1001) +- Updated CHANGELOG.md [`f196bf7`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f196bf7747485266dab094f5c69a22b0d9008012) +- upload接口透传参数到complete [`9906bd9`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9906bd932c94e3dec6cabb105e936f397b63fd79) +- update ZipPreview test [`0f07c52`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0f07c529b834448079ace3a8ceb629dc9b129daa) + +## [v0.7.52](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.51...v0.7.52) - 2024-07-01 + +1、更新lifecycle、policy、intelligent参数 +2、增加重试标识,Upload传递自定义头部 + +### Merged + +- update lifecycle,policy,intelligent params, 增加重试标识,增加upload时自定义参数传递 [`#264`](https://github.com/tencentyun/cos-go-sdk-v5/pull/264) + +### Commits + +- Updated CHANGELOG.md [`55bbddb`](https://github.com/tencentyun/cos-go-sdk-v5/commit/55bbddbd4b891a108dd376d55a70f8a0681db683) + +## [v0.7.51](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.50...v0.7.51) - 2024-06-24 + +1、CI 支持 meta insight +2、abort multipart 校验key + +### Merged + +- 检查abort multi的路径 [`#262`](https://github.com/tencentyun/cos-go-sdk-v5/pull/262) +- Feature jojoliang e16e7c98 [`#261`](https://github.com/tencentyun/cos-go-sdk-v5/pull/261) + +### Commits + +- 支持metainsight [`cbd9ea9`](https://github.com/tencentyun/cos-go-sdk-v5/commit/cbd9ea9c5c3811d39fa8157d40836e9747cb011d) +- 忽略测试文件 [`119d6ff`](https://github.com/tencentyun/cos-go-sdk-v5/commit/119d6ff6b73440dff6aa061270e16c00cad1a1bd) +- 支持metainsight单测 [`a2547fc`](https://github.com/tencentyun/cos-go-sdk-v5/commit/a2547fc092227ce413e64a898dbaf0da9aa8cd33) +- metainsight1.1 sdk [`2bd433a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2bd433a7ab37427f8a548601f9358180ee8562ab) +- 优化边转边播示例 [`c5f0e59`](https://github.com/tencentyun/cos-go-sdk-v5/commit/c5f0e59566799a4b68f1b9142bf5dffb7cc529b3) +- 新增图片搜索和人脸搜索单测 [`0f9a4e8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0f9a4e83213cf0b5b875699dc394a802d76ca768) +- Updated CHANGELOG.md [`f585425`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f585425752d4d1c44b4a657253e9d0f7b63136c4) + +## [v0.7.50](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.49...v0.7.50) - 2024-06-12 + +COS 预签名URL不对/做编码 + +### Merged + +- 预签名URL不编码 [`#259`](https://github.com/tencentyun/cos-go-sdk-v5/pull/259) + +### Commits + +- 预签名URL不编码/ [`99de629`](https://github.com/tencentyun/cos-go-sdk-v5/commit/99de62963ec569abbabcf37384912690b77e2846) +- Updated CHANGELOG.md [`d09d568`](https://github.com/tencentyun/cos-go-sdk-v5/commit/d09d568e871486662bbee1c36a6cff96e88f458a) + +## [v0.7.49](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.48...v0.7.49) - 2024-06-04 + +1、修复MultiCopy分块是sourceurl编码 +2、CI 审核14.3 SDK,支持长短边开关 + +### Merged + +- multicopy source url编码 [`#257`](https://github.com/tencentyun/cos-go-sdk-v5/pull/257) +- Feature jojoliang b462cc0f [`#256`](https://github.com/tencentyun/cos-go-sdk-v5/pull/256) +- 审核14.3 sdk [`#255`](https://github.com/tencentyun/cos-go-sdk-v5/pull/255) + +### Commits + +- Updated CHANGELOG.md [`bd0557e`](https://github.com/tencentyun/cos-go-sdk-v5/commit/bd0557e60c3a0de768996d5ad6d3ac78db581730) +- 支持长短边开关 [`531dec3`](https://github.com/tencentyun/cos-go-sdk-v5/commit/531dec3dd22e719170ab4eab13084f6f75cd8373) + +## [v0.7.48](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.47...v0.7.48) - 2024-05-22 + +1、增加Download接口进度,修复copy接口sourceURL存在VersionId问题,增加历史版本恢复demo。简单上传允许5GB文件,更新MultiCopy 5GB文件采用Copy接口。 +2、CI DocPreviewHTMLOptions 增加weboffice_url和tokenuid参数,支持开通媒体桶接口,支持视频标签多模态接口,支持边转边播,新增crf参数。 +3、增加COS和CI的单元测试,当前覆盖率接近91%。 + +### Merged + +- Feature jojoliang 2dababd3 [`#254`](https://github.com/tencentyun/cos-go-sdk-v5/pull/254) +- Feature jojoliang 5a15001b [`#252`](https://github.com/tencentyun/cos-go-sdk-v5/pull/252) +- Feature jojoliang c307996b [`#251`](https://github.com/tencentyun/cos-go-sdk-v5/pull/251) +- Feature jojoliang 74fd0658 [`#250`](https://github.com/tencentyun/cos-go-sdk-v5/pull/250) +- Feature jojoliang 85b92bed [`#248`](https://github.com/tencentyun/cos-go-sdk-v5/pull/248) +- Feature jojoliang 5e79ea1b [`#246`](https://github.com/tencentyun/cos-go-sdk-v5/pull/246) +- Feature jojoliang 81564773 [`#244`](https://github.com/tencentyun/cos-go-sdk-v5/pull/244) +- Feature jojoliang b21eefa1 [`#242`](https://github.com/tencentyun/cos-go-sdk-v5/pull/242) +- Feature jojoliang e76fab9d [`#241`](https://github.com/tencentyun/cos-go-sdk-v5/pull/241) +- Feature jojoliang 1e58093b [`#240`](https://github.com/tencentyun/cos-go-sdk-v5/pull/240) +- DocPreviewHTMLOptions 增加weboffice_url和tokenuid参数 [`#239`](https://github.com/tencentyun/cos-go-sdk-v5/pull/239) + +### Commits + +- 下载校验key,增加ut [`7af5453`](https://github.com/tencentyun/cos-go-sdk-v5/commit/7af54534c8c380149ac7dedb0709a5f85b92bed1) +- 支持边转边播 [`8e69739`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8e69739607592f4c364e6947eeea1ff3e3bad7c4) +- 新增单测用例 [`241cd5a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/241cd5a3d80d294a098789d365a9b26d3e393bcb) +- 新增单测 [`e3785be`](https://github.com/tencentyun/cos-go-sdk-v5/commit/e3785be3f63959057c782a67bc3bfadbb689c212) +- 增加历史版本恢复demo [`413e910`](https://github.com/tencentyun/cos-go-sdk-v5/commit/413e910d57b30e6efdc122b28ebcaf65e79ea1b9) +- 修复copy sourceURL存在versionId问题,增加Download进度,默认不切换 [`9265a98`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9265a98076f849905e5590c6921d29432f1f32b7) +- 新增方法 [`9762204`](https://github.com/tencentyun/cos-go-sdk-v5/commit/97622042d1aa5beef3d2c3ac42aecf8e6d3b1e67) +- 完善单元测试 [`0411781`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0411781fc635d522ef7acc8864c5e9bee8730764) +- 支持开通媒体桶接口 [`54de4fd`](https://github.com/tencentyun/cos-go-sdk-v5/commit/54de4fd0b462620d0e3ceb6ffdb65e2db76806f3) +- cdn场景如何生成Url [`a209897`](https://github.com/tencentyun/cos-go-sdk-v5/commit/a209897a36eda6ebc75dfa736be629fe4c7e0552) +- Updated CHANGELOG.md [`2f05c98`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2f05c9814f68f14af9edc3e124286348709d5496) +- 支持视频标签多模态接口 [`0268b78`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0268b78d0bfd5914b2a32115f60eb0de4a308ee8) +- demo边转边播场景ci-process参数 [`fddf7c4`](https://github.com/tencentyun/cos-go-sdk-v5/commit/fddf7c41a80f4817a1e4080945b132851658c128) +- 简单上传允许上传刚好5GB文件 [`9992cbb`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9992cbb1853c2b260522d4f078cd6372dababd3f) +- 更新MultiCopy [`29884e8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/29884e8626c2af72b51a3df0b2c51d0d888fbbcb) +- 新增crf参数 [`24cb28b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/24cb28b9b0de52d3b0f3597ed587c015161cc202) +- 直接拼接参数 [`ace1c70`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ace1c707150fdda400bd0705d7902bc26a1406a7) + +## [v0.7.47](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.46...v0.7.47) - 2024-03-01 + +1、更新预签名做urlencode,添加ACL常量,兼容key非法时分块上传返回xml解析失败。 +2、GetService增加地域过滤,增加BucketType +2、CI支持Dataset接口,FileMetaIndex接口 + +### Merged + +- Feature jojoliang 5a030823 [`#236`](https://github.com/tencentyun/cos-go-sdk-v5/pull/236) +- add ACL enum demo [`#235`](https://github.com/tencentyun/cos-go-sdk-v5/pull/235) +- 更新ACL常量,兼容key非法时分块上传返回xml解析失败 [`#234`](https://github.com/tencentyun/cos-go-sdk-v5/pull/234) +- update GetPresignedURL [`#232`](https://github.com/tencentyun/cos-go-sdk-v5/pull/232) + +### Commits + +- 支持9个接口 [`623c33c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/623c33c18d441fc6210fe692d08f739d0c7d7f32) +- 支持dataindex的14个接口 [`ddf959a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ddf959ae97bc00c6f9e434e02bdbb450daeb2753) +- Updated CHANGELOG.md [`92a2e31`](https://github.com/tencentyun/cos-go-sdk-v5/commit/92a2e311df0af3cfb9b080d80d6dd64f4fa94a10) +- format 文件 [`f709661`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f70966132a774bb3a389d1ef30b2602dfc767141) +- 忽略桶信息 [`ed8db26`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ed8db265e7796532764fc7cf316b5e75ab9fc610) +- getservice增加地域过滤,增加BucketType [`9b29d2f`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9b29d2f72a0ce5b323f1ebb6c4864ca753bf3433) +- 增加忽略文件 [`4363cb6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/4363cb6aaff05646df6db9a0755263877f436ee4) + +## [v0.7.46](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.45...v0.7.46) - 2024-01-09 + +1、COS 增加对象软链接,对象操作增加重试,更新cors,更新GetPresignedURL。 +2、CI 更新文档对比、商品抠图、充拼接接口、ai1.4补充、pic-operations算到签名里。 + +### Merged + +- 更新预签名 [`#230`](https://github.com/tencentyun/cos-go-sdk-v5/pull/230) +- update bucket cors, add x-cos-tagging in putbucket, update Presignurl [`#229`](https://github.com/tencentyun/cos-go-sdk-v5/pull/229) +- update cos-website [`#228`](https://github.com/tencentyun/cos-go-sdk-v5/pull/228) +- Feature jojoliang 07c6039e [`#227`](https://github.com/tencentyun/cos-go-sdk-v5/pull/227) +- update domain [`#226`](https://github.com/tencentyun/cos-go-sdk-v5/pull/226) +- Feature lilang 49f346d6 [`#224`](https://github.com/tencentyun/cos-go-sdk-v5/pull/224) +- Feature jojoliang 4df53093 [`#223`](https://github.com/tencentyun/cos-go-sdk-v5/pull/223) +- Feature lilang d38c66dd [`#222`](https://github.com/tencentyun/cos-go-sdk-v5/pull/222) +- Feature lilang 4cee3f5c [`#220`](https://github.com/tencentyun/cos-go-sdk-v5/pull/220) +- 填充拼接接口新增模式和参考索引参数 [`#218`](https://github.com/tencentyun/cos-go-sdk-v5/pull/218) +- add object symlink [`#217`](https://github.com/tencentyun/cos-go-sdk-v5/pull/217) +- Feature jojoliang 2a0e39c7 [`#216`](https://github.com/tencentyun/cos-go-sdk-v5/pull/216) +- Feature lilang 1c333bc2 [`#215`](https://github.com/tencentyun/cos-go-sdk-v5/pull/215) +- 修改demo [`#213`](https://github.com/tencentyun/cos-go-sdk-v5/pull/213) + +### Commits + +- add retry for put object [`b037b1d`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b037b1d3efc0b10f9d7ba56f31667b313f931572) +- ai1.4补充 [`6c34926`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6c34926a6bc1e35ce26e50de37ef88d6227679d2) +- CI17 [`0d8107c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0d8107c396f3ed7fb99178ff3df4c5594e3a42e7) +- 文档对比 [`caaca46`](https://github.com/tencentyun/cos-go-sdk-v5/commit/caaca46dbc273207cc3a9ccd912e40400b9b794a) +- 支持查询播放key [`6c43b9f`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6c43b9fd45793ea67d3c3f9c0eedc8c5f9195ac7) +- update bucket cors, add x-cos-tagging in putbucket, update GetPresignedURL [`35b83ed`](https://github.com/tencentyun/cos-go-sdk-v5/commit/35b83ed71e7879f647779aac3233409662e13188) +- 添加方法 [`8b6c807`](https://github.com/tencentyun/cos-go-sdk-v5/commit/8b6c8070c61915c8fb1d7b9b08b6011b1c178eb6) +- update [`b110e20`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b110e2021fa245b614ce844299e519b07c6039eb) +- Updated CHANGELOG.md [`500a8f6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/500a8f60f324e44ce67f4bac4c81cd5c6e4d6528) +- 支持xml [`5c51c3a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/5c51c3ae8866835a74121eb3a96bad21c333bc22) +- update retry [`2c500a8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2c500a86ed9b1f5997e589824cd72b11544065be) +- appid隐藏 [`2a08bcb`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2a08bcb5fb86ef9a0b80a693a5f1bf662df3e8ae) +- pic-operations算到签名里 [`cd1d04e`](https://github.com/tencentyun/cos-go-sdk-v5/commit/cd1d04e326cceda488ee93172072ae144f601de8) +- 商品抠图新增detect-url参数 [`776c1b2`](https://github.com/tencentyun/cos-go-sdk-v5/commit/776c1b2c85860c676173f3901cb10d08be3f985a) + +## [v0.7.45](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.44...v0.7.45) - 2023-10-18 + +更新bucket origin接口,更新Copy接口。 + +### Merged + +- fix copy object, update bucket origin [`#212`](https://github.com/tencentyun/cos-go-sdk-v5/pull/212) +- Feature lilang 8d637ca2 [`#211`](https://github.com/tencentyun/cos-go-sdk-v5/pull/211) + +### Commits + +- generate_token demo [`0fc7f23`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0fc7f231da7096341a0a71e8bff57894c206c6b5) +- Updated CHANGELOG.md [`2d08098`](https://github.com/tencentyun/cos-go-sdk-v5/commit/2d08098de11e75468b20925cf12e7619aa9dfcb1) +- generate_token [`66a66a1`](https://github.com/tencentyun/cos-go-sdk-v5/commit/66a66a1d183d3c6f2e804dd0cf43ac1eed444bab) + +## [v0.7.44](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.43...v0.7.44) - 2023-10-09 + +1、增加GetPresignedURL接口。 +2、CI 更新文件处理参数、媒体参数,增加AI检测接口,增加黑产检查同步接口。 + +### Merged + +- add getPresignedURL2 [`#210`](https://github.com/tencentyun/cos-go-sdk-v5/pull/210) +- Feature jojoliang 3259afb9 [`#208`](https://github.com/tencentyun/cos-go-sdk-v5/pull/208) + +### Commits + +- 添加方法 [`69f446a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/69f446a7a0009b5ac9e0f470ff55eef544d3e907) +- 参数补充 [`b598e3c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b598e3c860e2574c9c2474c3d31185a40cd7d860) +- 黑产检查同步接口 [`d3e671c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/d3e671c1360d24edc34ce7fa209bf11d8b5f09d0) +- ai1.4 [`697a287`](https://github.com/tencentyun/cos-go-sdk-v5/commit/697a287ee214e48b560cf58eb49d91bc808397e3) +- 媒体参数补充 [`9f2c7d7`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9f2c7d77301e91e9400a5bb4d92003a76a5fa775) +- 文件处理1.2 [`1a47db9`](https://github.com/tencentyun/cos-go-sdk-v5/commit/1a47db9ea5e44258b67c7eb42e7df3f7dc703c05) +- Updated CHANGELOG.md [`ceda434`](https://github.com/tencentyun/cos-go-sdk-v5/commit/ceda43486b032a0a2d88afb28dc1adc3a0af7321) + +## [v0.7.43](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.42...v0.7.43) - 2023-09-05 + +1、增加客户端加密KMS请求重试。 +2、增加对象锁定功能,更新静态网站字段,更新ACL允许header和body同时设置。 +3、CI 更新请求参数。 + +### Merged + +- update bucket acl [`#206`](https://github.com/tencentyun/cos-go-sdk-v5/pull/206) +- update bucket website [`#205`](https://github.com/tencentyun/cos-go-sdk-v5/pull/205) +- Feature jojoliang 1038d35f [`#204`](https://github.com/tencentyun/cos-go-sdk-v5/pull/204) +- Feature jojoliang bcf65425 [`#203`](https://github.com/tencentyun/cos-go-sdk-v5/pull/203) + +### Commits + +- 参数补充 [`e7ef3e5`](https://github.com/tencentyun/cos-go-sdk-v5/commit/e7ef3e55e8e9735594681f2415dfeddc14547751) +- crypto add kms request retry [`9b4c409`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9b4c409f7663c5a12dcd4984ef09fc8c2b2f69e0) +- add Put ObjectRetention [`13ccff3`](https://github.com/tencentyun/cos-go-sdk-v5/commit/13ccff3ee377461da10b5ef4abb1e604ce5066c4) +- Updated CHANGELOG.md [`0ef69db`](https://github.com/tencentyun/cos-go-sdk-v5/commit/0ef69dbdef58d337733fa8951972eabb90954a0a) +- 添加参数 [`05212d8`](https://github.com/tencentyun/cos-go-sdk-v5/commit/05212d89d32455c87c7af85e791a421c2dd9d634) +- 添加字段 [`b74737f`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b74737fa7bb5dfb00953d5eb4570a4dd576c9209) +- 删除queue id [`f019b7c`](https://github.com/tencentyun/cos-go-sdk-v5/commit/f019b7c95d47a5f9465d309d43b7ba55a2c25422) + +## [v0.7.42](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.41...v0.7.42) - 2023-06-29 + +1、增加UT测试,更新tencentcloud-sdk-go 版本到 v1.0.563。 +2、增加PostInventory接口,增加object lock,增加DeleteBatchJob。 +3、CI 文件处理接口、文档浏览、视频质量打分任务、审核等参数变更。 +4、CI支持倍速转码、AI人体检测接口、海报合成任务、地图拼接、内容识别、闲时转码标记位等。 + +### Merged + +- Feature jojoliang 6a39e426 [`#201`](https://github.com/tencentyun/cos-go-sdk-v5/pull/201) +- Feature jojoliang 985bbfa3 [`#200`](https://github.com/tencentyun/cos-go-sdk-v5/pull/200) +- Feature jojoliang 51a2f385 [`#199`](https://github.com/tencentyun/cos-go-sdk-v5/pull/199) +- Feature lilang d8d6b147 [`#198`](https://github.com/tencentyun/cos-go-sdk-v5/pull/198) +- update getservice [`#197`](https://github.com/tencentyun/cos-go-sdk-v5/pull/197) +- Feature jojoliang d0d7edf5 [`#195`](https://github.com/tencentyun/cos-go-sdk-v5/pull/195) +- add GetService params [`#194`](https://github.com/tencentyun/cos-go-sdk-v5/pull/194) +- add restore versionid [`#193`](https://github.com/tencentyun/cos-go-sdk-v5/pull/193) +- add object lock [`#192`](https://github.com/tencentyun/cos-go-sdk-v5/pull/192) +- Feature jojoliang 64cbd1f5 [`#191`](https://github.com/tencentyun/cos-go-sdk-v5/pull/191) +- 支持原图下载 [`#189`](https://github.com/tencentyun/cos-go-sdk-v5/pull/189) +- Feature jojoliang 3e3dda77 [`#188`](https://github.com/tencentyun/cos-go-sdk-v5/pull/188) +- Feature jojoliang 3762ef4f [`#187`](https://github.com/tencentyun/cos-go-sdk-v5/pull/187) +- Feature jojoliang aa6c7cad [`#185`](https://github.com/tencentyun/cos-go-sdk-v5/pull/185) +- update ut [`#184`](https://github.com/tencentyun/cos-go-sdk-v5/pull/184) +- update ut [`#183`](https://github.com/tencentyun/cos-go-sdk-v5/pull/183) + +### Commits + +- demo优化 [`4d341bb`](https://github.com/tencentyun/cos-go-sdk-v5/commit/4d341bbaf14bec3b9f12d3f35188deea603cf65d) +- 修改demo [`b40dd06`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b40dd06977d9344df521437462515939c72c0559) +- 单元测试补充 [`e6c9884`](https://github.com/tencentyun/cos-go-sdk-v5/commit/e6c98845f37d1ae3d75d171c8324948a1d764583) +- 补充单元测试 [`a7288cd`](https://github.com/tencentyun/cos-go-sdk-v5/commit/a7288cdc4f21cab561d8acdab9b00fa2ea34d6f5) +- 单元测试补充 [`87de5ef`](https://github.com/tencentyun/cos-go-sdk-v5/commit/87de5efc42fb939898ef6dfe5b6291009cd5becc) +- 内容识别 [`7bdcb1d`](https://github.com/tencentyun/cos-go-sdk-v5/commit/7bdcb1d2629fe0ff8d8491b8123fc0eb85ff54b2) +- 万象sdk 补充 [`200e93b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/200e93b73f8095347133897213f2655e28002feb) +- 内容识别&ut [`7a45ecb`](https://github.com/tencentyun/cos-go-sdk-v5/commit/7a45ecbfc547a90ecf5760d90108b86409d3442a) +- 万象15期需求 [`c3b96c0`](https://github.com/tencentyun/cos-go-sdk-v5/commit/c3b96c0ac52fe51689bef854adb9115625e1530f) +- 海报合成任务 [`dbc50da`](https://github.com/tencentyun/cos-go-sdk-v5/commit/dbc50daa74594217c69d4ecd11af1a8c47a3d2a9) +- ut [`a994d4a`](https://github.com/tencentyun/cos-go-sdk-v5/commit/a994d4a2cc7e2cec4ad6cb16a42f3c5616401deb) +- 补充单元测试 [`9b90a6b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/9b90a6bb75b827790cc96bc50576e108074718d0) +- 单元测试补充 [`b528bb6`](https://github.com/tencentyun/cos-go-sdk-v5/commit/b528bb6faf4fe9ba0ff11675999d61a2911b1213) +- add post bucket inventory [`492db1b`](https://github.com/tencentyun/cos-go-sdk-v5/commit/492db1bb1490f32188c757504fa7221be99a63ed) +- 地图拼接需求 [`6ac0209`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6ac02098fd4d25c165b17030988316ed3036bfed) +- ai人体检测接口 [`544f5ad`](https://github.com/tencentyun/cos-go-sdk-v5/commit/544f5adf6b66433c9d85d35be8e520695c93dc52) +- TDCRefresh [`af06387`](https://github.com/tencentyun/cos-go-sdk-v5/commit/af06387eb0e16c83175ec7a18625ea5b341128fc) +- ut [`dbe46a4`](https://github.com/tencentyun/cos-go-sdk-v5/commit/dbe46a4056417d7daba2cb03aea34d1d8d6b1477) +- 文件处理1.1 [`3292425`](https://github.com/tencentyun/cos-go-sdk-v5/commit/329242519c53bc7c71cd98d47ea79f868d9f62ac) +- add delete batch job [`6a05212`](https://github.com/tencentyun/cos-go-sdk-v5/commit/6a052122fda04ed5c65c7a72d98b4b1ac27bb8f5) + ## [v0.7.41](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.40...v0.7.41) - 2023-01-09 1、CI 质量评分新增参数、质量评分新增参数、新增审核冻结参数、直播审核转存参数 @@ -317,10 +686,6 @@ fix the go.mod ## [v0.7.26](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.25...v0.7.26) - 2021-06-25 -1、add cse-kms -2、add get-object-url -3、add unit test - ### Merged - update go.mod [`#139`](https://github.com/tencentyun/cos-go-sdk-v5/pull/139) @@ -354,10 +719,6 @@ fix the go.mod ## [v0.7.25](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.24...v0.7.25) - 2021-05-10 -1、update ci -2、update demo -3、add download checkpoint - ### Merged - fix demo [`#126`](https://github.com/tencentyun/cos-go-sdk-v5/pull/126) @@ -381,8 +742,6 @@ fix the go.mod ## [v0.7.24](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.23...v0.7.24) - 2021-03-27 -update PutFromFile - ### Merged - Cos v4 dev [`#116`](https://github.com/tencentyun/cos-go-sdk-v5/pull/116) @@ -397,8 +756,6 @@ update PutFromFile ## [v0.7.23](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.22...v0.7.23) - 2021-03-23 -a stable release - ### Merged - latest 0.7.23 stable [`#113`](https://github.com/tencentyun/cos-go-sdk-v5/pull/113) @@ -410,8 +767,6 @@ a stable release ## [v0.7.22](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.21...v0.7.22) - 2021-03-12 -update crc - ### Merged - Cos v4 dev [`#111`](https://github.com/tencentyun/cos-go-sdk-v5/pull/111) @@ -424,8 +779,6 @@ update crc ## [v0.7.21](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.20...v0.7.21) - 2021-03-08 -高级接口增加数据校验功能 - ### Merged - Cos v4 dev [`#108`](https://github.com/tencentyun/cos-go-sdk-v5/pull/108) @@ -447,8 +800,6 @@ update crc ## [v0.7.20](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.19...v0.7.20) - 2021-02-25 -fix multicopy and multiupload send on closed channel error - ### Merged - fix multicopy and multiupload send on closed channel panic [`#104`](https://github.com/tencentyun/cos-go-sdk-v5/pull/104) @@ -461,8 +812,6 @@ fix multicopy and multiupload send on closed channel error ## [v0.7.19](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.18...v0.7.19) - 2021-02-01 -Add Get Object Optional Header && Add Test - ### Merged - add get object optional and test [`#101`](https://github.com/tencentyun/cos-go-sdk-v5/pull/101) @@ -483,8 +832,6 @@ Add Get Object Optional Header && Add Test ## [v0.7.17](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.16...v0.7.17) - 2020-12-29 -add multicopy - ### Merged - add MultiCopy [`#99`](https://github.com/tencentyun/cos-go-sdk-v5/pull/99) @@ -495,8 +842,6 @@ add multicopy ## [v0.7.16](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.15...v0.7.16) - 2020-12-24 -add bucket accelerate && update upload progress - ### Merged - Cos v4 dev [`#98`](https://github.com/tencentyun/cos-go-sdk-v5/pull/98) @@ -510,8 +855,6 @@ add bucket accelerate && update upload progress ## [v0.7.15](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.14...v0.7.15) - 2020-12-11 -update ci & ci document - ### Merged - update ci [`#96`](https://github.com/tencentyun/cos-go-sdk-v5/pull/96) @@ -522,8 +865,6 @@ update ci & ci document ## [v0.7.14](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.13...v0.7.14) - 2020-12-09 -fix bucket lifecycle - ### Merged - update version [`#95`](https://github.com/tencentyun/cos-go-sdk-v5/pull/95) @@ -535,8 +876,6 @@ fix bucket lifecycle ## [v0.7.13](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.12...v0.7.13) - 2020-12-08 -add ci document && add progress - ### Merged - Cos v4 dev [`#93`](https://github.com/tencentyun/cos-go-sdk-v5/pull/93) @@ -551,8 +890,6 @@ add ci document && add progress ## [v0.7.12](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.11...v0.7.12) - 2020-11-25 -update presignedurl && copy - ### Merged - fix ci_test [`#89`](https://github.com/tencentyun/cos-go-sdk-v5/pull/89) @@ -561,8 +898,6 @@ update presignedurl && copy ## [v0.7.11](https://github.com/tencentyun/cos-go-sdk-v5/compare/v0.7.10...v0.7.11) - 2020-11-15 -断点续传、select、CI内容审核、CI云上处理、单链接限制 - ### Merged - Cos v4 dev [`#90`](https://github.com/tencentyun/cos-go-sdk-v5/pull/90) diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/auth.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/auth.go index 6f06395812..f9e3c10f48 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/auth.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/auth.go @@ -4,9 +4,11 @@ import ( "context" "crypto/hmac" "crypto/sha1" + "encoding/base64" "encoding/json" "fmt" "hash" + "io" "io/ioutil" math_rand "math/rand" "net" @@ -26,11 +28,13 @@ const ( ) var ( - defaultCVMAuthExpire = int64(600) + defaultTmpAuthExpire = int64(600) defaultCVMSchema = "http" defaultCVMMetaHost = "metadata.tencentyun.com" defaultCVMCredURI = "latest/meta-data/cam/security-credentials" internalHost = regexp.MustCompile(`^.*cos-internal\.[a-z-1]+\.tencentcos\.cn$`) + defaultStsHost = "sts.tencentcloudapi.com" + defaultStsSchema = "https" ) var DNSScatterDialContext = DNSScatterDialContextFunc @@ -39,7 +43,7 @@ var DNSScatterTransport = &http.Transport{ Proxy: http.ProxyFromEnvironment, DialContext: DNSScatterDialContext, MaxIdleConns: 100, - IdleConnTimeout: 90 * time.Second, + IdleConnTimeout: 60 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, } @@ -106,6 +110,7 @@ var NeedSignHeaders = map[string]bool{ "access-control-request-method": true, "access-control-request-headers": true, "x-cos-object-type": true, + "pic-operations": true, } // 非线程安全,只能在进程初始化(而不是Client初始化)时做设置 @@ -160,7 +165,7 @@ type AuthTime struct { // NewAuthTime 生成 AuthTime 的便捷函数 // -// expire: 从现在开始多久过期. +// expire: 从现在开始多久过期. func NewAuthTime(expire time.Duration) *AuthTime { signStartTime := time.Now() keyStartTime := signStartTime @@ -413,7 +418,7 @@ func (t *CVMCredentialTransport) GetRoles() ([]string, error) { return nil, err } roles := strings.Split(strings.TrimSpace(string(bs)), "\n") - if len(roles) == 0 { + if string(bs) == "" || len(roles) == 0 { return nil, fmt.Errorf("get cvm security-credentials role failed, No valid cam role was found") } return roles, nil @@ -423,7 +428,7 @@ func (t *CVMCredentialTransport) GetRoles() ([]string, error) { func (t *CVMCredentialTransport) UpdateCredential(now int64) (string, string, string, error) { t.rwLocker.Lock() defer t.rwLocker.Unlock() - if t.expiredTime > now+defaultCVMAuthExpire { + if t.expiredTime > now+defaultTmpAuthExpire { return t.secretID, t.secretKey, t.sessionToken, nil } roleName := t.RoleName @@ -459,8 +464,8 @@ func (t *CVMCredentialTransport) UpdateCredential(now int64) (string, string, st func (t *CVMCredentialTransport) GetCredential() (string, string, string, error) { now := time.Now().Unix() t.rwLocker.RLock() - // 提前 defaultCVMAuthExpire 获取重新获取临时密钥 - if t.expiredTime <= now+defaultCVMAuthExpire { + // 提前 defaultTmpAuthExpire 获取重新获取临时密钥 + if t.expiredTime <= now+defaultTmpAuthExpire { expiredTime := t.expiredTime t.rwLocker.RUnlock() secretID, secretKey, secretToken, err := t.UpdateCredential(now) @@ -544,3 +549,208 @@ func (c *Credential) GetSecretId() string { func (c *Credential) GetToken() string { return c.SessionToken } + +// 通过sts访问 +type Credentials struct { + TmpSecretID string `json:"TmpSecretId,omitempty"` + TmpSecretKey string `json:"TmpSecretKey,omitempty"` + SessionToken string `json:"Token,omitempty"` +} +type CredentialError struct { + Code string `json:"Code,omitempty"` + Message string `json:"Message,omitempty"` + RequestId string `json:"RequestId,omitempty"` +} + +func (e *CredentialError) Error() string { + return fmt.Sprintf("Code: %v, Message: %v, RequestId: %v", e.Code, e.Message, e.RequestId) +} + +type CredentialResult struct { + Credentials *Credentials `json:"Credentials,omitempty"` + ExpiredTime int64 `json:"ExpiredTime,omitempty"` + RequestId string `json:"RequestId,omitempty"` + Error *CredentialError `json:"Error,omitempty"` +} + +type CredentialCompleteResult struct { + Response *CredentialResult `json:"Response"` +} + +type CredentialPolicyStatement struct { + Action []string `json:"action,omitempty"` + Effect string `json:"effect,omitempty"` + Resource []string `json:"resource,omitempty"` + Condition map[string]map[string]interface{} `json:"condition,omitempty"` +} + +type CredentialPolicy struct { + Version string `json:"version,omitempty"` + Statement []CredentialPolicyStatement `json:"statement,omitempty"` +} + +type StsCredentialTransport struct { + Transport http.RoundTripper + SecretID string + SecretKey string + Policy *CredentialPolicy + Host string + Region string + expiredTime int64 + credential Credentials + rwLocker sync.RWMutex +} + +func (t *StsCredentialTransport) UpdateCredential(now int64) (string, string, string, error) { + t.rwLocker.Lock() + defer t.rwLocker.Unlock() + if t.expiredTime > now+defaultTmpAuthExpire { + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, nil + } + region := t.Region + if region == "" { + region = "ap-guangzhou" + } + policy, err := getPolicy(t.Policy) + if err != nil { + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, err + } + params := map[string]interface{}{ + "SecretId": t.SecretID, + "Policy": url.QueryEscape(policy), + "DurationSeconds": 1800, + "Region": region, + "Timestamp": time.Now().Unix(), + "Nonce": math_rand.Int(), + "Name": "cos-sts-sdk", + "Action": "GetFederationToken", + "Version": "2018-08-13", + } + resp, err := t.sendRequest(params) + if err != nil { + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, err + } + defer resp.Body.Close() + if resp.StatusCode > 299 { + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, fmt.Errorf("sts StatusCode error: %v", resp.StatusCode) + } + result := &CredentialCompleteResult{} + err = json.NewDecoder(resp.Body).Decode(result) + if err == io.EOF { + err = nil // ignore EOF errors caused by empty response body + } + if err != nil { + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, err + } + if result.Response != nil && result.Response.Error != nil { + result.Response.Error.RequestId = result.Response.RequestId + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, result.Response.Error + } + if result.Response != nil && result.Response.Credentials != nil { + t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, t.expiredTime = result.Response.Credentials.TmpSecretID, result.Response.Credentials.TmpSecretKey, result.Response.Credentials.SessionToken, result.Response.ExpiredTime + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, nil + } + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, fmt.Errorf("GetCredential failed, result: %v", result.Response) +} + +func (t *StsCredentialTransport) GetCredential() (string, string, string, error) { + now := time.Now().Unix() + t.rwLocker.RLock() + // 提前 defaultTmpAuthExpire 获取重新获取临时密钥 + if t.expiredTime <= now+defaultTmpAuthExpire { + expiredTime := t.expiredTime + t.rwLocker.RUnlock() + secretID, secretKey, secretToken, err := t.UpdateCredential(now) + // 获取临时密钥失败但密钥未过期 + if err != nil && now < expiredTime { + err = nil + } + return secretID, secretKey, secretToken, err + } + defer t.rwLocker.RUnlock() + return t.credential.TmpSecretID, t.credential.TmpSecretKey, t.credential.SessionToken, nil +} + +func (t *StsCredentialTransport) RoundTrip(req *http.Request) (*http.Response, error) { + ak, sk, token, err := t.GetCredential() + if err != nil { + return nil, err + } + req = cloneRequest(req) + // 增加 Authorization header + authTime := NewAuthTime(defaultAuthExpire) + AddAuthorizationHeader(ak, sk, token, req, authTime) + + resp, err := t.transport().RoundTrip(req) + return resp, err +} + +func (t *StsCredentialTransport) transport() http.RoundTripper { + if t.Transport != nil { + return t.Transport + } + return http.DefaultTransport +} + +func (t *StsCredentialTransport) sendRequest(params map[string]interface{}) (*http.Response, error) { + paramValues := url.Values{} + for k, v := range params { + paramValues.Add(fmt.Sprintf("%v", k), fmt.Sprintf("%v", v)) + } + sign := t.signed("POST", params) + paramValues.Add("Signature", sign) + + host := defaultStsHost + if t.Host != "" { + host = t.Host + } + resp, err := http.DefaultClient.PostForm(defaultStsSchema+"://"+host, paramValues) + return resp, err +} + +func (t *StsCredentialTransport) signed(method string, params map[string]interface{}) string { + host := defaultStsHost + if t.Host != "" { + host = t.Host + } + source := method + host + "/?" + makeFlat(params) + + hmacObj := hmac.New(sha1.New, []byte(t.SecretKey)) + hmacObj.Write([]byte(source)) + + sign := base64.StdEncoding.EncodeToString(hmacObj.Sum(nil)) + + return sign +} + +func getPolicy(policy *CredentialPolicy) (string, error) { + if policy == nil { + return "", nil + } + res := policy + if policy.Version == "" { + res = &CredentialPolicy{ + Version: "2.0", + Statement: policy.Statement, + } + } + bs, err := json.Marshal(res) + if err != nil { + return "", err + } + return string(bs), nil +} + +func makeFlat(params map[string]interface{}) string { + keys := make([]string, 0, len(params)) + for k, _ := range params { + keys = append(keys, k) + } + sort.Strings(keys) + + var plainParms string + for _, k := range keys { + plainParms += fmt.Sprintf("&%v=%v", k, params[k]) + } + return plainParms[1:] +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket.go index 9d062c9c68..65995aeba7 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket.go @@ -1,8 +1,10 @@ package cos import ( + "bytes" "context" "encoding/xml" + "errors" "net/http" ) @@ -59,6 +61,8 @@ type BucketPutOptions struct { XCosGrantFullControl string `header:"x-cos-grant-full-control,omitempty" url:"-" xml:"-"` XCosGrantReadACP string `header:"x-cos-grant-read-acp,omitempty" url:"-" xml:"-"` XCosGrantWriteACP string `header:"x-cos-grant-write-acp,omitempty" url:"-" xml:"-"` + XCosTagging string `header:"x-cos-tagging,omitempty" url:"-" xml:"-"` + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` CreateBucketConfiguration *CreateBucketConfiguration `header:"-" url:"-" xml:"-"` } type CreateBucketConfiguration struct { @@ -148,6 +152,7 @@ type Bucket struct { Name string Region string `xml:"Location,omitempty"` CreationDate string `xml:",omitempty"` + BucketType string `xml:",omitempty"` } type BucketGetObjectVersionsOptions struct { @@ -209,3 +214,153 @@ func (s *BucketService) GetObjectVersions(ctx context.Context, opt *BucketGetObj resp, err := s.client.doRetry(ctx, &sendOpt) return &res, resp, err } + +type BucketGetMetadataResult struct { + BucketUrl string + BucketName string + Location string + MAZ bool + OFS bool + Encryption *BucketGetEncryptionResult + ACL *BucketGetACLResult + Website *BucketGetWebsiteResult + Logging *BucketGetLoggingResult + CORS *BucketGetCORSResult + Versioning *BucketGetVersionResult + Lifecycle *BucketGetLifecycleResult + IntelligentTiering *ListIntelligentTieringConfigurations + Tagging *BucketGetTaggingResult + ObjectLock *BucketGetObjectLockResult + Replication *BucketGetReplicationResult +} + +func (s *BucketService) GetMeta(ctx context.Context, bucket ...string) (*BucketGetMetadataResult, *Response, error) { + if s.client.BaseURL.BucketURL == nil { + return nil, nil, errors.New("BucketURL is empty") + } + var customDomain bool + if !hostPrefix.MatchString(s.client.BaseURL.BucketURL.String()) { + customDomain = true + if len(bucket) == 0 || !bucketChecker.MatchString(bucket[0]) { + return nil, nil, errors.New("you must provide bucket-appid param in using custom domain") + } + } + var err error + var resp *Response + var res BucketGetMetadataResult + + resp, err = s.Head(ctx) + if err != nil { + return nil, resp, err + } + // 非自定义域名 + if !customDomain { + res.BucketName, res.Location = GetBucketRegionFromUrl(s.client.BaseURL.BucketURL) + } else { + res.BucketName, res.Location = bucket[0], resp.Header.Get("X-Cos-Bucket-Region") + } + w := bytes.NewBuffer(nil) + bucketURLTemplate.Execute(w, struct { + Schema string + BucketName string + Region string + }{"https", res.BucketName, res.Location}) + res.BucketUrl = w.String() + + if resp.Header.Get("X-Cos-Bucket-Az-Type") == "MAZ" { + res.MAZ = true + } + if resp.Header.Get("X-Cos-Bucket-Arch") == "OFS" { + res.OFS = true + } + + res.Encryption, resp, err = s.GetEncryption(ctx) + if err != nil { + if IsNotFoundError(err) { + res.Encryption = nil + } else { + return nil, resp, err + } + } + res.ACL, resp, err = s.GetACL(ctx) + if err != nil { + if IsNotFoundError(err) { + res.ACL = nil + } else { + return nil, resp, err + } + } + res.Website, resp, err = s.GetWebsite(ctx) + if err != nil { + if IsNotFoundError(err) { + res.Website = nil + } else { + return nil, resp, err + } + } + res.Logging, resp, err = s.GetLogging(ctx) + if err != nil { + if IsNotFoundError(err) { + res.Logging = nil + } else { + return nil, resp, err + } + } + res.CORS, resp, err = s.GetCORS(ctx) + if err != nil { + if IsNotFoundError(err) { + res.CORS = nil + } else { + return nil, resp, err + } + } + res.Versioning, resp, err = s.GetVersioning(ctx) + if err != nil { + if IsNotFoundError(err) { + res.Versioning = nil + } else { + return nil, resp, err + } + } + res.Lifecycle, resp, err = s.GetLifecycle(ctx) + if err != nil { + if IsNotFoundError(err) { + res.Lifecycle = nil + } else { + return nil, resp, err + } + } + res.IntelligentTiering, resp, err = s.ListIntelligentTiering(ctx) + if err != nil { + if IsNotFoundError(err) { + res.IntelligentTiering = nil + } else { + return nil, resp, err + } + } + res.Tagging, resp, err = s.GetTagging(ctx) + if err != nil { + if IsNotFoundError(err) { + res.Tagging = nil + } else { + return nil, resp, err + } + } + res.ObjectLock, resp, err = s.GetObjectLockConfiguration(ctx) + if err != nil { + if IsNotFoundError(err) { + res.ObjectLock = nil + } else { + return nil, resp, err + } + } + res.Replication, resp, err = s.GetBucketReplication(ctx) + if err != nil { + if IsNotFoundError(err) { + res.Replication = nil + } else { + return nil, resp, err + } + } + return &res, resp, nil +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_acl.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_acl.go index d0575c8527..d2069cfa3a 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_acl.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_acl.go @@ -39,20 +39,17 @@ type BucketPutACLOptions struct { // // Put Bucket ACL是一个覆盖操作,传入新的ACL将覆盖原有ACL。只有所有者有权操作。 // -// "x-cos-acl":枚举值为public-read,private;public-read意味这个Bucket有公有读私有写的权限, -// private意味这个Bucket有私有读写的权限。 +// "x-cos-acl":枚举值为public-read,private;public-read意味这个Bucket有公有读私有写的权限, +// private意味这个Bucket有私有读写的权限。 // -// "x-cos-grant-read":意味被赋予权限的用户拥有该Bucket的读权限 -// "x-cos-grant-write":意味被赋予权限的用户拥有该Bucket的写权限 -// "x-cos-grant-full-control":意味被赋予权限的用户拥有该Bucket的读写权限 +// "x-cos-grant-read":意味被赋予权限的用户拥有该Bucket的读权限 +// "x-cos-grant-write":意味被赋予权限的用户拥有该Bucket的写权限 +// "x-cos-grant-full-control":意味被赋予权限的用户拥有该Bucket的读写权限 // // https://www.qcloud.com/document/product/436/7737 func (s *BucketService) PutACL(ctx context.Context, opt *BucketPutACLOptions) (*Response, error) { header := opt.Header body := opt.Body - if body != nil { - header = nil - } sendOpt := sendOptions{ baseURL: s.client.BaseURL.BucketURL, uri: "/?acl", diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_cors.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_cors.go index 6edc6ccf5d..29f085fedf 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_cors.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_cors.go @@ -18,8 +18,9 @@ type BucketCORSRule struct { // BucketGetCORSResult is the result of GetBucketCORS type BucketGetCORSResult struct { - XMLName xml.Name `xml:"CORSConfiguration"` - Rules []BucketCORSRule `xml:"CORSRule,omitempty"` + XMLName xml.Name `xml:"CORSConfiguration"` + Rules []BucketCORSRule `xml:"CORSRule,omitempty"` + ResponseVary string `xml:"ResponseVary,omitempty"` } // GetCORS 实现 Bucket 跨域访问配置读取。 @@ -39,8 +40,9 @@ func (s *BucketService) GetCORS(ctx context.Context) (*BucketGetCORSResult, *Res // BucketPutCORSOptions is the option of PutBucketCORS type BucketPutCORSOptions struct { - XMLName xml.Name `xml:"CORSConfiguration"` - Rules []BucketCORSRule `xml:"CORSRule,omitempty"` + XMLName xml.Name `xml:"CORSConfiguration"` + Rules []BucketCORSRule `xml:"CORSRule,omitempty"` + ResponseVary string `xml:"ResponseVary,omitempty"` } // PutCORS 实现 Bucket 跨域访问设置,您可以通过传入XML格式的配置文件实现配置,文件大小限制为64 KB。 diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_domain.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_domain.go index a89068e25d..4efe06cdbd 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_domain.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_domain.go @@ -30,23 +30,41 @@ func (s *BucketService) PutDomain(ctx context.Context, opt *BucketPutDomainOptio return resp, err } -func (s *BucketService) GetDomain(ctx context.Context) (*BucketGetDomainResult, *Response, error) { +type BucketGetDomainOptions struct { + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +func (s *BucketService) GetDomain(ctx context.Context, opt ...*BucketGetDomainOptions) (*BucketGetDomainResult, *Response, error) { + var gopt *BucketGetDomainOptions + if len(opt) > 0 { + gopt = opt[0] + } var res BucketGetDomainResult sendOpt := &sendOptions{ - baseURL: s.client.BaseURL.BucketURL, - uri: "/?domain", - method: http.MethodGet, - result: &res, + baseURL: s.client.BaseURL.BucketURL, + uri: "/?domain", + method: http.MethodGet, + result: &res, + optHeader: gopt, } resp, err := s.client.doRetry(ctx, sendOpt) return &res, resp, err } -func (s *BucketService) DeleteDomain(ctx context.Context) (*Response, error) { +type BucketDeleteDomainOptions struct { + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +func (s *BucketService) DeleteDomain(ctx context.Context, opt ...*BucketDeleteDomainOptions) (*Response, error) { + var dopt *BucketDeleteDomainOptions + if len(opt) > 0 { + dopt = opt[0] + } sendOpt := &sendOptions{ - baseURL: s.client.BaseURL.BucketURL, - uri: "/?domain", - method: http.MethodDelete, + baseURL: s.client.BaseURL.BucketURL, + uri: "/?domain", + method: http.MethodDelete, + optHeader: dopt, } resp, err := s.client.doRetry(ctx, sendOpt) return resp, err diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_encryption.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_encryption.go index 432928424f..2fa2f98902 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_encryption.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_encryption.go @@ -7,7 +7,7 @@ import ( ) type BucketEncryptionConfiguration struct { - SSEAlgorithm string `xml:"SSEAlgorithm"` + SSEAlgorithm string `xml:"SSEAlgorithm"` KMSMasterKeyID string `xml:"KMSMasterKeyID,omitempty"` } diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_intelligenttiering.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_intelligenttiering.go index 2777b28ebd..d5967a8a70 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_intelligenttiering.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_intelligenttiering.go @@ -3,19 +3,38 @@ package cos import ( "context" "encoding/xml" + "errors" "net/http" ) +type BucketIntelligentTieringFilterAnd struct { + Prefix string `xml:"Prefix,omitempty" header:"-"` + Tag []*BucketTaggingTag `xml:"Tag,omitempty" header:"-"` +} + +type BucketIntelligentTieringFilter struct { + And *BucketIntelligentTieringFilterAnd `xml:"And,omitempty" header:"-"` + Prefix string `xml:"Prefix,omitempty" header:"-"` + Tag []*BucketTaggingTag `xml:"Tag,omitempty" header:"-"` +} + type BucketIntelligentTieringTransition struct { - Days int `xml:"Days,omitempty" header:"-"` - RequestFrequent int `xml:"RequestFrequent,omitempty" header:"-"` + AccessTier string `xml:"AccessTier,omitempty" header:"-"` + Days int `xml:"Days,omitempty" header:"-"` + RequestFrequent int `xml:"RequestFrequent,omitempty" header:"-"` } type BucketPutIntelligentTieringOptions struct { - XMLName xml.Name `xml:"IntelligentTieringConfiguration" header:"-"` - Status string `xml:"Status,omitempty" header:"-"` - Transition *BucketIntelligentTieringTransition `xml:"Transition,omitempty" header:"-"` - XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` + XMLName xml.Name `xml:"IntelligentTieringConfiguration" header:"-"` + Status string `xml:"Status,omitempty" header:"-"` + Transition *BucketIntelligentTieringTransition `xml:"Transition,omitempty" header:"-"` + + // V2 + Id string `xml:"Id,omitempty" header:"-"` + Tiering []*BucketIntelligentTieringTransition `xml:"Tiering,omitempty" header:"-"` + Filter *BucketIntelligentTieringFilter `xml:"Filter,omitempty" header:"-"` + + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` } type BucketGetIntelligentTieringResult BucketPutIntelligentTieringOptions @@ -24,6 +43,18 @@ type BucketGetIntelligentTieringOptions struct { XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` } +type IntelligentTieringConfiguration struct { + Id string `xml:"Id"` + Status string `xml:"Status"` + Tiering []*BucketIntelligentTieringTransition `xml:"Tiering"` + Filter *BucketIntelligentTieringFilter `xml:"Filter,omitempty"` +} + +type ListIntelligentTieringConfigurations struct { + XMLName xml.Name `xml:"ListBucketIntelligentTieringConfigurationsOutput"` + Configurations []*IntelligentTieringConfiguration `xml:"IntelligentTieringConfiguration,omitempty"` +} + func (s *BucketService) PutIntelligentTiering(ctx context.Context, opt *BucketPutIntelligentTieringOptions) (*Response, error) { if opt != nil && opt.Transition != nil { opt.Transition.RequestFrequent = 1 @@ -54,5 +85,58 @@ func (s *BucketService) GetIntelligentTiering(ctx context.Context, opt ...*Bucke } resp, err := s.client.doRetry(ctx, &sendOpt) return &res, resp, err +} + +func (s *BucketService) PutIntelligentTieringV2(ctx context.Context, opt *BucketPutIntelligentTieringOptions) (*Response, error) { + if opt == nil || opt.Id == "" { + return nil, errors.New("id is empty") + } + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?intelligent-tiering&id=" + opt.Id, + method: http.MethodPut, + optHeader: opt, + body: opt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} + +func (s *BucketService) GetIntelligentTieringV2(ctx context.Context, id string, opt ...*BucketGetIntelligentTieringOptions) (*BucketGetIntelligentTieringResult, *Response, error) { + var optHeader *BucketGetIntelligentTieringOptions + if len(opt) > 0 { + optHeader = opt[0] + } + var res BucketGetIntelligentTieringResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?intelligent-tiering&id=" + id, + method: http.MethodGet, + optHeader: optHeader, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} + +func (s *BucketService) ListIntelligentTiering(ctx context.Context) (*ListIntelligentTieringConfigurations, *Response, error) { + var res ListIntelligentTieringConfigurations + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?intelligent-tiering", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return &res, resp, err +} +func (s *BucketService) DeleteIntelligentTiering(ctx context.Context, id string) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?intelligent-tiering&id=" + id, + method: http.MethodDelete, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err } diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_inventory.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_inventory.go index 6188e12069..747086f4b5 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_inventory.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_inventory.go @@ -149,6 +149,6 @@ func (s *BucketService) PostInventory(ctx context.Context, id string, opt *Bucke method: http.MethodPost, body: opt, } - resp, err := s.client.send(ctx, &sendOpt) + resp, err := s.client.doRetry(ctx, &sendOpt) return resp, err } diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_lifecycle.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_lifecycle.go index 9d5e3eb892..64f4b06b04 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_lifecycle.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_lifecycle.go @@ -7,8 +7,11 @@ import ( ) type BucketLifecycleAndOperator struct { - Prefix string `xml:"Prefix,omitempty" header:"-"` - Tag []BucketTaggingTag `xml:"Tag,omitempty" header:"-"` + Prefix string `xml:"Prefix,omitempty" header:"-"` + Tag []BucketTaggingTag `xml:"Tag,omitempty" header:"-"` + PrefixNotEquals string `xml:"PrefixNotEquals,omitempty" header:"-"` + ObjectSizeGreaterThan int64 `xml:"ObjectSizeGreaterThan,omitempty" header:"-"` + ObjectSizeLessThan int64 `xml:"ObjectSizeLessThan,omitempty" header:"-"` } // BucketLifecycleFilter is the param of BucketLifecycleRule @@ -25,16 +28,23 @@ type BucketLifecycleExpiration struct { ExpiredObjectDeleteMarker bool `xml:"ExpiredObjectDeleteMarker,omitempty" header:"-"` } +type BucketAccessFrequency struct { + AccessCountLessThan int `xml:"AccessCountLessThan,omitempty" header:"-"` + RecentDays int `xml:"RecentDays,omitempty" header:"-"` +} + // BucketLifecycleTransition is the param of BucketLifecycleRule type BucketLifecycleTransition struct { - Date string `xml:"Date,omitempty" header:"-"` - Days int `xml:"Days,omitempty" header:"-"` - StorageClass string `xml:"StorageClass,omitempty" header:"-"` + Date string `xml:"Date,omitempty" header:"-"` + Days int `xml:"Days,omitempty" header:"-"` + StorageClass string `xml:"StorageClass,omitempty" header:"-"` + AccessFrequency *BucketAccessFrequency `xml:"AccessFrequency,omitempty" header:"-"` } type BucketLifecycleNoncurrentVersion struct { - NoncurrentDays int `xml:"NoncurrentDays,omitempty" header:"-"` - StorageClass string `xml:"StorageClass,omitempty" header:"-"` + NoncurrentDays int `xml:"NoncurrentDays,omitempty" header:"-"` + StorageClass string `xml:"StorageClass,omitempty" header:"-"` + AccessFrequency *BucketAccessFrequency `xml:"AccessFrequency,omitempty" header:"-"` } // BucketLifecycleAbortIncompleteMultipartUpload is the param of BucketLifecycleRule diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_location.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_location.go index dd4b5a55d4..d449f96d25 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_location.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_location.go @@ -23,6 +23,6 @@ func (s *BucketService) GetLocation(ctx context.Context) (*BucketGetLocationResu method: http.MethodGet, result: &res, } - resp, err := s.client.send(ctx, &sendOpt) + resp, err := s.client.doRetry(ctx, &sendOpt) return &res, resp, err } diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_object_lock.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_object_lock.go index 29d25cfef3..662181190c 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_object_lock.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_object_lock.go @@ -48,6 +48,7 @@ type ObjectGetRetentionOptions struct { type ObjectGetRetentionResult struct { XMLName xml.Name `xml:"Retention"` RetainUntilDate string `xml:"RetainUntilDate,omitempty"` + Mode string `xml:"Mode,omitempty"` } func (s *ObjectService) GetRetention(ctx context.Context, key string, opt *ObjectGetRetentionOptions) (*ObjectGetRetentionResult, *Response, error) { @@ -62,3 +63,20 @@ func (s *ObjectService) GetRetention(ctx context.Context, key string, opt *Objec resp, err := s.client.doRetry(ctx, &sendOpt) return &res, resp, err } + +type ObjectPutRetentionOptions struct { + XMLName xml.Name `xml:"Retention"` + RetainUntilDate string `xml:"RetainUntilDate,omitempty"` + Mode string `xml:"Mode,omitempty"` +} + +func (s *ObjectService) PutRetention(ctx context.Context, key string, opt *ObjectPutRetentionOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(key) + "?retention", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.doRetry(ctx, &sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_origin.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_origin.go index c6cc5fd727..f58d5d8240 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_origin.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_origin.go @@ -3,7 +3,11 @@ package cos import ( "context" "encoding/xml" + "fmt" + "github.com/clbanning/mxj" "net/http" + "strconv" + "strings" ) type BucketPutOriginOptions struct { @@ -35,9 +39,10 @@ type BucketOriginParameter struct { type BucketOriginHttpHeader struct { // 目前还不支持 FollowAllHeaders - // FollowAllHeaders bool `xml:"FollowAllHeaders,omitempty"` - NewHttpHeaders []OriginHttpHeader `xml:"NewHttpHeaders>Header,omitempty"` - FollowHttpHeaders []OriginHttpHeader `xml:"FollowHttpHeaders>Header,omitempty"` + FollowAllHeaders bool `xml:"FollowAllHeaders,omitempty"` + NewHttpHeaders []OriginHttpHeader `xml:"NewHttpHeaders>Header,omitempty"` + FollowHttpHeaders []OriginHttpHeader `xml:"FollowHttpHeaders>Header,omitempty"` + ForbidFollowHeaders []OriginHttpHeader `xml:"ForbidFollowHeaders>Header,omitempty"` } type OriginHttpHeader struct { @@ -46,17 +51,109 @@ type OriginHttpHeader struct { } type BucketOriginInfo struct { - HostInfo string `xml:"HostInfo>HostName,omitempty"` + HostInfo *BucketOriginHostInfo `xml:"HostInfo,omitempty"` FileInfo *BucketOriginFileInfo `xml:"FileInfo,omitempty"` } + +type BucketOriginHostInfo struct { + HostName string + Weight int64 + StandbyHostName_N []string +} + type BucketOriginFileInfo struct { - PrefixDirective bool `xml:"PrefixDirective,omitempty"` - Prefix string `xml:"Prefix,omitempty"` - Suffix string `xml:"Suffix,omitempty"` + PrefixConfiguration *OriginPrefixConfiguration `xml:"PrefixConfiguration,omitempty"` + SuffixConfiguration *OriginSuffixConfiguration `xml:"SuffixConfiguration,omitempty"` + FixedFileConfiguration *OriginFixedFileConfiguration `xml:"FixedFileConfiguration,omitempty"` +} + +type OriginPrefixConfiguration struct { + Prefix string `xml:"Prefix,omitempty"` +} + +type OriginSuffixConfiguration struct { + Suffix string `xml:"Suffix,omitempty"` +} + +type OriginFixedFileConfiguration struct { + FixedFilePath string `xml:"FixedFilePath,omitempty"` } type BucketGetOriginResult BucketPutOriginOptions +func (this *BucketOriginHostInfo) MarshalXML(e *xml.Encoder, start xml.StartElement) error { + if this == nil { + return nil + } + err := e.EncodeToken(start) + if err != nil { + return err + } + if this.HostName != "" { + err = e.EncodeElement(this.HostName, xml.StartElement{Name: xml.Name{Local: "HostName"}}) + if err != nil { + return err + } + } + if this.Weight != 0 { + err = e.EncodeElement(this.Weight, xml.StartElement{Name: xml.Name{Local: "Weight"}}) + if err != nil { + return err + } + } + for index, standByHostName := range this.StandbyHostName_N { + err = e.EncodeElement(standByHostName, xml.StartElement{Name: xml.Name{Local: fmt.Sprintf("StandbyHostName_%v", index+1)}}) + if err != nil { + return err + } + } + return e.EncodeToken(xml.EndElement{Name: start.Name}) +} + +func (this *BucketOriginHostInfo) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { + var val struct { + XMLName xml.Name + Inner []byte `xml:",innerxml"` + } + err := d.DecodeElement(&val, &start) + if err != nil { + return err + } + str := "" + string(val.Inner) + "" + myMxjMap, err := mxj.NewMapXml([]byte(str)) + if err != nil { + return err + } + myMap, ok := myMxjMap["HostInfo"].(map[string]interface{}) + if !ok { + return fmt.Errorf("XML HostInfo Parse failed") + } + + var total int + for key, value := range myMap { + if key == "HostName" { + this.HostName = value.(string) + } + if key == "Weight" { + v := value.(string) + this.Weight, err = strconv.ParseInt(v, 10, 64) + if err != nil { + return err + } + } + if strings.HasPrefix(key, "StandbyHostName_") { + total++ + } + } + // 按顺序执行 + for i := 1; i <= total; i++ { + key := fmt.Sprintf("StandbyHostName_%v", i) + this.StandbyHostName_N = append(this.StandbyHostName_N, myMap[key].(string)) + } + + return nil +} + func (s *BucketService) PutOrigin(ctx context.Context, opt *BucketPutOriginOptions) (*Response, error) { sendOpt := &sendOptions{ baseURL: s.client.BaseURL.BucketURL, diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_part.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_part.go index e77b4207a2..85923cec79 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_part.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_part.go @@ -32,12 +32,13 @@ type ListMultipartUploadsResult struct { // ListMultipartUploadsOptions is the option of ListMultipartUploads type ListMultipartUploadsOptions struct { - Delimiter string `url:"delimiter,omitempty"` - EncodingType string `url:"encoding-type,omitempty"` - Prefix string `url:"prefix,omitempty"` - MaxUploads int `url:"max-uploads,omitempty"` - KeyMarker string `url:"key-marker,omitempty"` - UploadIDMarker string `url:"upload-id-marker,omitempty"` + Delimiter string `url:"delimiter,omitempty"` + EncodingType string `url:"encoding-type,omitempty"` + Prefix string `url:"prefix,omitempty"` + MaxUploads int `url:"max-uploads,omitempty"` + KeyMarker string `url:"key-marker,omitempty"` + UploadIDMarker string `url:"upload-id-marker,omitempty"` + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` } // ListMultipartUploads 用来查询正在进行中的分块上传。单次最多列出1000个正在进行中的分块上传。 @@ -46,12 +47,13 @@ type ListMultipartUploadsOptions struct { func (s *BucketService) ListMultipartUploads(ctx context.Context, opt *ListMultipartUploadsOptions) (*ListMultipartUploadsResult, *Response, error) { var res ListMultipartUploadsResult sendOpt := sendOptions{ - baseURL: s.client.BaseURL.BucketURL, - uri: "/?uploads", - method: http.MethodGet, - result: &res, - optQuery: opt, + baseURL: s.client.BaseURL.BucketURL, + uri: "/?uploads", + method: http.MethodGet, + result: &res, + optQuery: opt, + optHeader: opt, } - resp, err := s.client.send(ctx, &sendOpt) + resp, err := s.client.doRetry(ctx, &sendOpt) return &res, resp, err } diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_policy.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_policy.go index 5ec4f8966d..5930198087 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_policy.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_policy.go @@ -14,6 +14,7 @@ type BucketStatement struct { Effect string `json:"effect,omitempty"` Resource []string `json:"resource,omitempty"` Condition map[string]map[string]interface{} `json:"condition,omitempty"` + Sid string `json:"sid,omitempty"` } type BucketPutPolicyOptions struct { diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_referer.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_referer.go index cad5a73fd1..52e7a24739 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_referer.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_referer.go @@ -2,6 +2,7 @@ package cos import ( "context" + "encoding/base64" "encoding/xml" "net/http" ) @@ -12,6 +13,7 @@ type BucketPutRefererOptions struct { RefererType string `xml:"RefererType"` DomainList []string `xml:"DomainList>Domain"` EmptyReferConfiguration string `xml:"EmptyReferConfiguration,omitempty"` + VerifySignatureURL string `xml:"VerifySignatureURL,omitempty"` } type BucketGetRefererResult BucketPutRefererOptions @@ -38,3 +40,19 @@ func (s *BucketService) GetReferer(ctx context.Context) (*BucketGetRefererResult resp, err := s.client.doRetry(ctx, sendOpt) return &res, resp, err } + +// Put空 +func (s *BucketService) DeleteReferer(ctx context.Context) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?referer", + method: http.MethodPut, + optHeader: &struct { + Md5 string `header:"Content-Md5"` + }{ + Md5: base64.StdEncoding.EncodeToString(calMD5Digest([]byte(""))), + }, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_replication.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_replication.go index 9b2d07b587..cd23a99ebd 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_replication.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_replication.go @@ -27,8 +27,9 @@ type PutBucketReplicationOptions struct { Rule []BucketReplicationRule `xml:"Rule"` } -// GetBucketReplicationResult is the result of GetBucketReplication +// GetBucketReplicationResult is the result of GetBucketReplication type GetBucketReplicationResult PutBucketReplicationOptions +type BucketGetReplicationResult = GetBucketReplicationResult // PutBucketReplication https://cloud.tencent.com/document/product/436/19223 func (s *BucketService) PutBucketReplication(ctx context.Context, opt *PutBucketReplicationOptions) (*Response, error) { diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_website.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_website.go index f97f4d64ef..9a97e9c7aa 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_website.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/bucket_website.go @@ -19,8 +19,13 @@ type WebsiteRoutingRules struct { Rules []WebsiteRoutingRule `xml:"RoutingRule,omitempty"` } +type AutoAddressing struct { + Status string `xml:"Status,omitempty"` +} + type ErrorDocument struct { - Key string `xml:"Key,omitempty"` + Key string `xml:"Key,omitempty"` + OriginalHttpStatus string `xml:"OriginalHttpStatus,omitempty"` } type RedirectRequestsProtocol struct { @@ -31,6 +36,7 @@ type BucketPutWebsiteOptions struct { XMLName xml.Name `xml:"WebsiteConfiguration"` Index string `xml:"IndexDocument>Suffix"` RedirectProtocol *RedirectRequestsProtocol `xml:"RedirectAllRequestsTo,omitempty"` + AutoAddressing *AutoAddressing `xml:"AutoAddressing,omitempty"` Error *ErrorDocument `xml:"ErrorDocument,omitempty"` RoutingRules *WebsiteRoutingRules `xml:"RoutingRules,omitempty"` } diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/ci.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci.go index f47bf89790..63bafd74ad 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/ci.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci.go @@ -43,6 +43,9 @@ type ImageProcessResult struct { XMLName xml.Name `xml:"UploadResult"` OriginalInfo *PicOriginalInfo `xml:"OriginalInfo,omitempty"` ProcessResults []PicProcessObject `xml:"ProcessResults>Object,omitempty"` + // 历史兼容考虑不建议抽象单独struct防止客户使用影响 + ProcessResultsText string `xml:"ProcessResults>Text,omitempty"` + ProcessResultsWatermarkStatusCode int `xml:"ProcessResults>WatermarkStatusCode,omitempty"` } type PicOriginalInfo struct { Key string `xml:"Key,omitempty"` @@ -144,7 +147,7 @@ type AuditingMaskLiveInfo struct { Output string `xml:"Output,omitempty"` } -//UserListResults 命中账号黑白名单信息 +// UserListResults 命中账号黑白名单信息 type UserListResults struct { ListType *int `xml:",omitempty"` ListName string `xml:",omitempty"` @@ -705,6 +708,8 @@ type TextAuditingJobDetail struct { UserInfo *UserExtraInfo `xml:",omitempty"` ListInfo *UserListInfo `xml:",omitempty"` ForbidState int `xml:",omitempty"` + ValueInfo *TextRecognitionInfo `xml:",omitempty"` + SpamInfo *TextRecognitionInfo `xml:",omitempty"` } // TextLibResult @@ -736,6 +741,8 @@ type TextSectionResult struct { AdsInfo *TextRecognitionInfo `xml:",omitempty"` IllegalInfo *TextRecognitionInfo `xml:",omitempty"` AbuseInfo *TextRecognitionInfo `xml:",omitempty"` + ValueInfo *TextRecognitionInfo `xml:",omitempty"` + SpamInfo *TextRecognitionInfo `xml:",omitempty"` } // 文本审核-查询任务 https://cloud.tencent.com/document/product/436/56288 @@ -1265,6 +1272,37 @@ func (s *CIService) GetQRcode(ctx context.Context, name string, cover int, opt * return &res, resp, err } +type GetQRcodeResultV2 struct { + XMLName xml.Name `xml:"Response"` + CodeStatus int `xml:"CodeStatus,omitempty"` + QRcodeInfo []QRcodeInfo `xml:"QRcodeInfo,omitempty"` + ResultImage string `xml:"ResultImage,omitempty"` +} + +// 二维码识别-下载时识别 https://cloud.tencent.com/document/product/436/54070 +func (s *CIService) GetQRcodeV2(ctx context.Context, name string, cover int, opt *ObjectGetOptions, id ...string) (*GetQRcodeResultV2, *Response, error) { + var u string + if len(id) == 1 { + u = fmt.Sprintf("/%s?versionId=%s&ci-process=QRcode&cover=%v", encodeURIComponent(name), id[0], cover) + } else if len(id) == 0 { + u = fmt.Sprintf("/%s?ci-process=QRcode&cover=%v", encodeURIComponent(name), cover) + } else { + return nil, nil, errors.New("wrong params") + } + + var res GetQRcodeResultV2 + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodGet, + optQuery: opt, + optHeader: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + type GenerateQRcodeOptions struct { QRcodeContent string `url:"qrcode-content,omitempty"` Mode int `url:"mode,omitempty"` @@ -1774,6 +1812,126 @@ func (s *CIService) FaceEffect(ctx context.Context, obj string, opt *FaceEffectO return &res, resp, err } +type PetEffectResult struct { + XMLName xml.Name `xml:"Response"` + ResultInfo []struct { + Score int `xml:"Score,omitempty"` + Name string `xml:"Name,omitempty"` + Location struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + Height int `xml:"Height,omitempty"` + Width int `xml:"Width,omitempty"` + } `xml:"Location,omitempty"` + } `xml:"ResultInfo,omitempty"` +} + +func (s *CIService) EffectPet(ctx context.Context, obj string) (*PetEffectResult, *Response, error) { + var res PetEffectResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + method: http.MethodGet, + uri: "/" + encodeURIComponent(obj) + "?ci-process=detect-pet", + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type PetDetectOption struct { + DetectUrl string `url:"detect-url,omitempty"` +} + +type PetDetectResult struct { + XMLName xml.Name `xml:"Response"` + ResultInfo []struct { + Score int `xml:"Score,omitempty"` + Name string `xml:"Name,omitempty"` + Location struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + Height int `xml:"Height,omitempty"` + Width int `xml:"Width,omitempty"` + } `xml:"Location,omitempty"` + } `xml:"ResultInfo,omitempty"` +} + +func (s *CIService) DetectPet(ctx context.Context, obj string, opt *PetDetectOption) (*PetDetectResult, *Response, error) { + var res PetDetectResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + method: http.MethodGet, + uri: "/" + encodeURIComponent(obj) + "?ci-process=detect-pet", + result: &res, + optQuery: opt, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type AILicenseRecOptions struct { + DetectUrl string `url:"detect-url,omitempty"` + CardType string `url:"CardType,omitempty"` +} + +type AILicenseRecResult struct { + XMLName xml.Name `xml:"Response"` + Status int `xml:"Status,omitempty"` + IdInfo []struct { + Name string `xml:"Name,omitempty"` + DetectedText string `xml:"DetectedText,omitempty"` + Score int `xml:"Score,omitempty"` + Location struct { + Point []string `xml:"Point,omitempty"` + } `xml:"Location,omitempty"` + } `xml:"IdInfo,omitempty"` +} + +func (s *CIService) AILicenseRec(ctx context.Context, obj string, opt *AILicenseRecOptions) (*AILicenseRecResult, *Response, error) { + var res AILicenseRecResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + method: http.MethodGet, + uri: "/" + encodeURIComponent(obj) + "?ci-process=AILicenseRec", + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type AIObjectDetectOptions struct { + DetectUrl string `url:"detect-url,omitempty"` +} + +type AIObjectDetectResult struct { + XMLName xml.Name `xml:"RecognitionResult"` + Status int `xml:"Status,omitempty"` + DetectMultiObj []struct { + Name string `xml:"Name,omitempty"` + Confidence int `xml:"Confidence,omitempty"` + Location struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + Width int `xml:"Width,omitempty"` + Height int `xml:"Height,omitempty"` + } `xml:"Location,omitempty"` + } `xml:"DetectMultiObj,omitempty"` +} + +func (s *CIService) AIObjectDetect(ctx context.Context, obj string, opt *AIObjectDetectOptions) (*AIObjectDetectResult, *Response, error) { + var res AIObjectDetectResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + method: http.MethodGet, + uri: "/" + encodeURIComponent(obj) + "?ci-process=AIObjectDetect", + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + type IdCardOCROptions struct { CardSide string `url:"CardSide,omitempty"` Config *IdCardOCROptionsConfig `url:"Config,omitempty"` @@ -2011,6 +2169,7 @@ func (s *CIService) LivenessRecognitionWhenUpload(ctx context.Context, obj, file type GoodsMattingptions struct { CenterLayout string `url:"center-layout,omitempty"` PaddingLayout string `url:"padding-layout,omitempty"` + DetectUrl string `url:"detect-url,omitempty"` } // GoodsMatting 商品抠图 @@ -2175,6 +2334,23 @@ func (s *CIService) GetAIImageColoring(ctx context.Context, name string) (*Respo return resp, err } +// AIImageColoringOptions TODO +type AIImageColoringOptions struct { + DetectUrl string `url:"detect-url,omitempty"` +} + +func (s *CIService) GetAIImageColoringV2(ctx context.Context, name string, opt *AIImageColoringOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=AIImageColoring", + method: http.MethodGet, + optQuery: opt, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + // GetAISuperResolution https://cloud.tencent.com/document/product/460/83793 func (s *CIService) GetAISuperResolution(ctx context.Context, name string) (*Response, error) { sendOpt := sendOptions{ @@ -2187,6 +2363,24 @@ func (s *CIService) GetAISuperResolution(ctx context.Context, name string) (*Res return resp, err } +// AIImageColoringOptions TODO +type AISuperResolutionOptions struct { + DetectUrl string `url:"detect-url,omitempty"` +} + +// GetAISuperResolution https://cloud.tencent.com/document/product/460/83793 +func (s *CIService) GetAISuperResolutionV2(ctx context.Context, name string, opt *AISuperResolutionOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=AISuperResolution", + method: http.MethodGet, + optQuery: opt, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + // GetAIEnhanceImage https://cloud.tencent.com/document/product/460/83792 func (s *CIService) GetAIEnhanceImage(ctx context.Context, name string) (*Response, error) { sendOpt := sendOptions{ @@ -2199,6 +2393,27 @@ func (s *CIService) GetAIEnhanceImage(ctx context.Context, name string) (*Respon return resp, err } +// AIEnhanceImageOptions 图像增强选项 +type AIEnhanceImageOptions struct { + DetectUrl string `url:"detect-url,omitempty"` + Senoise int `url:"denoise,omitempty"` + Sharpen int `url:"sharpen,omitempty"` + IgnoreError int `url:"ignore-error,omitempty"` +} + +// GetAIEnhanceImage https://cloud.tencent.com/document/product/460/83792 +func (s *CIService) GetAIEnhanceImageV2(ctx context.Context, name string, opt *AIEnhanceImageOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=AIEnhanceImage", + method: http.MethodGet, + optQuery: opt, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + // AIImageCropOptions 图像智能裁剪选项 type AIImageCropOptions struct { DetectUrl string `url:"detect-url,omitempty"` @@ -2253,8 +2468,9 @@ func (s *CIService) GetAutoTranslationBlock(ctx context.Context, opt *AutoTransl // ImageRepairOptions 图像修复选项 type ImageRepairOptions struct { - MaskPic string `url:"MaskPic,omitempty"` - MaskPoly string `url:"MaskPoly,omitempty"` + DetectUrl string `url:"detect-url,omitempty"` + MaskPic string `url:"MaskPic,omitempty"` + MaskPoly string `url:"MaskPoly,omitempty"` } // GetImageRepair https://cloud.tencent.com/document/product/460/79042 @@ -2341,3 +2557,234 @@ func (s *CIService) TDCRefresh(ctx context.Context, name string) (*Response, err resp, err := s.client.send(ctx, &sendOpt) return resp, err } + +type AIGameRecOptions struct { + DetectUrl string `url:"detect-url,omitempty"` +} + +type AIGameRecResult struct { + XMLName xml.Name `xml:"RecognitionResult"` + GameLabels *struct { + Confidence int `xml:"Confidence,omitempty"` + FirstCategory string `xml:"FirstCategory,omitempty"` + SecondCategory string `xml:"SecondCategory,omitempty"` + GameName string `xml:"GameName,omitempty"` + } `xml:"GameLabels,omitempty"` +} + +func (s *CIService) AIGameRec(ctx context.Context, obj string, opt *AIGameRecOptions) (*AIGameRecResult, *Response, error) { + var res AIGameRecResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + method: http.MethodGet, + uri: "/" + encodeURIComponent(obj) + "?ci-process=AIGameRec", + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +type AIPicMattingOptions struct { + DetectUrl string `url:"detect-url, omitempty" json:"-"` // 您可以通过填写 detect-url 处理任意公网可访问的图片链接。不填写 detect-url 时,后台会默认处理 ObjectKey ,填写了 detect-url 时,后台会处理 detect-url 链接,无需再填写 ObjectKey detect-url 示例:http://www.example.com/abc.jpg ,需要进行 UrlEncode,处理后为http%25253A%25252F%25252Fwww.example.com%25252Fabc.jpg。 + CenterLayout int `url:"center-layout, omitempty" json:"-"` // 抠图主体居中显示;值为1时居中显示,值为0不做处理,默认为0 + PaddingLayout string `url:"padding-layout, omitempty" json:"-"` // 将处理后的图片四边进行留白,形式为 padding-layout=x,左右两边各进行 dx 像素的留白,上下两边各进行 dy 像素的留白,例如:padding-layout=20x10默认不进行留白操作,dx、dy 最大值为1000像素。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +// 通用抠图 +// https://cloud.tencent.com/document/product/460/106750 +func (s *CIService) AIPicMatting(ctx context.Context, ObjectKey string, opt *AIPicMattingOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(ObjectKey) + "?ci-process=AIPicMatting", + method: http.MethodGet, + optQuery: opt, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +type AIPortraitMattingOptions struct { + DetectUrl string `url:"detect-url, omitempty" json:"-"` // 您可以通过填写 detect-url 处理任意公网可访问的图片链接。不填写 detect-url 时,后台会默认处理 ObjectKey ,填写了 detect-url 时,后台会处理 detect-url 链接,无需再填写 ObjectKey。 detect-url 示例:http://www.example.com/abc.jpg,需要进行 UrlEncode,处理后为http%25253A%25252F%25252Fwww.example.com%25252Fabc.jpg。 + CenterLayout int `url:"center-layout, omitempty" json:"-"` // 抠图主体居中显示;值为1时居中显示,值为0不做处理,默认为0 + PaddingLayout string `url:"padding-layout, omitempty" json:"-"` // 将处理后的图片四边进行留白,形式为 padding-layout=x,左右两边各进行 dx 像素的留白,上下两边各进行 dy 像素的留白,例如:padding-layout=20x10默认不进行留白操作,dx、dy最大值为1000像素。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +// 人像抠图 +// https://cloud.tencent.com/document/product/460/106751 +func (s *CIService) AIPortraitMatting(ctx context.Context, ObjectKey string, opt *AIPortraitMattingOptions) (*Response, error) { + + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(ObjectKey) + "?ci-process=AIPortraitMatting", + method: http.MethodGet, + optQuery: opt, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + +type AIRecognitionResult struct { + XMLName xml.Name `xml:"Response" json:"response,omitempty"` + // BodyJointsDetect struct { + // BodyJointsResults []struct { + // BodyJoints []struct { + // KeyPointType string `xml:"KeyPointType"` + // X string `xml:"X"` + // Y string `xml:"Y"` + // } `xml:"BodyJoints" json:"bodyjoints,omitempty"` + // BoundBox struct { + // Height string `xml:"Height"` + // Width string `xml:"Width"` + // X string `xml:"X"` + // Y string `xml:"Y"` + // } `xml:"BoundBox" json:"boundbox,omitempty"` + // Confidence string `xml:"Confidence"` + // } `xml:"BodyJointsResults" json:"bodyjointsresults,omitempty"` + // RequestId string `xml:"RequestId"` + // } `xml:"BodyJointsDetect" json:"bodyjointsdetect,omitempty"` + // DetectLabel struct { + // Labels []struct { + // Confidence string `xml:"Confidence"` + // Name string `xml:"Name"` + // } `xml:"Labels" json:"labels,omitempty"` + // } `xml:"DetectLabel" json:"detectlabel,omitempty"` + // OCR struct { + // Angel string `xml:"Angel"` + // Language string `xml:"Language"` + // PdfPageSize string `xml:"PdfPageSize"` + // RequestId string `xml:"RequestId"` + // TextDetections []struct { + // Confidence string `xml:"Confidence"` + // DetectedText string `xml:"DetectedText"` + // ItemPolygon struct { + // Height string `xml:"Height"` + // Width string `xml:"Width"` + // X string `xml:"X"` + // Y string `xml:"Y"` + // } `xml:"ItemPolygon" json:"itempolygon,omitempty"` + // Polygon []struct { + // X string `xml:"X"` + // Y string `xml:"Y"` + // } `xml:"Polygon" json:"polygon,omitempty"` + // Words string `xml:"Words"` + // } `xml:"TextDetections" json:"textdetections,omitempty"` + // } `xml:"OCR" json:"ocr,omitempty"` + // EnhanceImage struct { + // EnhancedImage string `xml:"EnhancedImage"` + // } `xml:"EnhanceImage" json:"enhanceimage,omitempty"` + DetectVehicle struct { + Vehicles []struct { + Location struct { + Height int `xml:"Height"` + Width int `xml:"Width"` + X int `xml:"X"` + Y int `xml:"Y"` + } `xml:"Location" json:"location,omitempty"` + Name string `xml:"Name"` + Score int `xml:"Score"` + } `xml:"Vehicles" json:"vehicles,omitempty"` + } `xml:"DetectVehicle" json:"detectvehicle,omitempty"` + DetectPedestrian struct { + Pedestrians []struct { + Location struct { + Height int `xml:"Height"` + Width int `xml:"Width"` + X int `xml:"X"` + Y int `xml:"Y"` + } `xml:"Location" json:"location,omitempty"` + Name string `xml:"Name"` + Score int `xml:"Score"` + } `xml:"Pedestrians" json:"pedestrians,omitempty"` + } `xml:"DetectPedestrian" json:"detectpedestrian,omitempty"` + DetectPet struct { + Pets []struct { + Location struct { + Height int `xml:"Height"` + Width int `xml:"Width"` + X int `xml:"X"` + Y int `xml:"Y"` + } `xml:"Location" json:"location,omitempty"` + Name string `xml:"Name"` + Score int `xml:"Score"` + } `xml:"Pets" json:"pets,omitempty"` + } `xml:"DetectPet" json:"detectpet,omitempty"` +} + +type AIRecognitionOptions struct { + DetectType string `url:"detect-type, omitempty" json:"-"` + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +// 多AI接口合一 +func (s *CIService) AIRecognition(ctx context.Context, ObjectKey string, opt *AIRecognitionOptions) (*AIRecognitionResult, *Response, error) { + var res AIRecognitionResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(ObjectKey) + "?ci-process=ai-recognition", + method: http.MethodGet, + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type ImageSlimSuffixs struct { + Suffix []string `xml:"Suffix,omitempty"` +} + +type ImageSlim struct { + XMLName xml.Name `xml:"ImageSlim"` + SlimMode string `xml:"SlimMode,omitempty"` + Suffixs *ImageSlimSuffixs `xml:"Suffixs,omitempty"` +} + +type ImageSlimResult struct { + XMLName xml.Name `xml:"ImageSlim"` + SlimMode string `xml:"SlimMode,omitempty"` + Status string `xml:"Status,omitempty"` + Suffixs *ImageSlimSuffixs `xml:"Suffixs,omitempty"` +} + +type ImageSlimOptions ImageSlim + +// 开通 极智压缩ImageSlim https://cloud.tencent.com/document/product/460/95042 +func (s *CIService) PutImageSlim(ctx context.Context, opt *ImageSlimOptions) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/?image-slim", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +// 查询 极智压缩ImageSlim https://cloud.tencent.com/document/product/460/95043 +func (s *CIService) GetImageSlim(ctx context.Context) (*ImageSlimResult, *Response, error) { + var res ImageSlimResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/?image-slim", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +// 关闭 极智压缩ImageSlim https://cloud.tencent.com/document/product/460/95044 +func (s *CIService) DeleteImageSlim(ctx context.Context) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/?image-slim", + method: http.MethodDelete, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_doc.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_doc.go index dd3dfe47cb..df1ebf376f 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_doc.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_doc.go @@ -1,9 +1,11 @@ package cos import ( + "bytes" "context" "encoding/json" "encoding/xml" + "io" "net/http" "net/url" ) @@ -293,9 +295,58 @@ func (s *CIService) DocPreview(ctx context.Context, name string, opt *DocPreview return resp, err } +type CIDocCompareOptions struct { + Object string `url:"object,omitempty"` + ComparePath string `url:"comparePath,omitempty"` + CompareUrl string `url:"compareUrl,omitempty"` + SrcType string `url:"srcType,omitempty"` + TgtUri string `url:"tgtUri,omitempty"` +} + +type CIDocCompareResult struct { + XMLName xml.Name `xml:"Response"` + Code string `xml:"Code,omitempty" json:"code,omitempty"` + ETag string `xml:"ETag,omitempty" json:"eTag,omitempty"` + Msg string `xml:"Msg,omitempty" json:"msg,omitempty"` + ResultPath string `xml:"ResultPath,omitempty" json:"resultPath,omitempty"` +} + +// 优先 json +func (w *CIDocCompareResult) Write(p []byte) (n int, err error) { + err = json.Unmarshal(p, w) + if err != nil { + err = xml.NewDecoder(bytes.NewReader(p)).Decode(w) + if err == nil { + return len(p), nil + } + if err == io.EOF { + err = nil // ignore EOF errors caused by empty response body + } + return 0, err + } + return len(p), nil +} + +// DocCompare TODO +func (s *CIService) CIDocCompare(ctx context.Context, opt *CIDocCompareOptions) (*Response, *CIDocCompareResult, error) { + var res CIDocCompareResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/doccompare", + optQuery: opt, + method: http.MethodGet, + disableCloseBody: true, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, &res, err +} + type DocPreviewHTMLOptions struct { DstType string `url:"dstType,omitempty"` SrcType string `url:"srcType,omitempty"` + WebofficeUrl string `url:"weboffice_url,omitempty"` + TokenUid string `url:"tokenuid,omitempty"` Sign string `url:"sign,omitempty"` Copyable string `url:"copyable,omitempty"` HtmlParams *HtmlParams `url:"htmlParams,omitempty"` diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_fileprocess.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_fileprocess.go index 78250b5673..d737cae05f 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_fileprocess.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_fileprocess.go @@ -21,9 +21,16 @@ type FileHashCodeResult struct { } type FileUncompressConfig struct { - Prefix string `xml:",omitempty"` - PrefixReplaced string `xml:",omitempty"` - UnCompressKey string `xml:",omitempty"` + Prefix string `xml:",omitempty"` + PrefixReplaced string `xml:",omitempty"` + UnCompressKey string `xml:",omitempty"` + Mode string `xml:",omitempty"` + DownloadConfig *FileUncompressDownloadConfig `xml:",omitempty"` +} + +type FileUncompressDownloadConfig struct { + Prefix string `xml:",omitempty"` + Key []string `xml:",omitempty"` } type FileUncompressResult struct { @@ -32,20 +39,37 @@ type FileUncompressResult struct { FileCount string `xml:",omitempty"` } +type KeyConfig struct { + Key string `xml:",omitempty"` + Folder string `xml:",omitempty"` + Rename string `xml:",omitempty"` + ImageParams string `xml:",omitempty"` +} + type FileCompressConfig struct { - Flatten string `xml:",omitempty"` - Format string `xml:",omitempty"` - UrlList string `xml:",omitempty"` - Prefix string `xml:",omitempty"` - Key []string `xml:",omitempty"` - Type string `xml:",omitempty"` - CompressKey string `xml:",omitempty"` + Flatten string `xml:",omitempty"` + Format string `xml:",omitempty"` + UrlList string `xml:",omitempty"` + Prefix string `xml:",omitempty"` + Key []string `xml:",omitempty"` + Type string `xml:",omitempty"` + CompressKey string `xml:",omitempty"` + IgnoreError string `xml:",omitempty"` + KeyConfig []KeyConfig `xml:",omitempty"` } type FileCompressResult struct { - Region string `xml:",omitempty"` - Bucket string `xml:",omitempty"` - Object string `xml:",omitempty"` + Region string `xml:",omitempty"` + Bucket string `xml:",omitempty"` + Object string `xml:",omitempty"` + CompressFileCount int `xml:",omitempty"` + ErrorCount int `xml:",omitempty"` + ErrorDetail *ErrorDetail `xml:",omitempty"` +} + +type ErrorDetail struct { + ErrorCount string `xml:",omitempty"` + ErrorFile []string `xml:",omitempty"` } type FileProcessInput FileCompressResult @@ -89,6 +113,7 @@ type FileProcessJobsDetail struct { StartTime string `xml:",omitempty"` EndTime string `xml:",omitempty"` QueueId string `xml:",omitempty"` + Progress int `xml:",omitempty"` Input *FileProcessInput `xml:",omitempty"` Operation *FileProcessJobOperation `xml:",omitempty"` } @@ -154,9 +179,10 @@ func (s *CIService) GetFileHash(ctx context.Context, name string, opt *GetFileHa // ZipPreviewResult 压缩包预览结果 type ZipPreviewResult struct { - XMLName xml.Name `xml:"Response"` - FileNumber int `xml:"FileNumber,omitempty"` - Contents []*struct { + XMLName xml.Name `xml:"Response"` + FileNumber int `xml:"FileNumber,omitempty"` + IsTruncated bool `xml:"IsTruncated,omitempty"` + Contents []*struct { Key string `xml:"Key,omitempty"` LastModified string `xml:"LastModified,omitempty"` UncompressedSize int `xml:"UncompressedSize,omitempty"` @@ -164,11 +190,15 @@ type ZipPreviewResult struct { } // ZipPreview 压缩包预览 -func (s *CIService) ZipPreview(ctx context.Context, name string) (*ZipPreviewResult, *Response, error) { +func (s *CIService) ZipPreview(ctx context.Context, name, uncompress_key string) (*ZipPreviewResult, *Response, error) { var res ZipPreviewResult + uriStr := "/" + encodeURIComponent(name) + "?ci-process=zippreview" + if uncompress_key != "" { + uriStr += "&uncompress-key=" + encodeURIComponent(uncompress_key) + } sendOpt := sendOptions{ baseURL: s.client.BaseURL.BucketURL, - uri: "/" + encodeURIComponent(name) + "?ci-process=zippreview", + uri: uriStr, method: http.MethodGet, result: &res, } diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_media.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_media.go index 13ace1ecb8..550d04ea67 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_media.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_media.go @@ -1,18 +1,26 @@ package cos import ( + "bytes" "context" + "encoding/json" "encoding/xml" "errors" "fmt" "net/http" "sort" "strings" + "time" "github.com/clbanning/mxj" "github.com/mitchellh/mapstructure" ) +type VodInfo struct { + FileId string `xml:"FileId,omitempty"` + SubAppId string `xml:"SubAppId,omitempty"` +} + // JobInput TODO type JobInput struct { Object string `xml:"Object,omitempty"` @@ -23,6 +31,8 @@ type JobInput struct { Key string `xml:"Key"` Value string `xml:"Value"` } `xml:"CosHeaders"` + Url string `xml:"Url,omitempty"` + Vod *VodInfo `xml:"Vod,omitempty"` } // StreamExtract TODO @@ -38,6 +48,8 @@ type JobOutput struct { Object string `xml:"Object,omitempty"` SpriteObject string `xml:"SpriteObject,omitempty"` AuObject string `xml:"AuObject,omitempty"` + BassObject string `xml:"BassObject,omitempty"` + DrumObject string `xml:"DrumObject,omitempty"` StreamExtract []StreamExtract `xml:"StreamExtract,omitempty"` } @@ -54,30 +66,38 @@ type Container struct { // Video TODO type Video struct { - Codec string `xml:"Codec"` - Width string `xml:"Width,omitempty"` - Height string `xml:"Height,omitempty"` - Fps string `xml:"Fps,omitempty"` - Remove string `xml:"Remove,omitempty"` - Profile string `xml:"Profile,omitempty"` - Bitrate string `xml:"Bitrate,omitempty"` - Crf string `xml:"Crf,omitempty"` - Gop string `xml:"Gop,omitempty"` - Preset string `xml:"Preset,omitempty"` - Bufsize string `xml:"Bufsize,omitempty"` - Maxrate string `xml:"Maxrate,omitempty"` - HlsTsTime string `xml:"HlsTsTime,omitempty"` - DashSegment string `xml:"DashSegment,omitempty"` - Pixfmt string `xml:"Pixfmt,omitempty"` - LongShortMode string `xml:"LongShortMode,omitempty"` - Rotate string `xml:"Rotate,omitempty"` - AnimateOnlyKeepKeyFrame string `xml:"AnimateOnlyKeepKeyFrame,omitempty"` - AnimateTimeIntervalOfFrame string `xml:"AnimateTimeIntervalOfFrame,omitempty"` - AnimateFramesPerSecond string `xml:"AnimateFramesPerSecond,omitempty"` - Quality string `xml:"Quality,omitempty"` - Roi string `xml:"Roi,omitempty"` - Crop string `xml:"Crop,omitempty"` - Interlaced string `xml:"Interlaced,omitempty"` + Codec string `xml:"Codec"` + Width string `xml:"Width,omitempty"` + Height string `xml:"Height,omitempty"` + Fps string `xml:"Fps,omitempty"` + Remove string `xml:"Remove,omitempty"` + Profile string `xml:"Profile,omitempty"` + Bitrate string `xml:"Bitrate,omitempty"` + Crf string `xml:"Crf,omitempty"` + Gop string `xml:"Gop,omitempty"` + Preset string `xml:"Preset,omitempty"` + Bufsize string `xml:"Bufsize,omitempty"` + Maxrate string `xml:"Maxrate,omitempty"` + HlsTsTime string `xml:"HlsTsTime,omitempty"` + DashSegment string `xml:"DashSegment,omitempty"` + Pixfmt string `xml:"Pixfmt,omitempty"` + LongShortMode string `xml:"LongShortMode,omitempty"` + Rotate string `xml:"Rotate,omitempty"` + AnimateOnlyKeepKeyFrame string `xml:"AnimateOnlyKeepKeyFrame,omitempty"` + AnimateTimeIntervalOfFrame string `xml:"AnimateTimeIntervalOfFrame,omitempty"` + AnimateFramesPerSecond string `xml:"AnimateFramesPerSecond,omitempty"` + Quality string `xml:"Quality,omitempty"` + Roi string `xml:"Roi,omitempty"` + Crop string `xml:"Crop,omitempty"` + Interlaced string `xml:"Interlaced,omitempty"` + ColorParam *VideoColorParam `xml:"ColorParam,omitempty"` +} + +type VideoColorParam struct { + ColorRange string `xml:"ColorRange,omitempty"` + ColorSpace string `xml:"ColorSpace,omitempty"` + ColorTrc string `xml:"ColorTrc,omitempty"` + ColorPrimaries string `xml:"ColorPrimaries,omitempty"` } // TranscodeProVideo TODO @@ -262,6 +282,7 @@ type ConcatFragment struct { StartTime string `xml:"StartTime,omitempty"` EndTime string `xml:"EndTime,omitempty"` FragmentIndex string `xml:"FragmentIndex,omitempty"` + Duration string `xml:"Duration,omitempty"` } // ConcatTemplate TODO @@ -274,6 +295,7 @@ type ConcatTemplate struct { AudioMix *AudioMix `xml:"AudioMix,omitempty"` AudioMixArray []AudioMix `xml:"AudioMixArray,omitempty"` SceneChangeInfo *SceneChangeInfo `xml:"SceneChangeInfo,omitempty"` + DirectConcat string `xml:"DirectConcat,omitempty"` } // SceneChangeInfo 转场参数 @@ -339,9 +361,12 @@ type HlsEncrypt struct { // Segment TODO type Segment struct { - Format string `xml:"Format,omitempty"` - Duration string `xml:"Duration,omitempty"` - HlsEncrypt *HlsEncrypt `xml:"HlsEncrypt,omitempty"` + Format string `xml:"Format,omitempty"` + Duration string `xml:"Duration,omitempty"` + TranscodeIndex string `xml:"TranscodeIndex,omitempty"` + HlsEncrypt *HlsEncrypt `xml:"HlsEncrypt,omitempty"` + StartTime string `xml:"StartTime,omitempty"` + EndTime string `xml:"EndTime,omitempty"` } // VideoMontageVideo TODO @@ -432,12 +457,19 @@ type Subtitles struct { // Subtitle TODO type Subtitle struct { - Url []Subtitle `xml:"Url,omitempty"` + Url string `xml:"Url,omitempty"` + Embed string `xml:"Embed,omitempty"` + FontType string `xml:"FontType,omitempty"` + FontSize string `xml:"FontSize,omitempty"` + FontColor string `xml:"FontColor,omitempty"` + OutlineColor string `xml:"OutlineColor,omitempty"` + VMargin string `xml:"VMargin,omitempty"` } // VideoTag TODO type VideoTag struct { - Scenario string `xml:"Scenario,omitempty"` + Scenario string `xml:"Scenario,omitempty"` // 1. Stream 2. ShortVideo + Text string `xml:"Text,omitempty"` } // VideoTagResult TODO @@ -459,6 +491,7 @@ type VideoTagResultStreamDataData struct { PlaceTags []VideoTagResultStreamDataDataPlaceTags `xml:"PlaceTags,omitempty"` ActionTags []VideoTagResultStreamDataDataActionTags `xml:"ActionTags,omitempty"` ObjectTags []VideoTagResultStreamDataDataObjectTags `xml:"ObjectTags,omitempty"` + Labels []VideoTagResultStreamDataDataLabels `xml:"Labels,omitempty"` } // VideoTagResultStreamDataDataTags TODO @@ -515,6 +548,12 @@ type VideoTagResultStreamDataDataObjectTags struct { TimeStamp string `xml:"TimeStamp,omitempty"` } +type VideoTagResultStreamDataDataLabels struct { + First string `xml:"First,omitempty"` + Second string `xml:"Second,omitempty"` + Confidence float64 `xml:"Confidence,omitempty"` +} + // QualityEstimate TODO type QualityEstimate struct { Score string `xml:"Score,omitempty"` @@ -731,20 +770,30 @@ type MediaProcessJobOperation struct { SoundHoundResult *SoundHoundResult `xml:"SoundHoundResult,omitempty"` FillConcat *FillConcat `xml:"FillConcat,omitempty"` VideoSynthesis *VideoSynthesis `xml:"VideoSynthesis,omitempty"` + DnaConfig *DnaConfig `xml:"DnaConfig,omitempty"` + DnaResult *DnaResult `xml:"DnaResult,omitempty"` + VocalScore *VocalScore `xml:"VocalScore,omitempty"` + VocalScoreResult *VocalScoreResult `xml:"VocalScoreResult,omitempty"` + ImageInspect *ImageInspect `xml:"ImageInspect,omitempty"` + ImageInspectResult *ImageInspectResult `xml:"ImageInspectResult,omitempty"` + SnapshotPrefix string `xml:"SnapshotPrefix,omitempty"` + ImageOCR *ImageOCRTemplate `xml:"ImageOCR,omitempty"` + Detection *ImageOCRDetection `xml:"Detection,omitempty"` } // CreatePicJobsOptions TODO type CreatePicJobsOptions struct { - XMLName xml.Name `xml:"Request"` - Tag string `xml:"Tag,omitempty"` - Input *JobInput `xml:"Input,omitempty"` - Operation *PicProcessJobOperation `xml:"Operation,omitempty"` - QueueId string `xml:"QueueId,omitempty"` - CallBack string `xml:"CallBack,omitempty"` - QueueType string `xml:"QueueType,omitempty"` - CallBackFormat string `xml:"CallBackFormat,omitempty"` - CallBackType string `xml:"CallBackType,omitempty"` - CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"` + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Input *JobInput `xml:"Input,omitempty"` + Operation *PicProcessJobOperation `xml:"Operation,omitempty"` + QueueId string `xml:"QueueId,omitempty"` + CallBack string `xml:"CallBack,omitempty"` + QueueType string `xml:"QueueType,omitempty"` + CallBackFormat string `xml:"CallBackFormat,omitempty"` + CallBackType string `xml:"CallBackType,omitempty"` + CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"` + CallBackKafkaConfig *KafkaConfig `xml:"CallBackKafkaConfig,omitempty"` } // CreateAIJobsOptions TODO @@ -752,16 +801,17 @@ type CreateAIJobsOptions CreateMediaJobsOptions // CreateMediaJobsOptions TODO type CreateMediaJobsOptions struct { - XMLName xml.Name `xml:"Request"` - Tag string `xml:"Tag,omitempty"` - Input *JobInput `xml:"Input,omitempty"` - Operation *MediaProcessJobOperation `xml:"Operation,omitempty"` - QueueId string `xml:"QueueId,omitempty"` - QueueType string `xml:"QueueType,omitempty"` - CallBackFormat string `xml:"CallBackFormat,omitempty"` - CallBackType string `xml:"CallBackType,omitempty"` - CallBack string `xml:"CallBack,omitempty"` - CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"` + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Input *JobInput `xml:"Input,omitempty"` + Operation *MediaProcessJobOperation `xml:"Operation,omitempty"` + QueueId string `xml:"QueueId,omitempty"` + QueueType string `xml:"QueueType,omitempty"` + CallBackFormat string `xml:"CallBackFormat,omitempty"` + CallBackType string `xml:"CallBackType,omitempty"` + CallBack string `xml:"CallBack,omitempty"` + CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"` + CallBackKafkaConfig *KafkaConfig `xml:"CallBackKafkaConfig,omitempty"` } // NotifyConfigCallBackMqConfig TODO @@ -808,16 +858,17 @@ type CreateMediaJobsResult struct { // CreateMultiMediaJobsOptions TODO type CreateMultiMediaJobsOptions struct { - XMLName xml.Name `xml:"Request"` - Tag string `xml:"Tag,omitempty"` - Input *JobInput `xml:"Input,omitempty"` - Operation []MediaProcessJobOperation `xml:"Operation,omitempty"` - QueueId string `xml:"QueueId,omitempty"` - QueueType string `xml:"QueueType,omitempty"` - CallBackFormat string `xml:"CallBackFormat,omitempty"` - CallBackType string `xml:"CallBackType,omitempty"` - CallBack string `xml:"CallBack,omitempty"` - CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"` + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Input *JobInput `xml:"Input,omitempty"` + Operation []MediaProcessJobOperation `xml:"Operation,omitempty"` + QueueId string `xml:"QueueId,omitempty"` + QueueType string `xml:"QueueType,omitempty"` + CallBackFormat string `xml:"CallBackFormat,omitempty"` + CallBackType string `xml:"CallBackType,omitempty"` + CallBack string `xml:"CallBack,omitempty"` + CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"` + CallBackKafkaConfig *KafkaConfig `xml:"CallBackKafkaConfig,omitempty"` } // CreateMultiMediaJobsResult TODO @@ -865,11 +916,12 @@ type WorkflowExecutionNotifyBody struct { ObjectCount int `xml:"ObjectCount"` SpriteObjectCount int `xml:"SpriteObjectCount"` ObjectInfo []struct { - ObjectName string `xml:"ObjectName"` - ObjectUrl string `xml:"ObjectUrl"` - InputObjectName string `xml:"InputObjectName"` - Code string `xml:"Code"` - Message string `xml:"Message"` + ObjectName string `xml:"ObjectName"` + ObjectUrl string `xml:"ObjectUrl"` + InputObjectName string `xml:"InputObjectName"` + Code string `xml:"Code"` + Message string `xml:"Message"` + ImageOcrResult *ImageOCRDetection `xml:"ImageOcrResult,omitempty"` } `xml:"ObjectInfo,omitempty"` SpriteObjectInfo []struct { ObjectName string `xml:"ObjectName"` @@ -1095,14 +1147,21 @@ type MediaProcessQueue struct { // MediaProcessQueueNotifyConfig TODO type MediaProcessQueueNotifyConfig struct { - Url string `xml:"Url,omitempty"` - State string `xml:"State,omitempty"` - Type string `xml:"Type,omitempty"` - Event string `xml:"Event,omitempty"` - ResultFormat string `xml:"ResultFormat,omitempty"` - MqMode string `xml:"MqMode,omitempty"` - MqRegion string `xml:"MqRegion,omitempty"` - MqName string `xml:"MqName,omitempty"` + Url string `xml:"Url,omitempty"` + State string `xml:"State,omitempty"` + Type string `xml:"Type,omitempty"` + Event string `xml:"Event,omitempty"` + ResultFormat string `xml:"ResultFormat,omitempty"` + MqMode string `xml:"MqMode,omitempty"` + MqRegion string `xml:"MqRegion,omitempty"` + MqName string `xml:"MqName,omitempty"` + KafkaConfig *KafkaConfig `xml:"KafkaConfig,omitempty"` +} + +type KafkaConfig struct { + Region string `xml:"Region,omitempty"` + InstanceId string `xml:"InstanceId,omitempty"` + Topic string `xml:"Topic,omitempty"` } // DescribeMediaProcessQueues TODO @@ -1161,6 +1220,23 @@ func (s *CIService) DescribeASRProcessQueues(ctx context.Context, opt *DescribeM return &res, resp, err } +type DescribeFielProcessQueuesOptions DescribeMediaProcessQueuesOptions +type DescribeFileProcessQueuesResult DescribeMediaProcessQueuesResult + +// DescribeFileProcessQueues TODO +func (s *CIService) DescribeFileProcessQueues(ctx context.Context, opt *DescribeFielProcessQueuesOptions) (*DescribeFileProcessQueuesResult, *Response, error) { + var res DescribeFileProcessQueuesResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/file_queue", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + // UpdateMediaProcessQueueOptions TODO type UpdateMediaProcessQueueOptions struct { XMLName xml.Name `xml:"Request"` @@ -1270,6 +1346,27 @@ type MediaProcessBucket struct { CreateTime string `xml:"CreateTime,omitempty"` } +type CreateMediaProcessBucketOptions struct { +} + +type CreateMediaProcessBucketResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + MediaBucket MediaProcessBucket `xml:"MediaBucket,omitempty"` +} + +func (s *CIService) CreateMediaProcessBucket(ctx context.Context, opt *CreateMediaProcessBucketOptions) (*CreateMediaProcessBucketResult, *Response, error) { + var res CreateMediaProcessBucketResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/mediabucket", + method: http.MethodPost, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + // DescribeMediaProcessBuckets TODO // 媒体bucket接口 https://cloud.tencent.com/document/product/436/48988 func (s *CIService) DescribeMediaProcessBuckets(ctx context.Context, opt *DescribeMediaProcessBucketsOptions) (*DescribeMediaProcessBucketsResult, *Response, error) { @@ -1352,9 +1449,9 @@ type GetMediaInfoResult struct { func (s *CIService) GetMediaInfo(ctx context.Context, name string, opt *ObjectGetOptions, id ...string) (*GetMediaInfoResult, *Response, error) { var u string if len(id) == 1 { - u = fmt.Sprintf("/%s?versionId=%s&ci-process=videoinfo", encodeURIComponent(name), id[0]) + u = fmt.Sprintf("/%s?versionId=%s&ci-process=videoinfo", encodeURIComponent(name, []byte{'/'}), id[0]) } else if len(id) == 0 { - u = fmt.Sprintf("/%s?ci-process=videoinfo", encodeURIComponent(name)) + u = fmt.Sprintf("/%s?ci-process=videoinfo", encodeURIComponent(name, []byte{'/'})) } else { return nil, nil, fmt.Errorf("wrong params") } @@ -1372,6 +1469,74 @@ func (s *CIService) GetMediaInfo(ctx context.Context, name string, opt *ObjectGe return &res, resp, err } +type PlayKey struct { + MasterPlayKey string `xml:"MasterPlayKey"` + BackupPlayKey string `xml:"BackupPlayKey"` +} + +type PlayKeyResult struct { + XMLName xml.Name `xml:"Response"` + PlayKeyList *PlayKey `xml:"PlayKeyList"` +} + +func (s *CIService) CreatePlayKey(ctx context.Context) (*PlayKeyResult, *Response, error) { + var res PlayKeyResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/playKey", + method: http.MethodPost, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +func (s *CIService) CreateMediaPlayKey(ctx context.Context) (*PlayKeyResult, *Response, error) { + return s.CreatePlayKey(ctx) +} + +func (s *CIService) GetPlayKey(ctx context.Context) (*PlayKeyResult, *Response, error) { + var res PlayKeyResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/playKey", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +func (s *CIService) DescribeMediaPlayKey(ctx context.Context) (*PlayKeyResult, *Response, error) { + var res PlayKeyResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/playKey", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +type UpdateMediaPlayKeyOptions struct { + MasterPlayKey string `url:"masterPlayKey,omitempty"` + BackupPlayKey string `url:"backupPlayKey,omitempty"` +} + +func (s *CIService) UpdateMediaPlayKey(ctx context.Context, opt *UpdateMediaPlayKeyOptions) (*PlayKeyResult, *Response, error) { + var res PlayKeyResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/playKey", + method: http.MethodPut, + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + // GenerateMediaInfoOptions TODO type GenerateMediaInfoOptions struct { XMLName xml.Name `xml:"Request"` @@ -1393,6 +1558,80 @@ func (s *CIService) GenerateMediaInfo(ctx context.Context, opt *GenerateMediaInf return &res, resp, err } +// GenerateMediaInfoOptions TODO +type GenerateAVInfoOptions struct { + XMLName xml.Name `xml:"Request"` + Input *JobInput `xml:"Input,omitempty"` + OptHeaders *OptHeaders `header:"-,omitempty" url:"-" json:"-" xml:"-"` +} +type GetAVInfoResult struct { + Format struct { + BitRate string `json:"bit_rate"` + Duration string `json:"duration"` + FormatLongName string `json:"format_long_name"` + FormatName string `json:"format_name"` + NbPrograms int `json:"nb_programs"` + NbStreams int `json:"nb_streams"` + Size string `json:"size"` + StartTime string `json:"start_time"` + } `json:"format"` + Streams []struct { + AvgFrameRate string `json:"avg_frame_rate,omitempty"` + BitRate string `json:"bit_rate"` + CodecLongName string `json:"codec_long_name"` + CodecName string `json:"codec_name"` + CodecTag string `json:"codec_tag"` + CodecTagString string `json:"codec_tag_string"` + CodecTimeBase string `json:"codec_time_base"` + CodecType string `json:"codec_type"` + ColorPrimaries string `json:"color_primaries,omitempty"` + ColorRange string `json:"color_range,omitempty"` + ColorTransfer string `json:"color_transfer,omitempty"` + CreationTime time.Time `json:"creation_time"` + DisplayAspectRatio string `json:"display_aspect_ratio,omitempty"` + Duration string `json:"duration"` + FiledOrder string `json:"filed_order,omitempty"` + HasBFrames string `json:"has_b_frames,omitempty"` + Height int `json:"height,omitempty"` + Index int `json:"index"` + Language string `json:"language"` + Level int `json:"level,omitempty"` + NbFrames string `json:"nb_frames,omitempty"` + PixFmt string `json:"pix_fmt,omitempty"` + Profile string `json:"profile,omitempty"` + RFrameRate string `json:"r_frame_rate,omitempty"` + Refs int `json:"refs,omitempty"` + Rotation string `json:"rotation,omitempty"` + SampleAspectRatio string `json:"sample_aspect_ratio,omitempty"` + StartTime string `json:"start_time"` + Timebase string `json:"timebase"` + Width int `json:"width,omitempty"` + ChannelLayout string `json:"channel_layout,omitempty"` + Channels int `json:"channels,omitempty"` + SampleFmt string `json:"sample_fmt,omitempty"` + SampleRate string `json:"sample_rate,omitempty"` + } `json:"streams"` +} + +// GenerateMediaInfo TODO +// 生成媒体信息接口,支持大文件,耗时较大请求 +func (s *CIService) GenerateAVInfo(ctx context.Context, opt *GenerateAVInfoOptions) (*GetAVInfoResult, *Response, error) { + var buf bytes.Buffer + var res GetAVInfoResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/avinfo", + method: http.MethodPost, + body: opt, + result: &buf, + } + resp, err := s.client.send(ctx, &sendOpt) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + // GetSnapshotOptions TODO type GetSnapshotOptions struct { Time float32 `url:"time,omitempty"` @@ -1459,6 +1698,19 @@ func (s *CIService) PostSnapshot(ctx context.Context, opt *PostSnapshotOptions) return &res, resp, err } +// PostCISnapshot +func (s *CIService) PostCISnapshot(ctx context.Context, opt *PostSnapshotOptions) (*Response, error) { + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/cisnapshot", + body: opt, + method: http.MethodPost, + disableCloseBody: true, + } + resp, err := s.client.send(ctx, &sendOpt) + return resp, err +} + // GetPrivateM3U8Options TODO type GetPrivateM3U8Options struct { Expires int `url:"expires"` @@ -1562,19 +1814,25 @@ func (s *CIService) DescribeWorkflowExecutions(ctx context.Context, opt *Describ // NotifyConfig TODO type NotifyConfig struct { - URL string `xml:"Url,omitempty"` - Event string `xml:"Event,omitempty"` - Type string `xml:"Type,omitempty"` - ResultFormat string `xml:"ResultFormat,omitempty"` + URL string `xml:"Url,omitempty"` + Event string `xml:"Event,omitempty"` + Type string `xml:"Type,omitempty"` + ResultFormat string `xml:"ResultFormat,omitempty"` + State string `xml:"State,omitempty"` + KafkaConfig *KafkaConfig `xml:"KafkaConfig,omitempty" json:"KafkaConfig,omitempty"` } // ExtFilter TODO type ExtFilter struct { - State string `xml:"State,omitempty"` - Audio string `xml:"Audio,omitempty"` - Custom string `xml:"Custom,omitempty"` - CustomExts string `xml:"CustomExts,omitempty"` - AllFile string `xml:"AllFile,omitempty"` + State string `xml:"State,omitempty"` + Video string `xml:"Video,omitempty"` + Audio string `xml:"Audio,omitempty"` + Image string `xml:"Image,omitempty"` + ContentType string `xml:"ContentType,omitempty"` + Custom string `xml:"Custom,omitempty"` + CustomExts string `xml:"CustomExts,omitempty"` + AllFile string `xml:"AllFile,omitempty"` + AutoContentType []string `xml:"AutoContentType,omitempty"` } // NodeInput TODO @@ -1587,11 +1845,14 @@ type NodeInput struct { // NodeOutput TODO type NodeOutput struct { - Region string `xml:"Region,omitempty"` - Bucket string `xml:"Bucket,omitempty"` - Object string `xml:"Object,omitempty"` - AuObject string `xml:"AuObject,omitempty"` - SpriteObject string `xml:"SpriteObject,omitempty"` + Region string `xml:"Region,omitempty"` + Bucket string `xml:"Bucket,omitempty"` + Object string `xml:"Object,omitempty"` + AuObject string `xml:"AuObject,omitempty"` + SpriteObject string `xml:"SpriteObject,omitempty"` + BassObject string `xml:"BassObject,omitempty"` + DrumObject string `xml:"DrumObject,omitempty"` + StreamExtract []StreamExtract `xml:"StreamExtract,omitempty"` } // DelogoParam TODO @@ -1639,6 +1900,10 @@ type SegmentVideoBody struct { BackgroundRed string `xml:"BackgroundRed,omitempty"` BackgroundGreen string `xml:"BackgroundGreen,omitempty"` BackgroundLogoUrl string `xml:"BackgroundLogoUrl,omitempty"` + BinaryThreshold string `xml:"BinaryThreshold,omitempty"` + RemoveRed string `xml:"RemoveRed,omitempty"` + RemoveGreen string `xml:"RemoveGreen,omitempty"` + RemoveBlue string `xml:"RemoveBlue,omitempty"` } // NodeSmartCover TODO @@ -1680,6 +1945,10 @@ type NodeOperation struct { StreamPackInfo *NodeHlsPackInfo `xml:"StreamPackInfo,omitempty" json:"StreamPackInfo,omitempty"` Condition *WorkflowNodeCondition `xml:"Condition,omitempty" json:"Condition,omitempty"` SegmentVideoBody *SegmentVideoBody `xml:"SegmentVideoBody,omitempty" json:"SegmentVideoBody,omitempty"` + ImageInspect *ImageInspect `xml:"ImageInspect,omitempty" json:"ImageInspect,omitempty"` + TranscodeConfig *struct { + FreeTranscode string `xml:"FreeTranscode,omitempty" json:"FreeTranscode,omitempty"` + } `xml:"TranscodeConfig,omitempty" json:"TranscodeConfig,omitempty"` } // Node TODO @@ -1870,16 +2139,17 @@ type ASRJobOperation struct { // CreateASRJobsOptions TODO type CreateASRJobsOptions struct { - XMLName xml.Name `xml:"Request"` - Tag string `xml:"Tag,omitempty"` - Input *JobInput `xml:"Input,omitempty"` - Operation *ASRJobOperation `xml:"Operation,omitempty"` - QueueId string `xml:"QueueId,omitempty"` - CallBack string `xml:"CallBack,omitempty"` - QueueType string `xml:"QueueType,omitempty"` - CallBackFormat string `xml:"CallBackFormat,omitempty"` - CallBackType string `xml:"CallBackType,omitempty"` - CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"` + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Input *JobInput `xml:"Input,omitempty"` + Operation *ASRJobOperation `xml:"Operation,omitempty"` + QueueId string `xml:"QueueId,omitempty"` + CallBack string `xml:"CallBack,omitempty"` + QueueType string `xml:"QueueType,omitempty"` + CallBackFormat string `xml:"CallBackFormat,omitempty"` + CallBackType string `xml:"CallBackType,omitempty"` + CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"` + CallBackKafkaConfig *KafkaConfig `xml:"CallBackKafkaConfig,omitempty"` } // ASRJobDetail TODO @@ -2179,18 +2449,41 @@ type CreateVideoTargetRecTemplateOptions struct { VideoTargetRec *VideoTargetRec `xml:"VideoTargetRec,omitempty" json:"VideoTargetRec,omitempty"` } +// VTRTranscode TODO +type VTRTranscode struct { + Container *Container `xml:"Container,omitempty"` + Video *VTRVideo `xml:"Video,omitempty"` +} + +// VTRVideo TODO +type VTRVideo struct { + Codec string `xml:"Codec"` + Bitrate string `xml:"Bitrate,omitempty"` + Crf string `xml:"Crf,omitempty"` + Width string `xml:"Width,omitempty"` + Height string `xml:"Height,omitempty"` + Fps string `xml:"Fps,omitempty"` +} + // VideoTargetRec TODO type VideoTargetRec struct { - Body string `xml:"Body,omitempty"` - Pet string `xml:"Pet,omitempty"` - Car string `xml:"Car,omitempty"` + Body string `xml:"Body,omitempty"` + Pet string `xml:"Pet,omitempty"` + Car string `xml:"Car,omitempty"` + Face string `xml:"Face,omitempty"` + Plate string `xml:"Plate,omitempty"` + ProcessType string `xml:"ProcessType,omitempty"` + TransTpl *VTRTranscode `xml:"TransTpl,omitempty"` } // VideoTargetRecResult TODO type VideoTargetRecResult struct { - BodyRecognition []*BodyRecognition `xml:"BodyRecognition,omitempty"` - PetRecognition []*PetRecognition `xml:"PetRecognition,omitempty"` - CarRecognition []*CarRecognition `xml:"CarRecognition,omitempty"` + BodyRecognition []*BodyRecognition `xml:"BodyRecognition,omitempty"` + PetRecognition []*PetRecognition `xml:"PetRecognition,omitempty"` + CarRecognition []*CarRecognition `xml:"CarRecognition,omitempty"` + FaceRecognition []*FaceRecognition `xml:"FaceRecognition,omitempty"` + LicenseRecognitionResult []*LicenseRecognitionResult `xml:"LicenseRecognitionResult,omitempty"` + Sensitive string `xml:"Sensitive,omitempty"` } // BodyRecognition TODO @@ -2214,6 +2507,20 @@ type CarRecognition struct { CarInfo []*VideoTargetRecInfo `xml:"CarInfo,omitempty"` } +// FaceRecognition TODO +type FaceRecognition struct { + Time string `xml:"Time,omitempty"` + Url string `xml:"Url,omitempty"` + FaceInfo []*VideoTargetRecInfo `xml:"FaceInfo,omitempty"` +} + +// LicenseRecognitionResult TODO +type LicenseRecognitionResult struct { + Time string `xml:"Time,omitempty"` + Url string `xml:"Url,omitempty"` + PlateInfo []*VideoTargetRecInfo `xml:"PlateInfo,omitempty"` +} + // BodyInfo TODO type VideoTargetRecInfo struct { Name string `xml:"Name,omitempty"` @@ -2276,6 +2583,7 @@ type Template struct { NoiseReduction *NoiseReduction `xml:"NoiseReduction,omitempty" json:"NoiseReduction,omitempty"` VideoEnhance *VideoEnhance `xml:"VideoEnhance,omitempty" json:"VideoEnhance,omitempty"` VideoTargetRec *VideoTargetRec `xml:"VideoTargetRec,omitempty" json:"VideoTargetRec,omitempty"` + ImageOCR *ImageOCRTemplate `xml:"ImageOCR,omitempty" json:"ImageOCR,omitempty"` } // CreateMediaSnapshotTemplate 创建截图模板 @@ -3021,6 +3329,7 @@ type InventoryTriggerJobOperation struct { Tag string `xml:"Tag,omitempty"` JobParam *InventoryTriggerJobOperationJobParam `xml:"JobParam,omitempty"` Output *JobOutput `xml:"Output,omitempty"` + FreeTranscode string `xml:"FreeTranscode,omitempty"` } // InventoryTriggerJobOperationJobParam TODO @@ -3053,6 +3362,14 @@ type InventoryTriggerJobOperationJobParam struct { WordsGeneralize *WordsGeneralize `xml:"WordsGeneralize,omitempty"` WordsGeneralizeResult *WordsGeneralizeResult `xml:"WordsGeneralizeResult,omitempty"` NoiseReduction *NoiseReduction `xml:"NoiseReduction,omitempty"` + DnaConfig *DnaConfig `xml:"DnaConfig,omitempty"` + DnaResult *DnaResult `xml:"DnaResult,omitempty"` + VocalScore *VocalScore `xml:"VocalScore,omitempty"` + VocalScoreResult *VocalScoreResult `xml:"VocalScoreResult,omitempty"` + ImageInspect *ImageInspect `xml:"ImageInspect,omitempty"` + ImageInspectResult *ImageInspectResult `xml:"ImageInspectResult,omitempty"` + ImageOCR *ImageOCRTemplate `xml:"ImageOCR,omitempty"` + Detection *ImageOCRDetection `xml:"Detection,omitempty"` } // InventoryTriggerJob TODO @@ -3407,6 +3724,8 @@ func (s *CIService) DeleteTemplate(ctx context.Context, tempalteId string) (*Del type FillConcat struct { Format string `xml:"Format,omitempty"` FillInput []FillConcatInput `xml:"FillInput,omitempty"` + RefMode string `xml:"RefMode,omitempty"` + RefIndex string `xml:"RefIndex,omitempty"` } // FillConcatInput 填充拼接输入 @@ -3429,3 +3748,439 @@ type VideoSynthesisSpliceInfo struct { Width string `xml:"Width,omitempty"` Height string `xml:"Height,omitempty"` } + +// DnaConfig DNA任务配置 +type DnaConfig struct { + RuleType string `xml:"RuleType,omitempty"` + DnaDbId string `xml:"DnaDbId,omitempty"` + VideoId string `xml:"VideoId,omitempty"` +} + +// DnaResult DNA任务结果 +type DnaResult struct { + VideoId string `xml:"VideoId,omitempty"` + Duration int `xml:"Duration,omitempty"` + Detection *DnaResultDetection `xml:"Detection,omitempty"` +} + +// DnaResultDetection DNA任务结果 +type DnaResultDetection struct { + VideoId string `xml:"VideoId,omitempty"` + Similar int `xml:"Similar,omitempty"` + SimilarDuration int `xml:"SimilarDuration,omitempty"` + Duration int `xml:"Duration,omitempty"` + MatchDetail []DnaResultMatchDetail `xml:"MatchDetail,omitempty"` + Audio DnaResultAudio `xml:"Audio,omitempty"` +} + +// DnaResultDetection DNA任务结果 +type DnaResultMatchDetail struct { + MatchStartTime int `xml:"MatchStartTime,omitempty"` + MatchEndTime int `xml:"MatchEndTime,omitempty"` + SrcStartTime int `xml:"SrcStartTime,omitempty"` + SrcEndTime int `xml:"SrcEndTime,omitempty"` +} + +// DnaResultAudio DNA任务结果 +type DnaResultAudio struct { + Similar int `xml:"Similar,omitempty"` +} + +// GetDnaDbOptions 查询 DNA 库列表参数 +type GetDnaDbOptions struct { + Ids string `url:"ids,omitempty"` + PageNumber string `url:"pageNumber,omitempty"` + PageSize string `url:"pageSize,omitempty"` +} + +// GetDnaDbResult 查询 DNA 库列表结果 +type GetDnaDbResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + TotalCount int `xml:"TotalCount,omitempty"` + PageNumber int `xml:"PageNumber,omitempty"` + PageSize int `xml:"PageSize,omitempty"` + DNADbConfig []DNADbConfig `xml:"DNADbConfig,omitempty"` + NonExistIDs []string `xml:"NonExistIDs,omitempty"` +} + +// DNADbConfig DNA 库详情 +type DNADbConfig struct { + BucketId string `xml:"BucketId,omitempty"` + Region string `xml:"Region,omitempty"` + DNADbId string `xml:"DNADbId,omitempty"` + DNADbName string `xml:"DNADbName,omitempty"` + Capacity int `xml:"Capacity,omitempty"` + Description string `xml:"Description,omitempty"` + UpdateTime string `xml:"UpdateTime,omitempty"` + CreateTime string `xml:"CreateTime,omitempty"` +} + +// GetDnaDb 查询 DNA 库列表 +func (s *CIService) GetDnaDb(ctx context.Context, opt *GetDnaDbOptions) (*GetDnaDbResult, *Response, error) { + var res GetDnaDbResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/dnadb", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// GetDnaDbFilesOptions 获取 DNA 库中文件列表参数 +type GetDnaDbFilesOptions struct { + object string `url:"object,omitempty"` + DnaDbId string `url:"dnaDbId,omitempty"` + PageNumber string `url:"pageNumber,omitempty"` + PageSize string `url:"pageSize,omitempty"` +} + +// GetDnaDbFilesResult 查询 DNA 库列表结果 +type GetDnaDbFilesResult struct { + XMLName xml.Name `xml:"Response"` + RequestId string `xml:"RequestId,omitempty"` + TotalCount int `xml:"TotalCount,omitempty"` + PageNumber int `xml:"PageNumber,omitempty"` + PageSize int `xml:"PageSize,omitempty"` + DNADbFiles []DNADbFiles `xml:"DNADbFiles,omitempty"` +} + +// DNADbFiles DNA 文件详情 +type DNADbFiles struct { + BucketId string `xml:"BucketId,omitempty"` + Region string `xml:"Region,omitempty"` + DNADbId string `xml:"DNADbId,omitempty"` + VideoId string `xml:"VideoId,omitempty"` + Object int `xml:"Object,omitempty"` + ETag string `xml:"ETag,omitempty"` + UpdateTime string `xml:"UpdateTime,omitempty"` + CreateTime string `xml:"CreateTime,omitempty"` +} + +// GetDnaDb 查询 DNA 库列表 +func (s *CIService) GetDnaDbFiles(ctx context.Context, opt *GetDnaDbFilesOptions) (*GetDnaDbFilesResult, *Response, error) { + var res GetDnaDbFilesResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/dnadb_files", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// VocalScore 音乐评分 +type VocalScore struct { + StandardObject string `xml:"StandardObject,omitempty"` +} + +// VocalScore 音乐评分结果 +type VocalScoreResult struct { + PitchScore *VocalScoreResultPitchScore `xml:"PitchScore,omitempty"` + RhythemScore *VocalScoreResultRhythemScore `xml:"RhythemScore,omitempty"` +} + +type VocalScoreResultPitchScore struct { + TotalScore float64 `xml:"TotalScore,omitempty"` + SentenceScores []VocalScoreResultSentenceScores `xml:"SentenceScores,omitempty"` +} + +type VocalScoreResultSentenceScores struct { + StartTime float64 `xml:"StartTime,omitempty"` + EndTime float64 `xml:"EndTime,omitempty"` + Score float64 `xml:"Score,omitempty"` +} + +type VocalScoreResultRhythemScore struct { + TotalScore float64 `xml:"TotalScore,omitempty"` + SentenceScores []VocalScoreResultSentenceScores `xml:"SentenceScores,omitempty"` +} + +// ImageInspect 黑产检测 +type ImageInspect struct { + AutoProcess string `xml:"AutoProcess,omitempty"` + ProcessType string `xml:"ProcessType,omitempty"` +} + +// ImageInspectResult 黑产检测结果 +type ImageInspectResult struct { + State string `xml:"State,omitempty"` + Code string `xml:"Code,omitempty"` + Message string `xml:"Message,omitempty"` + InputObjectName string `xml:"InputObjectName,omitempty"` + InputObjectUrl string `xml:"InputObjectUrl,omitempty"` + ProcessResult *ImageInspectProcessResult `xml:"ProcessResult,omitempty"` +} + +// ImageInspectProcessResult 黑产检测结果 +type ImageInspectProcessResult struct { + PicSize int `xml:"PicSize,omitempty"` + PicType string `xml:"PicType,omitempty"` + Suspicious string `xml:"Suspicious,omitempty"` + SuspiciousBeginByte int `xml:"SuspiciousBeginByte,omitempty"` + SuspiciousEndByte int `xml:"SuspiciousEndByte,omitempty"` + SuspiciousSize int `xml:"SuspiciousSize,omitempty"` + SuspiciousType string `xml:"SuspiciousType,omitempty"` + AutoProcessResult *ImageInspectAutoProcessResult `xml:"AutoProcessResult,omitempty"` +} + +// ImageInspectResult 黑产检测结果 +type ImageInspectAutoProcessResult struct { + Code string `xml:"Code,omitempty"` + Message string `xml:"Message,omitempty"` +} + +type CosImageInspectOptions struct { +} + +// CosImageInspectProcessResult 黑产检测同步接口结果 +type CosImageInspectProcessResult struct { + PicSize int `json:"picSize,omitempty"` + PicType string `json:"picType,omitempty"` + Suspicious bool `json:"suspicious,omitempty"` + SuspiciousBeginByte int `json:"suspiciousBeginByte,omitempty"` + SuspiciousEndByte int `json:"suspiciousEndByte,omitempty"` + SuspiciousSize int `json:"suspiciousSize,omitempty"` + SuspiciousType string `json:"suspiciousType,omitempty"` +} + +// Write 回包是json格式序列化 +func (w *CosImageInspectProcessResult) Write(p []byte) (n int, err error) { + err = json.Unmarshal(p, w) + if err != nil { + return 0, err + } + return len(p), nil +} + +// ImageInspect 黑产检查同步接口 +func (s *CIService) CosImageInspect(ctx context.Context, name string, opt *CosImageInspectOptions) (*CosImageInspectProcessResult, *Response, error) { + var res CosImageInspectProcessResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?ci-process=ImageInspect", + optQuery: opt, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateOCRTemplateOptions TODO +type CreateOCRTemplateOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Name string `xml:"Name,omitempty"` + ImageOCR *ImageOCRTemplate `xml:"ImageOCR,omitempty" json:"ImageOCR,omitempty"` +} + +// ImageOCRTemplate TODO +type ImageOCRTemplate struct { + Type string `xml:"Type,omitempty"` + LanguageType string `xml:"LanguageType,omitempty"` + IsPdf string `xml:"IsPdf,omitempty"` + PdfPageNumber string `xml:"PdfPageNumber,omitempty"` + IsWord string `xml:"IsWord,omitempty"` + EnableWordPolygon string `xml:"EnableWordPolygon,omitempty"` +} + +// CreateOCRTemplate 创建OCR模板 +func (s *CIService) CreateOCRTemplate(ctx context.Context, opt *CreateOCRTemplateOptions) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// UpdateOCRTemplate 更新OCR模板 +func (s *CIService) UpdateOCRTemplate(ctx context.Context, opt *CreateOCRTemplateOptions, templateId string) (*CreateMediaTemplateResult, *Response, error) { + var res CreateMediaTemplateResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/template/" + templateId, + method: http.MethodPut, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// ImageOCRDetection TODO +type ImageOCRDetection struct { + InputObjectName string `xml:"InputObjectName,omitempty"` + InputObjectUrl string `xml:"InputObjectUrl,omitempty"` + ObjectName string `xml:"ObjectName,omitempty"` + ObjectUrl string `xml:"ObjectUrl,omitempty"` + Code string `xml:"Code,omitempty"` + State string `xml:"State,omitempty"` + Message string `xml:"Message,omitempty"` + TextDetections []ImageOCRTextDetections `xml:"TextDetections,omitempty"` + Language string `xml:"Language,omitempty"` + Angel string `xml:"Angel,omitempty"` + PdfPageSize int `xml:"PdfPageSize,omitempty"` +} + +// ImageOCRTextDetections TODO +type ImageOCRTextDetections struct { + DetectedText string `xml:"DetectedText,omitempty"` + Confidence int `xml:"Confidence,omitempty"` + Polygon []ImageOCRTextPolygon `xml:"Polygon,omitempty"` + ItemPolygon []ImageOCRTextItemPolygon `xml:"ItemPolygon,omitempty"` + Words []ImageOCRTextWords `xml:"Words,omitempty"` + WordPolygon []ImageOCRTextWordPolygon `xml:"WordPolygon,omitempty"` +} + +// ImageOCRTextPolygon TODO +type ImageOCRTextPolygon struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` +} + +// ImageOCRTextItemPolygon TODO +type ImageOCRTextItemPolygon struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + Width int `xml:"Width,omitempty"` + Height int `xml:"Height,omitempty"` +} + +// ImageOCRTextWords TODO +type ImageOCRTextWords struct { + Confidence int `xml:"Confidence,omitempty"` + Character string `xml:"Character,omitempty"` + WordCoordPoint []struct { + WordCoordinate []struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + } `xml:"WordCoordinate,omitempty"` + } `xml:"WordCoordPoint,omitempty"` +} + +// ImageOCRTextWordPolygon TODO +type ImageOCRTextWordPolygon struct { + LeftTop []struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + } `xml:"LeftTop,omitempty"` + RightTop []struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + } `xml:"RightTop,omitempty"` + LeftBottom []struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + } `xml:"LeftBottom,omitempty"` + RightBottom []struct { + X int `xml:"X,omitempty"` + Y int `xml:"Y,omitempty"` + } `xml:"RightBottom,omitempty"` +} + +type LiveTanscodeVideo struct { + Codec string `xml:"Codec"` + Width string `xml:"Width,omitempty"` + Height string `xml:"Height,omitempty"` + Fps string `xml:"Fps,omitempty"` + Profile string `xml:"Profile,omitempty"` + Bitrate string `xml:"Bitrate,omitempty"` + Gop string `xml:"Gop,omitempty"` + Maxrate string `xml:"Maxrate,omitempty"` + Crf string `xml:"Crf,omitempty"` + Pixfmt string `xml:"Pixfmt,omitempty"` + LongShortMode string `xml:"LongShortMode,omitempty"` + Interlaced string `xml:"Interlaced,omitempty"` + ColorParam *VideoColorParam `xml:"ColorParam,omitempty"` +} + +type LiveTanscodeTransConfig struct { + InitialClipNum string `xml:"InitialClipNum,omitempty"` + CosTag string `xml:"CosTag,omitempty"` + HlsEncrypt *HlsEncrypt `xml:"HlsEncrypt,omitempty"` +} + +type LiveTanscode struct { + Container *Container `xml:"Container,omitempty"` + Video *LiveTanscodeVideo `xml:"Video,omitempty"` + // TimeInterval *TimeInterval `xml:"TimeInterval,omitempty"` + // Audio *Audio `xml:"Audio,omitempty"` + TransConfig *LiveTanscodeTransConfig `xml:"TransConfig,omitempty"` +} + +type GeneratePlayListJobOperation struct { + Tag string `xml:"Tag,omitempty"` + Output *JobOutput `xml:"Output,omitempty"` + MediaResult *MediaResult `xml:"MediaResult,omitempty"` + MediaInfo *MediaInfo `xml:"MediaInfo,omitempty"` + Transcode *LiveTanscode `xml:"Transcode,omitempty"` + UserData string `xml:"UserData,omitempty"` + JobLevel int `xml:"JobLevel,omitempty"` +} + +type CreateGeneratePlayListJobOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Input *JobInput `xml:"Input,omitempty"` + Operation *GeneratePlayListJobOperation `xml:"Operation,omitempty"` + QueueId string `xml:"QueueId,omitempty"` + QueueType string `xml:"QueueType,omitempty"` + CallBackFormat string `xml:"CallBackFormat,omitempty"` + CallBackType string `xml:"CallBackType,omitempty"` + CallBack string `xml:"CallBack,omitempty"` + CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"` + CallBackKafkaConfig *KafkaConfig `xml:"CallBackKafkaConfig,omitempty"` +} + +func (s *CIService) CreateGeneratePlayListJob(ctx context.Context, opt *CreateGeneratePlayListJobOptions) (*CreateJobsResult, *Response, error) { + var res CreateJobsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/jobs", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} + +// CreateMultiGeneratePlayListJobsOptions TODO +type CreateMultiGeneratePlayListJobsOptions struct { + XMLName xml.Name `xml:"Request"` + Tag string `xml:"Tag,omitempty"` + Input *JobInput `xml:"Input,omitempty"` + Operation []GeneratePlayListJobOperation `xml:"Operation,omitempty"` + QueueId string `xml:"QueueId,omitempty"` + QueueType string `xml:"QueueType,omitempty"` + CallBackFormat string `xml:"CallBackFormat,omitempty"` + CallBackType string `xml:"CallBackType,omitempty"` + CallBack string `xml:"CallBack,omitempty"` + CallBackMqConfig *NotifyConfigCallBackMqConfig `xml:"CallBackMqConfig,omitempty"` + CallBackKafkaConfig *KafkaConfig `xml:"CallBackKafkaConfig,omitempty"` +} + +// CreateMultiGeneratePlayListJobs TODO +func (s *CIService) CreateMultiGeneratePlayListJobs(ctx context.Context, opt *CreateMultiGeneratePlayListJobsOptions) (*CreateMultiMediaJobsResult, *Response, error) { + var res CreateMultiMediaJobsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.CIURL, + uri: "/jobs", + method: http.MethodPost, + body: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_metainsight.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_metainsight.go new file mode 100644 index 0000000000..bb9dda1fc1 --- /dev/null +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/ci_metainsight.go @@ -0,0 +1,609 @@ +package cos + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "net/http" + "strings" +) + +type MetaInsightService service + +type OptHeaders struct { + XOptionHeader *http.Header `header:"-,omitempty" url:"-" json:"-" xml:"-"` +} + +func (s *MetaInsightService) baseSend(ctx context.Context, opt interface{}, optionHeader *OptHeaders, uri string, method string) (*bytes.Buffer, *Response, error) { + var buf bytes.Buffer + var f *strings.Reader + var sendOpt *sendOptions + if optionHeader == nil { + optionHeader = &OptHeaders{ + XOptionHeader: &http.Header{}, + } + } + optionHeader.XOptionHeader.Add("Content-Type", "application/json") + optionHeader.XOptionHeader.Add("Accept", "application/json") + if method == http.MethodGet { + sendOpt = &sendOptions{ + baseURL: s.client.BaseURL.MetaInsightURL, + uri: uri, + method: method, + optHeader: optionHeader, + optQuery: opt, + result: &buf, + } + } else { + if opt != nil { + bs, err := json.Marshal(opt) + if err != nil { + return nil, nil, err + } + f = strings.NewReader(string(bs)) + } + sendOpt = &sendOptions{ + baseURL: s.client.BaseURL.MetaInsightURL, + uri: uri, + method: method, + body: f, + optHeader: optionHeader, + result: &buf, + } + } + resp, err := s.client.send(ctx, sendOpt) + return &buf, resp, err +} + +type CreateDatasetOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。命名规则如下: 长度为1~32字符。 只能包含小写英文字母,数字,短划线(-)。 必须以英文字母和数字开头。 + Description string `json:"Description, omitempty" url:"-" ` // 数据集描述信息。长度为1~256个英文或中文字符,默认值为空。 + TemplateId string `json:"TemplateId, omitempty" url:"-" ` // 指模板,在建立元数据索引时,后端将根据模板来决定收集哪些元数据。每个模板都包含一个或多个算子,不同的算子表示不同的元数据。目前支持的模板: Official:DefaultEmptyId:默认为空的模板,表示不进行元数据的采集。 Official:COSBasicMeta:基础信息模板,包含 COS 文件基础元信息算子,表示采集 COS 文件的名称、类型、ACL等基础元信息数据。 Official:FaceSearch:人脸检索模板,包含人脸检索、COS 文件基础元信息算子。Official:ImageSearch:图像检索模板,包含图像检索、COS 文件基础元信息算子。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type CreateDatasetResult struct { + RequestId string `json:"RequestId"` // 请求ID + Dataset *Dataset `json:"Dataset"` // 数据集信息 +} + +type Dataset struct { + TemplateId string `json:"TemplateId"` // 模板ID。 + Description string `json:"Description"` // 数据集描述信息 + CreateTime string `json:"CreateTime"` // 数据集创建时间的时间戳,格式为RFC3339Nano + UpdateTime string `json:"UpdateTime"` // 数据集修改时间的时间戳,格式为RFC3339Nano创建数据集后,如果未更新过数据集,则数据集修改时间的时间戳和数据集创建时间的时间戳相同 + BindCount int `json:"BindCount"` // 数据集当前绑定的COS Bucket数量 + FileCount int `json:"FileCount"` // 数据集当前文件数量 + TotalFileSize int `json:"TotalFileSize"` // 数据集中当前文件总大小,单位为字节 + DatasetName string `json:"DatasetName"` // 数据集名称 +} + +// 创建数据集 +// https://cloud.tencent.com/document/product/460/106020 +func (s *MetaInsightService) CreateDataset(ctx context.Context, opt *CreateDatasetOptions) (*CreateDatasetResult, *Response, error) { + var res CreateDatasetResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"dataset", http.MethodPost) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DescribeDatasetsOptions struct { + Maxresults int `url:"maxresults, omitempty" json:"-"` // 本次返回数据集的最大个数,取值范围为0~200。不设置此参数或者设置为0时,则默认值为100。 + Nexttoken string `url:"nexttoken, omitempty" json:"-"` // 翻页标记。当文件总数大于设置的MaxResults时,用于翻页的Token。从NextToken开始按字典序返回文件信息列表。填写上次查询返回的值,首次使用时填写为空。 + Prefix string `url:"prefix, omitempty" json:"-"` // 数据集名称前缀。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DescribeDatasetsResult struct { + RequestId string `json:"RequestId"` // 请求ID + Datasets []*Dataset `json:"Datasets"` // 数据集信息 + NextToken string `json:"NextToken"` // 翻页标记。当任务列表总数大于设置的MaxResults时,用于翻页的Token。符合条件的任务列表未全部返回时,此参数才有值。下一次列出任务列表时将此值作为NextToken传入,将后续的任务列表返回。 +} + +// 列出数据集 +// https://cloud.tencent.com/document/product/460/106158 +func (s *MetaInsightService) DescribeDatasets(ctx context.Context, opt *DescribeDatasetsOptions) (*DescribeDatasetsResult, *Response, error) { + var res DescribeDatasetsResult + + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"datasets", http.MethodGet) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type UpdateDatasetOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + Description string `json:"Description, omitempty" url:"-" ` // 数据集描述信息。长度为1~256个英文或中文字符,默认值为空。 + TemplateId string `json:"TemplateId, omitempty" url:"-" ` // 该参数表示模板,在建立元数据索引时,后端将根据模板来决定收集哪些元数据。每个模板都包含一个或多个算子,不同的算子表示不同的元数据。目前支持的模板: Official:Empty:默认为空的模板,表示不进行元数据的采集。 Official:COSBasicMeta:基础信息模板,包含COS文件基础元信息算子,表示采集cos文件的名称、类型、acl等基础元信息数据。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type UpdateDatasetResult struct { + RequestId string `json:"RequestId"` // 请求ID + Dataset *Dataset `json:"Dataset"` // 数据集信息 +} + +// 更新数据集 +// https://cloud.tencent.com/document/product/460/106156 +func (s *MetaInsightService) UpdateDataset(ctx context.Context, opt *UpdateDatasetOptions) (*UpdateDatasetResult, *Response, error) { + var res UpdateDatasetResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"dataset", http.MethodPut) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DeleteDatasetOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DeleteDatasetResult struct { + RequestId string `json:"RequestId"` // 请求ID + Dataset *Dataset `json:"Dataset"` // 数据集信息 +} + +// 删除数据集 +// https://cloud.tencent.com/document/product/460/106157 +func (s *MetaInsightService) DeleteDataset(ctx context.Context, opt *DeleteDatasetOptions) (*DeleteDatasetResult, *Response, error) { + var res DeleteDatasetResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"dataset", http.MethodDelete) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DescribeDatasetOptions struct { + Datasetname string `url:"datasetname, omitempty" json:"-"` // 数据集名称,同一个账户下唯一。 + Statistics bool `url:"statistics, omitempty" json:"-"` // 是否需要实时统计数据集中文件相关信息。有效值: false:不统计,返回的文件的总大小、数量信息可能不正确也可能都为0。 true:需要统计,返回数据集中当前的文件的总大小、数量信息。 默认值为false。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DescribeDatasetResult struct { + RequestId string `json:"RequestId"` // 请求ID + Dataset *Dataset `json:"Dataset"` // 数据集信息 +} + +// 查询数据集 +// https://cloud.tencent.com/document/product/460/106155 +func (s *MetaInsightService) DescribeDataset(ctx context.Context, opt *DescribeDatasetOptions) (*DescribeDatasetResult, *Response, error) { + var res DescribeDatasetResult + + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"dataset", http.MethodGet) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type CreateFileMetaIndexOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + File *File `json:"File, omitempty" url:"-" ` // 用于建立索引的文件信息。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type File struct { + CustomId string `json:"CustomId, omitempty" url:"-" ` // 自定义ID。该文件索引到数据集后,作为该行元数据的属性存储,用于和您的业务系统进行关联、对应。您可以根据业务需求传入该值,例如将某个URI关联到您系统内的某个ID。推荐传入全局唯一的值。在查询时,该字段支持前缀查询和排序,详情请见字段和操作符的支持列表。 + CustomLabels *map[string]string `json:"CustomLabels, omitempty" url:"-" ` // 自定义标签。您可以根据业务需要自定义添加标签键值对信息,用于在查询时可以据此为筛选项进行检索,详情请见字段和操作符的支持列表。 + Key string `json:"Key, omitempty" url:"-" ` // 自定义标签键 + Value string `json:"Value, omitempty" url:"-" ` // 自定义标签值 + MediaType string `json:"MediaType, omitempty" url:"-" ` // 可选项,文件媒体类型,枚举值: image:图片。 other:其他。 document:文档。 archive:压缩包。 video:视频。 audio:音频。 + ContentType string `json:"ContentType, omitempty" url:"-" ` // 可选项,文件内容类型(MIME Type),如image/jpeg。 + URI string `json:"URI, omitempty" url:"-" ` // 资源标识字段,表示需要建立索引的文件地址,当前仅支持COS上的文件,字段规则:cos:///,其中BucketName表示COS存储桶名称,ObjectKey表示文件完整路径,例如:cos://examplebucket-1250000000/test1/img.jpg。 注意: 1、仅支持本账号内的COS文件 2、不支持HTTP开头的地址 + MaxFaceNum int `json:"MaxFaceNum, omitempty" url:"-" ` // 输入图片中检索的人脸数量,默认值为20,最大值为20。(仅当数据集模板 ID 为 Official:FaceSearch 有效)。 + Persons []*Persons `json:"Persons, omitempty" url:"-" ` // 自定义人物属性(仅当数据集模板 ID 为 Official:FaceSearch 有效)。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type Persons struct { + PersonId string `json:"PersonId, omitempty" url:"-" ` // 自定义人物 ID。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type CreateFileMetaIndexResult struct { + RequestId string `json:"RequestId"` // 请求ID + EventId string `json:"EventId"` // 创建元数据索引的任务ID +} + +// 创建元数据索引 +// https://cloud.tencent.com/document/product/460/106022 +func (s *MetaInsightService) CreateFileMetaIndex(ctx context.Context, opt *CreateFileMetaIndexOptions) (*CreateFileMetaIndexResult, *Response, error) { + var res CreateFileMetaIndexResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"filemeta", http.MethodPost) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type UpdateFileMetaIndexOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + Callback string `json:"Callback, omitempty" url:"-" ` // 元数据索引结果(以回调形式发送至您的回调地址,支持以 http:// 或者 https:// 开头的地址,例如: http://www.callback.com + File *File `json:"File, omitempty" url:"-" ` // 用于建立索引的文件信息。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type UpdateFileMetaIndexResult struct { + RequestId string `json:"RequestId"` // 请求ID + EventId string `json:"EventId"` // 创建元数据索引的任务ID +} + +// 更新元数据索引 +// https://cloud.tencent.com/document/product/460/106162 +func (s *MetaInsightService) UpdateFileMetaIndex(ctx context.Context, opt *UpdateFileMetaIndexOptions) (*UpdateFileMetaIndexResult, *Response, error) { + var res UpdateFileMetaIndexResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"filemeta", http.MethodPut) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DescribeFileMetaIndexOptions struct { + Datasetname string `url:"datasetname, omitempty" json:"-"` // 数据集名称,同一个账户下唯一。 + Uri string `url:"uri, omitempty" json:"-"` // 资源标识字段,表示需要建立索引的文件地址,当前仅支持COS上的文件,字段规则:cos:///,其中BucketName表示COS存储桶名称,ObjectKey表示文件完整路径,例如:cos://examplebucket-1250000000/test1/img.jpg。 注意: 1、仅支持本账号内的COS文件 2、不支持HTTP开头的地址 3、需UrlEncode + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DescribeFileMetaIndexResult struct { + RequestId string `json:"RequestId"` // 请求ID。 + Files []*FilesDetail `json:"Files"` // 文件元数据的结构体。实际返回的数据可能并不包含该结构体的所有属性,这和您索引该文件时选用的工作流模板配置以及文件本身的内容有关。 +} + +type FilesDetail struct { + CreateTime string `json:"CreateTime"` // 元数据创建时间的时间戳,格式为RFC3339Nano + UpdateTime string `json:"UpdateTime"` // 元数据修改时间的时间戳,格式为RFC3339Nano创建元数据后,如果未更新过元数据,则元数据修改时间的时间戳和元数据创建时间的时间戳相同 + URI string `json:"URI"` // 资源标识字段,表示需要建立索引的文件地址 + Filename string `json:"Filename"` // 文件路径 + MediaType string `json:"MediaType"` // 文件媒体类型。 枚举值:image:图片。other:其他。document:文档。archive:压缩包。audio:音频。video:视频。 + ContentType string `json:"ContentType"` // 文件内容类型(MIME Type)。 + COSStorageClass string `json:"COSStorageClass"` // 文件存储空间类型。 + COSCRC64 string `json:"COSCRC64"` // 文件CRC64值。 + ObjectACL string `json:"ObjectACL"` // 对象ACL。 + Size int `json:"Size"` // 文件大小,单位为字节。 + CacheControl string `json:"CacheControl"` // 指定Object被下载时网页的缓存行为。 + ETag string `json:"ETag"` // Object生成时会创建相应的ETag ,ETag用于标识一个Object的内容。 + FileModifiedTime string `json:"FileModifiedTime"` // 文件最近一次修改时间的时间戳, 格式为RFC3339Nano。 + CustomId string `json:" CustomId"` // 该文件的自定义ID。该文件索引到数据集后,作为该行元数据的属性存储,用于和您的业务系统进行关联、对应。您可以根据业务需求传入该值,例如将某个URI关联到您系统内的某个ID。推荐传入全局唯一的值。 + CustomLabels *map[string]string `json:"CustomLabels"` // 文件自定义标签列表。储存您业务自定义的键名、键值对信息,用于在查询时可以据此为筛选项进行检索。 +} + +// 查询元数据索引 +// https://cloud.tencent.com/document/product/460/106164 +func (s *MetaInsightService) DescribeFileMetaIndex(ctx context.Context, opt *DescribeFileMetaIndexOptions) (*DescribeFileMetaIndexResult, *Response, error) { + var res DescribeFileMetaIndexResult + + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"filemeta", http.MethodGet) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DeleteFileMetaIndexOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + URI string `json:"URI, omitempty" url:"-" ` // 资源标识字段,表示需要建立索引的文件地址。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DeleteFileMetaIndexResult struct { + RequestId string `json:"RequestId"` // 请求ID +} + +// 删除元数据索引 +// https://cloud.tencent.com/document/product/460/106163 +func (s *MetaInsightService) DeleteFileMetaIndex(ctx context.Context, opt *DeleteFileMetaIndexOptions) (*DeleteFileMetaIndexResult, *Response, error) { + var res DeleteFileMetaIndexResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"filemeta", http.MethodDelete) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type CreateDatasetBindingOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + URI string `json:"URI, omitempty" url:"-" ` // 资源标识字段,表示需要与数据集绑定的资源,当前仅支持COS存储桶的资源,字段规则:cos:///,其中BucketName表示COS存储桶名称,Path表示资源路径,例如:cos://examplebucket-1250000000/test/。 + Mode int `json:"Mode", omitempty" url:"-" ` // 建立绑定后,以何种方式进行文件索引特征的提取,有效值:0,表示仅对增量文件建立索引;1,表示在对增量文件建立索引的同时,也会对存储桶中存量文件建立索引,存量文件索引建立的时长与存量文件数有关;默认值为0。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type CreateDatasetBindingResult struct { + RequestId string `json:"RequestId"` // 请求ID + Binding *Binding `json:"Binding"` // 绑定信息 +} + +type Binding struct { + URI string `json:"URI"` // 资源标识字段,表示需要与数据集绑定的资源,当前仅支持COS存储桶,字段规则:cos://,其中BucketName表示COS存储桶名称,例如:cos://examplebucket-1250000000 + State string `json:"State"` // 数据集和 COS Bucket绑定关系的状态。取值范围如下:Running:绑定关系运行中。 + StockState string `json:"StockState"` // 当前绑定的存储桶对应的存量索引的状态:有效值:NoIndexing(未进行存量建立索引)、Indexing(存量索引建立中)、Success(存量索引已建立完成)。 + CreateTime string `json:"CreateTime"` // 数据集和 COS Bucket绑定关系创建时间的时间戳,格式为RFC3339Nano。 + UpdateTime string `json:"UpdateTime"` // 数据集和 COS Bucket的绑定关系修改时间的时间戳,格式为RFC3339Nano。创建绑定关系后,如果未暂停或者未重启过绑定关系,则绑定关系修改时间的时间戳和绑定关系创建时间的时间戳相同。 + DatasetName string `json:"DatasetName"` // 数据集名称。 + Detail string `json:"Detail"` // 详情 +} + +// 绑定存储桶与数据集 +// https://cloud.tencent.com/document/product/460/106159 +func (s *MetaInsightService) CreateDatasetBinding(ctx context.Context, opt *CreateDatasetBindingOptions) (*CreateDatasetBindingResult, *Response, error) { + var res CreateDatasetBindingResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"datasetbinding", http.MethodPost) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DescribeDatasetBindingOptions struct { + Datasetname string `url:"datasetname, omitempty" json:"-"` // 数据集名称,同一个账户下唯一。 + Uri string `url:"uri, omitempty" json:"-"` // 资源标识字段,表示需要与数据集绑定的资源,当前仅支持COS存储桶,字段规则:cos://,其中BucketName表示COS存储桶名称,例如(需要进行urlencode):cos%3A%2F%2Fexample-125000 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DescribeDatasetBindingResult struct { + RequestId string `json:"RequestId"` // 请求ID + Binding *Binding `json:"Binding"` // 数据集和 COS Bucket 绑定关系信息的列表。 +} + +// 查询数据集与存储桶的绑定关系 +// https://cloud.tencent.com/document/product/460/106485 +func (s *MetaInsightService) DescribeDatasetBinding(ctx context.Context, opt *DescribeDatasetBindingOptions) (*DescribeDatasetBindingResult, *Response, error) { + var res DescribeDatasetBindingResult + + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"datasetbinding", http.MethodGet) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DescribeDatasetBindingsOptions struct { + Datasetname string `url:"datasetname, omitempty" json:"-"` // 数据集名称,同一个账户下唯一。 + Maxresults int `url:"maxresults, omitempty" json:"-"` // 返回绑定关系的最大个数,取值范围为0~200。不设置此参数或者设置为0时,则默认值为100。 + Nexttoken string `url:"nexttoken, omitempty" json:"-"` // 当绑定关系总数大于设置的MaxResults时,用于翻页的token。从NextToken开始按字典序返回绑定关系信息列表。第一次调用此接口时,设置为空。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DescribeDatasetBindingsResult struct { + RequestId string `json:"RequestId"` // 请求ID + NextToken string `json:"NextToken"` // 当绑定关系总数大于设置的MaxResults时,用于翻页的token。下一次列出绑定关系信息时以此值为NextToken,将未返回的结果返回。当绑定关系未全部返回时,此参数才有值。 + Bindings []*Binding `json:"Bindings"` // 数据集和 COS Bucket 绑定关系信息的列表。 +} + +// 查询绑定关系列表 +// https://cloud.tencent.com/document/product/460/106161 +func (s *MetaInsightService) DescribeDatasetBindings(ctx context.Context, opt *DescribeDatasetBindingsOptions) (*DescribeDatasetBindingsResult, *Response, error) { + var res DescribeDatasetBindingsResult + + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"datasetbindings", http.MethodGet) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DeleteDatasetBindingOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + URI string `json:"URI, omitempty" url:"-" ` // 资源标识字段,表示需要与数据集绑定的资源,当前仅支持COS存储桶,字段规则:cos://,其中BucketName表示COS存储桶名称,例如:cos://examplebucket-1250000000 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DeleteDatasetBindingResult struct { + RequestId string `json:"RequestId"` // 请求ID +} + +// 解绑存储桶与数据集 +// https://cloud.tencent.com/document/product/460/106160 +func (s *MetaInsightService) DeleteDatasetBinding(ctx context.Context, opt *DeleteDatasetBindingOptions) (*DeleteDatasetBindingResult, *Response, error) { + var res DeleteDatasetBindingResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"datasetbinding", http.MethodDelete) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DatasetSimpleQueryOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + Query *Query `json:"Query, omitempty" url:"-" ` // 简单查询参数条件,可自嵌套。 + MaxResults int `json:"MaxResults, omitempty" url:"-" ` // 返回文件元数据的最大个数,取值范围为0200。 使用聚合参数时,该值表示返回分组的最大个数,取值范围为02000。 不设置此参数或者设置为0时,则取默认值100。 + NextToken string `json:"NextToken, omitempty" url:"-" ` // 当绑定关系总数大于设置的MaxResults时,用于翻页的token。从NextToken开始按字典序返回绑定关系信息列表。第一次调用此接口时,设置为空。 + Sort string `json:"Sort, omitempty" url:"-" ` // 排序字段列表。请参考字段和操作符的支持列表。 多个排序字段可使用半角逗号(,)分隔,例如:Size,Filename。 最多可设置5个排序字段。 排序字段顺序即为排序优先级顺序。 + Order string `json:"Order, omitempty" url:"-" ` // 排序字段的排序方式。取值如下: asc:升序; desc(默认):降序。 多个排序方式可使用半角逗号(,)分隔,例如:asc,desc。 排序方式不可多于排序字段,即参数Order的元素数量需小于等于参数Sort的元素数量。例如Sort取值为Size,Filename时,Order可取值为asc,desc或asc。 排序方式少于排序字段时,未排序的字段默认取值asc。例如Sort取值为Size,Filename,Order取值为asc时,Filename默认排序方式为asc,即升序排列 + Aggregations []*Aggregations `json:"Aggregations, omitempty" url:"-" ` // 聚合字段信息列表。 当您使用聚合查询时,仅返回聚合结果,不再返回匹配到的元信息列表。 + WithFields []string `json:"WithFields, omitempty" url:"-" ` // 仅返回特定字段的值,而不是全部已有的元信息字段。可用于降低返回的结构体大小。不填或留空则返回所有字段。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type Aggregations struct { + Operation string `json:"Operation, omitempty" url:"-" ` // 聚合字段的操作符。枚举值:min:最小值。max:最大值。average:平均数sum:求和。count:计数。distinct:去重计数。group:分组计数,按照分组计数结果从高到低排序。 + Field string `json:"Field, omitempty" url:"-" ` // 字段名称。关于支持的字段,请参考字段和操作符的支持列表。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type Query struct { + Operation string `json:"Operation, omitempty" url:"-" ` // 操作运算符。枚举值: not:逻辑非。 or:逻辑或。 and:逻辑与。 lt:小于。 lte:小于等于。 gt:大于。 gte:大于等于。 eq:等于。 exist:存在性查询。 prefix:前缀查询。 match-phrase:字符串匹配查询。 nested:字段为数组时,其中同一对象内逻辑条件查询。 + SubQueries []*SubQueries `json:"SubQueries, omitempty" url:"-" ` // 子查询的结构体。 只有当Operations为逻辑运算符(and、or、not或nested)时,才能设置子查询条件。 在逻辑运算符为and/or/not时,其SubQueries内描述的所有条件需符合父级设置的and/or/not逻辑关系。 在逻辑运算符为nested时,其父级的Field必须为一个数组类的字段(如:Labels)。 子查询条件SubQueries组的Operation必须为and/or/not中的一个或多个,其Field必须为父级Field的子属性。 + Field string `json:"Field, omitempty" url:"-" ` // 字段名称。关于支持的字段,请参考字段和操作符的支持列表。 + Value string `json:"Value, omitempty" url:"-" ` // 查询的字段值。当Operations为逻辑运算符(and、or、not或nested)时,该字段无效。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type SubQueries struct { + Value string `json:"Value, omitempty" url:"-" ` // 查询的字段值。当Operations为逻辑运算符(and、or、not或nested)时,该字段无效。 + Operation string `json:"Operation, omitempty" url:"-" ` // 操作运算符。枚举值:not:逻辑非。or:逻辑或。and:逻辑与。lt:小于。lte:小于等于。gt:大于。gte:大于等于。eq:等于。exist:存在性查询。prefix:前缀查询。match-phrase:字符串匹配查询。nested:字段为数组时,其中同一对象内逻辑条件查询。 + Field string `json:"Field, omitempty" url:"-" ` // 字段名称。关于支持的字段,请参考字段和操作符的支持列表。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DatasetSimpleQueryResult struct { + RequestId string `json:"RequestId"` // 请求ID + Files []*FileResult `json:"Files"` // 文件信息列表。仅在请求的Aggregations为空时返回。 + Aggregations []*AggregationsResult `json:"Aggregations"` // 聚合字段信息列表。仅在请求的Aggregations不为空时返回。 + NextToken string `json:"NextToken"` // 翻页标记。当文件总数大于设置的MaxResults时,用于翻页的Token。符合条件的文件信息未全部返回时,此参数才有值。下一次列出文件信息时将此值作为NextToken传入,将后续的文件信息返回。 +} + +type AggregationsResult struct { + Operation string `json:"Operation"` // 聚合字段的聚合操作符。 + Value float64 `json:"Value"` // 聚合的统计结果。 + Groups []*Groups `json:"Groups"` // 分组聚合的结果列表。仅在请求的Aggregations中存在group类型的Operation时才会返回。 + Field string `json:"Field"` // 聚合字段名称。 +} + +type Groups struct { + Count int `json:"Count"` // 分组聚合的总个数。 + Value string `json:"Value"` // 分组聚合的值。 +} + +type FileResult struct { + ObjectId string `json:"ObjectId"` // 对象唯一ID。 + CreateTime string `json:"CreateTime"` // 元数据创建时间的时间戳,格式为RFC3339Nano + UpdateTime string `json:"UpdateTime"` // 元数据修改时间的时间戳,格式为RFC3339Nano创建元数据后,如果未更新过元数据,则元数据修改时间的时间戳和元数据创建时间的时间戳相同 + URI string `json:"URI"` // 资源标识字段,表示需要建立索引的文件地址 + Filename string `json:"Filename"` // 文件路径 + MediaType string `json:"MediaType"` // 文件媒体类型。 枚举值:image:图片。other:其他。document:文档。archive:压缩包。audio:音频。video:视频。 + ContentType string `json:"ContentType"` // 文件内容类型(MIME Type)。 + COSStorageClass string `json:"COSStorageClass"` // 文件存储空间类型。 + COSCRC64 string `json:"COSCRC64"` // 文件CRC64值。 + Size int `json:"Size"` // 文件大小,单位为字节。 + CacheControl string `json:"CacheControl"` // 指定Object被下载时网页的缓存行为。该字段需要设置COS Object HTTP属性Cache-Control。 + ContentDisposition string `json:"ContentDisposition"` // 指定Object被下载时的名称。需要设置COS Object HTTP属性Content-Disposition。 + ContentEncoding string `json:"ContentEncoding"` // 指定该Object被下载时的内容编码格式。需要设置COS Object HTTP属性Content-Encoding。 + ContentLanguage string `json:"ContentLanguage"` // Object内容使用的语言。需要设置COS Object HTTP属性Content-Language。 + ServerSideEncryption string `json:"ServerSideEncryption"` // 加密算法,需要设置x-cos-server-side-encryption。 + ETag string `json:"ETag"` // Object生成时会创建相应的ETag ,ETag用于标识一个Object的内容。 + FileModifiedTime string `json:"FileModifiedTime"` // 文件最近一次修改时间的时间戳, 格式为RFC3339Nano。 + CustomId string `json:"CustomId"` // 该文件的自定义ID。该文件索引到数据集后,作为该行元数据的属性存储,用于和您的业务系统进行关联、对应。您可以根据业务需求传入该值,例如将某个URI关联到您系统内的某个ID。推荐传入全局唯一的值。 + CustomLabels *map[string]string `json:"CustomLabels"` // 文件自定义标签列表。储存您业务自定义的键名、键值对信息,用于在查询时可以据此为筛选项进行检索。 + COSUserMeta *map[string]string `json:"COSUserMeta"` // cos自定义头部。储存您业务在cos object上的键名、键值对信息,用于在查询时可以据此为筛选项进行检索。 + ObjectACL string `json:"ObjectACL"` // 文件访问权限属性。 + COSTagging *map[string]string `json:"COSTagging"` // cos自定义标签。储存您业务在cos object上的自定义标签的键名、键值对信息,用于在查询时可以据此为筛选项进行检索。 + COSTaggingCount int `json:"COSTaggingCount"` // cos自定义标签的数量。 + DatasetName string `json:"DatasetName"` // 数据集名称。 +} + +// 简单查询 +// https://cloud.tencent.com/document/product/460/106375 +func (s *MetaInsightService) DatasetSimpleQuery(ctx context.Context, opt *DatasetSimpleQueryOptions) (*DatasetSimpleQueryResult, *Response, error) { + var res DatasetSimpleQueryResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"datasetquery"+"/"+"simple", http.MethodPost) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type DatasetFaceSearchOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + URI string `json:"URI, omitempty" url:"-" ` // 资源标识字段,表示需要建立索引的文件地址。 + MaxFaceNum int `json:"MaxFaceNum, omitempty" url:"-" ` // 输入图片中检索的人脸数量,默认值为1(传0或不传采用默认值),最大值为10。 + Limit int `json:"Limit, omitempty" url:"-" ` // 检索的每张人脸返回相关人脸数量,默认值为10,最大值为100。 + MatchThreshold int `json:"MatchThreshold, omitempty" url:"-" ` // 出参 Score 中,只有超过 MatchThreshold 值的结果才会返回。范围:1-100,默认值为0,推荐值为80。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type DatasetFaceSearchResult struct { + FaceResult []*FaceResult `json:"FaceResult"` // 人脸检索识别结果信息列表。 + RequestId string `json:"RequestId"` // 请求 ID。 +} + +type FaceResult struct { + FaceInfos []*FaceInfosInMeta `json:"FaceInfos"` // 相关人脸信息列表。 + InputFaceBoundary *FaceBoundary `json:"InputFaceBoundary"` // 输入图片的人脸框位置。 +} + +type FaceBoundary struct { + Height int `json:"Height"` // 人脸高度。 + Width int `json:"Width"` // 人脸宽度。 + Left int `json:"Left"` // 人脸框左上角横坐标。 + Top int `json:"Top"` // 人脸框左上角纵坐标。 +} + +type FaceInfosInMeta struct { + PersonId string `json:"PersonId"` // 自定义人物ID。 + FaceBoundary *FaceBoundary `json:"FaceBoundary"` // 相关人脸框位置。 + FaceId string `json:"FaceId"` // 人脸ID。 + Score int `json:"Score"` // 相关人脸匹配得分。 + URI string `json:"URI"` // 资源标识字段,表示需要建立索引的文件地址。 +} + +// 人脸搜索 +// https://cloud.tencent.com/document/product/460/106166 +func (s *MetaInsightService) DatasetFaceSearch(ctx context.Context, opt *DatasetFaceSearchOptions) (*DatasetFaceSearchResult, *Response, error) { + var res DatasetFaceSearchResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"datasetquery"+"/"+"facesearch", http.MethodPost) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} + +type SearchImageOptions struct { + DatasetName string `json:"DatasetName, omitempty" url:"-" ` // 数据集名称,同一个账户下唯一。 + Mode string `json:"Mode, omitempty" url:"-" ` // 指定检索方式为图片或文本,pic 为图片检索,text 为文本检索,默认为 pic。 + URI string `json:"URI, omitempty" url:"-" ` // 资源标识字段,表示需要建立索引的文件地址(Mode 为 pic 时必选)。 + Limit int `json:"Limit, omitempty" url:"-" ` // 返回相关图片的数量,默认值为10,最大值为100。 + Text string `json:"Text, omitempty" url:"-" ` // 检索语句,检索方式为 text 时必填,最多支持60个字符 (Mode 为 text 时必选)。 + MatchThreshold int `json:"MatchThreshold, omitempty" url:"-" ` // 出参 Score(相关图片匹配得分) 中,只有超过 MatchThreshold 值的结果才会返回。默认值为0,推荐值为80。 + OptHeaders *OptHeaders `header:"-, omitempty" url:"-" json:"-" xml:"-"` +} + +type SearchImageResult struct { + ImageResult []*ImageResult `json:"ImageResult"` // 图像检索识别结果信息列表。 + RequestId string `json:"RequestId"` // 请求ID。 +} + +type ImageResult struct { + URI string `json:"URI"` // 资源标识字段,表示需要建立索引的文件地址。 + Score int `json:"Score"` // 相关图片匹配得分。 +} + +// 图像检索 +// https://cloud.tencent.com/document/product/460/106376 +func (s *MetaInsightService) SearchImage(ctx context.Context, opt *SearchImageOptions) (*SearchImageResult, *Response, error) { + var res SearchImageResult + if opt == nil { + return nil, nil, fmt.Errorf("opt param nil") + } + buf, resp, err := s.baseSend(ctx, opt, opt.OptHeaders, "/"+"datasetquery"+"/"+"imagesearch", http.MethodPost) + if buf.Len() > 0 { + err = json.Unmarshal(buf.Bytes(), &res) + } + return &res, resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/cos.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/cos.go index 84ceb12592..454b21821e 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/cos.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/cos.go @@ -5,11 +5,13 @@ import ( "context" "encoding/base64" "encoding/xml" + "errors" "fmt" "io" "io/ioutil" "net/http" "net/url" + "path/filepath" "reflect" "strings" "text/template" @@ -24,7 +26,7 @@ import ( const ( // Version current go sdk version - Version = "0.7.42" + Version = "0.7.58" UserAgent = "cos-go-sdk-v5/" + Version contentTypeXML = "application/xml" defaultServiceBaseURL = "http://service.cos.myqcloud.com" @@ -39,9 +41,25 @@ var ( ) // {|}{bucketname-appid}.{cos|cos-internal|cos-website|ci}.{region}.{myqcloud.com/tencentcos.cn}{/} - hostSuffix = regexp.MustCompile(`^.*((cos|cos-internal|cos-website|ci)\.[a-z-1]+|file)\.(myqcloud\.com|tencentcos\.cn).*$`) - hostPrefix = regexp.MustCompile(`^(http://|https://){0,1}([a-z0-9-]+-[0-9]+\.){0,1}((cos|cos-internal|cos-website|ci)\.[a-z-1]+|file)\.(myqcloud\.com|tencentcos\.cn).*$`) - invalidBucketErr = fmt.Errorf("invalid bucket format, please check your cos.BaseURL") + hostSuffix = regexp.MustCompile(`^.*((cos|cos-internal|cos-website|ci)\.[a-z-1]+|file)\.(myqcloud\.com|tencentcos\.cn).*$`) + hostPrefix = regexp.MustCompile(`^(http://|https://){0,1}([a-z0-9-]+-[0-9]+\.){0,1}((cos|cos-internal|cos-website|ci)\.[a-z-1]+|file)\.(myqcloud\.com|tencentcos\.cn).*$`) + metaInsightHostPrefix = regexp.MustCompile(`^(http://|https://){0,1}([0-9]+\.){1}((cos|cos-internal|cos-website|ci)\.[a-z-1]+|file)\.(myqcloud\.com|tencentcos\.cn).*$`) + bucketChecker = regexp.MustCompile(`^[a-z0-9-]+-[0-9]+$`) + regionChecker = regexp.MustCompile(`^[a-z-1]+$`) + + // 校验传入的url + domainSuffix = regexp.MustCompile(`^.*\.(myqcloud\.com(:[0-9]+){0,1}|tencentcos\.cn(:[0-9]+){0,1})$`) + bucketDomainChecker = regexp.MustCompile(`^(http://|https://){0,1}([a-z0-9-]+-[0-9]+\.){0,1}((cos|cos-internal|cos-website|ci)\.[a-z-1]+|file)\.(myqcloud\.com|tencentcos\.cn)(:[0-9]+){0,1}$`) + serviceDomainChecker = regexp.MustCompile(`^(http://|https://){0,1}((service.cos.myqcloud.com|service.cos-internal.tencentcos.cn|service.cos.tencentcos.cn)|(cos|cos-internal)\.[a-z-1]+\.(myqcloud\.com|tencentcos\.cn))(:[0-9]+){0,1}$`) + batchDomainChecker = regexp.MustCompile(`^(http://|https://){0,1}([0-9]+\.){1}cos-control\.[a-z-1]+\.(myqcloud\.com|tencentcos\.cn)(:[0-9]+){0,1}$`) + invalidBucketErr = fmt.Errorf("invalid bucket format, please check your cos.BaseURL") + + switchHost = regexp.MustCompile(`([a-z0-9-]+-[0-9]+\.)(cos\.[a-z-1]+)\.(myqcloud\.com)(:[0-9]+){0,1}$`) + accelerateDomainSuffix = "accelerate.myqcloud.com" + oldDomainSuffix = ".myqcloud.com" + newDomainSuffix = ".tencentcos.cn" + + ObjectKeySimplifyCheckErr = fmt.Errorf("The Getobject Key is illegal") ) // BaseURL 访问各 API 所需的基础 URL @@ -56,6 +74,28 @@ type BaseURL struct { CIURL *url.URL // 访问 Fetch Task 的基础 URL FetchURL *url.URL + // 访问 MetaInsight 的基础 URL + MetaInsightURL *url.URL +} + +func (*BaseURL) innerCheck(u *url.URL, reg *regexp.Regexp) bool { + if u == nil { + return true + } + urlStr := strings.TrimRight(u.String(), "/") + if !strings.HasPrefix(urlStr, "https://") && !strings.HasPrefix(urlStr, "http://") { + return false + } + if domainSuffix.MatchString(urlStr) && !reg.MatchString(urlStr) { + return false + } + return true +} + +func (u *BaseURL) Check() bool { + return u.innerCheck(u.BucketURL, bucketDomainChecker) && + (u.innerCheck(u.ServiceURL, serviceDomainChecker) || u.innerCheck(u.ServiceURL, bucketDomainChecker)) && + (u.innerCheck(u.BatchURL, batchDomainChecker) || u.innerCheck(u.BatchURL, bucketDomainChecker)) } // NewBucketURL 生成 BaseURL 所需的 BucketURL @@ -69,7 +109,7 @@ func NewBucketURL(bucketName, region string, secure bool) (*url.URL, error) { schema = "http" } - if region == "" { + if region == "" || !regionChecker.MatchString(region) { return nil, fmt.Errorf("region[%v] is invalid", region) } if bucketName == "" || !strings.ContainsAny(bucketName, "-") { @@ -89,14 +129,15 @@ func NewBucketURL(bucketName, region string, secure bool) (*url.URL, error) { } type RetryOptions struct { - Count int - Interval time.Duration - StatusCode []int + Count int + Interval time.Duration + AutoSwitchHost bool } type Config struct { - EnableCRC bool - RequestBodyClose bool - RetryOpt RetryOptions + EnableCRC bool + RequestBodyClose bool + RetryOpt RetryOptions + ObjectKeySimplifyCheck bool } // Client is a client manages communication with the COS API. @@ -109,24 +150,41 @@ type Client struct { common service - Service *ServiceService - Bucket *BucketService - Object *ObjectService - Batch *BatchService - CI *CIService + Service *ServiceService + Bucket *BucketService + Object *ObjectService + Batch *BatchService + CI *CIService + MetaInsight *MetaInsightService Conf *Config + + invalidURL bool } type service struct { client *Client } +// go http default CheckRedirect +func HttpDefaultCheckRedirect(req *http.Request, via []*http.Request) error { + if len(via) >= 10 { + return errors.New("stopped after 10 redirects") + } + return nil +} + // NewClient returns a new COS API client. func NewClient(uri *BaseURL, httpClient *http.Client) *Client { if httpClient == nil { httpClient = &http.Client{} } + // avoid SSRF, default don't follow 3xx + if httpClient.CheckRedirect == nil { + httpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + } + } baseURL := &BaseURL{} if uri != nil { @@ -135,10 +193,15 @@ func NewClient(uri *BaseURL, httpClient *http.Client) *Client { baseURL.BatchURL = uri.BatchURL baseURL.CIURL = uri.CIURL baseURL.FetchURL = uri.FetchURL + baseURL.MetaInsightURL = uri.MetaInsightURL } if baseURL.ServiceURL == nil { baseURL.ServiceURL, _ = url.Parse(defaultServiceBaseURL) } + var invalidURL bool + if !baseURL.Check() { + invalidURL = true + } c := &Client{ client: httpClient, @@ -148,10 +211,13 @@ func NewClient(uri *BaseURL, httpClient *http.Client) *Client { EnableCRC: true, RequestBodyClose: false, RetryOpt: RetryOptions{ - Count: 3, - Interval: time.Duration(0), + Count: 3, + Interval: time.Duration(0), + AutoSwitchHost: false, }, + ObjectKeySimplifyCheck: true, }, + invalidURL: invalidURL, } c.common.client = c c.Service = (*ServiceService)(&c.common) @@ -159,9 +225,14 @@ func NewClient(uri *BaseURL, httpClient *http.Client) *Client { c.Object = (*ObjectService)(&c.common) c.Batch = (*BatchService)(&c.common) c.CI = (*CIService)(&c.common) + c.MetaInsight = (*MetaInsightService)(&c.common) return c } +func (c *Client) DisableURLCheck() { + c.invalidURL = false +} + type Credential struct { SecretID string SecretKey string @@ -200,10 +271,16 @@ func (c *Client) GetCredential() *Credential { return nil } -func (c *Client) newRequest(ctx context.Context, baseURL *url.URL, uri, method string, body interface{}, optQuery interface{}, optHeader interface{}) (req *http.Request, err error) { - if !checkURL(baseURL) { +func (c *Client) newRequest(ctx context.Context, baseURL *url.URL, uri, method string, body interface{}, optQuery interface{}, optHeader interface{}, isRetry bool) (req *http.Request, err error) { + if c.invalidURL { return nil, invalidBucketErr } + if !checkURL(baseURL) { + host := baseURL.String() + if c.BaseURL.MetaInsightURL != baseURL || !metaInsightHostPrefix.MatchString(host) { + return nil, invalidBucketErr + } + } uri, err = addURLOptions(uri, optQuery) if err != nil { return @@ -253,6 +330,9 @@ func (c *Client) newRequest(ctx context.Context, baseURL *url.URL, uri, method s if req.Header.Get("Content-Type") == "" && contentType != "" { req.Header.Set("Content-Type", contentType) } + if isRetry { + req.Header.Set("X-Cos-Sdk-Retry", "true") + } if c.Host != "" { req.Host = c.Host } @@ -317,7 +397,10 @@ func (c *Client) doAPI(ctx context.Context, req *http.Request, result interface{ if result != nil { if w, ok := result.(io.Writer); ok { - io.Copy(w, resp.Body) + _, err = io.Copy(w, resp.Body) + if err != nil { // read body failed + return response, err + } } else { err = xml.NewDecoder(resp.Body).Decode(result) if err == io.EOF { @@ -347,6 +430,46 @@ type sendOptions struct { // 是否禁用自动调用 resp.Body.Close() // 自动调用 Close() 是为了能够重用连接 disableCloseBody bool + // 是否重试 + isRetry bool +} + +func toSwitchHost(oldURL *url.URL) *url.URL { + // 判断域名是否能够切换 + if !switchHost.MatchString(oldURL.Host) { + return oldURL + } + newURL, _ := url.Parse(oldURL.String()) + hostAndPort := strings.SplitN(newURL.Host, ":", 2) + newHost := hostAndPort[0] + // 加速域名不切换 + if strings.HasSuffix(newHost, accelerateDomainSuffix) { + return oldURL + } + newHost = newHost[:len(newHost)-len(oldDomainSuffix)] + newDomainSuffix + if len(hostAndPort) > 1 { + newHost += ":" + hostAndPort[1] + } + newURL.Host = newHost + return newURL +} + +func (c *Client) CheckRetrieable(u *url.URL, resp *Response, err error, secondLast bool) (*url.URL, bool) { + res := u + if err != nil && err != invalidBucketErr { + // 不重试 + if resp != nil && resp.StatusCode < 500 { + return res, false + } + if c.Conf.RetryOpt.AutoSwitchHost && secondLast { + // 收不到报文 或者 不存在RequestId + if resp == nil || resp.Header.Get("X-Cos-Request-Id") == "" { + res = toSwitchHost(u) + } + } + return res, true + } + return res, false } func (c *Client) doRetry(ctx context.Context, opt *sendOptions) (resp *Response, err error) { @@ -357,39 +480,39 @@ func (c *Client) doRetry(ctx context.Context, opt *sendOptions) (resp *Response, } } count := 1 - if count < c.Conf.RetryOpt.Count { + if c.Conf.RetryOpt.Count > 0 { count = c.Conf.RetryOpt.Count } - nr := 0 - interval := c.Conf.RetryOpt.Interval - for nr < count { + retryErr := &RetryError{} + var retrieable bool + for nr := 0; nr < count; nr++ { + // 把上一次错误记录下来 + if err != nil { + retryErr.Add(err) + } + opt.isRetry = nr > 0 resp, err = c.send(ctx, opt) - if err != nil && err != invalidBucketErr { - if resp != nil && resp.StatusCode <= 499 { - dobreak := true - for _, v := range c.Conf.RetryOpt.StatusCode { - if resp.StatusCode == v { - dobreak = false - break - } - } - if dobreak { - break - } - } - nr++ - if interval > 0 && nr < count { - time.Sleep(interval) + opt.baseURL, retrieable = c.CheckRetrieable(opt.baseURL, resp, err, nr >= count-2) + if retrieable { + if c.Conf.RetryOpt.Interval > 0 && nr+1 < count { + time.Sleep(c.Conf.RetryOpt.Interval) } continue } break } + // 最后一次非COS错误,输出三次结果 + if err != nil { + if _, ok := err.(*ErrorResponse); !ok { + retryErr.Add(err) + err = retryErr + } + } return - } + func (c *Client) send(ctx context.Context, opt *sendOptions) (resp *Response, err error) { - req, err := c.newRequest(ctx, opt.baseURL, opt.uri, opt.method, opt.body, opt.optQuery, opt.optHeader) + req, err := c.newRequest(ctx, opt.baseURL, opt.uri, opt.method, opt.body, opt.optQuery, opt.optHeader, opt.isRetry) if err != nil { return } @@ -471,6 +594,12 @@ func addHeaderOptions(ctx context.Context, header http.Header, opt interface{}) } func checkURL(baseURL *url.URL) bool { + if baseURL == nil { + return false + } + if baseURL.Scheme == "" || baseURL.Hostname() == "" { + return false + } host := baseURL.String() if hostSuffix.MatchString(host) && !hostPrefix.MatchString(host) { return false @@ -478,6 +607,14 @@ func checkURL(baseURL *url.URL) bool { return true } +func CheckObjectKeySimplify(key string) bool { + res, err := filepath.Abs(key) + if res == "/" || err != nil { + return false + } + return true +} + // Owner defines Bucket/Object's owner type Owner struct { UIN string `xml:"uin,omitempty"` @@ -511,12 +648,13 @@ type ACLHeaderOptions struct { // ACLGrantee is the param of ACLGrant type ACLGrantee struct { - Type string `xml:"type,attr"` - UIN string `xml:"uin,omitempty"` - URI string `xml:"URI,omitempty"` - ID string `xml:",omitempty"` - DisplayName string `xml:",omitempty"` - SubAccount string `xml:"Subaccount,omitempty"` + TypeAttr xml.Attr `xml:",attr,omitempty"` + Type string `xml:"type,attr,omitempty"` + UIN string `xml:"uin,omitempty"` + URI string `xml:"URI,omitempty"` + ID string `xml:",omitempty"` + DisplayName string `xml:",omitempty"` + SubAccount string `xml:"Subaccount,omitempty"` } // ACLGrant is the param of ACLXml @@ -532,6 +670,26 @@ type ACLXml struct { AccessControlList []ACLGrant `xml:"AccessControlList>Grant,omitempty"` } +type aclEnum struct { + Private string + PublicRead string + PublicReadWrite string + AuthenticatedRead string + Default string + BucketOwnerRead string + BucketOwnerFullControl string +} + +var ACL = &aclEnum{ + Private: "private", + PublicRead: "public-read", + PublicReadWrite: "public-read-write", + AuthenticatedRead: "authenticated-read", + Default: "default", + BucketOwnerRead: "bucket-owner-read", + BucketOwnerFullControl: "bucket-owner-full-control", +} + func decodeACL(resp *Response, res *ACLXml) { ItemMap := map[string]string{ "ACL": "x-cos-acl", diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/error.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/error.go index 8f0a7c8e6a..d3a20e44ec 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/error.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/error.go @@ -10,6 +10,22 @@ import ( "strings" ) +type RetryError struct { + Errs []error +} + +func (r *RetryError) Error() string { + var errStr []string + for _, err := range r.Errs { + errStr = append(errStr, err.Error()) + } + return strings.Join(errStr, "; ") +} + +func (r *RetryError) Add(err error) { + r.Errs = append(r.Errs, err) +} + // ErrorResponse 包含 API 返回的错误信息 // // https://www.qcloud.com/document/product/436/7730 diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/helper.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/helper.go index 5d6556952c..87b8ddaff6 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/helper.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/helper.go @@ -12,6 +12,7 @@ import ( "net/http" "net/url" "os" + "regexp" "strconv" "strings" ) @@ -180,7 +181,7 @@ func IsLenReader(reader io.Reader) bool { func CheckReaderLen(reader io.Reader) error { nlen, err := GetReaderLen(reader) - if err != nil || nlen < singleUploadMaxLength { + if err != nil || nlen <= singleUploadMaxLength { return nil } return errors.New("The single object size you upload can not be larger than 5GB") @@ -233,6 +234,7 @@ func CloneObjectPutOptions(opt *ObjectPutOptions) *ObjectPutOptions { res := &ObjectPutOptions{ &ACLHeaderOptions{}, &ObjectPutHeaderOptions{}, + nil, } if opt != nil { if opt.ACLHeaderOptions != nil { @@ -243,6 +245,9 @@ func CloneObjectPutOptions(opt *ObjectPutOptions) *ObjectPutOptions { res.XCosMetaXXX = cloneHeader(opt.XCosMetaXXX) res.XOptionHeader = cloneHeader(opt.XOptionHeader) } + if opt.innerSwitchURL != nil { + res.innerSwitchURL = opt.innerSwitchURL + } } return res } @@ -296,6 +301,15 @@ func CloneCompleteMultipartUploadOptions(opt *CompleteMultipartUploadOptions) *C return &res } +func cloneObjectCopyPartOptions(opt *ObjectCopyPartOptions) *ObjectCopyPartOptions { + var res ObjectCopyPartOptions + if opt != nil { + res = *opt + res.XOptionHeader = cloneHeader(opt.XOptionHeader) + } + return &res +} + type RangeOptions struct { HasStart bool HasEnd bool @@ -368,7 +382,7 @@ func isDeliverHeader(key string) bool { return true } } - return strings.HasPrefix(key, privateHeaderPrefix) + return strings.HasPrefix(key, privateHeaderPrefix) || strings.HasPrefix(key, "x-") } func deliverInitOptions(opt *InitiateMultipartUploadOptions) (*http.Header, error) { @@ -390,3 +404,73 @@ func deliverInitOptions(opt *InitiateMultipartUploadOptions) (*http.Header, erro } return header, nil } + +var ( + bucketReg = regexp.MustCompile(`([a-z0-9-]+-[0-9]+)`) + keyReg = regexp.MustCompile(`(.*?)`) + uploadIdReg = regexp.MustCompile(`([a-z0-9]+)`) + locationReg = regexp.MustCompile(`(.*?)`) + etagReg = regexp.MustCompile(`"(.*?)"`) +) + +func UnmarshalInitMultiUploadResult(data []byte, res *InitiateMultipartUploadResult) error { + match := bucketReg.FindStringSubmatch(string(data)) + if len(match) > 1 { + res.Bucket = match[1] + } else { + return fmt.Errorf("Unmarshal failed, %v", string(data)) + } + match = keyReg.FindStringSubmatch(string(data)) + if len(match) > 1 { + res.Key = match[1] + } else { + return fmt.Errorf("Unmarshal failed, %v", string(data)) + } + match = uploadIdReg.FindStringSubmatch(string(data)) + if len(match) > 1 { + res.UploadID = match[1] + } else { + return fmt.Errorf("Unmarshal failed, %v", string(data)) + } + return nil +} + +func UnmarshalCompleteMultiUploadResult(data []byte, res *CompleteMultipartUploadResult) error { + match := locationReg.FindStringSubmatch(string(data)) + if len(match) > 1 { + res.Location = match[1] + } else { + return fmt.Errorf("Unmarshal Location failed, %v", string(data)) + } + match = bucketReg.FindStringSubmatch(string(data)) + if len(match) > 1 { + res.Bucket = match[1] + } else { + return fmt.Errorf("Unmarshal Bucket failed, %v", string(data)) + } + match = keyReg.FindStringSubmatch(string(data)) + if len(match) > 1 { + res.Key = match[1] + } else { + return fmt.Errorf("Unmarshal Key failed, %v", string(data)) + } + match = etagReg.FindStringSubmatch(string(data)) + if len(match) > 1 { + res.ETag = "\"" + match[1] + "\"" + } else { + return fmt.Errorf("Unmarshal Etag failed, %v", string(data)) + } + + return nil +} + +func GetBucketRegionFromUrl(u *url.URL) (string, string) { + if u == nil { + return "", "" + } + vec := strings.Split(u.Host, ".") + if len(vec) < 3 { + return "", "" + } + return vec[0], vec[2] +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/object.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/object.go index 96198bd708..dae557d991 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/object.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/object.go @@ -57,6 +57,9 @@ type presignedURLTestingOptions struct { // // https://www.qcloud.com/document/product/436/7753 func (s *ObjectService) Get(ctx context.Context, name string, opt *ObjectGetOptions, id ...string) (*Response, error) { + if s.client.Conf.ObjectKeySimplifyCheck && !CheckObjectKeySimplify("/"+name) { + return nil, ObjectKeySimplifyCheckErr + } var u string if len(id) == 1 { u = fmt.Sprintf("/%s?versionId=%s", encodeURIComponent(name), id[0]) @@ -115,14 +118,19 @@ func (s *ObjectService) GetObjectURL(name string) *url.URL { } type PresignedURLOptions struct { - Query *url.Values `xml:"-" url:"-" header:"-"` - Header *http.Header `header:"-,omitempty" url:"-" xml:"-"` - SignMerged bool `xml:"-" url:"-" header:"-"` + Query *url.Values `xml:"-" url:"-" header:"-"` + Header *http.Header `header:"-,omitempty" url:"-" xml:"-"` + SignMerged bool `xml:"-" url:"-" header:"-"` + AuthTime *AuthTime `xml:"-" url:"-" header:"-"` + EncodeDelimiter bool `xml:"-" url:"-" header:"-"` } // GetPresignedURL get the object presigned to down or upload file by url // 预签名函数,signHost: 默认签入Header Host, 您也可以选择不签入Header Host,但可能导致请求失败或安全漏洞 func (s *ObjectService) GetPresignedURL(ctx context.Context, httpMethod, name, ak, sk string, expired time.Duration, opt interface{}, signHost ...bool) (*url.URL, error) { + if name == "" { + return nil, fmt.Errorf("object key is empty.") + } // 兼容 name 以 / 开头的情况 if strings.HasPrefix(name, "/") { name = encodeURIComponent("/") + encodeURIComponent(name[1:], []byte{'/'}) @@ -137,25 +145,28 @@ func (s *ObjectService) GetPresignedURL(ctx context.Context, httpMethod, name, a optQuery: opt, optHeader: opt, } - if popt, ok := opt.(*PresignedURLOptions); ok { - if popt != nil && popt.Query != nil { - qs := popt.Query.Encode() - if qs != "" { - sendOpt.uri = fmt.Sprintf("%s?%s", sendOpt.uri, qs) + var authTime *AuthTime + if opt != nil { + if popt, ok := opt.(*presignedURLTestingOptions); ok { + authTime = popt.authTime + } + if popt, ok := opt.(*PresignedURLOptions); ok { + if popt.Query != nil { + qs := popt.Query.Encode() + if qs != "" { + sendOpt.uri = fmt.Sprintf("%s?%s", sendOpt.uri, qs) + } + } + if popt.AuthTime != nil { + authTime = popt.AuthTime } } } - req, err := s.client.newRequest(ctx, sendOpt.baseURL, sendOpt.uri, sendOpt.method, sendOpt.body, sendOpt.optQuery, sendOpt.optHeader) + req, err := s.client.newRequest(ctx, sendOpt.baseURL, sendOpt.uri, sendOpt.method, sendOpt.body, sendOpt.optQuery, sendOpt.optHeader, false) if err != nil { return nil, err } - var authTime *AuthTime - if opt != nil { - if opt, ok := opt.(*presignedURLTestingOptions); ok { - authTime = opt.authTime - } - } if authTime == nil { authTime = NewAuthTime(expired) } @@ -187,7 +198,10 @@ func (s *ObjectService) GetPresignedURL(ctx context.Context, httpMethod, name, a return req.URL, nil } -func (s *ObjectService) GetSignature(ctx context.Context, httpMethod, name, ak, sk string, expired time.Duration, opt *PresignedURLOptions, signHost ...bool) string { +func (s *ObjectService) GetPresignedURL2(ctx context.Context, httpMethod, name string, expired time.Duration, opt interface{}, signHost ...bool) (*url.URL, error) { + if name == "" { + return nil, fmt.Errorf("object key is empty.") + } // 兼容 name 以 / 开头的情况 if strings.HasPrefix(name, "/") { name = encodeURIComponent("/") + encodeURIComponent(name[1:], []byte{'/'}) @@ -195,6 +209,166 @@ func (s *ObjectService) GetSignature(ctx context.Context, httpMethod, name, ak, name = encodeURIComponent(name, []byte{'/'}) } + cred := s.client.GetCredential() + if cred == nil { + return nil, fmt.Errorf("GetCredential failed") + } + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + name, + method: httpMethod, + optQuery: opt, + optHeader: opt, + } + var authTime *AuthTime + mark := "?" + if opt != nil { + if popt, ok := opt.(*presignedURLTestingOptions); ok { + authTime = popt.authTime + } + if popt, ok := opt.(*PresignedURLOptions); ok { + if popt.Query != nil { + qs := popt.Query.Encode() + if qs != "" { + sendOpt.uri = fmt.Sprintf("%s?%s", sendOpt.uri, qs) + mark = "&" + } + } + if popt.AuthTime != nil { + authTime = popt.AuthTime + } + } + } + if cred.SessionToken != "" { + sendOpt.uri = fmt.Sprintf("%s%s%s", sendOpt.uri, mark, url.Values{"x-cos-security-token": []string{cred.SessionToken}}.Encode()) + } + + req, err := s.client.newRequest(ctx, sendOpt.baseURL, sendOpt.uri, sendOpt.method, sendOpt.body, sendOpt.optQuery, sendOpt.optHeader, false) + if err != nil { + return nil, err + } + + if authTime == nil { + authTime = NewAuthTime(expired) + } + signedHost := true + if len(signHost) > 0 { + signedHost = signHost[0] + } + authorization := newAuthorization(cred.SecretID, cred.SecretKey, req, authTime, signedHost) + if opt != nil { + if opt, ok := opt.(*PresignedURLOptions); ok { + if opt.SignMerged { + sign := encodeURIComponent(authorization) + if req.URL.RawQuery == "" { + req.URL.RawQuery = fmt.Sprintf("sign=%s", sign) + } else { + req.URL.RawQuery = fmt.Sprintf("%s&sign=%s", req.URL.RawQuery, sign) + } + return req.URL, nil + } + } + } + sign := encodeURIComponent(authorization, []byte{'&', '='}) + + if req.URL.RawQuery == "" { + req.URL.RawQuery = fmt.Sprintf("%s", sign) + } else { + req.URL.RawQuery = fmt.Sprintf("%s&%s", req.URL.RawQuery, sign) + } + return req.URL, nil +} + +func (s *ObjectService) GetPresignedURL3(ctx context.Context, httpMethod, name string, expired time.Duration, opt interface{}, signHost ...bool) (*url.URL, error) { + if name == "" { + return nil, fmt.Errorf("object key is empty.") + } + var encodeDelimiter bool + if opt != nil { + if popt, ok := opt.(*PresignedURLOptions); ok { + encodeDelimiter = popt.EncodeDelimiter + } + } + if encodeDelimiter { + name = encodeURIComponent(name) + } else { + name = encodeURIComponent(name, []byte("/")) + } + + cred := s.client.GetCredential() + if cred == nil { + return nil, fmt.Errorf("GetCredential failed") + } + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + name, + method: httpMethod, + optQuery: opt, + optHeader: opt, + } + var authTime *AuthTime + mark := "?" + if opt != nil { + if popt, ok := opt.(*presignedURLTestingOptions); ok { + authTime = popt.authTime + } + if popt, ok := opt.(*PresignedURLOptions); ok { + if popt.Query != nil { + qs := popt.Query.Encode() + if qs != "" { + sendOpt.uri = fmt.Sprintf("%s?%s", sendOpt.uri, qs) + mark = "&" + } + } + if popt.AuthTime != nil { + authTime = popt.AuthTime + } + } + } + if cred.SessionToken != "" { + sendOpt.uri = fmt.Sprintf("%s%s%s", sendOpt.uri, mark, url.Values{"x-cos-security-token": []string{cred.SessionToken}}.Encode()) + } + + req, err := s.client.newRequest(ctx, sendOpt.baseURL, sendOpt.uri, sendOpt.method, sendOpt.body, sendOpt.optQuery, sendOpt.optHeader, false) + if err != nil { + return nil, err + } + + if authTime == nil { + authTime = NewAuthTime(expired) + } + signedHost := true + if len(signHost) > 0 { + signedHost = signHost[0] + } + authorization := newAuthorization(cred.SecretID, cred.SecretKey, req, authTime, signedHost) + if opt != nil { + if opt, ok := opt.(*PresignedURLOptions); ok { + if opt.SignMerged { + sign := encodeURIComponent(authorization) + if req.URL.RawQuery == "" { + req.URL.RawQuery = fmt.Sprintf("sign=%s", sign) + } else { + req.URL.RawQuery = fmt.Sprintf("%s&sign=%s", req.URL.RawQuery, sign) + } + return req.URL, nil + } + } + } + sign := encodeURIComponent(authorization, []byte{'&', '='}) + + if req.URL.RawQuery == "" { + req.URL.RawQuery = fmt.Sprintf("%s", sign) + } else { + req.URL.RawQuery = fmt.Sprintf("%s&%s", req.URL.RawQuery, sign) + } + return req.URL, nil +} + +func (s *ObjectService) GetSignature(ctx context.Context, httpMethod, name, ak, sk string, expired time.Duration, opt *PresignedURLOptions, signHost ...bool) string { + // 兼容 name 以 / 开头的情况 + name = encodeURIComponent(name) + sendOpt := sendOptions{ baseURL: s.client.BaseURL.BucketURL, uri: "/" + name, @@ -208,7 +382,7 @@ func (s *ObjectService) GetSignature(ctx context.Context, httpMethod, name, ak, sendOpt.uri = fmt.Sprintf("%s?%s", sendOpt.uri, qs) } } - req, err := s.client.newRequest(ctx, sendOpt.baseURL, sendOpt.uri, sendOpt.method, sendOpt.body, sendOpt.optQuery, sendOpt.optHeader) + req, err := s.client.newRequest(ctx, sendOpt.baseURL, sendOpt.uri, sendOpt.method, sendOpt.body, sendOpt.optQuery, sendOpt.optHeader, false) if err != nil { return "" } @@ -257,6 +431,9 @@ type ObjectPutHeaderOptions struct { type ObjectPutOptions struct { *ACLHeaderOptions `header:",omitempty" url:"-" xml:"-"` *ObjectPutHeaderOptions `header:",omitempty" url:"-" xml:"-"` + + // PutFromFile 使用 + innerSwitchURL *url.URL `header:"-" url:"-" xml:"-"` } // Put Object请求可以将一个文件(Oject)上传至指定Bucket。 @@ -283,27 +460,69 @@ func (s *ObjectService) Put(ctx context.Context, name string, r io.Reader, uopt opt.ContentLength = totalBytes } } - reader := TeeReader(r, nil, totalBytes, nil) - if s.client.Conf.EnableCRC { - reader.writer = crc64.New(crc64.MakeTable(crc64.ECMA)) + // 如果是io.Seeker,则重试 + count := 1 + var position int64 + if seeker, ok := r.(io.Seeker); ok { + // 记录原始位置 + position, err = seeker.Seek(0, io.SeekCurrent) + if err == nil && s.client.Conf.RetryOpt.Count > 0 { + count = s.client.Conf.RetryOpt.Count + } } - if opt != nil && opt.Listener != nil { - reader.listener = opt.Listener + var resp *Response + var retrieable bool + sUrl := s.client.BaseURL.BucketURL + if opt.innerSwitchURL != nil { + sUrl = opt.innerSwitchURL + } + retryErr := &RetryError{} + for nr := 0; nr < count; nr++ { + reader := TeeReader(r, nil, totalBytes, nil) + if s.client.Conf.EnableCRC { + reader.writer = crc64.New(crc64.MakeTable(crc64.ECMA)) + } + if opt != nil && opt.Listener != nil { + reader.listener = opt.Listener + } + sendOpt := sendOptions{ + baseURL: sUrl, + uri: "/" + encodeURIComponent(name), + method: http.MethodPut, + body: reader, + optHeader: opt, + } + + // 把上一次错误记录下来 + if err != nil { + retryErr.Add(err) + } + resp, err = s.client.send(ctx, &sendOpt) + sUrl, retrieable = s.client.CheckRetrieable(sUrl, resp, err, nr >= count-2) + if retrieable && nr+1 < count { + if seeker, ok := r.(io.Seeker); ok { + _, e := seeker.Seek(position, io.SeekStart) + if e != nil { + break + } + continue + } + } + break } - sendOpt := sendOptions{ - baseURL: s.client.BaseURL.BucketURL, - uri: "/" + encodeURIComponent(name), - method: http.MethodPut, - body: reader, - optHeader: opt, + if err != nil { + if _, ok := err.(*ErrorResponse); !ok { + retryErr.Add(err) + err = retryErr + } } - resp, err := s.client.send(ctx, &sendOpt) return resp, err } // PutFromFile put object from local file -func (s *ObjectService) PutFromFile(ctx context.Context, name string, filePath string, opt *ObjectPutOptions) (resp *Response, err error) { +func (s *ObjectService) PutFromFile(ctx context.Context, name string, filePath string, uopt *ObjectPutOptions) (resp *Response, err error) { + opt := CloneObjectPutOptions(uopt) nr := 0 for nr < 3 { fd, e := os.Open(filePath) @@ -315,6 +534,12 @@ func (s *ObjectService) PutFromFile(ctx context.Context, name string, filePath s if err != nil { nr++ fd.Close() + if s.client.Conf.RetryOpt.AutoSwitchHost { + // 收不到报文 或者 不存在RequestId + if resp == nil || resp.Header.Get("X-Cos-Request-Id") == "" { + opt.innerSwitchURL = toSwitchHost(s.client.BaseURL.BucketURL) + } + } continue } fd.Close() @@ -378,6 +603,9 @@ type ObjectCopyResult struct { // // https://cloud.tencent.com/document/product/436/10881 func (s *ObjectService) Copy(ctx context.Context, name, sourceURL string, opt *ObjectCopyOptions, id ...string) (*ObjectCopyResult, *Response, error) { + if strings.HasPrefix(sourceURL, "http://") || strings.HasPrefix(sourceURL, "https://") { + return nil, nil, errors.New("sourceURL format is invalid.") + } surl := strings.SplitN(sourceURL, "/", 2) if len(surl) < 2 { return nil, nil, errors.New(fmt.Sprintf("x-cos-copy-source format error: %s", sourceURL)) @@ -386,7 +614,12 @@ func (s *ObjectService) Copy(ctx context.Context, name, sourceURL string, opt *O if len(id) == 1 { u = fmt.Sprintf("%s/%s?versionId=%s", surl[0], encodeURIComponent(surl[1]), id[0]) } else if len(id) == 0 { - u = fmt.Sprintf("%s/%s", surl[0], encodeURIComponent(surl[1])) + keyAndVer := strings.SplitN(surl[1], "?", 2) + if len(keyAndVer) < 2 { + u = fmt.Sprintf("%s/%s", surl[0], encodeURIComponent(surl[1], []byte{'/'})) + } else { + u = fmt.Sprintf("%v/%v?%v", surl[0], encodeURIComponent(keyAndVer[0], []byte{'/'}), encodeURIComponent(keyAndVer[1], []byte{'='})) + } } else { return nil, nil, errors.New("wrong params") } @@ -419,9 +652,6 @@ func (s *ObjectService) Copy(ctx context.Context, name, sourceURL string, opt *O if err == nil { // 请求正常 err = xml.Unmarshal(bs.Bytes(), &res) // body 正常返回 - if err == io.EOF { - err = nil - } // If the error occurs during the copy operation, the error response is embedded in the 200 OK response. This means that a 200 OK response can contain either a success or an error. if resp != nil && resp.StatusCode == 200 { if err != nil { @@ -450,10 +680,14 @@ type ObjectDeleteOptions struct { // https://www.qcloud.com/document/product/436/7743 func (s *ObjectService) Delete(ctx context.Context, name string, opt ...*ObjectDeleteOptions) (*Response, error) { var optHeader *ObjectDeleteOptions - // When use "" string might call the delete bucket interface if len(name) == 0 || name == "/" { return nil, errors.New("empty object name") } + // When use "" string might call the delete bucket interface + if s.client.Conf.ObjectKeySimplifyCheck && !CheckObjectKeySimplify("/"+name) { + return nil, ObjectKeySimplifyCheckErr + } + if len(opt) > 0 { optHeader = opt[0] } @@ -500,7 +734,7 @@ func (s *ObjectService) Head(ctx context.Context, name string, opt *ObjectHeadOp } resp, err := s.client.doRetry(ctx, &sendOpt) if resp != nil && resp.Header["X-Cos-Object-Type"] != nil && resp.Header["X-Cos-Object-Type"][0] == "appendable" { - resp.Header.Add("x-cos-next-append-position", resp.Header["Content-Length"][0]) + resp.Header.Add("x-cos-next-append-position", resp.Header.Get("Content-Length")) } return resp, err @@ -548,7 +782,7 @@ type CASJobParameters struct { // ObjectRestoreOptions is the option of object restore type ObjectRestoreOptions struct { XMLName xml.Name `xml:"RestoreRequest" header:"-" url:"-"` - Days int `xml:"Days" header:"-" url:"-"` + Days int `xml:"Days,omitempty" header:"-" url:"-"` Tier *CASJobParameters `xml:"CASJobParameters" header:"-" url:"-"` XOptionHeader *http.Header `xml:"-" header:",omitempty" url:"-"` } @@ -828,6 +1062,12 @@ func worker(ctx context.Context, s *ObjectService, jobs <-chan *Jobs, results ch results <- &res break } + if s.client.Conf.RetryOpt.AutoSwitchHost { + // 收不到报文 或者 不存在RequestId + if resp == nil || resp.Header.Get("X-Cos-Request-Id") == "" { + j.Opt.innerSwitchURL = toSwitchHost(s.client.BaseURL.BucketURL) + } + } time.Sleep(time.Millisecond) continue } @@ -1056,6 +1296,7 @@ func (s *ObjectService) Upload(ctx context.Context, name string, filepath string opt0 = &ObjectPutOptions{ opt.OptIni.ACLHeaderOptions, opt.OptIni.ObjectPutHeaderOptions, + nil, } } rsp, err := s.PutFromFile(ctx, name, filepath, opt0) @@ -1138,6 +1379,7 @@ func (s *ObjectService) Upload(ctx context.Context, name string, filepath string partOpt.XCosSSECustomerKey = optini.XCosSSECustomerKey partOpt.XCosSSECustomerKeyMD5 = optini.XCosSSECustomerKeyMD5 partOpt.XCosTrafficLimit = optini.XCosTrafficLimit + partOpt.XOptionHeader = optini.XOptionHeader } job := &Jobs{ Name: name, @@ -1244,6 +1486,37 @@ func SplitSizeIntoChunks(totalBytes int64, partSize int64) ([]Chunk, int, error) return chunks, int(partNum), nil } +func SplitSizeIntoChunksToDownload(totalBytes int64, partSize int64) ([]Chunk, int, error) { + var partNum int64 + if partSize > 0 { + if partSize < 1024*1024 { + return nil, 0, errors.New("partSize>=1048576 is required") + } + partNum = totalBytes / partSize + } else { + partNum, partSize = DividePart(totalBytes, 16) + } + + var chunks []Chunk + var chunk = Chunk{} + for i := int64(0); i < partNum; i++ { + chunk.Number = int(i + 1) + chunk.OffSet = i * partSize + chunk.Size = partSize + chunks = append(chunks, chunk) + } + + if totalBytes%partSize > 0 { + chunk.Number = len(chunks) + 1 + chunk.OffSet = int64(len(chunks)) * partSize + chunk.Size = totalBytes % partSize + chunks = append(chunks, chunk) + partNum++ + } + + return chunks, int(partNum), nil +} + func (s *ObjectService) checkDownloadedParts(opt *MultiDownloadCPInfo, chfile string, chunks []Chunk) (*MultiDownloadCPInfo, bool) { var defaultRes MultiDownloadCPInfo defaultRes = *opt @@ -1288,6 +1561,10 @@ func (s *ObjectService) checkDownloadedParts(opt *MultiDownloadCPInfo, chfile st } func (s *ObjectService) Download(ctx context.Context, name string, filepath string, opt *MultiDownloadOptions, id ...string) (*Response, error) { + // key 校验 + if s.client.Conf.ObjectKeySimplifyCheck && !CheckObjectKeySimplify("/"+name) { + return nil, ObjectKeySimplifyCheckErr + } // 参数校验 if opt == nil { opt = &MultiDownloadOptions{} @@ -1316,7 +1593,7 @@ func (s *ObjectService) Download(ctx context.Context, name string, filepath stri } // 切分 - chunks, partNum, err := SplitSizeIntoChunks(totalBytes, opt.PartSize*1024*1024) + chunks, partNum, err := SplitSizeIntoChunksToDownload(totalBytes, opt.PartSize*1024*1024) if err != nil { return resp, err } @@ -1389,6 +1666,14 @@ func (s *ObjectService) Download(ctx context.Context, name string, filepath stri go downloadWorker(ctx, s, chjobs, chresults) } + var listener ProgressListener + var consumedBytes int64 + if opt.Opt != nil && opt.Opt.Listener != nil { + listener = opt.Opt.Listener + } + event := newProgressEvent(ProgressStartedEvent, 0, 0, totalBytes) + progressCallback(listener, event) + go func() { for _, chunk := range chunks { if chunk.Done { @@ -1416,6 +1701,11 @@ func (s *ObjectService) Download(ctx context.Context, name string, filepath stri err = nil for i := 0; i < partNum; i++ { if chunks[i].Done { + if err == nil { + consumedBytes += chunks[i].Size + event = newProgressEvent(ProgressDataEvent, chunks[i].Size, consumedBytes, totalBytes) + progressCallback(listener, event) + } continue } res := <-chresults @@ -1433,12 +1723,19 @@ func (s *ObjectService) Download(ctx context.Context, name string, filepath stri }) json.NewEncoder(cpfd).Encode(resumableInfo) } + + // 更新进度 + consumedBytes += chunks[res.PartNumber-1].Size + event = newProgressEvent(ProgressDataEvent, chunks[res.PartNumber-1].Size, consumedBytes, totalBytes) + progressCallback(listener, event) } close(chresults) if cpfd != nil { cpfd.Close() } if err != nil { + event = newProgressEvent(ProgressFailedEvent, 0, consumedBytes, totalBytes, err) + progressCallback(listener, event) return nil, err } // 下载成功,删除checkpoint文件 @@ -1460,6 +1757,9 @@ func (s *ObjectService) Download(ctx context.Context, name string, filepath stri return resp, fmt.Errorf("verification failed, want:%v, return:%v, header:%+v", icoscrc, localcrc, resp.Header) } } + event = newProgressEvent(ProgressCompletedEvent, 0, consumedBytes, totalBytes) + progressCallback(listener, event) + return resp, err } @@ -1523,9 +1823,13 @@ func (s *ObjectService) GetTagging(ctx context.Context, name string, opt ...inte } func (s *ObjectService) DeleteTagging(ctx context.Context, name string, opt ...interface{}) (*Response, error) { + // When use "" string might call the delete bucket interface if len(name) == 0 || name == "/" { return nil, errors.New("empty object name") } + if s.client.Conf.ObjectKeySimplifyCheck && !CheckObjectKeySimplify("/"+name) { + return nil, ObjectKeySimplifyCheckErr + } var optHeader *ObjectGetTaggingOptions u := fmt.Sprintf("/%s?tagging", encodeURIComponent(name)) if len(opt) > 2 { @@ -1634,3 +1938,43 @@ func (s *ObjectService) GetFetchTask(ctx context.Context, bucket string, taskid } return &res, resp, err } + +type ObjectPutSymlinkOptions struct { + SymlinkTarget string `header:"x-cos-symlink-target" url:"-"` + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +type ObjectGetSymlinkOptions struct { + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + +func (s *ObjectService) PutSymlink(ctx context.Context, name string, opt *ObjectPutSymlinkOptions) (*Response, error) { + if opt == nil || opt.SymlinkTarget == "" { + return nil, errors.New("SymlinkTarget is empty") + } + copt := &ObjectPutSymlinkOptions{ + SymlinkTarget: encodeURIComponent(opt.SymlinkTarget), + XOptionHeader: opt.XOptionHeader, + } + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?symlink", + method: http.MethodPut, + optHeader: copt, + } + resp, err := s.client.doRetry(ctx, sendOpt) + return resp, err +} + +func (s *ObjectService) GetSymlink(ctx context.Context, name string, opt *ObjectGetSymlinkOptions) (string, *Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name) + "?symlink", + method: http.MethodGet, + } + resp, err := s.client.doRetry(ctx, sendOpt) + if err != nil || resp == nil { + return "", resp, err + } + return resp.Header.Get("x-cos-symlink-target"), resp, err +} diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/object_part.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/object_part.go index 86e67a1a54..185d5f25d7 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/object_part.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/object_part.go @@ -33,15 +33,26 @@ type InitiateMultipartUploadResult struct { // // https://www.qcloud.com/document/product/436/7746 func (s *ObjectService) InitiateMultipartUpload(ctx context.Context, name string, opt *InitiateMultipartUploadOptions) (*InitiateMultipartUploadResult, *Response, error) { + var buff bytes.Buffer var res InitiateMultipartUploadResult sendOpt := sendOptions{ baseURL: s.client.BaseURL.BucketURL, uri: "/" + encodeURIComponent(name) + "?uploads", method: http.MethodPost, optHeader: opt, - result: &res, + result: &buff, } resp, err := s.client.doRetry(ctx, &sendOpt) + if err == nil { + err = xml.Unmarshal(buff.Bytes(), &res) + if err != nil { + // xml body存在非法字符(key存在非法字符) + if _, ok := err.(*xml.SyntaxError); ok { + err = UnmarshalInitMultiUploadResult(buff.Bytes(), &res) + return &res, resp, err + } + } + } return &res, resp, err } @@ -60,6 +71,9 @@ type ObjectUploadPartOptions struct { XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` // 上传进度, ProgressCompleteEvent不能表示对应API调用成功,API是否调用成功的判断标准为返回err==nil Listener ProgressListener `header:"-" url:"-" xml:"-"` + + // Upload方法使用 + innerSwitchURL *url.URL `header:"-" url:"-" xml:"-"` } // UploadPart 请求实现在初始化以后的分块上传,支持的块的数量为1到10000,块的大小为1 MB 到5 GB。 @@ -71,8 +85,8 @@ type ObjectUploadPartOptions struct { // // https://www.qcloud.com/document/product/436/7750 func (s *ObjectService) UploadPart(ctx context.Context, name, uploadID string, partNumber int, r io.Reader, uopt *ObjectUploadPartOptions) (*Response, error) { - if r == nil { - return nil, fmt.Errorf("reader is nil") + if (r == nil || r == http.NoBody) && uopt != nil && uopt.ContentLength != 0 { + return nil, fmt.Errorf("ContentLength must be 0 when reader is nil or http.NoBody.") } if err := CheckReaderLen(r); err != nil { return nil, err @@ -93,22 +107,67 @@ func (s *ObjectService) UploadPart(ctx context.Context, name, uploadID string, p opt.ContentLength = totalBytes } } - reader := TeeReader(r, nil, totalBytes, nil) - if s.client.Conf.EnableCRC { - reader.writer = crc64.New(crc64.MakeTable(crc64.ECMA)) + // 如果是io.Seeker,则重试 + count := 1 + var position int64 + if seeker, ok := r.(io.Seeker); ok { + // 记录原始位置 + position, err = seeker.Seek(0, io.SeekCurrent) + if err == nil && s.client.Conf.RetryOpt.Count > 0 { + count = s.client.Conf.RetryOpt.Count + } } - if opt != nil && opt.Listener != nil { - reader.listener = opt.Listener + var resp *Response + var retrieable bool + sUrl := s.client.BaseURL.BucketURL + if opt.innerSwitchURL != nil { + sUrl = opt.innerSwitchURL + } + retryErr := &RetryError{} + for nr := 0; nr < count; nr++ { + var reader io.Reader + if r != nil && r != http.NoBody { + tReader := TeeReader(r, nil, totalBytes, nil) + if s.client.Conf.EnableCRC { + tReader.writer = crc64.New(crc64.MakeTable(crc64.ECMA)) + } + if opt != nil && opt.Listener != nil { + tReader.listener = opt.Listener + } + reader = tReader + } + u := fmt.Sprintf("/%s?partNumber=%d&uploadId=%s", encodeURIComponent(name), partNumber, uploadID) + sendOpt := sendOptions{ + baseURL: sUrl, + uri: u, + method: http.MethodPut, + optHeader: opt, + body: reader, + } + // 把上一次错误记录下来 + if err != nil { + retryErr.Add(err) + } + resp, err = s.client.send(ctx, &sendOpt) + sUrl, retrieable = s.client.CheckRetrieable(sUrl, resp, err, nr >= count-2) + if retrieable && nr+1 < count { + if seeker, ok := r.(io.Seeker); ok { + _, e := seeker.Seek(position, io.SeekStart) + if e != nil { + break + } + continue + } + } + break } - u := fmt.Sprintf("/%s?partNumber=%d&uploadId=%s", encodeURIComponent(name), partNumber, uploadID) - sendOpt := sendOptions{ - baseURL: s.client.BaseURL.BucketURL, - uri: u, - method: http.MethodPut, - optHeader: opt, - body: reader, + if err != nil { + if _, ok := err.(*ErrorResponse); !ok { + retryErr.Add(err) + err = retryErr + } } - resp, err := s.client.send(ctx, &sendOpt) + return resp, err } @@ -201,6 +260,7 @@ func (o ObjectList) Less(i, j int) bool { // rewrite the Less method from small // https://www.qcloud.com/document/product/436/7742 func (s *ObjectService) CompleteMultipartUpload(ctx context.Context, name, uploadID string, opt *CompleteMultipartUploadOptions) (*CompleteMultipartUploadResult, *Response, error) { u := fmt.Sprintf("/%s?uploadId=%s", encodeURIComponent(name), uploadID) + var buff bytes.Buffer var res CompleteMultipartUploadResult sendOpt := sendOptions{ baseURL: s.client.BaseURL.BucketURL, @@ -208,33 +268,57 @@ func (s *ObjectService) CompleteMultipartUpload(ctx context.Context, name, uploa method: http.MethodPost, optHeader: opt, body: opt, - result: &res, + result: &buff, } resp, err := s.client.doRetry(ctx, &sendOpt) // If the error occurs during the copy operation, the error response is embedded in the 200 OK response. This means that a 200 OK response can contain either a success or an error. if err == nil && resp.StatusCode == 200 { + err = xml.Unmarshal(buff.Bytes(), &res) + if err != nil { + // xml body存在非法字符(key存在非法字符) + if _, ok := err.(*xml.SyntaxError); ok { + err = UnmarshalCompleteMultiUploadResult(buff.Bytes(), &res) + if err != nil { + return &res, resp, err + } + } + } if res.ETag == "" { - return &res, resp, errors.New("response 200 OK, but body contains an error") + return &res, resp, fmt.Errorf("response 200 OK, but body contains an error, %v", buff.Bytes()) } } return &res, resp, err } +type AbortMultipartUploadOptions struct { + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} + // AbortMultipartUpload 用来实现舍弃一个分块上传并删除已上传的块。当您调用Abort Multipart Upload时, // 如果有正在使用这个Upload Parts上传块的请求,则Upload Parts会返回失败。当该UploadID不存在时,会返回404 NoSuchUpload。 // // 建议您及时完成分块上传或者舍弃分块上传,因为已上传但是未终止的块会占用存储空间进而产生存储费用。 // // https://www.qcloud.com/document/product/436/7740 -func (s *ObjectService) AbortMultipartUpload(ctx context.Context, name, uploadID string) (*Response, error) { +func (s *ObjectService) AbortMultipartUpload(ctx context.Context, name, uploadID string, opt ...*AbortMultipartUploadOptions) (*Response, error) { if len(name) == 0 || name == "/" { return nil, errors.New("empty object name") } + // When use "" string might call the delete bucket interface + if s.client.Conf.ObjectKeySimplifyCheck && !CheckObjectKeySimplify("/"+name) { + return nil, ObjectKeySimplifyCheckErr + } + + var optHeader *AbortMultipartUploadOptions + if len(opt) > 0 { + optHeader = opt[0] + } u := fmt.Sprintf("/%s?uploadId=%s", encodeURIComponent(name), uploadID) sendOpt := sendOptions{ - baseURL: s.client.BaseURL.BucketURL, - uri: u, - method: http.MethodDelete, + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodDelete, + optHeader: optHeader, } resp, err := s.client.doRetry(ctx, &sendOpt) return resp, err @@ -272,11 +356,25 @@ type CopyPartResult struct { // // https://www.qcloud.com/document/product/436/7750 func (s *ObjectService) CopyPart(ctx context.Context, name, uploadID string, partNumber int, sourceURL string, opt *ObjectCopyPartOptions) (*CopyPartResult, *Response, error) { - if opt == nil { - opt = &ObjectCopyPartOptions{} + if strings.HasPrefix(sourceURL, "http://") || strings.HasPrefix(sourceURL, "https://") { + return nil, nil, errors.New("sourceURL format is invalid.") } - opt.XCosCopySource = sourceURL - u := fmt.Sprintf("/%s?partNumber=%d&uploadId=%s", encodeURIComponent(name), partNumber, uploadID) + surl := strings.SplitN(sourceURL, "/", 2) + if len(surl) < 2 { + return nil, nil, errors.New(fmt.Sprintf("x-cos-copy-source format error: %s", sourceURL)) + } + var u string + keyAndVer := strings.SplitN(surl[1], "?", 2) + if len(keyAndVer) < 2 { + u = fmt.Sprintf("%s/%s", surl[0], encodeURIComponent(surl[1], []byte{'/'})) + } else { + u = fmt.Sprintf("%v/%v?%v", surl[0], encodeURIComponent(keyAndVer[0], []byte{'/'}), encodeURIComponent(keyAndVer[1], []byte{'='})) + } + + opt = cloneObjectCopyPartOptions(opt) + opt.XCosCopySource = u + + u = fmt.Sprintf("/%s?partNumber=%d&uploadId=%s", encodeURIComponent(name), partNumber, uploadID) var res CopyPartResult var bs bytes.Buffer sendOpt := sendOptions{ @@ -290,9 +388,6 @@ func (s *ObjectService) CopyPart(ctx context.Context, name, uploadID string, par if err == nil { // 请求正常 err = xml.Unmarshal(bs.Bytes(), &res) // body 正常返回 - if err == io.EOF { - err = nil - } // If the error occurs during the copy operation, the error response is embedded in the 200 OK response. This means that a 200 OK response can contain either a success or an error. if resp != nil && resp.StatusCode == 200 { if err != nil { @@ -405,45 +500,54 @@ func copyworker(ctx context.Context, s *ObjectService, jobs <-chan *CopyJobs, re } } -func (s *ObjectService) innerHead(ctx context.Context, sourceURL string, opt *ObjectHeadOptions, id []string) (resp *Response, err error) { +func (s *ObjectService) innerHead(ctx context.Context, sourceURL string, opt *ObjectHeadOptions, id []string) (*Response, error) { surl := strings.SplitN(sourceURL, "/", 2) if len(surl) < 2 { - err = errors.New(fmt.Sprintf("sourceURL format error: %s", sourceURL)) - return + return nil, fmt.Errorf("sourceURL format error: %s", sourceURL) } u, err := url.Parse(fmt.Sprintf("http://%s", surl[0])) if err != nil { - return + return nil, err } b := &BaseURL{BucketURL: u} client := NewClient(b, &http.Client{ Transport: s.client.client.Transport, }) if len(id) > 0 { - resp, err = client.Object.Head(ctx, surl[1], nil, id[0]) + return client.Object.Head(ctx, surl[1], nil, id[0]) } else { - resp, err = client.Object.Head(ctx, surl[1], nil) + keyAndVer := strings.SplitN(surl[1], "?", 2) + if len(keyAndVer) < 2 { + // 不存在versionId + return client.Object.Head(ctx, surl[1], nil) + } else { + q, err := url.ParseQuery(keyAndVer[1]) + if err != nil { + return nil, fmt.Errorf("sourceURL format error: %s", sourceURL) + } + return client.Object.Head(ctx, keyAndVer[0], nil, q.Get("versionId")) + } } - return + return nil, fmt.Errorf("Head Err") } // 如果源对象大于5G,则采用分块复制的方式进行拷贝,此时源对象的元信息如果COPY func (s *ObjectService) MultiCopy(ctx context.Context, name string, sourceURL string, opt *MultiCopyOptions, id ...string) (*ObjectCopyResult, *Response, error) { + if strings.HasPrefix(sourceURL, "http://") || strings.HasPrefix(sourceURL, "https://") { + return nil, nil, errors.New("sourceURL format is invalid.") + } + resp, err := s.innerHead(ctx, sourceURL, nil, id) if err != nil { return nil, nil, err } totalBytes := resp.ContentLength - surl := strings.SplitN(sourceURL, "/", 2) - if len(surl) < 2 { - return nil, nil, errors.New(fmt.Sprintf("x-cos-copy-source format error: %s", sourceURL)) - } var u string if len(id) == 1 { - u = fmt.Sprintf("%s/%s?versionId=%s", surl[0], encodeURIComponent(surl[1]), id[0]) + u = fmt.Sprintf("%s?versionId=%s", sourceURL, id[0]) } else if len(id) == 0 { - u = fmt.Sprintf("%s/%s", surl[0], encodeURIComponent(surl[1])) + u = sourceURL } else { return nil, nil, errors.New("wrong params") } @@ -455,7 +559,8 @@ func (s *ObjectService) MultiCopy(ctx context.Context, name string, sourceURL st if err != nil { return nil, nil, err } - if partNum == 0 || (totalBytes < singleUploadMaxLength && !opt.useMulti) { + + if partNum == 0 || (totalBytes <= singleUploadMaxLength && !opt.useMulti) { if len(id) > 0 { return s.Copy(ctx, name, sourceURL, opt.OptCopy, id[0]) } else { diff --git a/vendor/github.com/tencentyun/cos-go-sdk-v5/service.go b/vendor/github.com/tencentyun/cos-go-sdk-v5/service.go index 0f1b4f363e..483af72af1 100644 --- a/vendor/github.com/tencentyun/cos-go-sdk-v5/service.go +++ b/vendor/github.com/tencentyun/cos-go-sdk-v5/service.go @@ -26,6 +26,7 @@ type ServiceGetOptions struct { Marker string `url:"marker,omitempty"` Range string `url:"range,omitempty"` CreateTime int64 `url:"create-time,omitempty"` + Region string `url:"region,omitempty"` } // Get Service 接口实现获取该用户下所有Bucket列表。 @@ -47,6 +48,6 @@ func (s *ServiceService) Get(ctx context.Context, opt ...*ServiceGetOptions) (*S optQuery: sopt, result: &res, } - resp, err := s.client.send(ctx, &sendOpt) + resp, err := s.client.doRetry(ctx, &sendOpt) return &res, resp, err } diff --git a/vendor/modules.txt b/vendor/modules.txt index affb4ba554..eee02c3f88 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1352,7 +1352,7 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/wedata/v20210820 # github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/wss v1.0.199 ## explicit; go 1.14 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/wss/v20180426 -# github.com/tencentyun/cos-go-sdk-v5 v0.7.42-0.20230629101357-7edd77448a0f +# github.com/tencentyun/cos-go-sdk-v5 v0.7.58 ## explicit; go 1.12 github.com/tencentyun/cos-go-sdk-v5 # github.com/tetafro/godot v1.4.11 diff --git a/website/docs/d/cos_object_signed_url.html.markdown b/website/docs/d/cos_object_signed_url.html.markdown new file mode 100644 index 0000000000..f3e13f9caf --- /dev/null +++ b/website/docs/d/cos_object_signed_url.html.markdown @@ -0,0 +1,41 @@ +--- +subcategory: "Cloud Object Storage(COS)" +layout: "tencentcloud" +page_title: "TencentCloud: tencentcloud_cos_object_signed_url" +sidebar_current: "docs-tencentcloud-datasource-cos_object_signed_url" +description: |- + Use this data source to query the signed url of the COS object. +--- + +# tencentcloud_cos_object_signed_url + +Use this data source to query the signed url of the COS object. + +## Example Usage + +```hcl +data "tencentcloud_cos_object_signed_url" "cos_object_signed_url" { + bucket = "xxxxxx" + path = "path/to/file" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `bucket` - (Required, String) Name of the bucket. +* `path` - (Required, String) The full path to the object inside the bucket. +* `method` - (Optional, String) Method, GET or PUT. Default value is GET. +* `duration` - (Optional, String) Duration of signed url. Default value is 1m. +* `headers` - (Optional, Map) Request headers. +* `queries` - (Optional, Map) Request query parameters. +* `result_output_file` - (Optional, String) Used to save results. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `signed_url` - Signed URL. + + diff --git a/website/tencentcloud.erb b/website/tencentcloud.erb index 6034e9e5e6..1089595f16 100644 --- a/website/tencentcloud.erb +++ b/website/tencentcloud.erb @@ -1648,6 +1648,9 @@
  • tencentcloud_cos_buckets
  • +
  • + tencentcloud_cos_object_signed_url +