Browse Source

改进:增加对Upload part - copy API的支持

API文档:https://cloud.tencent.com/document/product/436/8287
tags/v0.7.8
Qiu Jian 5 years ago
parent
commit
d9e03a346e
  1. 68
      example/object/copyPart.go
  2. 49
      object_part.go
  3. 41
      object_part_test.go

68
example/object/copyPart.go

@ -0,0 +1,68 @@
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 initUpload(c *cos.Client, name string) *cos.InitiateMultipartUploadResult {
v, _, err := c.Object.InitiateMultipartUpload(context.Background(), name, nil)
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", v)
return v
}
func main() {
u, _ := url.Parse("https://test-1253846586.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,
},
},
})
sourceUrl := "test-1253846586.cos.ap-guangzhou.myqcloud.com/source/copy_multi_upload.go"
name := "test/test_multi_upload.go"
up := initUpload(c, name)
uploadID := up.UploadID
opt := &cos.ObjectCopyPartOptions{}
res, _, err := c.Object.CopyPart(
context.Background(), name, uploadID, 1, sourceUrl, opt)
if err != nil {
panic(err)
}
fmt.Println("ETag:", res.ETag)
completeOpt := &cos.CompleteMultipartUploadOptions{}
completeOpt.Parts = append(completeOpt.Parts, cos.Object{
PartNumber: 1,
ETag: res.ETag,
})
v, resp, err := c.Object.CompleteMultipartUpload(
context.Background(), name, uploadID, completeOpt,
)
if err != nil {
panic(err)
}
fmt.Printf("%s\n", resp.Status)
fmt.Printf("%#v\n", v)
fmt.Printf("%s\n", v.Location)
}

49
object_part.go

@ -193,3 +193,52 @@ func (s *ObjectService) AbortMultipartUpload(ctx context.Context, name, uploadID
resp, err := s.client.send(ctx, &sendOpt)
return resp, err
}
// ObjectCopyPartOptions is the options of copy-part
type ObjectCopyPartOptions struct {
XCosCopySource string `header:"x-cos-copy-source" url:"-"`
XCosCopySourceRange string `header:"x-cos-copy-source-range,omitempty" url:"-"`
XCosCopySourceIfModifiedSince string `header:"x-cos-copy-source-If-Modified-Since,omitempty" url:"-"`
XCosCopySourceIfUnmodifiedSince string `header:"x-cos-copy-source-If-Unmodified-Since,omitempty" url:"-"`
XCosCopySourceIfMatch string `header:"x-cos-copy-source-If-Match,omitempty" url:"-"`
XCosCopySourceIfNoneMatch string `header:"x-cos-copy-source-If-None-Match,omitempty" url:"-"`
}
// CopyPartResult is the result CopyPart
type CopyPartResult struct {
XMLName xml.Name `xml:"CopyPartResult"`
ETag string
LastModified string
}
// CopyPart 请求实现在初始化以后的分块上传,支持的块的数量为1到10000,块的大小为1 MB 到5 GB。
// 在每次请求Upload Part时候,需要携带partNumber和uploadID,partNumber为块的编号,支持乱序上传。
// ObjectCopyPartOptions的XCosCopySource为必填参数,格式为<bucket-name>-<app-id>.cos.<region-id>.myqcloud.com/<object-key>
// ObjectCopyPartOptions的XCosCopySourceRange指定源的Range,格式为bytes=<start>-<end>
//
// 当传入uploadID和partNumber都相同的时候,后传入的块将覆盖之前传入的块。当uploadID不存在时会返回404错误,NoSuchUpload.
//
// https://www.qcloud.com/document/product/436/7750
func (s *ObjectService) CopyPart(ctx context.Context, name, uploadID string, partNumber int, sourceURL string, opt *ObjectCopyPartOptions) (*CopyPartResult, *Response, error) {
if opt == nil {
opt = &ObjectCopyPartOptions{}
}
opt.XCosCopySource = sourceURL
u := fmt.Sprintf("/%s?partNumber=%d&uploadId=%s", encodeURIComponent(name), partNumber, uploadID)
var res CopyPartResult
sendOpt := sendOptions{
baseURL: s.client.BaseURL.BucketURL,
uri: u,
method: http.MethodPut,
optHeader: opt,
result: &res,
}
resp, err := s.client.send(ctx, &sendOpt)
// If the error occurs during the copy operation, the error response is embedded in the 200 OK response. This means that a 200 OK response can contain either a success or an error.
if err == nil && resp != nil && resp.StatusCode == 200 {
if res.ETag == "" {
return &res, resp, errors.New("response 200 OK, but body contains an error")
}
}
return &res, resp, err
}

41
object_part_test.go

@ -271,3 +271,44 @@ func TestObjectService_CompleteMultipartUpload(t *testing.T) {
t.Errorf("Object.CompleteMultipartUpload returned \n%#v, want \n%#v", ref, want)
}
}
func TestObjectService_CopyPart(t *testing.T) {
setup()
defer teardown()
sourceUrl := "test-1253846586.cos.ap-guangzhou.myqcloud.com/test.source"
opt := &ObjectCopyPartOptions{}
name := "test/hello.txt"
uploadID := "xxxxx"
partNumber := 1
mux.HandleFunc("/test/hello.txt", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodPut)
vs := values{
"uploadId": uploadID,
"partNumber": "1",
}
testFormValues(t, r, vs)
fmt.Fprint(w, `<CopyPartResult>
<ETag>&quot;ba82b57cfdfda8bd17ad4e5879ebb4fe&quot;</ETag>
<LastModified>2017-09-04T04:45:45</LastModified>
</CopyPartResult>`)
})
r, _, err := client.Object.CopyPart(context.Background(),
name, uploadID, partNumber, sourceUrl, opt)
if err != nil {
t.Fatalf("Object.CopyPart returned error: %v", err)
}
want := &CopyPartResult{
XMLName: xml.Name{Local: "CopyPartResult"},
ETag: `"ba82b57cfdfda8bd17ad4e5879ebb4fe"`,
LastModified: "2017-09-04T04:45:45",
}
if !reflect.DeepEqual(r, want) {
t.Errorf("Object.Copy returned %+v, want %+v", r, want)
}
}
Loading…
Cancel
Save