From 156deaea3caacc5249050ae1e7378ae8af909c5d Mon Sep 17 00:00:00 2001 From: jojoliang Date: Thu, 2 Jan 2020 10:13:07 +0800 Subject: [PATCH 01/15] update batch --- batch.go | 170 +++++++++++++++++++++++++++++++-------------------------------- go.mod | 1 + go.sum | 2 + 3 files changed, 88 insertions(+), 85 deletions(-) diff --git a/batch.go b/batch.go index 8e6891d..390d20c 100644 --- a/batch.go +++ b/batch.go @@ -10,100 +10,100 @@ import ( type BatchService service type BatchRequestHeaders struct { - XCosAppid int `header:"x-cos-appid"` - ContentLength string `header:"Content-Length,omitempty"` - ContentType string `header:"Content-Type,omitempty"` - Headers *http.Header `header:"-"` + XCosAppid int `header:"x-cos-appid" xml:"-" url:"-"` + ContentLength string `header:"Content-Length,omitempty" xml:"-" url:"-"` + ContentType string `header:"Content-Type,omitempty" xml:"-" url:"-"` + Headers *http.Header `header:"-" xml:"-", url:"-"` } // BatchProgressSummary type BatchProgressSummary struct { - NumberOfTasksFailed int `xml:"NumberOfTasksFailed"` - NumberOfTasksSucceeded int `xml:"NumberOfTasksSucceeded"` - TotalNumberOfTasks int `xml:"TotalNumberOfTasks"` + NumberOfTasksFailed int `xml:"NumberOfTasksFailed" header:"-" url:"-"` + NumberOfTasksSucceeded int `xml:"NumberOfTasksSucceeded" header:"-" url:"-"` + TotalNumberOfTasks int `xml:"TotalNumberOfTasks" header:"-" url:"-"` } // BatchJobReport type BatchJobReport struct { - Bucket string `xml:"Bucket"` - Enabled string `xml:"Enabled"` - Format string `xml:"Format"` - Prefix string `xml:"Prefix,omitempty"` - ReportScope string `xml:"ReportScope"` + Bucket string `xml:"Bucket" header:"-" url:"-"` + Enabled string `xml:"Enabled" header:"-" url:"-"` + Format string `xml:"Format" header:"-" url:"-"` + Prefix string `xml:"Prefix,omitempty" header:"-" url:"-"` + ReportScope string `xml:"ReportScope" header:"-" url:"-"` } // BatchJobOperationCopy type BatchMetadata struct { - Key string `xml:"Key"` - Value string `xml:"Value"` + Key string `xml:"Key" header:"-" url:"-"` + Value string `xml:"Value" header:"-" url:"-"` } type BatchNewObjectMetadata struct { - CacheControl string `xml:"CacheControl,omitempty"` - ContentDisposition string `xml:"ContentDisposition,omitempty"` - ContentEncoding string `xml:"ContentEncoding,omitempty"` - ContentType string `xml:"ContentType,omitempty"` - HttpExpiresDate string `xml:"HttpExpiresDate,omitempty"` - SSEAlgorithm string `xml:"SSEAlgorithm,omitempty"` - UserMetadata []BatchMetadata `xml:"UserMetadata>member,omitempty"` + CacheControl string `xml:"CacheControl,omitempty" header:"-" url:"-"` + ContentDisposition string `xml:"ContentDisposition,omitempty" header:"-" url:"-"` + ContentEncoding string `xml:"ContentEncoding,omitempty" header:"-" url:"-"` + ContentType string `xml:"ContentType,omitempty" header:"-" url:"-"` + HttpExpiresDate string `xml:"HttpExpiresDate,omitempty" header:"-" url:"-"` + SSEAlgorithm string `xml:"SSEAlgorithm,omitempty" header:"-" url:"-"` + UserMetadata []BatchMetadata `xml:"UserMetadata>member,omitempty" header:"-" url:"-"` } type BatchGrantee struct { - DisplayName string `xml:"DisplayName,omitempty"` - Identifier string `xml:"Identifier"` - TypeIdentifier string `xml:"TypeIdentifier"` + DisplayName string `xml:"DisplayName,omitempty" header:"-" url:"-"` + Identifier string `xml:"Identifier" header:"-" url:"-"` + TypeIdentifier string `xml:"TypeIdentifier" header:"-" url:"-"` } type BatchCOSGrant struct { - Grantee *BatchGrantee `xml:"Grantee"` - Permission string `xml:"Permission"` + Grantee *BatchGrantee `xml:"Grantee" header:"-" url:"-"` + Permission string `xml:"Permission" header:"-" url:"-"` } type BatchAccessControlGrants struct { - COSGrants *BatchCOSGrant `xml:"COSGrant,omitempty"` + COSGrants *BatchCOSGrant `xml:"COSGrant,omitempty" header:"-" url:"-"` } type BatchJobOperationCopy struct { - AccessControlGrants *BatchAccessControlGrants `xml:"AccessControlGrants,omitempty"` - CannedAccessControlList string `xml:"CannedAccessControlList,omitempty"` - MetadataDirective string `xml:"MetadataDirective,omitempty"` - ModifiedSinceConstraint int64 `xml:"ModifiedSinceConstraint,omitempty"` - UnModifiedSinceConstraint int64 `xml:"UnModifiedSinceConstraint,omitempty"` - NewObjectMetadata *BatchNewObjectMetadata `xml:"NewObjectMetadata,omitempty"` - StorageClass string `xml:"StorageClass,omitempty"` - TargetResource string `xml:"TargetResource"` + AccessControlGrants *BatchAccessControlGrants `xml:"AccessControlGrants,omitempty" header:"-" url:"-"` + CannedAccessControlList string `xml:"CannedAccessControlList,omitempty" header:"-" url:"-"` + MetadataDirective string `xml:"MetadataDirective,omitempty" header:"-" url:"-"` + ModifiedSinceConstraint int64 `xml:"ModifiedSinceConstraint,omitempty" header:"-" url:"-"` + UnModifiedSinceConstraint int64 `xml:"UnModifiedSinceConstraint,omitempty" header:"-" url:"-"` + NewObjectMetadata *BatchNewObjectMetadata `xml:"NewObjectMetadata,omitempty" header:"-" url:"-"` + StorageClass string `xml:"StorageClass,omitempty" header:"-" url:"-"` + TargetResource string `xml:"TargetResource" header:"-" url:"-"` } // BatchJobOperation type BatchJobOperation struct { - PutObjectCopy *BatchJobOperationCopy `xml:"COSPutObjectCopy,omitempty" header:"-"` + PutObjectCopy *BatchJobOperationCopy `xml:"COSPutObjectCopy,omitempty" header:"-" url:"-"` } // BatchJobManifest type BatchJobManifestLocation struct { - ETag string `xml:"ETag" header:"-"` - ObjectArn string `xml:"ObjectArn" header:"-"` - ObjectVersionId string `xml:"ObjectVersionId,omitempty" header:"-"` + ETag string `xml:"ETag" header:"-" url:"-"` + ObjectArn string `xml:"ObjectArn" header:"-" url:"-"` + ObjectVersionId string `xml:"ObjectVersionId,omitempty" header:"-" url:"-"` } type BatchJobManifestSpec struct { - Fields []string `xml:"Fields>member,omitempty" header:"-"` - Format string `xml:"Format" header:"-"` + Fields []string `xml:"Fields>member,omitempty" header:"-" url:"-"` + Format string `xml:"Format" header:"-" url:"-"` } type BatchJobManifest struct { - Location *BatchJobManifestLocation `xml:"Location" header:"-"` - Spec *BatchJobManifestSpec `xml:"Spec" header:"-"` + Location *BatchJobManifestLocation `xml:"Location" header:"-" url:"-"` + Spec *BatchJobManifestSpec `xml:"Spec" header:"-" url:"-"` } type BatchCreateJobOptions struct { - XMLName xml.Name `xml:"CreateJobRequest" header:"-"` - ClientRequestToken string `xml:"ClientRequestToken" header:"-"` - ConfirmationRequired string `xml:"ConfirmationRequired,omitempty" header:"-"` - Description string `xml:"Description,omitempty" header:"-"` - Manifest *BatchJobManifest `xml:"Manifest" header:"-"` - Operation *BatchJobOperation `xml:"Operation" header:"-"` - Priority int `xml:"Priority" header:"-"` - Report *BatchJobReport `xml:"Report" header:"-"` - RoleArn string `xml:"RoleArn" header:"-"` + XMLName xml.Name `xml:"CreateJobRequest" header:"-" url:"-"` + ClientRequestToken string `xml:"ClientRequestToken" header:"-" url:"-"` + ConfirmationRequired string `xml:"ConfirmationRequired,omitempty" header:"-" url:"-"` + Description string `xml:"Description,omitempty" header:"-" url:"-"` + Manifest *BatchJobManifest `xml:"Manifest" header:"-" url:"-"` + Operation *BatchJobOperation `xml:"Operation" header:"-" url:"-"` + Priority int `xml:"Priority" header:"-" url:"-"` + Report *BatchJobReport `xml:"Report" header:"-" url:"-"` + RoleArn string `xml:"RoleArn" header:"-" url:"-"` } type BatchCreateJobResult struct { XMLName xml.Name `xml:"CreateJobResult"` - JobId string `xml:"JobId"` + JobId string `xml:"JobId,omitempty"` } func processETag(opt *BatchCreateJobOptions) *BatchCreateJobOptions { @@ -129,31 +129,31 @@ func (s *BatchService) CreateJob(ctx context.Context, opt *BatchCreateJobOptions } type BatchJobFailureReasons struct { - FailureCode string `xml:"FailureCode"` - FailureReason string `xml:"FailureReason"` + FailureCode string `xml:"FailureCode" header:"-" url:"-"` + FailureReason string `xml:"FailureReason" header:"-" url:"-"` } type BatchDescribeJob struct { - ConfirmationRequired string `xml:"ConfirmationRequired,omitempty"` - CreationTime string `xml:"CreationTime,omitempty"` - Description string `xml:"Description,omitempty"` - FailureReasons *BatchJobFailureReasons `xml:"FailureReasons>JobFailure,omitempty"` - JobId string `xml:"JobId"` - Manifest *BatchJobManifest `xml:"Manifest"` - Operation *BatchJobOperation `xml:"Operation"` - Priority int `xml:"Priority"` - ProgressSummary *BatchProgressSummary `xml:"ProgressSummary"` - Report *BatchJobReport `xml:"Report,omitempty"` - RoleArn string `xml:"RoleArn,omitempty"` - Status string `xml:"Status,omitempty"` - StatusUpdateReason string `xml:"StatusUpdateReason,omitempty"` - SuspendedCause string `xml:"SuspendedCause,omitempty"` - SuspendedDate string `xml:"SuspendedDate,omitempty"` - TerminationDate string `xml:"TerminationDate,omitempty"` + ConfirmationRequired string `xml:"ConfirmationRequired,omitempty" header:"-" url:"-"` + CreationTime string `xml:"CreationTime,omitempty" header:"-" url:"-"` + Description string `xml:"Description,omitempty" header:"-" url:"-"` + FailureReasons *BatchJobFailureReasons `xml:"FailureReasons>JobFailure,omitempty" header:"-" url:"-"` + JobId string `xml:"JobId" header:"-" url:"-"` + Manifest *BatchJobManifest `xml:"Manifest" header:"-" url:"-"` + Operation *BatchJobOperation `xml:"Operation" header:"-" url:"-"` + Priority int `xml:"Priority" header:"-" url:"-"` + ProgressSummary *BatchProgressSummary `xml:"ProgressSummary" header:"-" url:"-"` + Report *BatchJobReport `xml:"Report,omitempty" header:"-" url:"-"` + RoleArn string `xml:"RoleArn,omitempty" header:"-" url:"-"` + Status string `xml:"Status,omitempty" header:"-" url:"-"` + StatusUpdateReason string `xml:"StatusUpdateReason,omitempty" header:"-" url:"-"` + SuspendedCause string `xml:"SuspendedCause,omitempty" header:"-" url:"-"` + SuspendedDate string `xml:"SuspendedDate,omitempty" header:"-" url:"-"` + TerminationDate string `xml:"TerminationDate,omitempty" header:"-" url:"-"` } type BatchDescribeJobResult struct { XMLName xml.Name `xml:"DescribeJobResult"` - Job *BatchDescribeJob `xml:"Job"` + Job *BatchDescribeJob `xml:"Job,omitempty"` } func (s *BatchService) DescribeJob(ctx context.Context, id string, headers *BatchRequestHeaders) (*BatchDescribeJobResult, *Response, error) { @@ -171,27 +171,27 @@ func (s *BatchService) DescribeJob(ctx context.Context, id string, headers *Batc } type BatchListJobsOptions struct { - JobStatuses string `url:"jobStatuses,omitempty" header:"-"` - MaxResults int `url:"maxResults,omitempty" header:"-"` - NextToken string `url:"nextToken,omitempty" header:"-"` + JobStatuses string `url:"jobStatuses,omitempty" header:"-" xml:"-"` + MaxResults int `url:"maxResults,omitempty" header:"-" xml:"-"` + NextToken string `url:"nextToken,omitempty" header:"-" xml:"-"` } type BatchListJobsMember struct { - CreationTime string `xml:"CreationTime,omitempty"` - Description string `xml:"Description,omitempty"` - JobId string `xml:"JobId,omitempty"` - Operation string `xml:"Operation,omitempty"` - Priority int `xml:"Priority,omitempty"` - ProgressSummary *BatchProgressSummary `xml:"ProgressSummary,omitempty"` - Status string `xml:"Status,omitempty"` - TerminationDate string `xml:"TerminationDate,omitempty"` + CreationTime string `xml:"CreationTime,omitempty" header:"-" url:"-"` + Description string `xml:"Description,omitempty" header:"-" url:"-"` + JobId string `xml:"JobId,omitempty" header:"-" url:"-"` + Operation string `xml:"Operation,omitempty" header:"-" url:"-"` + Priority int `xml:"Priority,omitempty" header:"-" url:"-"` + ProgressSummary *BatchProgressSummary `xml:"ProgressSummary,omitempty" header:"-" url:"-"` + Status string `xml:"Status,omitempty" header:"-" url:"-"` + TerminationDate string `xml:"TerminationDate,omitempty" header:"-" url:"-"` } type BatchListJobs struct { - Members []BatchListJobsMember `xml:"member,omitempty"` + Members []BatchListJobsMember `xml:"member,omitempty" header:"-" url:"-"` } type BatchListJobsResult struct { XMLName xml.Name `xml:"ListJobsResult"` - Jobs *BatchListJobs `xml:"Jobs"` + Jobs *BatchListJobs `xml:"Jobs,omitempty"` NextToken string `xml:"NextToken,omitempty"` } diff --git a/go.mod b/go.mod index 35afc5c..c01628b 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.12 require ( github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409 github.com/google/go-querystring v1.0.0 + github.com/google/uuid v1.1.1 github.com/mozillazg/go-httpheader v0.2.1 github.com/stretchr/testify v1.3.0 ) diff --git a/go.sum b/go.sum index 5ee5a1d..ab8a08d 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ= github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= From 699fef215987bcf7f2459b9843ce8641900135f7 Mon Sep 17 00:00:00 2001 From: jojoliang Date: Sun, 19 Jan 2020 16:48:48 +0800 Subject: [PATCH 02/15] update batch --- batch_test.go | 20 ++++++++++---------- costesting/ci_test.go | 6 +++--- example/batch/create_job.go | 9 +++++---- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/batch_test.go b/batch_test.go index e54bbe8..8421486 100644 --- a/batch_test.go +++ b/batch_test.go @@ -8,7 +8,7 @@ import ( "reflect" "testing" - "github.com/google/uuid" + "github.com/google/uuid" ) func TestBatchService_CreateJob(t *testing.T) { @@ -21,7 +21,7 @@ func TestBatchService_CreateJob(t *testing.T) { Manifest: &BatchJobManifest{ Location: &BatchJobManifestLocation{ ETag: "15150651828fa9cdcb8356b6d1c7638b", - ObjectArn: "qcs::cos:ap-chengdu::sourcebucket-1250000000/manifests/batch-copy-manifest.csv", + ObjectArn: "qcs::cos:ap-chengdu:uid/1250000000:sourcebucket-1250000000/manifests/batch-copy-manifest.csv", }, Spec: &BatchJobManifestSpec{ Fields: []string{"Bucket", "Key"}, @@ -30,12 +30,12 @@ func TestBatchService_CreateJob(t *testing.T) { }, Operation: &BatchJobOperation{ PutObjectCopy: &BatchJobOperationCopy{ - TargetResource: "qcs::cos:ap-chengdu::destinationbucket-1250000000", + TargetResource: "qcs::cos:ap-chengdu:uid/1250000000:destinationbucket-1250000000", }, }, Priority: 1, Report: &BatchJobReport{ - Bucket: "qcs::cos:ap-chengdu::sourcebucket-1250000000", + Bucket: "qcs::cos:ap-chengdu:uid/1250000000:sourcebucket-1250000000", Enabled: "true", Format: "Report_CSV_V1", Prefix: "job-result", @@ -104,7 +104,7 @@ func TestBatchService_DescribeJob(t *testing.T) { "15150651828fa9cdcb8356b6d1c7638b" - qcs::cos:ap-chengdu::sourcebucket-1250000000/manifests/batch-copy-manifest.csv + qcs::cos:ap-chengdu:uid/1250000000:sourcebucket-1250000000/manifests/batch-copy-manifest.csv @@ -116,7 +116,7 @@ func TestBatchService_DescribeJob(t *testing.T) { - qcs::cos:ap-chengdu::destinationbucket-1250000000 + qcs::cos:ap-chengdu:uid/1250000000:destinationbucket-1250000000 10 @@ -126,7 +126,7 @@ func TestBatchService_DescribeJob(t *testing.T) { 10 - qcs::cos:ap-chengdu::sourcebucket-1250000000 + qcs::cos:ap-chengdu:uid/1250000000:sourcebucket-1250000000 true Report_CSV_V1 job-result @@ -159,7 +159,7 @@ func TestBatchService_DescribeJob(t *testing.T) { Manifest: &BatchJobManifest{ Location: &BatchJobManifestLocation{ ETag: "\"15150651828fa9cdcb8356b6d1c7638b\"", - ObjectArn: "qcs::cos:ap-chengdu::sourcebucket-1250000000/manifests/batch-copy-manifest.csv", + ObjectArn: "qcs::cos:ap-chengdu:uid/1250000000:sourcebucket-1250000000/manifests/batch-copy-manifest.csv", }, Spec: &BatchJobManifestSpec{ Fields: []string{"Bucket", "Key"}, @@ -168,7 +168,7 @@ func TestBatchService_DescribeJob(t *testing.T) { }, Operation: &BatchJobOperation{ PutObjectCopy: &BatchJobOperationCopy{ - TargetResource: "qcs::cos:ap-chengdu::destinationbucket-1250000000", + TargetResource: "qcs::cos:ap-chengdu:uid/1250000000:destinationbucket-1250000000", }, }, Priority: 10, @@ -178,7 +178,7 @@ func TestBatchService_DescribeJob(t *testing.T) { TotalNumberOfTasks: 10, }, Report: &BatchJobReport{ - Bucket: "qcs::cos:ap-chengdu::sourcebucket-1250000000", + Bucket: "qcs::cos:ap-chengdu:uid/1250000000:sourcebucket-1250000000", Enabled: "true", Format: "Report_CSV_V1", Prefix: "job-result", diff --git a/costesting/ci_test.go b/costesting/ci_test.go index 79389f4..01d5006 100644 --- a/costesting/ci_test.go +++ b/costesting/ci_test.go @@ -751,7 +751,7 @@ func (s *CosTestSuite) TestBatch() { Manifest: &cos.BatchJobManifest{ Location: &cos.BatchJobManifestLocation{ ETag: etag, - ObjectArn: "qcs::cos:" + kBatchRegion + "::" + kBatchBucket + "/" + manifest_name, + ObjectArn: "qcs::cos:" + kBatchRegion + ":uid/" + s.Appid + ":" + kBatchBucket + "/" + manifest_name, }, Spec: &cos.BatchJobManifestSpec{ Fields: []string{"Bucket", "Key"}, @@ -760,12 +760,12 @@ func (s *CosTestSuite) TestBatch() { }, Operation: &cos.BatchJobOperation{ PutObjectCopy: &cos.BatchJobOperationCopy{ - TargetResource: "qcs::cos:" + kBatchRegion + "::" + kTargetBatchBucket, + TargetResource: "qcs::cos:" + kBatchRegion + ":uid/" + s.Appid + ":" + kTargetBatchBucket, }, }, Priority: 1, Report: &cos.BatchJobReport{ - Bucket: "qcs::cos:" + kBatchRegion + "::" + kBatchBucket, + Bucket: "qcs::cos:" + kBatchRegion + ":uid/" + s.Appid + ":" + kBatchBucket, Enabled: "true", Format: "Report_CSV_V1", Prefix: "job-result", diff --git a/example/batch/create_job.go b/example/batch/create_job.go index 63d3720..223f6bb 100644 --- a/example/batch/create_job.go +++ b/example/batch/create_job.go @@ -2,20 +2,21 @@ package main import ( "context" + "fmt" "net/http" "net/url" "os" + "strconv" "strings" - "fmt" + "github.com/google/uuid" "github.com/tencentyun/cos-go-sdk-v5" "github.com/tencentyun/cos-go-sdk-v5/debug" - "github.com/google/uuid" ) func main() { test_batch_bucket := "testcd-1259654469" - target_batch_bucket := "targetcd-1259654469" + target_batch_bucket := "cosgosdkreptest-1259654469" appid := 1259654469 uin := "100010805041" region := "ap-chengdu" @@ -73,7 +74,7 @@ func main() { }, Operation: &cos.BatchJobOperation{ PutObjectCopy: &cos.BatchJobOperationCopy{ - TargetResource: "qcs::cos:" + region + "::" + target_batch_bucket, + TargetResource: "qcs::cos:" + region + ":uid/" + strconv.Itoa(appid) + ":" + target_batch_bucket, }, }, Priority: 1, From 7269ed131c234ad3cbc6c40b60ee430d2c8b5fa1 Mon Sep 17 00:00:00 2001 From: jojoliang Date: Mon, 20 Jan 2020 10:07:05 +0800 Subject: [PATCH 03/15] add restore object for batch --- batch.go | 9 +++- example/batch/create_job_restore.go | 105 ++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 example/batch/create_job_restore.go diff --git a/batch.go b/batch.go index 390d20c..05089dd 100644 --- a/batch.go +++ b/batch.go @@ -69,9 +69,16 @@ type BatchJobOperationCopy struct { TargetResource string `xml:"TargetResource" header:"-" url:"-"` } +// BatchInitiateRestoreObject +type BatchInitiateRestoreObject struct { + ExpirationInDays int `xml:"ExpirationInDays"` + JobTier string `xml:"JobTier"` +} + // BatchJobOperation type BatchJobOperation struct { - PutObjectCopy *BatchJobOperationCopy `xml:"COSPutObjectCopy,omitempty" header:"-" url:"-"` + PutObjectCopy *BatchJobOperationCopy `xml:"COSPutObjectCopy,omitempty" header:"-" url:"-"` + RestoreObject *BatchInitiateRestoreObject `xml:"COSInitiateRestoreObject,omitempty" header:"-" url:"-"` } // BatchJobManifest diff --git a/example/batch/create_job_restore.go b/example/batch/create_job_restore.go new file mode 100644 index 0000000..e51627f --- /dev/null +++ b/example/batch/create_job_restore.go @@ -0,0 +1,105 @@ +package main + +import ( + "context" + "fmt" + "net/http" + "net/url" + "os" + "strings" + + "github.com/google/uuid" + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/tencentyun/cos-go-sdk-v5/debug" +) + +func main() { + test_batch_bucket := "testcd-1259654469" + appid := 1259654469 + uin := "100010805041" + region := "ap-chengdu" + + // bucket url:.cos..mycloud.com + bucketurl, _ := url.Parse("https://" + test_batch_bucket + ".cos." + region + ".myqcloud.com") + // batch url:.cos-control..myqcloud.ccom + batchurl, _ := url.Parse("https://" + uin + ".cos-control." + region + ".myqcloud.com") + + b := &cos.BaseURL{BucketURL: bucketurl, BatchURL: batchurl} + c := cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: os.Getenv("COS_SECRETID"), + SecretKey: os.Getenv("COS_SECRETKEY"), + Transport: &debug.DebugRequestTransport{ + RequestHeader: true, + RequestBody: true, + ResponseHeader: true, + ResponseBody: true, + }, + }, + }) + + // 创建需要归档恢复的文件 + source_name := "test/restore.txt" + sf := strings.NewReader("batch test content") + objopt := &cos.ObjectPutOptions{ + nil, + &cos.ObjectPutHeaderOptions{ + XCosStorageClass: "Archive", + }, + } + _, err := c.Object.Put(context.Background(), source_name, sf, objopt) + if err != nil { + panic(err) + } + + // 创建清单文件 + manifest_name := "test/manifest.csv" + f := strings.NewReader(test_batch_bucket + "," + source_name) + resp, err := c.Object.Put(context.Background(), manifest_name, f, nil) + if err != nil { + panic(err) + } + etag := resp.Header.Get("ETag") + + uuid_str := uuid.New().String() + opt := &cos.BatchCreateJobOptions{ + ClientRequestToken: uuid_str, + ConfirmationRequired: "true", + Description: "test batch", + Manifest: &cos.BatchJobManifest{ + Location: &cos.BatchJobManifestLocation{ + ETag: etag, + ObjectArn: "qcs::cos:" + region + "::" + test_batch_bucket + "/" + manifest_name, + }, + Spec: &cos.BatchJobManifestSpec{ + Fields: []string{"Bucket", "Key"}, + Format: "COSBatchOperations_CSV_V1", + }, + }, + Operation: &cos.BatchJobOperation{ + RestoreObject: &cos.BatchInitiateRestoreObject{ + ExpirationInDays: 3, + JobTier: "Standard", + }, + }, + Priority: 1, + Report: &cos.BatchJobReport{ + Bucket: "qcs::cos:" + region + "::" + test_batch_bucket, + Enabled: "true", + Format: "Report_CSV_V1", + Prefix: "job-result", + ReportScope: "AllTasks", + }, + RoleArn: "qcs::cam::uin/" + uin + ":roleName/COSBatch_QcsRole", + } + headers := &cos.BatchRequestHeaders{ + XCosAppid: appid, + } + + res, _, err := c.Batch.CreateJob(context.Background(), opt, headers) + if err != nil { + panic(err) + } + fmt.Println(res) + +} From b427226ae44b1c0f25b8681147e828f4603a9014 Mon Sep 17 00:00:00 2001 From: jojoliang Date: Wed, 4 Dec 2019 21:52:59 +0800 Subject: [PATCH 04/15] add policy --- bucket_policy.go | 71 +++++++++++++++++++++++++++++++++++++++++++++ example/bucket/delPolicy.go | 35 ++++++++++++++++++++++ example/bucket/getPolicy.go | 39 +++++++++++++++++++++++++ example/bucket/putPolicy.go | 63 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 208 insertions(+) create mode 100644 bucket_policy.go create mode 100644 example/bucket/delPolicy.go create mode 100644 example/bucket/getPolicy.go create mode 100644 example/bucket/putPolicy.go diff --git a/bucket_policy.go b/bucket_policy.go new file mode 100644 index 0000000..a2fd7da --- /dev/null +++ b/bucket_policy.go @@ -0,0 +1,71 @@ +package cos + +import ( + "bytes" + "context" + "encoding/json" + "net/http" + "strings" +) + +type BucketStatement struct { + Principal map[string][]string `json:"principal,omitempty"` + 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 BucketPutPolicyOptions struct { + Statement []BucketStatement `json:"statement,omitempty"` + Version string `json:"version,omitempty"` + Principal map[string][]string `json:"principal,omitempty"` +} + +type BucketGetPolicyResult BucketPutPolicyOptions + +func (s *BucketService) PutPolicy(ctx context.Context, opt *BucketPutPolicyOptions) (*Response, error) { + var f *strings.Reader + if opt != nil { + bs, err := json.Marshal(opt) + if err != nil { + return nil, err + } + body := string(bs) + f = strings.NewReader(body) + } + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?policy", + method: http.MethodPut, + body: f, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +func (s *BucketService) GetPolicy(ctx context.Context) (*BucketGetPolicyResult, *Response, error) { + var bs bytes.Buffer + var res BucketGetPolicyResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?policy", + method: http.MethodGet, + result: &bs, + } + resp, err := s.client.send(ctx, sendOpt) + if err == nil { + err = json.Unmarshal(bs.Bytes(), &res) + } + return &res, resp, err +} + +func (s *BucketService) DeletePolicy(ctx context.Context) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?policy", + method: http.MethodDelete, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} diff --git a/example/bucket/delPolicy.go b/example/bucket/delPolicy.go new file mode 100644 index 0000000..cefc709 --- /dev/null +++ b/example/bucket/delPolicy.go @@ -0,0 +1,35 @@ +package main + +import ( + "context" + "net/http" + "net/url" + "os" + + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/tencentyun/cos-go-sdk-v5/debug" +) + +func main() { + u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") + b := &cos.BaseURL{ + BucketURL: u, + } + c := cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: os.Getenv("COS_SECRETID"), + SecretKey: os.Getenv("COS_SECRETKEY"), + Transport: &debug.DebugRequestTransport{ + RequestHeader: true, + RequestBody: true, + ResponseHeader: true, + ResponseBody: true, + }, + }, + }) + + _, err := c.Bucket.DeletePolicy(context.Background()) + if err != nil { + panic(err) + } +} diff --git a/example/bucket/getPolicy.go b/example/bucket/getPolicy.go new file mode 100644 index 0000000..0ac95c2 --- /dev/null +++ b/example/bucket/getPolicy.go @@ -0,0 +1,39 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/url" + "os" + + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/tencentyun/cos-go-sdk-v5/debug" +) + +func main() { + u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") + b := &cos.BaseURL{ + BucketURL: u, + } + c := cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: os.Getenv("COS_SECRETID"), + SecretKey: os.Getenv("COS_SECRETKEY"), + Transport: &debug.DebugRequestTransport{ + RequestHeader: true, + RequestBody: true, + ResponseHeader: true, + ResponseBody: true, + }, + }, + }) + + res, _, err := c.Bucket.GetPolicy(context.Background()) + if err != nil { + panic(err) + } + bs, err := json.Marshal(res) + fmt.Println(string(bs)) +} diff --git a/example/bucket/putPolicy.go b/example/bucket/putPolicy.go new file mode 100644 index 0000000..d4e3a10 --- /dev/null +++ b/example/bucket/putPolicy.go @@ -0,0 +1,63 @@ +package main + +import ( + "context" + "net/http" + "net/url" + "os" + + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/tencentyun/cos-go-sdk-v5/debug" +) + +func main() { + u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") + b := &cos.BaseURL{ + BucketURL: u, + } + c := cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: os.Getenv("COS_SECRETID"), + SecretKey: os.Getenv("COS_SECRETKEY"), + Transport: &debug.DebugRequestTransport{ + RequestHeader: true, + RequestBody: true, + ResponseHeader: true, + ResponseBody: true, + }, + }, + }) + + opt := &cos.BucketPutPolicyOptions{ + Version: "2.0", + Statement: []cos.BucketStatement{ + { + Principal: map[string][]string{ + "qcs": []string{ + "qcs::cam::uin/100000000001:uin/100000000011", //替换成您想授予权限的账户uin + }, + }, + Action: []string{ + "name/cos:GetObject", + }, + Effect: "allow", + Resource: []string{ + //这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的具体路径,例子: a.jpg 或者 a/* 或者 * (使用通配符*存在重大安全风险, 请谨慎评估使用) + "qcs::cos:ap-guangzhou:uid/1259654469:test-1259654469/exampleobject", + }, + Condition: map[string]map[string]interface{}{ + "ip_not_equal": map[string]interface{}{ + "qcs:ip": []string{ + "192.168.1.1", + }, + }, + }, + }, + }, + } + + _, err := c.Bucket.PutPolicy(context.Background(), opt) + if err != nil { + panic(err) + } +} From 3fded9612127c70a609df9941b8684bff6f7c487 Mon Sep 17 00:00:00 2001 From: jojoliang Date: Wed, 11 Mar 2020 11:16:40 +0800 Subject: [PATCH 05/15] add IsNoSuchKeyError function --- error.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/error.go b/error.go index 9d06194..ad60cc6 100644 --- a/error.go +++ b/error.go @@ -47,3 +47,17 @@ func checkResponse(r *http.Response) error { } return errorResponse } + +func IsNoSuchKeyError(e error) bool { + if e == nil { + return false + } + err, ok := e.(*ErrorResponse) + if !ok { + return false + } + if err.Response != nil && err.Response.StatusCode == 404 && err.Code == "NoSuchKey" { + return true + } + return false +} From e7237f4b030d117a4868abf2eb8cff3c37dd4aba Mon Sep 17 00:00:00 2001 From: jojoliang Date: Thu, 2 Apr 2020 20:24:59 +0800 Subject: [PATCH 06/15] update ci and error --- ci.go | 24 +++++++++++++++++ error.go | 14 +++++++--- example/object/ci_put.go | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 ci.go create mode 100644 example/object/ci_put.go diff --git a/ci.go b/ci.go new file mode 100644 index 0000000..2cf1713 --- /dev/null +++ b/ci.go @@ -0,0 +1,24 @@ +package cos + +import ( + "encoding/json" +) + +type PicOperations struct { + IsPicInfo int `json:"is_pic_info,omitempty"` + Rules []PicOperationsRules `json:"rules,omitemtpy"` +} + +type PicOperationsRules struct { + Bucket string `json:"bucket,omitempty"` + FileId string `json:"fileid"` + Rule string `json:"rule"` +} + +func EncodePicOperations(pic *PicOperations) string { + bs, err := json.Marshal(pic) + if err != nil { + return "" + } + return string(bs) +} diff --git a/error.go b/error.go index ad60cc6..23741e7 100644 --- a/error.go +++ b/error.go @@ -16,7 +16,7 @@ type ErrorResponse struct { Code string Message string Resource string - RequestID string `header:"x-cos-request-id,omitempty" url:"-" xml:"-"` + RequestID string `header:"x-cos-request-id,omitempty" url:"-" xml:"RequestId,omitempty"` TraceID string `xml:"TraceId,omitempty"` } @@ -48,7 +48,7 @@ func checkResponse(r *http.Response) error { return errorResponse } -func IsNoSuchKeyError(e error) bool { +func IsNotFoundError(e error) bool { if e == nil { return false } @@ -56,8 +56,16 @@ func IsNoSuchKeyError(e error) bool { if !ok { return false } - if err.Response != nil && err.Response.StatusCode == 404 && err.Code == "NoSuchKey" { + if err.Response != nil && err.Response.StatusCode == 404 { return true } return false } + +func IsCOSError(e error) (*ErrorResponse, bool) { + if e == nil { + return nil, false + } + err, ok := e.(*ErrorResponse) + return err, ok +} diff --git a/example/object/ci_put.go b/example/object/ci_put.go new file mode 100644 index 0000000..de36848 --- /dev/null +++ b/example/object/ci_put.go @@ -0,0 +1,70 @@ +package main + +import ( + "context" + "fmt" + "net/http" + "net/url" + "os" + + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/tencentyun/cos-go-sdk-v5/debug" +) + +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("Code: %v\n", e.Code) + fmt.Printf("Message: %v\n", e.Message) + fmt.Printf("Resource: %v\n", e.Resource) + fmt.Printf("RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Println(err) + // ERROR + } +} + +func main() { + u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") + b := &cos.BaseURL{BucketURL: u} + c := cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: os.Getenv("COS_SECRETID"), + SecretKey: os.Getenv("COS_SECRETKEY"), + Transport: &debug.DebugRequestTransport{ + RequestHeader: true, + // Notice when put a large file and set need the request body, might happend out of memory error. + RequestBody: false, + ResponseHeader: true, + ResponseBody: true, + }, + }, + }) + + opt := &cos.ObjectPutOptions{ + nil, + &cos.ObjectPutHeaderOptions{ + XOptionHeader: &http.Header{}, + }, + } + pic := &cos.PicOperations{ + IsPicInfo: 1, + Rules: []cos.PicOperationsRules{ + { + FileId: "format.jpg", + Rule: "imageView2/format/png", + }, + }, + } + opt.XOptionHeader.Add("Pic-Operations", cos.EncodePicOperations(pic)) + name := "test.jpg" + local_filename := "./test.jpg" + _, err := c.Object.PutFromFile(context.Background(), name, local_filename, opt) + log_status(err) +} From 63b6872acd7bb275f42af18120b16b6d7776dc87 Mon Sep 17 00:00:00 2001 From: jojoliang Date: Sun, 12 Apr 2020 17:28:28 +0800 Subject: [PATCH 07/15] add encryption and referer --- bucket_encryption.go | 51 ++++++++++++++++++++++ bucket_encryption_test.go | 100 +++++++++++++++++++++++++++++++++++++++++++ bucket_referer.go | 40 +++++++++++++++++ bucket_referer_test.go | 88 +++++++++++++++++++++++++++++++++++++ costesting/ci_test.go | 41 ++++++++++++++++++ example/bucket/encryption.go | 68 +++++++++++++++++++++++++++++ example/bucket/referer.go | 67 +++++++++++++++++++++++++++++ 7 files changed, 455 insertions(+) create mode 100644 bucket_encryption.go create mode 100644 bucket_encryption_test.go create mode 100644 bucket_referer.go create mode 100644 bucket_referer_test.go create mode 100644 example/bucket/encryption.go create mode 100644 example/bucket/referer.go diff --git a/bucket_encryption.go b/bucket_encryption.go new file mode 100644 index 0000000..eae8334 --- /dev/null +++ b/bucket_encryption.go @@ -0,0 +1,51 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +type BucketEncryptionConfiguration struct { + SSEAlgorithm string `xml:"SSEAlgorithm"` +} + +type BucketPutEncryptionOptions struct { + XMLName xml.Name `xml:"ServerSideEncryptionConfiguration"` + Rule *BucketEncryptionConfiguration `xml:"Rule>ApplySideEncryptionConfiguration"` +} + +type BucketGetEncryptionResult BucketPutEncryptionOptions + +func (s *BucketService) PutEncryption(ctx context.Context, opt *BucketPutEncryptionOptions) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?encryption", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +func (s *BucketService) GetEncryption(ctx context.Context) (*BucketGetEncryptionResult, *Response, error) { + var res BucketGetEncryptionResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?encryption", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +func (s *BucketService) DeleteEncryption(ctx context.Context) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?encryption", + method: http.MethodDelete, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} diff --git a/bucket_encryption_test.go b/bucket_encryption_test.go new file mode 100644 index 0000000..64be1e1 --- /dev/null +++ b/bucket_encryption_test.go @@ -0,0 +1,100 @@ +package cos + +import ( + "context" + "encoding/xml" + "fmt" + "net/http" + "reflect" + "testing" +) + +func TestBucketService_GetEncryption(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + vs := values{ + "encryption": "", + } + testFormValues(t, r, vs) + fmt.Fprint(w, ` + + + AES256 + + +`) + + }) + + res, _, err := client.Bucket.GetEncryption(context.Background()) + if err != nil { + t.Fatalf("Bucket.GetEncryption returned error %v", err) + } + + want := &BucketGetEncryptionResult{ + XMLName: xml.Name{Local: "ServerSideEncryptionConfiguration"}, + Rule: &BucketEncryptionConfiguration{ + SSEAlgorithm: "AES256", + }, + } + + if !reflect.DeepEqual(res, want) { + t.Errorf("Bucket.GetEncryption returned %+v, want %+v", res, want) + } +} + +func TestBucketService_PutEncryption(t *testing.T) { + setup() + defer teardown() + + opt := &BucketPutEncryptionOptions{ + Rule: &BucketEncryptionConfiguration{ + SSEAlgorithm: "AES256", + }, + } + + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + vs := values{ + "encryption": "", + } + testFormValues(t, r, vs) + + body := new(BucketPutEncryptionOptions) + xml.NewDecoder(r.Body).Decode(body) + want := opt + want.XMLName = xml.Name{Local: "ServerSideEncryptionConfiguration"} + if !reflect.DeepEqual(body, want) { + t.Errorf("Bucket.PutEncryption request\n body: %+v\n, want %+v\n", body, want) + } + }) + + _, err := client.Bucket.PutEncryption(context.Background(), opt) + if err != nil { + t.Fatalf("Bucket.PutEncryption returned error: %v", err) + } +} + +func TestBucketService_DeleteEncryption(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodDelete) + vs := values{ + "encryption": "", + } + testFormValues(t, r, vs) + + w.WriteHeader(http.StatusNoContent) + }) + + _, err := client.Bucket.DeleteEncryption(context.Background()) + if err != nil { + t.Fatalf("Bucket.DeleteEncryption returned error: %v", err) + } + +} diff --git a/bucket_referer.go b/bucket_referer.go new file mode 100644 index 0000000..fe8b6a0 --- /dev/null +++ b/bucket_referer.go @@ -0,0 +1,40 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +type BucketPutRefererOptions struct { + XMLName xml.Name `xml:"RefererConfiguration"` + Status string `xml:"Status"` + RefererType string `xml:"RefererType"` + DomainList []string `xml:"DomainList>Domain"` + EmptyReferConfiguration string `xml:"EmptyReferConfiguration,omitempty"` +} + +type BucketGetRefererResult BucketPutRefererOptions + +func (s *BucketService) PutReferer(ctx context.Context, opt *BucketPutRefererOptions) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?referer", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +func (s *BucketService) GetReferer(ctx context.Context) (*BucketGetRefererResult, *Response, error) { + var res BucketGetRefererResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?referer", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} diff --git a/bucket_referer_test.go b/bucket_referer_test.go new file mode 100644 index 0000000..b648e37 --- /dev/null +++ b/bucket_referer_test.go @@ -0,0 +1,88 @@ +package cos + +import ( + "context" + "encoding/xml" + "fmt" + "net/http" + "reflect" + "testing" +) + +func TestBucketService_GetReferer(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + vs := values{ + "referer": "", + } + testFormValues(t, r, vs) + fmt.Fprint(w, ` + Enabled + White-List + + *.qq.com + *.qcloud.com + + Allow +`) + }) + + res, _, err := client.Bucket.GetReferer(context.Background()) + if err != nil { + t.Fatalf("Bucket.GetReferer returned error %v", err) + } + + want := &BucketGetRefererResult{ + XMLName: xml.Name{Local: "RefererConfiguration"}, + Status: "Enabled", + RefererType: "White-List", + DomainList: []string{ + "*.qq.com", + "*.qcloud.com", + }, + EmptyReferConfiguration: "Allow", + } + + if !reflect.DeepEqual(res, want) { + t.Errorf("Bucket.GetReferer returned %+v, want %+v", res, want) + } +} + +func TestBucketService_PutReferer(t *testing.T) { + setup() + defer teardown() + + opt := &BucketPutRefererOptions{ + Status: "Enabled", + RefererType: "White-List", + DomainList: []string{ + "*.qq.com", + "*.qcloud.com", + }, + EmptyReferConfiguration: "Allow", + } + + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + vs := values{ + "referer": "", + } + testFormValues(t, r, vs) + + body := new(BucketPutRefererOptions) + xml.NewDecoder(r.Body).Decode(body) + want := opt + want.XMLName = xml.Name{Local: "RefererConfiguration"} + if !reflect.DeepEqual(body, want) { + t.Errorf("Bucket.PutReferer request\n body: %+v\nwant %+v\n", body, want) + } + }) + + _, err := client.Bucket.PutReferer(context.Background(), opt) + if err != nil { + t.Fatalf("Bucket.PutReferer returned error: %v", err) + } +} diff --git a/costesting/ci_test.go b/costesting/ci_test.go index 01d5006..38a8ffa 100644 --- a/costesting/ci_test.go +++ b/costesting/ci_test.go @@ -802,6 +802,7 @@ func (s *CosTestSuite) TestBatch() { assert.Equal(s.T(), res3.JobId, jobid, "jobid failed") assert.Equal(s.T(), res3.Priority, 3, "priority not right") + // 等待状态变成Suspended for i := 0; i < 10; i = i + 1 { res, _, err := client.Batch.DescribeJob(context.Background(), jobid, headers) assert.Nil(s.T(), err, "describe job Failed") @@ -830,6 +831,46 @@ func (s *CosTestSuite) TestBatch() { assert.Equal(s.T(), res4.StatusUpdateReason, "to test", "StatusUpdateReason failed") } +func (s *CosTestSuite) TestEncryption() { + opt := &cos.BucketPutEncryptionOptions{ + Rule: &cos.BucketEncryptionConfiguration{ + SSEAlgorithm: "AES256", + }, + } + + _, err := s.Client.Bucket.PutEncryption(context.Background(), opt) + assert.Nil(s.T(), err, "PutEncryption Failed") + + res, _, err := s.Client.Bucket.GetEncryption(context.Background()) + assert.Nil(s.T(), err, "GetEncryption Failed") + assert.Equal(s.T(), opt.Rule.SSEAlgorithm, res.Rule.SSEAlgorithm, "GetEncryption Failed") + + _, err = s.Client.Bucket.DeleteEncryption(context.Background()) + assert.Nil(s.T(), err, "DeleteEncryption Failed") +} + +func (s *CosTestSuite) TestReferer() { + opt := &cos.BucketPutRefererOptions{ + Status: "Enabled", + RefererType: "White-List", + DomainList: []string{ + "*.qq.com", + "*.qcloud.com", + }, + EmptyReferConfiguration: "Allow", + } + + _, err := s.Client.Bucket.PutReferer(context.Background(), opt) + assert.Nil(s.T(), err, "PutReferer Failed") + + res, _, err := s.Client.Bucket.GetReferer(context.Background()) + assert.Nil(s.T(), err, "GetReferer Failed") + assert.Equal(s.T(), opt.Status, res.Status, "GetReferer Failed") + assert.Equal(s.T(), opt.RefererType, res.RefererType, "GetReferer Failed") + assert.Equal(s.T(), opt.DomainList, res.DomainList, "GetReferer Failed") + assert.Equal(s.T(), opt.EmptyReferConfiguration, res.EmptyReferConfiguration, "GetReferer Failed") +} + // End of api test // All methods that begin with "Test" are run as tests within a diff --git a/example/bucket/encryption.go b/example/bucket/encryption.go new file mode 100644 index 0000000..addeee4 --- /dev/null +++ b/example/bucket/encryption.go @@ -0,0 +1,68 @@ +package main + +import ( + "context" + "encoding/xml" + "fmt" + "net/http" + "net/url" + "os" + + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/tencentyun/cos-go-sdk-v5/debug" +) + +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("Code: %v\n", e.Code) + fmt.Printf("Message: %v\n", e.Message) + fmt.Printf("Resource: %v\n", e.Resource) + fmt.Printf("RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Println(err) + // ERROR + } +} + +func main() { + u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") + b := &cos.BaseURL{ + BucketURL: u, + } + c := cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: os.Getenv("COS_SECRETID"), + SecretKey: os.Getenv("COS_SECRETKEY"), + Transport: &debug.DebugRequestTransport{ + RequestHeader: true, + RequestBody: true, + ResponseHeader: true, + ResponseBody: true, + }, + }, + }) + + opt := &cos.BucketPutEncryptionOptions{ + XMLName: xml.Name{Local: "ServerSideEncryptionConfiguration"}, + Rule: &cos.BucketEncryptionConfiguration{ + SSEAlgorithm: "AES256", + }, + } + + _, err := c.Bucket.PutEncryption(context.Background(), opt) + log_status(err) + + res, _, err := c.Bucket.GetEncryption(context.Background()) + log_status(err) + fmt.Printf("%+v\n", res) + + _, err = c.Bucket.DeleteEncryption(context.Background()) + log_status(err) +} diff --git a/example/bucket/referer.go b/example/bucket/referer.go new file mode 100644 index 0000000..8820505 --- /dev/null +++ b/example/bucket/referer.go @@ -0,0 +1,67 @@ +package main + +import ( + "context" + "fmt" + "net/http" + "net/url" + "os" + + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/tencentyun/cos-go-sdk-v5/debug" +) + +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("Code: %v\n", e.Code) + fmt.Printf("Message: %v\n", e.Message) + fmt.Printf("Resource: %v\n", e.Resource) + fmt.Printf("RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Println(err) + // ERROR + } +} + +func main() { + u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") + b := &cos.BaseURL{ + BucketURL: u, + } + c := cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: os.Getenv("COS_SECRETID"), + SecretKey: os.Getenv("COS_SECRETKEY"), + Transport: &debug.DebugRequestTransport{ + RequestHeader: true, + RequestBody: true, + ResponseHeader: true, + ResponseBody: true, + }, + }, + }) + + opt := &cos.BucketPutRefererOptions{ + Status: "Enabled", + RefererType: "White-List", + DomainList: []string{ + "*.qq.com", + "*.qcloud.com", + }, + EmptyReferConfiguration: "Allow", + } + + _, err := c.Bucket.PutReferer(context.Background(), opt) + log_status(err) + + res, _, err := c.Bucket.GetReferer(context.Background()) + log_status(err) + fmt.Printf("%+v\n", res) +} From da7722b10af59762b8e4f687891850650f0100a9 Mon Sep 17 00:00:00 2001 From: jojoliang Date: Sun, 12 Apr 2020 17:53:11 +0800 Subject: [PATCH 08/15] version 0.7.4 --- cos.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cos.go b/cos.go index 132e128..ac005f8 100644 --- a/cos.go +++ b/cos.go @@ -21,7 +21,7 @@ import ( const ( // Version current go sdk version - Version = "0.7.3" + Version = "0.7.4" userAgent = "cos-go-sdk-v5/" + Version contentTypeXML = "application/xml" defaultServiceBaseURL = "http://service.cos.myqcloud.com" From 279cb4feb0a17b1125245cf459ea60c91ce2b7ea Mon Sep 17 00:00:00 2001 From: keroming Date: Thu, 7 May 2020 17:12:38 +0800 Subject: [PATCH 09/15] =?UTF-8?q?feat:=20Object.Delete=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20optHeader=20=E4=BC=A0=E9=80=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/object/delete.go | 2 +- object.go | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/example/object/delete.go b/example/object/delete.go index 55d4902..ed227c9 100644 --- a/example/object/delete.go +++ b/example/object/delete.go @@ -29,7 +29,7 @@ func main() { name := "test/objectPut.go" - _, err := c.Object.Delete(context.Background(), name) + _, err := c.Object.Delete(context.Background(), name, nil) if err != nil { panic(err) } diff --git a/object.go b/object.go index fd8285b..dd9c358 100644 --- a/object.go +++ b/object.go @@ -272,10 +272,18 @@ func (s *ObjectService) Copy(ctx context.Context, name, sourceURL string, opt *O return &res, resp, err } +type ObjectDeleteOptions struct { + // SSE-C + XCosSSECustomerAglo string `header:"x-cos-server-side-encryption-customer-algorithm,omitempty" url:"-" xml:"-"` + XCosSSECustomerKey string `header:"x-cos-server-side-encryption-customer-key,omitempty" url:"-" xml:"-"` + XCosSSECustomerKeyMD5 string `header:"x-cos-server-side-encryption-customer-key-MD5,omitempty" url:"-" xml:"-"` + //兼容其他自定义头部 + XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` +} // Delete Object请求可以将一个文件(Object)删除。 // // https://www.qcloud.com/document/product/436/7743 -func (s *ObjectService) Delete(ctx context.Context, name string) (*Response, error) { +func (s *ObjectService) Delete(ctx context.Context, name string, opt *ObjectDeleteOptions) (*Response, error) { // When use "" string might call the delete bucket interface if len(name) == 0 { return nil, errors.New("empty object name") @@ -285,6 +293,7 @@ func (s *ObjectService) Delete(ctx context.Context, name string) (*Response, err baseURL: s.client.BaseURL.BucketURL, uri: "/" + encodeURIComponent(name), method: http.MethodDelete, + optHeader: opt, } resp, err := s.client.send(ctx, &sendOpt) return resp, err From 2eee5149d727a045e80d28729bb60c90614e8275 Mon Sep 17 00:00:00 2001 From: keroming Date: Thu, 7 May 2020 17:46:43 +0800 Subject: [PATCH 10/15] =?UTF-8?q?feat:=20=E6=94=B9=E4=B8=BA=E5=8F=AF?= =?UTF-8?q?=E9=80=89=E5=8F=82=E6=95=B0=EF=BC=8C=E5=90=91=E4=B8=8B=E5=85=BC?= =?UTF-8?q?=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- object.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/object.go b/object.go index dd9c358..255c0d1 100644 --- a/object.go +++ b/object.go @@ -283,17 +283,21 @@ type ObjectDeleteOptions struct { // Delete Object请求可以将一个文件(Object)删除。 // // https://www.qcloud.com/document/product/436/7743 -func (s *ObjectService) Delete(ctx context.Context, name string, opt *ObjectDeleteOptions) (*Response, error) { +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 { return nil, errors.New("empty object name") } + if len(opt) > 0 { + optHeader = opt[0] + } sendOpt := sendOptions{ baseURL: s.client.BaseURL.BucketURL, uri: "/" + encodeURIComponent(name), method: http.MethodDelete, - optHeader: opt, + optHeader: optHeader, } resp, err := s.client.send(ctx, &sendOpt) return resp, err From d9d86f64ad286d7c939307e27048bdb25b288c78 Mon Sep 17 00:00:00 2001 From: jojoliang Date: Thu, 14 May 2020 20:24:26 +0800 Subject: [PATCH 11/15] update tag 0.7.5 --- cos.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cos.go b/cos.go index ac005f8..d9a67b8 100644 --- a/cos.go +++ b/cos.go @@ -21,7 +21,7 @@ import ( const ( // Version current go sdk version - Version = "0.7.4" + Version = "0.7.5" userAgent = "cos-go-sdk-v5/" + Version contentTypeXML = "application/xml" defaultServiceBaseURL = "http://service.cos.myqcloud.com" From 517ae20fdc06a6e0eb9e5482d1da6716f4542a5b Mon Sep 17 00:00:00 2001 From: jojoliang Date: Tue, 19 May 2020 21:07:37 +0800 Subject: [PATCH 12/15] add GetBucketObjectVersions & update tips when failed --- bucket.go | 58 ++++++++++++++++ bucket_test.go | 105 +++++++++++++++++++++++++++++ costesting/ci_test.go | 9 +++ example/bucket/getLogging.go | 38 +++++++++++ example/bucket/getObjectVersion.go | 64 ++++++++++++++++++ example/object/MultiUpload.go | 61 +++++++++++++++++ example/object/MutiUpload.go | 44 ------------ example/object/abortMultipartUpload.go | 27 ++++++-- example/object/ci_put.go | 12 ++-- example/object/completeMultipartUpload.go | 35 +++++++--- example/object/copy.go | 36 +++++++--- example/object/copyPart.go | 31 ++++++--- example/object/delete.go | 24 ++++++- example/object/deleteMultiple.go | 27 ++++++-- example/object/get.go | 42 +++++++----- example/object/getACL.go | 25 +++++-- example/object/getAnonymous.go | 24 +++++-- example/object/getByPresignedURL.go | 32 ++++++--- example/object/head.go | 24 ++++++- example/object/initiateMultipartUpload.go | 23 ++++++- example/object/listParts.go | 31 ++++++--- example/object/options.go | 26 +++++-- example/object/presigned_url_with_token.go | 44 ++++++++++++ example/object/put.go | 35 +++++++--- example/object/putACL.go | 28 ++++++-- example/object/restore.go | 24 ++++++- example/object/sse_c.go | 81 ++++++++++++++++++++++ example/object/sse_cos.go | 75 +++++++++++++++++++++ example/object/upload.go | 23 ++++++- example/object/uploadFile.go | 29 ++++++-- example/object/uploadPart.go | 27 ++++++-- 31 files changed, 985 insertions(+), 179 deletions(-) create mode 100644 example/bucket/getLogging.go create mode 100644 example/bucket/getObjectVersion.go create mode 100644 example/object/MultiUpload.go delete mode 100644 example/object/MutiUpload.go create mode 100644 example/object/presigned_url_with_token.go create mode 100644 example/object/sse_c.go create mode 100644 example/object/sse_cos.go diff --git a/bucket.go b/bucket.go index 2e3f92c..67f991b 100644 --- a/bucket.go +++ b/bucket.go @@ -102,3 +102,61 @@ type Bucket struct { Region string `xml:"Location,omitempty"` CreationDate string `xml:",omitempty"` } + +type BucketGetObjectVersionsOptions struct { + Prefix string `url:"prefix,omitempty"` + Delimiter string `url:"delimiter,omitempty"` + EncodingType string `url:"encoding-type,omitempty"` + KeyMarker string `url:"key-marker,omitempty"` + VersionIdMarker string `url:"version-id-marker,omitempty"` + MaxKeys int `url:"max-keys,omitempty"` +} + +type BucketGetObjectVersionsResult struct { + XMLName xml.Name `xml:"ListVersionsResult"` + Name string `xml:"Name,omitempty"` + EncodingType string `xml:"EncodingType,omitempty"` + Prefix string `xml:"Prefix,omitempty"` + KeyMarker string `xml:"KeyMarker,omitempty"` + VersionIdMarker string `xml:"VersionIdMarker,omitempty"` + MaxKeys int `xml:"MaxKeys,omitempty"` + Delimiter string `xml:"Delimiter,omitempty"` + IsTruncated bool `xml:"IsTruncated,omitempty"` + NextKeyMarker string `xml:"NextKeyMarker,omitempty"` + NextVersionIdMarker string `xml:"NextVersionIdMarker,omitempty"` + CommonPrefixes []string `xml:"CommonPrefixes>Prefix,omitempty"` + Version []ListVersionsResultVersion `xml:"Version,omitempty"` + DeleteMarker []ListVersionsResultDeleteMarker `xml:"DeleteMarker,omitempty"` +} + +type ListVersionsResultVersion struct { + Key string `xml:"Key,omitempty"` + VersionId string `xml:"VersionId,omitempty"` + IsLatest bool `xml:"IsLatest,omitempty"` + LastModified string `xml:"LastModified,omitempty"` + ETag string `xml:"ETag,omitempty"` + Size int `xml:"Size,omitempty"` + StorageClass string `xml:"StorageClass,omitempty"` + Owner *Owner `xml:"Owner,omitempty"` +} + +type ListVersionsResultDeleteMarker struct { + Key string `xml:"Key,omitempty"` + VersionId string `xml:"VersionId,omitempty"` + IsLatest bool `xml:"IsLatest,omitempty"` + LastModified string `xml:"LastModified,omitempty"` + Owner *Owner `xml:"Owner,omitempty"` +} + +func (s *BucketService) GetObjectVersions(ctx context.Context, opt *BucketGetObjectVersionsOptions) (*BucketGetObjectVersionsResult, *Response, error) { + var res BucketGetObjectVersionsResult + sendOpt := sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?versions", + method: http.MethodGet, + optQuery: opt, + result: &res, + } + resp, err := s.client.send(ctx, &sendOpt) + return &res, resp, err +} diff --git a/bucket_test.go b/bucket_test.go index 4a5812e..16c55a2 100644 --- a/bucket_test.go +++ b/bucket_test.go @@ -150,3 +150,108 @@ func TestBucketService_Head(t *testing.T) { t.Fatalf("Bucket.Head returned error: %v", err) } } + +func TestBucketService_GetObjectVersions(t *testing.T) { + setup() + defer teardown() + + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, http.MethodGet) + w.WriteHeader(http.StatusOK) + vs := values{ + "versions": "", + "delimiter": "/", + } + testFormValues(t, r, vs) + + fmt.Fprint(w, ` + + examplebucket-1250000000 + + + + 1000 + false + / + + example-folder-1/ + + + example-folder-2/ + + + example-object-1.jpg + MTg0NDUxNzgxMjEzNTU3NTk1Mjg + true + 2019-08-16T10:45:53.000Z + "5d1143df07a17b23320d0da161e2819e" + 30 + STANDARD + + 1250000000 + 1250000000 + + + + example-object-1.jpg + MTg0NDUxNzgxMjEzNjE1OTcxMzM + false + 2019-08-16T10:45:47.000Z + + 1250000000 + 1250000000 + + +`) + }) + + want := &BucketGetObjectVersionsResult { + XMLName: xml.Name { Local: "ListVersionsResult" }, + Name: "examplebucket-1250000000", + MaxKeys: 1000, + IsTruncated: false, + Delimiter: "/", + CommonPrefixes: []string { + "example-folder-1/", + "example-folder-2/", + }, + Version: []ListVersionsResultVersion { + { + Key: "example-object-1.jpg", + VersionId: "MTg0NDUxNzgxMjEzNTU3NTk1Mjg", + IsLatest: true, + LastModified: "2019-08-16T10:45:53.000Z", + ETag: "\"5d1143df07a17b23320d0da161e2819e\"", + Size: 30, + StorageClass: "STANDARD", + Owner: &Owner { + ID: "1250000000", + DisplayName: "1250000000", + }, + }, + }, + DeleteMarker: []ListVersionsResultDeleteMarker { + { + Key: "example-object-1.jpg", + VersionId: "MTg0NDUxNzgxMjEzNjE1OTcxMzM", + IsLatest: false, + LastModified: "2019-08-16T10:45:47.000Z", + Owner: &Owner { + ID: "1250000000", + DisplayName: "1250000000", + }, + }, + }, + } + opt := &BucketGetObjectVersionsOptions { + Delimiter: "/", + } + res, _, err := client.Bucket.GetObjectVersions(context.Background(), opt) + if err != nil { + t.Fatalf("Bucket.GetObjectVersions returned error: %v", err) + } + if !reflect.DeepEqual(res, want) { + t.Errorf("Bucket.GetObjectVersions returned\n%+v\nwant\n%+v", res, want) + } + +} diff --git a/costesting/ci_test.go b/costesting/ci_test.go index 38a8ffa..491bce8 100644 --- a/costesting/ci_test.go +++ b/costesting/ci_test.go @@ -184,6 +184,15 @@ func (s *CosTestSuite) TestGetBucket() { assert.Nil(s.T(), err, "GetBucket Failed") } +func (s *CosTestSuite) TestGetObjectVersions() { + opt := &cos.BucketGetObjectVersionsOptions { + Prefix: "中文", + MaxKeys: 3, + } + _, _, err := s.Client.Bucket.GetObjectVersions(context.Background(), opt) + assert.Nil(s.T(), err, "GetObjectVersions Failed") +} + func (s *CosTestSuite) TestGetBucketLocation() { v, _, err := s.Client.Bucket.GetLocation(context.Background()) assert.Nil(s.T(), err, "GetLocation Failed") diff --git a/example/bucket/getLogging.go b/example/bucket/getLogging.go new file mode 100644 index 0000000..6d68f7e --- /dev/null +++ b/example/bucket/getLogging.go @@ -0,0 +1,38 @@ +package main + +import ( + "context" + "fmt" + "net/url" + "os" + + "net/http" + + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/tencentyun/cos-go-sdk-v5/debug" +) + +func main() { + u, _ := url.Parse("https://bj-1259654469.cos.ap-beijing.myqcloud.com") + b := &cos.BaseURL{ + BucketURL: u, + } + c := cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: os.Getenv("COS_SECRETID"), + SecretKey: os.Getenv("COS_SECRETKEY"), + Transport: &debug.DebugRequestTransport{ + RequestHeader: true, + RequestBody: true, + ResponseHeader: true, + ResponseBody: true, + }, + }, + }) + + v, _, err := c.Bucket.GetLogging(context.Background()) + if err != nil { + panic(err) + } + fmt.Printf("%+v\n", v.LoggingEnabled) +} diff --git a/example/bucket/getObjectVersion.go b/example/bucket/getObjectVersion.go new file mode 100644 index 0000000..a9aca0a --- /dev/null +++ b/example/bucket/getObjectVersion.go @@ -0,0 +1,64 @@ +package main + +import ( + "context" + "fmt" + "os" + + "net/url" + + "net/http" + + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/tencentyun/cos-go-sdk-v5/debug" +) + +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + +func main() { + u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") + b := &cos.BaseURL{ + BucketURL: u, + } + c := cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: os.Getenv("COS_SECRETID"), + SecretKey: os.Getenv("COS_SECRETKEY"), + Transport: &debug.DebugRequestTransport{ + RequestHeader: true, + RequestBody: true, + ResponseHeader: true, + ResponseBody: true, + }, + }, + }) + + opt := &cos.BucketGetObjectVersionsOptions { + Delimiter: "/", + MaxKeys: 1, + } + v, _, err := c.Bucket.GetObjectVersions(context.Background(), opt) + log_status(err) + + for _, c := range v.Version { + fmt.Printf("%v, %v, %v\n", c.Key, c.Size, c.IsLatest) + } + +} diff --git a/example/object/MultiUpload.go b/example/object/MultiUpload.go new file mode 100644 index 0000000..1439c75 --- /dev/null +++ b/example/object/MultiUpload.go @@ -0,0 +1,61 @@ +package main + +import ( + "context" + "net/http" + "net/url" + "os" + "time" + + "fmt" + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/tencentyun/cos-go-sdk-v5/debug" +) + +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + +func main() { + u, _ := url.Parse("http://alanbj-1251668577.cos.ap-beijing.myqcloud.com") + b := &cos.BaseURL{BucketURL: u} + c := cos.NewClient(b, &http.Client{ + //设置超时时间 + Timeout: 100 * time.Second, + Transport: &cos.AuthorizationTransport{ + SecretID: os.Getenv("COS_SECRETID"), + SecretKey: os.Getenv("COS_SECRETKEY"), + Transport: &debug.DebugRequestTransport{ + RequestHeader: false, + RequestBody: false, + ResponseHeader: false, + ResponseBody: false, + }, + }, + }) + + opt := &cos.MultiUploadOptions{ + OptIni: nil, + PartSize: 1, + } + v, _, err := c.Object.MultiUpload( + context.Background(), "test/gomulput1G", "./test1G", opt, + ) + log_status(err) + fmt.Println(v) +} diff --git a/example/object/MutiUpload.go b/example/object/MutiUpload.go deleted file mode 100644 index 282f7af..0000000 --- a/example/object/MutiUpload.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - "context" - "net/http" - "net/url" - "os" - "time" - - "fmt" - "github.com/tencentyun/cos-go-sdk-v5" - "github.com/tencentyun/cos-go-sdk-v5/debug" -) - -func main() { - u, _ := url.Parse("http://alanbj-1251668577.cos.ap-beijing.myqcloud.com") - b := &cos.BaseURL{BucketURL: u} - c := cos.NewClient(b, &http.Client{ - //设置超时时间 - Timeout: 100 * time.Second, - Transport: &cos.AuthorizationTransport{ - SecretID: os.Getenv("COS_SECRETID"), - SecretKey: os.Getenv("COS_SECRETKEY"), - Transport: &debug.DebugRequestTransport{ - RequestHeader: false, - RequestBody: false, - ResponseHeader: false, - ResponseBody: false, - }, - }, - }) - - opt := &cos.MultiUploadOptions{ - OptIni: nil, - PartSize: 1, - } - v, _, err := c.Object.MultiUpload( - context.Background(), "test/gomulput1G", "./test1G", opt, - ) - if err != nil { - panic(err) - } - fmt.Println(v) -} diff --git a/example/object/abortMultipartUpload.go b/example/object/abortMultipartUpload.go index 1544169..3ada616 100644 --- a/example/object/abortMultipartUpload.go +++ b/example/object/abortMultipartUpload.go @@ -12,6 +12,25 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func main() { u, _ := url.Parse("https://test-1253846586.cos.ap-guangzhou.myqcloud.com") b := &cos.BaseURL{BucketURL: u} @@ -30,14 +49,10 @@ func main() { name := "test_multipart.txt" v, _, err := c.Object.InitiateMultipartUpload(context.Background(), name, nil) - if err != nil { - panic(err) - } + log_status(err) fmt.Printf("%s\n", v.UploadID) resp, err := c.Object.AbortMultipartUpload(context.Background(), name, v.UploadID) - if err != nil { - panic(err) - } + log_status(err) fmt.Printf("%s\n", resp.Status) } diff --git a/example/object/ci_put.go b/example/object/ci_put.go index de36848..5417431 100644 --- a/example/object/ci_put.go +++ b/example/object/ci_put.go @@ -17,15 +17,15 @@ func log_status(err error) { } if cos.IsNotFoundError(err) { // WARN - fmt.Println("Resource is not existed") + fmt.Println("WARN: Resource is not existed") } else if e, ok := cos.IsCOSError(err); ok { - fmt.Printf("Code: %v\n", e.Code) - fmt.Printf("Message: %v\n", e.Message) - fmt.Printf("Resource: %v\n", e.Resource) - fmt.Printf("RequestId: %v\n", e.RequestID) + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) // ERROR } else { - fmt.Println(err) + fmt.Printf("ERROR: %v\n", err) // ERROR } } diff --git a/example/object/completeMultipartUpload.go b/example/object/completeMultipartUpload.go index 9558158..a97c9d2 100644 --- a/example/object/completeMultipartUpload.go +++ b/example/object/completeMultipartUpload.go @@ -14,11 +14,28 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func initUpload(c *cos.Client, name string) *cos.InitiateMultipartUploadResult { v, _, err := c.Object.InitiateMultipartUpload(context.Background(), name, nil) - if err != nil { - panic(err) - } + log_status(err) fmt.Printf("%#v\n", v) return v } @@ -27,7 +44,7 @@ func uploadPart(c *cos.Client, name string, uploadID string, blockSize, n int) s b := make([]byte, blockSize) if _, err := rand.Read(b); err != nil { - panic(err) + log_status(err) } s := fmt.Sprintf("%X", b) f := strings.NewReader(s) @@ -35,15 +52,13 @@ func uploadPart(c *cos.Client, name string, uploadID string, blockSize, n int) s resp, err := c.Object.UploadPart( context.Background(), name, uploadID, n, f, nil, ) - if err != nil { - panic(err) - } + log_status(err) fmt.Printf("%s\n", resp.Status) return resp.Header.Get("Etag") } func main() { - u, _ := url.Parse("https://test-1253846586.cos.ap-guangzhou.myqcloud.com") + u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") b := &cos.BaseURL{BucketURL: u} c := cos.NewClient(b, &http.Client{ Transport: &cos.AuthorizationTransport{ @@ -86,9 +101,7 @@ func main() { v, resp, err := c.Object.CompleteMultipartUpload( context.Background(), name, uploadID, opt, ) - if err != nil { - panic(err) - } + log_status(err) fmt.Printf("%s\n", resp.Status) fmt.Printf("%#v\n", v) fmt.Printf("%s\n", v.Location) diff --git a/example/object/copy.go b/example/object/copy.go index 2a81cb3..199be64 100644 --- a/example/object/copy.go +++ b/example/object/copy.go @@ -16,8 +16,27 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func main() { - u, _ := url.Parse("https://test-1253846586.cos.ap-guangzhou.myqcloud.com") + u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") b := &cos.BaseURL{BucketURL: u} c := cos.NewClient(b, &http.Client{ Transport: &cos.AuthorizationTransport{ @@ -37,24 +56,19 @@ func main() { f := strings.NewReader(expected) _, err := c.Object.Put(context.Background(), source, f, nil) - if err != nil { - panic(err) - } + log_status(err) soruceURL := fmt.Sprintf("%s/%s", u.Host, source) dest := fmt.Sprintf("test/objectMove_%d.go", time.Now().Nanosecond()) //opt := &cos.ObjectCopyOptions{} res, _, err := c.Object.Copy(context.Background(), dest, soruceURL, nil) - if err != nil { - panic(err) - } + log_status(err) fmt.Printf("%+v\n\n", res) resp, err := c.Object.Get(context.Background(), dest, nil) - if err != nil { - panic(err) - } - bs, _ := ioutil.ReadAll(resp.Body) + log_status(err) + + bs, _ := ioutil.ReadAll(resp.Body) resp.Body.Close() result := string(bs) if result != expected { diff --git a/example/object/copyPart.go b/example/object/copyPart.go index 22ce620..5b96356 100644 --- a/example/object/copyPart.go +++ b/example/object/copyPart.go @@ -13,11 +13,28 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func initUpload(c *cos.Client, name string) *cos.InitiateMultipartUploadResult { v, _, err := c.Object.InitiateMultipartUpload(context.Background(), name, nil) - if err != nil { - panic(err) - } + log_status(err) fmt.Printf("%#v\n", v) return v } @@ -46,9 +63,7 @@ func main() { opt := &cos.ObjectCopyPartOptions{} res, _, err := c.Object.CopyPart( context.Background(), name, uploadID, 1, sourceUrl, opt) - if err != nil { - panic(err) - } + log_status(err) fmt.Println("ETag:", res.ETag) completeOpt := &cos.CompleteMultipartUploadOptions{} @@ -59,9 +74,7 @@ func main() { v, resp, err := c.Object.CompleteMultipartUpload( context.Background(), name, uploadID, completeOpt, ) - if err != nil { - panic(err) - } + log_status(err) fmt.Printf("%s\n", resp.Status) fmt.Printf("%#v\n", v) fmt.Printf("%s\n", v.Location) diff --git a/example/object/delete.go b/example/object/delete.go index ed227c9..bb8ffaf 100644 --- a/example/object/delete.go +++ b/example/object/delete.go @@ -2,6 +2,7 @@ package main import ( "context" + "fmt" "net/url" "os" @@ -11,6 +12,25 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func main() { u, _ := url.Parse("https://test-1253846586.cos.ap-guangzhou.myqcloud.com") b := &cos.BaseURL{BucketURL: u} @@ -30,7 +50,5 @@ func main() { name := "test/objectPut.go" _, err := c.Object.Delete(context.Background(), name, nil) - if err != nil { - panic(err) - } + log_status(err) } diff --git a/example/object/deleteMultiple.go b/example/object/deleteMultiple.go index 018e4a2..4faa846 100644 --- a/example/object/deleteMultiple.go +++ b/example/object/deleteMultiple.go @@ -18,10 +18,29 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func genBigData(blockSize int) []byte { b := make([]byte, blockSize) if _, err := rand.Read(b); err != nil { - panic(err) + log_status(err) } return b } @@ -46,7 +65,7 @@ func uploadMulti(c *cos.Client) []string { } func main() { - u, _ := url.Parse("https://test-1253846586.cos.ap-guangzhou.myqcloud.com") + u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") b := &cos.BaseURL{BucketURL: u} c := cos.NewClient(b, &http.Client{ Transport: &cos.AuthorizationTransport{ @@ -89,9 +108,7 @@ func main() { }) v, _, err := c.Object.DeleteMulti(ctx, opt) - if err != nil { - panic(err) - } + log_status(err) for _, x := range v.DeletedObjects { fmt.Printf("deleted %s\n", x.Key) diff --git a/example/object/get.go b/example/object/get.go index b2c1bcb..2650030 100644 --- a/example/object/get.go +++ b/example/object/get.go @@ -13,6 +13,25 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func main() { u, _ := url.Parse("https://test-1253846586.cos.ap-guangzhou.myqcloud.com") b := &cos.BaseURL{BucketURL: u} @@ -32,31 +51,26 @@ func main() { // Case1 Download object into ReadCloser(). the body needs to be closed name := "test/hello.txt" resp, err := c.Object.Get(context.Background(), name, nil) - if err != nil { - panic(err) - } + log_status(err) + bs, _ := ioutil.ReadAll(resp.Body) resp.Body.Close() fmt.Printf("%s\n", string(bs)) // Case2 Download object to local file. the body needs to be closed fd, err := os.OpenFile("hello.txt", os.O_WRONLY|os.O_CREATE, 0660) - if err != nil { - panic(err) - } + log_status(err) + defer fd.Close() resp, err = c.Object.Get(context.Background(), name, nil) - if err != nil { - panic(err) - } + log_status(err) + io.Copy(fd, resp.Body) resp.Body.Close() // Case3 Download object to local file path _, err = c.Object.GetToFile(context.Background(), name, "hello_1.txt", nil) - if err != nil { - panic(err) - } + log_status(err) // Case4 Download object with range header, can used to concurrent download opt := &cos.ObjectGetOptions{ @@ -64,9 +78,7 @@ func main() { Range: "bytes=0-3", } resp, err = c.Object.Get(context.Background(), name, opt) - if err != nil { - panic(err) - } + log_status(err) bs, _ = ioutil.ReadAll(resp.Body) resp.Body.Close() fmt.Printf("%s\n", string(bs)) diff --git a/example/object/getACL.go b/example/object/getACL.go index f098fe2..0beb495 100644 --- a/example/object/getACL.go +++ b/example/object/getACL.go @@ -12,8 +12,27 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func main() { - u, _ := url.Parse("https://test-1253846586.cos.ap-guangzhou.myqcloud.com") + u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") b := &cos.BaseURL{BucketURL: u} c := cos.NewClient(b, &http.Client{ Transport: &cos.AuthorizationTransport{ @@ -30,9 +49,7 @@ func main() { name := "test/hello.txt" v, _, err := c.Object.GetACL(context.Background(), name) - if err != nil { - panic(err) - } + log_status(err) for _, a := range v.AccessControlList { fmt.Printf("%s, %s, %s\n", a.Grantee.Type, a.Grantee.ID, a.Permission) } diff --git a/example/object/getAnonymous.go b/example/object/getAnonymous.go index be1d46e..90ceb30 100644 --- a/example/object/getAnonymous.go +++ b/example/object/getAnonymous.go @@ -11,6 +11,25 @@ import ( "github.com/tencentyun/cos-go-sdk-v5" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func upload(c *cos.Client, name string) { f := strings.NewReader("test") f = strings.NewReader("test xxx") @@ -35,10 +54,7 @@ func main() { upload(c, name) resp, err := c.Object.Get(context.Background(), name, nil) - if err != nil { - panic(err) - return - } + log_status(err) bs, _ := ioutil.ReadAll(resp.Body) defer resp.Body.Close() fmt.Printf("%s\n", string(bs)) diff --git a/example/object/getByPresignedURL.go b/example/object/getByPresignedURL.go index 61cf05b..d8bae12 100644 --- a/example/object/getByPresignedURL.go +++ b/example/object/getByPresignedURL.go @@ -14,6 +14,25 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func main() { ak := os.Getenv("COS_SECRETID") sk := os.Getenv("COS_SECRETKEY") @@ -38,22 +57,17 @@ func main() { // Normal header way to get object resp, err := c.Object.Get(ctx, name, nil) - if err != nil { - panic(err) - } + log_status(err) bs, _ := ioutil.ReadAll(resp.Body) resp.Body.Close() // Get presigned presignedURL, err := c.Object.GetPresignedURL(ctx, http.MethodGet, name, ak, sk, time.Hour, nil) - if err != nil { - panic(err) - } + log_status(err) + // Get object by presinged url resp2, err := http.Get(presignedURL.String()) - if err != nil { - panic(err) - } + log_status(err) bs2, _ := ioutil.ReadAll(resp2.Body) resp2.Body.Close() fmt.Printf("result2 is : %s\n", string(bs2)) diff --git a/example/object/head.go b/example/object/head.go index 87a37a8..e96b54d 100644 --- a/example/object/head.go +++ b/example/object/head.go @@ -2,6 +2,7 @@ package main import ( "context" + "fmt" "net/url" "os" @@ -11,6 +12,25 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func main() { u, _ := url.Parse("https://test-1253846586.cos.ap-guangzhou.myqcloud.com") b := &cos.BaseURL{BucketURL: u} @@ -29,7 +49,5 @@ func main() { name := "test/hello.txt" _, err := c.Object.Head(context.Background(), name, nil) - if err != nil { - panic(err) - } + log_status(err) } diff --git a/example/object/initiateMultipartUpload.go b/example/object/initiateMultipartUpload.go index a77501b..0eec7c6 100644 --- a/example/object/initiateMultipartUpload.go +++ b/example/object/initiateMultipartUpload.go @@ -13,6 +13,25 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func main() { u, _ := url.Parse("https://test-1253846586.cos.ap-guangzhou.myqcloud.com") b := &cos.BaseURL{BucketURL: u} @@ -31,8 +50,6 @@ func main() { name := "test_multipart" + time.Now().Format(time.RFC3339) v, _, err := c.Object.InitiateMultipartUpload(context.Background(), name, nil) - if err != nil { - panic(err) - } + log_status(err) fmt.Printf("%s\n", v.UploadID) } diff --git a/example/object/listParts.go b/example/object/listParts.go index ecf8674..43edd59 100644 --- a/example/object/listParts.go +++ b/example/object/listParts.go @@ -14,11 +14,28 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func initUpload(c *cos.Client, name string) *cos.InitiateMultipartUploadResult { v, _, err := c.Object.InitiateMultipartUpload(context.Background(), name, nil) - if err != nil { - panic(err) - } + log_status(err) fmt.Printf("%#v\n", v) return v } @@ -27,7 +44,7 @@ func uploadPart(c *cos.Client, name string, uploadID string, blockSize, n int) s b := make([]byte, blockSize) if _, err := rand.Read(b); err != nil { - panic(err) + log_status(err) } s := fmt.Sprintf("%X", b) f := strings.NewReader(s) @@ -35,9 +52,7 @@ func uploadPart(c *cos.Client, name string, uploadID string, blockSize, n int) s resp, err := c.Object.UploadPart( context.Background(), name, uploadID, n, f, nil, ) - if err != nil { - panic(err) - } + log_status(err) fmt.Printf("%s\n", resp.Status) return resp.Header.Get("Etag") } @@ -73,7 +88,7 @@ func main() { // } v, _, err := c.Object.ListParts(ctx, name, uploadID, nil) if err != nil { - panic(err) + log_status(err) return } for _, p := range v.Parts { diff --git a/example/object/options.go b/example/object/options.go index 1e770de..7df27a7 100644 --- a/example/object/options.go +++ b/example/object/options.go @@ -2,6 +2,7 @@ package main import ( "context" + "fmt" "net/url" "os" @@ -11,6 +12,25 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func main() { u, _ := url.Parse("https://test-1253846586.cos.ap-guangzhou.myqcloud.com") b := &cos.BaseURL{BucketURL: u} @@ -29,11 +49,9 @@ func main() { name := "test/hello.txt" opt := &cos.ObjectOptionsOptions{ - Origin: "http://www.qq.com", + Origin: "http://www.qq.com", AccessControlRequestMethod: "PUT", } _, err := c.Object.Options(context.Background(), name, opt) - if err != nil { - panic(err) - } + log_status(err) } diff --git a/example/object/presigned_url_with_token.go b/example/object/presigned_url_with_token.go new file mode 100644 index 0000000..200a815 --- /dev/null +++ b/example/object/presigned_url_with_token.go @@ -0,0 +1,44 @@ +package main + +import ( + "context" + "fmt" + "net/http" + "net/url" + "os" + "time" + + "github.com/tencentyun/cos-go-sdk-v5" +) + +type URLToken struct { + SessionToken string `url:"x-cos-security-token,omitempty" header:"-"` +} + +func main() { + // 替换成您的临时密钥 + tak := os.Getenv("COS_SECRETID") + tsk := os.Getenv("COS_SECRETKEY") + token := &URLToken{ + SessionToken: "", + } + u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") + b := &cos.BaseURL{BucketURL: u} + c := cos.NewClient(b, &http.Client{}) + + name := "exampleobject" + ctx := context.Background() + + // Get presigned + presignedURL, err := c.Object.GetPresignedURL(ctx, http.MethodGet, name, tak, tsk, time.Hour, token) + if err != nil { + fmt.Printf("Error: %v\n", err) + return + } + // Get object by presinged url + _, err = http.Get(presignedURL.String()) + if err != nil { + fmt.Printf("Error: %v\n", err) + } + fmt.Println(presignedURL.String()) +} diff --git a/example/object/put.go b/example/object/put.go index 8fd5839..a9f97f3 100644 --- a/example/object/put.go +++ b/example/object/put.go @@ -2,6 +2,7 @@ package main import ( "context" + "fmt" "net/url" "os" "strings" @@ -12,8 +13,27 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func main() { - u, _ := url.Parse("https://test-1253846586.cos.ap-guangzhou.myqcloud.com") + u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") b := &cos.BaseURL{BucketURL: u} c := cos.NewClient(b, &http.Client{ Transport: &cos.AuthorizationTransport{ @@ -34,9 +54,7 @@ func main() { f := strings.NewReader("test") _, err := c.Object.Put(context.Background(), name, f, nil) - if err != nil { - panic(err) - } + log_status(err) // Case2 put object with the options name = "test/put_option.go" @@ -51,14 +69,9 @@ func main() { }, } _, err = c.Object.Put(context.Background(), name, f, opt) - if err != nil { - panic(err) - } + log_status(err) // Case3 put object by local file path _, err = c.Object.PutFromFile(context.Background(), name, "./test", nil) - if err != nil { - panic(err) - } - + log_status(err) } diff --git a/example/object/putACL.go b/example/object/putACL.go index e30d4ab..82c7ef4 100644 --- a/example/object/putACL.go +++ b/example/object/putACL.go @@ -2,6 +2,7 @@ package main import ( "context" + "fmt" "net/url" "os" @@ -11,6 +12,25 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func main() { u, _ := url.Parse("https://test-1253846586.cos.ap-guangzhou.myqcloud.com") b := &cos.BaseURL{BucketURL: u} @@ -34,9 +54,7 @@ func main() { } name := "test/hello.txt" _, err := c.Object.PutACL(context.Background(), name, opt) - if err != nil { - panic(err) - } + log_status(err) // with body opt = &cos.ObjectPutACLOptions{ @@ -58,7 +76,5 @@ func main() { } _, err = c.Object.PutACL(context.Background(), name, opt) - if err != nil { - panic(err) - } + log_status(err) } diff --git a/example/object/restore.go b/example/object/restore.go index 984513c..0c58467 100644 --- a/example/object/restore.go +++ b/example/object/restore.go @@ -2,6 +2,7 @@ package main import ( "context" + "fmt" "net/http" "net/url" "os" @@ -10,6 +11,25 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func main() { u, _ := url.Parse("https://test-1253846586.cos.ap-guangzhou.myqcloud.com") b := &cos.BaseURL{BucketURL: u} @@ -35,7 +55,5 @@ func main() { } name := "archivetest" _, err := c.Object.PostRestore(context.Background(), name, opt) - if err != nil { - panic(err) - } + log_status(err) } diff --git a/example/object/sse_c.go b/example/object/sse_c.go new file mode 100644 index 0000000..95499db --- /dev/null +++ b/example/object/sse_c.go @@ -0,0 +1,81 @@ +package main + +import ( + "context" + "errors" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "os" + "strings" + + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/tencentyun/cos-go-sdk-v5/debug" +) + +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + +func main() { + u, _ := url.Parse("https://testcd-1259654469.cos.ap-chengdu.myqcloud.com") + b := &cos.BaseURL{BucketURL: u} + c := cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: os.Getenv("COS_SECRETID"), + SecretKey: os.Getenv("COS_SECRETKEY"), + Transport: &debug.DebugRequestTransport{ + RequestHeader: true, + // Notice when put a large file and set need the request body, might happend out of memory error. + RequestBody: false, + ResponseHeader: true, + ResponseBody: true, + }, + }, + }) + opt := &cos.ObjectPutOptions{ + ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{ + ContentType: "text/html", + XCosSSECustomerAglo: "AES256", + XCosSSECustomerKey: "MDEyMzQ1Njc4OUFCQ0RFRjAxMjM0NTY3ODlBQkNERUY=", + XCosSSECustomerKeyMD5: "U5L61r7jcwdNvT7frmUG8g==", + }, + ACLHeaderOptions: &cos.ACLHeaderOptions{}, + } + name := "PutFromGoWithSSE-C" + content := "Put Object From Go With SSE-C" + f := strings.NewReader(content) + _, err := c.Object.Put(context.Background(), name, f, opt) + log_status(err) + + getopt := &cos.ObjectGetOptions{ + XCosSSECustomerAglo: "AES256", + XCosSSECustomerKey: "MDEyMzQ1Njc4OUFCQ0RFRjAxMjM0NTY3ODlBQkNERUY=", + XCosSSECustomerKeyMD5: "U5L61r7jcwdNvT7frmUG8g==", + } + var resp *cos.Response + resp, err = c.Object.Get(context.Background(), name, getopt) + log_status(err) + + bodyBytes, _ := ioutil.ReadAll(resp.Body) + bodyContent := string(bodyBytes) + if bodyContent != content { + log_status(errors.New("Content inconsistency")) + } +} diff --git a/example/object/sse_cos.go b/example/object/sse_cos.go new file mode 100644 index 0000000..e558d68 --- /dev/null +++ b/example/object/sse_cos.go @@ -0,0 +1,75 @@ +package main + +import ( + "context" + "errors" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "os" + "strings" + + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/tencentyun/cos-go-sdk-v5/debug" +) + +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + +func main() { + u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") + b := &cos.BaseURL{BucketURL: u} + c := cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: os.Getenv("COS_SECRETID"), + SecretKey: os.Getenv("COS_SECRETKEY"), + Transport: &debug.DebugRequestTransport{ + RequestHeader: true, + // Notice when put a large file and set need the request body, might happend out of memory error. + RequestBody: false, + ResponseHeader: true, + ResponseBody: true, + }, + }, + }) + opt := &cos.ObjectPutOptions{ + ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{ + ContentType: "text/html", + XCosServerSideEncryption: "AES256", + }, + ACLHeaderOptions: &cos.ACLHeaderOptions{}, + } + name := "PutFromGoWithSSE-COS" + content := "Put Object From Go With SSE-COS" + f := strings.NewReader(content) + _, err := c.Object.Put(context.Background(), name, f, opt) + log_status(err) + + getopt := &cos.ObjectGetOptions{} + var resp *cos.Response + resp, err = c.Object.Get(context.Background(), name, getopt) + log_status(err) + + bodyBytes, _ := ioutil.ReadAll(resp.Body) + bodyContent := string(bodyBytes) + if bodyContent != content { + log_status(errors.New("Content inconsistency")) + } +} diff --git a/example/object/upload.go b/example/object/upload.go index 4f055d2..7894fda 100644 --- a/example/object/upload.go +++ b/example/object/upload.go @@ -12,6 +12,25 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func main() { u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") b := &cos.BaseURL{BucketURL: u} @@ -33,8 +52,6 @@ func main() { v, _, err := c.Object.Upload( context.Background(), "gomulput1G", "./test1G", nil, ) - if err != nil { - panic(err) - } + log_status(err) fmt.Println(v) } diff --git a/example/object/uploadFile.go b/example/object/uploadFile.go index ec4a73a..c2d3a12 100644 --- a/example/object/uploadFile.go +++ b/example/object/uploadFile.go @@ -13,6 +13,25 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func main() { u, _ := url.Parse("https://test-1253846586.cos.ap-guangzhou.myqcloud.com") b := &cos.BaseURL{BucketURL: u} @@ -32,11 +51,13 @@ func main() { name := "test/uploadFile.go" f, err := os.Open(os.Args[0]) if err != nil { - panic(err) + log_status(err) + return } s, err := f.Stat() if err != nil { - panic(err) + log_status(err) + return } fmt.Println(s.Size()) opt := &cos.ObjectPutOptions{ @@ -47,7 +68,5 @@ func main() { //opt.ContentLength = int(s.Size()) _, err = c.Object.Put(context.Background(), name, f, opt) - if err != nil { - panic(err) - } + log_status(err) } diff --git a/example/object/uploadPart.go b/example/object/uploadPart.go index f4a837f..945bfe5 100644 --- a/example/object/uploadPart.go +++ b/example/object/uploadPart.go @@ -14,11 +14,28 @@ import ( "github.com/tencentyun/cos-go-sdk-v5/debug" ) +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + func initUpload(c *cos.Client, name string) *cos.InitiateMultipartUploadResult { v, _, err := c.Object.InitiateMultipartUpload(context.Background(), name, nil) - if err != nil { - panic(err) - } + log_status(err) fmt.Printf("%#v\n", v) return v } @@ -47,7 +64,5 @@ func main() { _, err := c.Object.UploadPart( context.Background(), name, uploadID, 1, f, nil, ) - if err != nil { - panic(err) - } + log_status(err) } From bcc1ed2b8317cea8a32ab193ffad0a6482d63560 Mon Sep 17 00:00:00 2001 From: jojoliang Date: Tue, 19 May 2020 21:08:06 +0800 Subject: [PATCH 13/15] update version --- cos.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cos.go b/cos.go index d9a67b8..b20ee46 100644 --- a/cos.go +++ b/cos.go @@ -21,7 +21,7 @@ import ( const ( // Version current go sdk version - Version = "0.7.5" + Version = "0.7.6" userAgent = "cos-go-sdk-v5/" + Version contentTypeXML = "application/xml" defaultServiceBaseURL = "http://service.cos.myqcloud.com" From a0ab0eb0f80c02a2ce18d868197a523d5b7d0a8a Mon Sep 17 00:00:00 2001 From: jojoliang Date: Thu, 4 Jun 2020 14:59:34 +0800 Subject: [PATCH 14/15] add object tagging && bucket origin && add stsv3 demo --- bucket_origin.go | 90 +++++++++++++++++++++++++++++++++++ cos.go | 4 +- example/bucket/getObjectVersion.go | 12 ++--- example/bucket/origin.go | 92 ++++++++++++++++++++++++++++++++++++ example/object/tagging.go | 75 +++++++++++++++++++++++++++++ example/sts/sts_v3.go | 96 ++++++++++++++++++++++++++++++++++++++ object.go | 73 +++++++++++++++++++++++++++-- 7 files changed, 432 insertions(+), 10 deletions(-) create mode 100644 bucket_origin.go create mode 100644 example/bucket/origin.go create mode 100644 example/object/tagging.go create mode 100644 example/sts/sts_v3.go diff --git a/bucket_origin.go b/bucket_origin.go new file mode 100644 index 0000000..805440e --- /dev/null +++ b/bucket_origin.go @@ -0,0 +1,90 @@ +package cos + +import ( + "context" + "encoding/xml" + "net/http" +) + +type BucketPutOriginOptions struct { + XMLName xml.Name `xml:"OriginConfiguration"` + Rule []BucketOriginRule `xml:"OriginRule"` +} + +type BucketOriginRule struct { + OriginType string `xml:"OriginType"` + OriginCondition *BucketOriginCondition `xml:"OriginCondition"` + OriginParameter *BucketOriginParameter `xml:"OriginParameter"` + OriginInfo *BucketOriginInfo `xml:"OriginInfo"` +} + +type BucketOriginCondition struct { + HTTPStatusCode string `xml:"HTTPStatusCode,omitempty"` + Prefix string `xml:"Prefix,omitempty"` +} + +type BucketOriginParameter struct { + Protocol string `xml:"Protocol,omitempty"` + FollowQueryString bool `xml:"FollowQueryString,omitempty"` + HttpHeader *BucketOriginHttpHeader `xml:"HttpHeader,omitempty"` + FollowRedirection bool `xml:"FollowRedirection,omitempty"` + HttpRedirectCode string `xml:"HttpRedirectCode,omitempty"` + CopyOriginData bool `xml:"CopyOriginData,omitempty"` +} + +type BucketOriginHttpHeader struct { + // 目前还不支持 FollowAllHeaders + // FollowAllHeaders bool `xml:"FollowAllHeaders,omitempty"` + NewHttpHeaders []OriginHttpHeader `xml:"NewHttpHeaders>Header,omitempty"` + FollowHttpHeaders []OriginHttpHeader `xml:"FollowHttpHeaders>Header,omitempty"` +} + +type OriginHttpHeader struct { + Key string `xml:"Key,omitempty"` + Value string `xml:"Value,omitempty"` +} + +type BucketOriginInfo struct { + HostInfo string `xml:"HostInfo>HostName,omitempty"` + FileInfo *BucketOriginFileInfo `xml:"FileInfo,omitempty"` +} +type BucketOriginFileInfo struct { + PrefixDirective bool `xml:"PrefixDirective,omitempty"` + Prefix string `xml:"Prefix,omitempty"` + Suffix string `xml:"Suffix,omitempty"` +} + +type BucketGetOriginResult BucketPutOriginOptions + +func (s *BucketService) PutOrigin(ctx context.Context, opt *BucketPutOriginOptions) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?origin", + method: http.MethodPut, + body: opt, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +func (s *BucketService) GetOrigin(ctx context.Context) (*BucketGetOriginResult, *Response, error) { + var res BucketGetOriginResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?origin", + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +func (s *BucketService) DeleteOrigin(ctx context.Context) (*Response, error) { + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: "/?origin", + method: http.MethodDelete, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} diff --git a/cos.go b/cos.go index b20ee46..cf5f02b 100644 --- a/cos.go +++ b/cos.go @@ -21,7 +21,7 @@ import ( const ( // Version current go sdk version - Version = "0.7.6" + Version = "0.7.7" userAgent = "cos-go-sdk-v5/" + Version contentTypeXML = "application/xml" defaultServiceBaseURL = "http://service.cos.myqcloud.com" @@ -329,6 +329,8 @@ type ACLHeaderOptions struct { XCosGrantRead string `header:"x-cos-grant-read,omitempty" url:"-" xml:"-"` XCosGrantWrite string `header:"x-cos-grant-write,omitempty" url:"-" xml:"-"` 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:"-"` } // ACLGrantee is the param of ACLGrant diff --git a/example/bucket/getObjectVersion.go b/example/bucket/getObjectVersion.go index a9aca0a..bcb7285 100644 --- a/example/bucket/getObjectVersion.go +++ b/example/bucket/getObjectVersion.go @@ -1,7 +1,7 @@ package main import ( - "context" + "context" "fmt" "os" @@ -19,7 +19,7 @@ func log_status(err error) { } if cos.IsNotFoundError(err) { // WARN - fmt.Println("WARN: Resource is not existed") + fmt.Println("WARN: Resource is not existed") } else if e, ok := cos.IsCOSError(err); ok { fmt.Printf("ERROR: Code: %v\n", e.Code) fmt.Printf("ERROR: Message: %v\n", e.Message) @@ -50,12 +50,12 @@ func main() { }, }) - opt := &cos.BucketGetObjectVersionsOptions { - Delimiter: "/", - MaxKeys: 1, + opt := &cos.BucketGetObjectVersionsOptions{ + Delimiter: "/", + MaxKeys: 1, } v, _, err := c.Bucket.GetObjectVersions(context.Background(), opt) - log_status(err) + log_status(err) for _, c := range v.Version { fmt.Printf("%v, %v, %v\n", c.Key, c.Size, c.IsLatest) diff --git a/example/bucket/origin.go b/example/bucket/origin.go new file mode 100644 index 0000000..aaa4184 --- /dev/null +++ b/example/bucket/origin.go @@ -0,0 +1,92 @@ +package main + +import ( + "context" + "fmt" + "net/http" + "net/url" + "os" + + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/tencentyun/cos-go-sdk-v5/debug" +) + +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("Code: %v\n", e.Code) + fmt.Printf("Message: %v\n", e.Message) + fmt.Printf("Resource: %v\n", e.Resource) + fmt.Printf("RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Println(err) + // ERROR + } +} + +func main() { + u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") + b := &cos.BaseURL{ + BucketURL: u, + } + c := cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: os.Getenv("COS_SECRETID"), + SecretKey: os.Getenv("COS_SECRETKEY"), + Transport: &debug.DebugRequestTransport{ + RequestHeader: true, + RequestBody: true, + ResponseHeader: true, + ResponseBody: true, + }, + }, + }) + + opt := &cos.BucketPutOriginOptions{ + Rule: []cos.BucketOriginRule{ + { + OriginType: "Proxy", + OriginCondition: &cos.BucketOriginCondition{ + HTTPStatusCode: "404", + Prefix: "", + }, + OriginParameter: &cos.BucketOriginParameter{ + Protocol: "FOLLOW", + FollowQueryString: true, + HttpHeader: &cos.BucketOriginHttpHeader{ + NewHttpHeaders: []cos.OriginHttpHeader{ + { + Key: "x-cos-ContentType", + Value: "csv", + }, + }, + FollowHttpHeaders: []cos.OriginHttpHeader{ + { + Key: "Content-Type", + }, + }, + }, + FollowRedirection: true, + }, + OriginInfo: &cos.BucketOriginInfo{ + HostInfo: "examplebucket-1250000000.cos.ap-shanghai.myqcloud.com", + }, + }, + }, + } + + _, err := c.Bucket.PutOrigin(context.Background(), opt) + log_status(err) + res, _, err := c.Bucket.GetOrigin(context.Background()) + log_status(err) + fmt.Printf("%+v\n", res) + fmt.Printf("%+v\n", res.Rule) + _, err = c.Bucket.DeleteOrigin(context.Background()) + log_status(err) +} diff --git a/example/object/tagging.go b/example/object/tagging.go new file mode 100644 index 0000000..ab4a150 --- /dev/null +++ b/example/object/tagging.go @@ -0,0 +1,75 @@ +package main + +import ( + "context" + "fmt" + "net/url" + "os" + + "net/http" + + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/tencentyun/cos-go-sdk-v5/debug" +) + +func log_status(err error) { + if err == nil { + return + } + if cos.IsNotFoundError(err) { + // WARN + fmt.Println("WARN: Resource is not existed") + } else if e, ok := cos.IsCOSError(err); ok { + fmt.Printf("ERROR: Code: %v\n", e.Code) + fmt.Printf("ERROR: Message: %v\n", e.Message) + fmt.Printf("ERROR: Resource: %v\n", e.Resource) + fmt.Printf("ERROR: RequestId: %v\n", e.RequestID) + // ERROR + } else { + fmt.Printf("ERROR: %v\n", err) + // ERROR + } +} + +func main() { + u, _ := url.Parse("https://test-1259654469.cos.ap-guangzhou.myqcloud.com") + b := &cos.BaseURL{ + BucketURL: u, + } + c := cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + SecretID: os.Getenv("COS_SECRETID"), + SecretKey: os.Getenv("COS_SECRETKEY"), + Transport: &debug.DebugRequestTransport{ + RequestHeader: true, + RequestBody: true, + ResponseHeader: true, + ResponseBody: true, + }, + }, + }) + name := "test" + + opt := &cos.ObjectPutTaggingOptions{ + TagSet: []cos.ObjectTaggingTag{ + { + Key: "test_k2", + Value: "test_v2", + }, + { + Key: "test_k3", + Value: "test_v3", + }, + }, + } + + _, err := c.Object.PutTagging(context.Background(), name, opt) + log_status(err) + + res, _, err := c.Object.GetTagging(context.Background(), name) + log_status(err) + fmt.Printf("%v\n", res.TagSet) + + _, err = c.Object.DeleteTagging(context.Background(), name) + log_status(err) +} diff --git a/example/sts/sts_v3.go b/example/sts/sts_v3.go new file mode 100644 index 0000000..e1f5508 --- /dev/null +++ b/example/sts/sts_v3.go @@ -0,0 +1,96 @@ +package main + +import ( + "context" + "fmt" + "github.com/tencentyun/cos-go-sdk-v5" + "github.com/tencentyun/cos-go-sdk-v5/debug" + "github.com/tencentyun/qcloud-cos-sts-sdk/go" + "net/http" + "net/url" + "os" + "strings" + "time" +) + +func main() { + appid := "1259654469" + bucket := "test-1259654469" + c := sts.NewClient( + os.Getenv("COS_SECRETID"), + os.Getenv("COS_SECRETKEY"), + nil, + ) + opt := &sts.CredentialOptions{ + DurationSeconds: int64(time.Hour.Seconds()), + Region: "ap-guangzhou", + Policy: &sts.CredentialPolicy{ + Statement: []sts.CredentialPolicyStatement{ + { + Action: []string{ + "name/cos:PostObject", + "name/cos:PutObject", + "name/cos:GetObject", + }, + Effect: "allow", + Resource: []string{ + //这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的具体路径,例子: a.jpg 或者 a/* 或者 * (使用通配符*存在重大安全风险, 请谨慎评估使用) + "qcs::cos:ap-guangzhou:uid/" + appid + ":" + bucket + "/exampleobject", + }, + }, + }, + }, + } + res, err := c.GetCredential(opt) + if err != nil { + panic(err) + } + fmt.Printf("%+v\n", res.Credentials) + + //获取临时ak、sk、token + tAk := res.Credentials.TmpSecretID + tSk := res.Credentials.TmpSecretKey + token := res.Credentials.SessionToken + + u, _ := url.Parse("https://" + bucket + ".cos.ap-guangzhou.myqcloud.com") + b := &cos.BaseURL{BucketURL: u} + client := cos.NewClient(b, &http.Client{ + Transport: &cos.AuthorizationTransport{ + // 使用临时密钥 + SecretID: tAk, + SecretKey: tSk, + SessionToken: token, + Transport: &debug.DebugRequestTransport{ + RequestHeader: true, + RequestBody: true, + ResponseHeader: true, + ResponseBody: true, + }, + }, + }) + + name := "exampleobject" + f := strings.NewReader("test") + + _, err = client.Object.Put(context.Background(), name, f, nil) + if err != nil { + panic(err) + } + + name = "exampleobject" + f = strings.NewReader("test xxx") + optc := &cos.ObjectPutOptions{ + ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{ + ContentType: "text/html", + }, + ACLHeaderOptions: &cos.ACLHeaderOptions{ + //XCosACL: "public-read", + XCosACL: "private", + }, + } + _, err = client.Object.Put(context.Background(), name, f, optc) + if err != nil { + panic(err) + } + +} diff --git a/object.go b/object.go index 255c0d1..3c35eca 100644 --- a/object.go +++ b/object.go @@ -280,6 +280,7 @@ type ObjectDeleteOptions struct { //兼容其他自定义头部 XOptionHeader *http.Header `header:"-,omitempty" url:"-" xml:"-"` } + // Delete Object请求可以将一个文件(Object)删除。 // // https://www.qcloud.com/document/product/436/7743 @@ -294,9 +295,9 @@ func (s *ObjectService) Delete(ctx context.Context, name string, opt ...*ObjectD } sendOpt := sendOptions{ - baseURL: s.client.BaseURL.BucketURL, - uri: "/" + encodeURIComponent(name), - method: http.MethodDelete, + baseURL: s.client.BaseURL.BucketURL, + uri: "/" + encodeURIComponent(name), + method: http.MethodDelete, optHeader: optHeader, } resp, err := s.client.send(ctx, &sendOpt) @@ -675,3 +676,69 @@ func (s *ObjectService) Upload(ctx context.Context, name string, filepath string return v, resp, err } + +type ObjectPutTaggingOptions struct { + XMLName xml.Name `xml:"Tagging"` + TagSet []ObjectTaggingTag `xml:"TagSet>Tag,omitempty"` +} +type ObjectTaggingTag BucketTaggingTag +type ObjectGetTaggingResult ObjectPutTaggingOptions + +func (s *ObjectService) PutTagging(ctx context.Context, name string, opt *ObjectPutTaggingOptions, id ...string) (*Response, error) { + var u string + if len(id) == 1 { + u = fmt.Sprintf("/%s?tagging&versionId=%s", encodeURIComponent(name), id[0]) + } else if len(id) == 0 { + u = fmt.Sprintf("/%s?tagging", encodeURIComponent(name)) + } else { + return nil, errors.New("wrong params") + } + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodPut, + body: opt, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} + +func (s *ObjectService) GetTagging(ctx context.Context, name string, id ...string) (*ObjectGetTaggingResult, *Response, error) { + var u string + if len(id) == 1 { + u = fmt.Sprintf("/%s?tagging&versionId=%s", encodeURIComponent(name), id[0]) + } else if len(id) == 0 { + u = fmt.Sprintf("/%s?tagging", encodeURIComponent(name)) + } else { + return nil, nil, errors.New("wrong params") + } + + var res ObjectGetTaggingResult + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodGet, + result: &res, + } + resp, err := s.client.send(ctx, sendOpt) + return &res, resp, err +} + +func (s *ObjectService) DeleteTagging(ctx context.Context, name string, id ...string) (*Response, error) { + var u string + if len(id) == 1 { + u = fmt.Sprintf("/%s?tagging&versionId=%s", encodeURIComponent(name), id[0]) + } else if len(id) == 0 { + u = fmt.Sprintf("/%s?tagging", encodeURIComponent(name)) + } else { + return nil, errors.New("wrong params") + } + + sendOpt := &sendOptions{ + baseURL: s.client.BaseURL.BucketURL, + uri: u, + method: http.MethodDelete, + } + resp, err := s.client.send(ctx, sendOpt) + return resp, err +} From f9f617878dad23f915ecea978f065aa70486843c Mon Sep 17 00:00:00 2001 From: jojoliang Date: Wed, 10 Jun 2020 19:16:45 +0800 Subject: [PATCH 15/15] add host to signature --- auth.go | 1 + 1 file changed, 1 insertion(+) diff --git a/auth.go b/auth.go index 6b0cc55..f591a6d 100644 --- a/auth.go +++ b/auth.go @@ -125,6 +125,7 @@ func newAuthorization(secretID, secretKey string, req *http.Request, authTime *A keyTime := authTime.keyString() signKey := calSignKey(secretKey, keyTime) + req.Header.Set("Host", req.Host) formatHeaders := *new(string) signedHeaderList := *new([]string) formatHeaders, signedHeaderList = genFormatHeaders(req.Header)