You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
6.7 KiB

  1. package cos
  2. import (
  3. "context"
  4. "encoding/xml"
  5. "fmt"
  6. "io"
  7. "net/http"
  8. )
  9. // InitiateMultipartUploadOptions ...
  10. type InitiateMultipartUploadOptions struct {
  11. *ACLHeaderOptions
  12. *ObjectPutHeaderOptions
  13. }
  14. // InitiateMultipartUploadResult ...
  15. type InitiateMultipartUploadResult struct {
  16. XMLName xml.Name `xml:"InitiateMultipartUploadResult"`
  17. Bucket string
  18. Key string
  19. UploadID string `xml:"UploadId"`
  20. }
  21. // InitiateMultipartUpload ...
  22. //
  23. // Initiate Multipart Upload请求实现初始化分片上传,成功执行此请求以后会返回Upload ID用于后续的Upload Part请求。
  24. //
  25. // https://www.qcloud.com/document/product/436/7746
  26. func (s *ObjectService) InitiateMultipartUpload(ctx context.Context, name string, opt *InitiateMultipartUploadOptions) (*InitiateMultipartUploadResult, *Response, error) {
  27. var res InitiateMultipartUploadResult
  28. sendOpt := sendOptions{
  29. baseURL: s.client.BaseURL.BucketURL,
  30. uri: "/" + encodeURIComponent(name) + "?uploads",
  31. method: http.MethodPost,
  32. optHeader: opt,
  33. result: &res,
  34. }
  35. resp, err := s.client.send(ctx, &sendOpt)
  36. return &res, resp, err
  37. }
  38. // ObjectUploadPartOptions ...
  39. type ObjectUploadPartOptions struct {
  40. Expect string `header:"Expect,omitempty" url:"-"`
  41. XCosContentSHA1 string `header:"x-cos-content-sha1" url:"-"`
  42. ContentLength int `header:"Content-Length,omitempty" url:"-"`
  43. }
  44. // UploadPart ...
  45. //
  46. // Upload Part请求实现在初始化以后的分块上传,支持的块的数量为1到10000,块的大小为1 MB 到5 GB。
  47. // 在每次请求Upload Part时候,需要携带partNumber和uploadID,partNumber为块的编号,支持乱序上传。
  48. //
  49. // 当传入uploadID和partNumber都相同的时候,后传入的块将覆盖之前传入的块。当uploadID不存在时会返回404错误,NoSuchUpload.
  50. //
  51. // 当 r 不是 bytes.Buffer/bytes.Reader/strings.Reader 时,必须指定 opt.ContentLength
  52. //
  53. // https://www.qcloud.com/document/product/436/7750
  54. func (s *ObjectService) UploadPart(ctx context.Context, name, uploadID string, partNumber int, r io.Reader, opt *ObjectUploadPartOptions) (*Response, error) {
  55. u := fmt.Sprintf("/%s?partNumber=%d&uploadId=%s", encodeURIComponent(name), partNumber, uploadID)
  56. sendOpt := sendOptions{
  57. baseURL: s.client.BaseURL.BucketURL,
  58. uri: u,
  59. method: http.MethodPut,
  60. optHeader: opt,
  61. body: r,
  62. }
  63. resp, err := s.client.send(ctx, &sendOpt)
  64. return resp, err
  65. }
  66. // ObjectListPartsOptions ...
  67. type ObjectListPartsOptions struct {
  68. EncodingType string `url:"Encoding-type,omitempty"`
  69. MaxParts int `url:"max-parts,omitempty"`
  70. PartNumberMarker int `url:"part-number-marker,omitempty"`
  71. }
  72. // ObjectListPartsResult ...
  73. type ObjectListPartsResult struct {
  74. XMLName xml.Name `xml:"ListPartsResult"`
  75. Bucket string
  76. EncodingType string `xml:"Encoding-type,omitempty"`
  77. Key string
  78. UploadID string `xml:"UploadId"`
  79. Initiator *Initiator `xml:"Initiator,omitempty"`
  80. Owner *Owner `xml:"Owner,omitempty"`
  81. StorageClass string
  82. PartNumberMarker int
  83. NextPartNumberMarker int `xml:"NextPartNumberMarker,omitempty"`
  84. MaxParts int
  85. IsTruncated bool
  86. Parts []Object `xml:"Part,omitempty"`
  87. }
  88. // ListParts ...
  89. //
  90. // List Parts用来查询特定分块上传中的已上传的块。
  91. //
  92. // https://www.qcloud.com/document/product/436/7747
  93. func (s *ObjectService) ListParts(ctx context.Context, name, uploadID string) (*ObjectListPartsResult, *Response, error) {
  94. u := fmt.Sprintf("/%s?uploadId=%s", encodeURIComponent(name), uploadID)
  95. var res ObjectListPartsResult
  96. sendOpt := sendOptions{
  97. baseURL: s.client.BaseURL.BucketURL,
  98. uri: u,
  99. method: http.MethodGet,
  100. result: &res,
  101. }
  102. resp, err := s.client.send(ctx, &sendOpt)
  103. return &res, resp, err
  104. }
  105. // CompleteMultipartUploadOptions ...
  106. type CompleteMultipartUploadOptions struct {
  107. XMLName xml.Name `xml:"CompleteMultipartUpload"`
  108. Parts []Object `xml:"Part"`
  109. }
  110. // CompleteMultipartUploadResult ...
  111. type CompleteMultipartUploadResult struct {
  112. XMLName xml.Name `xml:"CompleteMultipartUploadResult"`
  113. Location string
  114. Bucket string
  115. Key string
  116. ETag string
  117. }
  118. // CompleteMultipartUpload ...
  119. //
  120. // Complete Multipart Upload用来实现完成整个分块上传。当您已经使用Upload Parts上传所有块以后,你可以用该API完成上传。
  121. // 在使用该API时,您必须在Body中给出每一个块的PartNumber和ETag,用来校验块的准确性。
  122. //
  123. // 由于分块上传的合并需要数分钟时间,因而当合并分块开始的时候,COS就立即返回200的状态码,在合并的过程中,
  124. // COS会周期性的返回空格信息来保持连接活跃,直到合并完成,COS会在Body中返回合并后块的内容。
  125. //
  126. // 当上传块小于1 MB的时候,在调用该请求时,会返回400 EntityTooSmall;
  127. // 当上传块编号不连续的时候,在调用该请求时,会返回400 InvalidPart;
  128. // 当请求Body中的块信息没有按序号从小到大排列的时候,在调用该请求时,会返回400 InvalidPartOrder;
  129. // 当UploadId不存在的时候,在调用该请求时,会返回404 NoSuchUpload。
  130. //
  131. // 建议您及时完成分块上传或者舍弃分块上传,因为已上传但是未终止的块会占用存储空间进而产生存储费用。
  132. //
  133. // https://www.qcloud.com/document/product/436/7742
  134. func (s *ObjectService) CompleteMultipartUpload(ctx context.Context, name, uploadID string, opt *CompleteMultipartUploadOptions) (*CompleteMultipartUploadResult, *Response, error) {
  135. u := fmt.Sprintf("/%s?uploadId=%s", encodeURIComponent(name), uploadID)
  136. var res CompleteMultipartUploadResult
  137. sendOpt := sendOptions{
  138. baseURL: s.client.BaseURL.BucketURL,
  139. uri: u,
  140. method: http.MethodPost,
  141. body: opt,
  142. result: &res,
  143. }
  144. resp, err := s.client.send(ctx, &sendOpt)
  145. return &res, resp, err
  146. }
  147. // AbortMultipartUpload ...
  148. //
  149. // Abort Multipart Upload用来实现舍弃一个分块上传并删除已上传的块。当您调用Abort Multipart Upload时,
  150. // 如果有正在使用这个Upload Parts上传块的请求,则Upload Parts会返回失败。当该UploadID不存在时,会返回404 NoSuchUpload。
  151. //
  152. // 建议您及时完成分块上传或者舍弃分块上传,因为已上传但是未终止的块会占用存储空间进而产生存储费用。
  153. //
  154. // https://www.qcloud.com/document/product/436/7740
  155. func (s *ObjectService) AbortMultipartUpload(ctx context.Context, name, uploadID string) (*Response, error) {
  156. u := fmt.Sprintf("/%s?uploadId=%s", encodeURIComponent(name), uploadID)
  157. sendOpt := sendOptions{
  158. baseURL: s.client.BaseURL.BucketURL,
  159. uri: u,
  160. method: http.MethodDelete,
  161. }
  162. resp, err := s.client.send(ctx, &sendOpt)
  163. return resp, err
  164. }