OSDN Git Service

Create ossClient.go (#574)
[bytom/vapor.git] / vendor / github.com / aliyun / aliyun-oss-go-sdk / oss / multipart.go
1 package oss
2
3 import (
4         "bytes"
5         "encoding/xml"
6         "io"
7         "net/http"
8         "net/url"
9         "os"
10         "sort"
11         "strconv"
12 )
13
14 // InitiateMultipartUpload initializes multipart upload
15 //
16 // objectKey    object name
17 // options    the object constricts for upload. The valid options are CacheControl, ContentDisposition, ContentEncoding, Expires,
18 //            ServerSideEncryption, Meta, check out the following link:
19 //            https://help.aliyun.com/document_detail/oss/api-reference/multipart-upload/InitiateMultipartUpload.html
20 //
21 // InitiateMultipartUploadResult    the return value of the InitiateMultipartUpload, which is used for calls later on such as UploadPartFromFile,UploadPartCopy.
22 // error    it's nil if the operation succeeds, otherwise it's an error object.
23 //
24 func (bucket Bucket) InitiateMultipartUpload(objectKey string, options ...Option) (InitiateMultipartUploadResult, error) {
25         var imur InitiateMultipartUploadResult
26         opts := AddContentType(options, objectKey)
27         params, _ := GetRawParams(options)
28         _, ok := params["sequential"]
29         if ok {
30                 // convert "" to nil
31                 params["sequential"] = nil
32         }
33         params["uploads"] = nil
34
35         resp, err := bucket.do("POST", objectKey, params, opts, nil, nil)
36         if err != nil {
37                 return imur, err
38         }
39         defer resp.Body.Close()
40
41         err = xmlUnmarshal(resp.Body, &imur)
42         return imur, err
43 }
44
45 // UploadPart uploads parts
46 //
47 // After initializing a Multipart Upload, the upload Id and object key could be used for uploading the parts.
48 // Each part has its part number (ranges from 1 to 10,000). And for each upload Id, the part number identifies the position of the part in the whole file.
49 // And thus with the same part number and upload Id, another part upload will overwrite the data.
50 // Except the last one, minimal part size is 100KB. There's no limit on the last part size.
51 //
52 // imur    the returned value of InitiateMultipartUpload.
53 // reader    io.Reader the reader for the part's data.
54 // size    the part size.
55 // partNumber    the part number (ranges from 1 to 10,000). Invalid part number will lead to InvalidArgument error.
56 //
57 // UploadPart    the return value of the upload part. It consists of PartNumber and ETag. It's valid when error is nil.
58 // error    it's nil if the operation succeeds, otherwise it's an error object.
59 //
60 func (bucket Bucket) UploadPart(imur InitiateMultipartUploadResult, reader io.Reader,
61         partSize int64, partNumber int, options ...Option) (UploadPart, error) {
62         request := &UploadPartRequest{
63                 InitResult: &imur,
64                 Reader:     reader,
65                 PartSize:   partSize,
66                 PartNumber: partNumber,
67         }
68
69         result, err := bucket.DoUploadPart(request, options)
70
71         return result.Part, err
72 }
73
74 // UploadPartFromFile uploads part from the file.
75 //
76 // imur    the return value of a successful InitiateMultipartUpload.
77 // filePath    the local file path to upload.
78 // startPosition    the start position in the local file.
79 // partSize    the part size.
80 // partNumber    the part number (from 1 to 10,000)
81 //
82 // UploadPart    the return value consists of PartNumber and ETag.
83 // error    it's nil if the operation succeeds, otherwise it's an error object.
84 //
85 func (bucket Bucket) UploadPartFromFile(imur InitiateMultipartUploadResult, filePath string,
86         startPosition, partSize int64, partNumber int, options ...Option) (UploadPart, error) {
87         var part = UploadPart{}
88         fd, err := os.Open(filePath)
89         if err != nil {
90                 return part, err
91         }
92         defer fd.Close()
93         fd.Seek(startPosition, os.SEEK_SET)
94
95         request := &UploadPartRequest{
96                 InitResult: &imur,
97                 Reader:     fd,
98                 PartSize:   partSize,
99                 PartNumber: partNumber,
100         }
101
102         result, err := bucket.DoUploadPart(request, options)
103
104         return result.Part, err
105 }
106
107 // DoUploadPart does the actual part upload.
108 //
109 // request    part upload request
110 //
111 // UploadPartResult    the result of uploading part.
112 // error    it's nil if the operation succeeds, otherwise it's an error object.
113 //
114 func (bucket Bucket) DoUploadPart(request *UploadPartRequest, options []Option) (*UploadPartResult, error) {
115         listener := GetProgressListener(options)
116         options = append(options, ContentLength(request.PartSize))
117         params := map[string]interface{}{}
118         params["partNumber"] = strconv.Itoa(request.PartNumber)
119         params["uploadId"] = request.InitResult.UploadID
120         resp, err := bucket.do("PUT", request.InitResult.Key, params, options,
121                 &io.LimitedReader{R: request.Reader, N: request.PartSize}, listener)
122         if err != nil {
123                 return &UploadPartResult{}, err
124         }
125         defer resp.Body.Close()
126
127         part := UploadPart{
128                 ETag:       resp.Headers.Get(HTTPHeaderEtag),
129                 PartNumber: request.PartNumber,
130         }
131
132         if bucket.GetConfig().IsEnableCRC {
133                 err = CheckCRC(resp, "DoUploadPart")
134                 if err != nil {
135                         return &UploadPartResult{part}, err
136                 }
137         }
138
139         return &UploadPartResult{part}, nil
140 }
141
142 // UploadPartCopy uploads part copy
143 //
144 // imur    the return value of InitiateMultipartUpload
145 // copySrc    source Object name
146 // startPosition    the part's start index in the source file
147 // partSize    the part size
148 // partNumber    the part number, ranges from 1 to 10,000. If it exceeds the range OSS returns InvalidArgument error.
149 // options    the constraints of source object for the copy. The copy happens only when these contraints are met. Otherwise it returns error.
150 //            CopySourceIfNoneMatch, CopySourceIfModifiedSince  CopySourceIfUnmodifiedSince, check out the following link for the detail
151 //            https://help.aliyun.com/document_detail/oss/api-reference/multipart-upload/UploadPartCopy.html
152 //
153 // UploadPart    the return value consists of PartNumber and ETag.
154 // error    it's nil if the operation succeeds, otherwise it's an error object.
155 //
156 func (bucket Bucket) UploadPartCopy(imur InitiateMultipartUploadResult, srcBucketName, srcObjectKey string,
157         startPosition, partSize int64, partNumber int, options ...Option) (UploadPart, error) {
158         var out UploadPartCopyResult
159         var part UploadPart
160         var opts []Option
161
162         //first find version id
163         versionIdKey := "versionId"
164         versionId, _ := FindOption(options, versionIdKey, nil)
165         if versionId == nil {
166                 opts = []Option{CopySource(srcBucketName, url.QueryEscape(srcObjectKey)),
167                         CopySourceRange(startPosition, partSize)}
168         } else {
169                 opts = []Option{CopySourceVersion(srcBucketName, url.QueryEscape(srcObjectKey), versionId.(string)),
170                         CopySourceRange(startPosition, partSize)}
171                 options = DeleteOption(options, versionIdKey)
172         }
173
174         opts = append(opts, options...)
175
176         params := map[string]interface{}{}
177         params["partNumber"] = strconv.Itoa(partNumber)
178         params["uploadId"] = imur.UploadID
179         resp, err := bucket.do("PUT", imur.Key, params, opts, nil, nil)
180         if err != nil {
181                 return part, err
182         }
183         defer resp.Body.Close()
184
185         err = xmlUnmarshal(resp.Body, &out)
186         if err != nil {
187                 return part, err
188         }
189         part.ETag = out.ETag
190         part.PartNumber = partNumber
191
192         return part, nil
193 }
194
195 // CompleteMultipartUpload completes the multipart upload.
196 //
197 // imur    the return value of InitiateMultipartUpload.
198 // parts    the array of return value of UploadPart/UploadPartFromFile/UploadPartCopy.
199 //
200 // CompleteMultipartUploadResponse    the return value when the call succeeds. Only valid when the error is nil.
201 // error    it's nil if the operation succeeds, otherwise it's an error object.
202 //
203 func (bucket Bucket) CompleteMultipartUpload(imur InitiateMultipartUploadResult,
204         parts []UploadPart, options ...Option) (CompleteMultipartUploadResult, error) {
205         var out CompleteMultipartUploadResult
206
207         sort.Sort(UploadParts(parts))
208         cxml := completeMultipartUploadXML{}
209         cxml.Part = parts
210         bs, err := xml.Marshal(cxml)
211         if err != nil {
212                 return out, err
213         }
214         buffer := new(bytes.Buffer)
215         buffer.Write(bs)
216
217         params := map[string]interface{}{}
218         params["uploadId"] = imur.UploadID
219         resp, err := bucket.do("POST", imur.Key, params, options, buffer, nil)
220         if err != nil {
221                 return out, err
222         }
223         defer resp.Body.Close()
224
225         err = xmlUnmarshal(resp.Body, &out)
226         return out, err
227 }
228
229 // AbortMultipartUpload aborts the multipart upload.
230 //
231 // imur    the return value of InitiateMultipartUpload.
232 //
233 // error    it's nil if the operation succeeds, otherwise it's an error object.
234 //
235 func (bucket Bucket) AbortMultipartUpload(imur InitiateMultipartUploadResult, options ...Option) error {
236         params := map[string]interface{}{}
237         params["uploadId"] = imur.UploadID
238         resp, err := bucket.do("DELETE", imur.Key, params, options, nil, nil)
239         if err != nil {
240                 return err
241         }
242         defer resp.Body.Close()
243         return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent})
244 }
245
246 // ListUploadedParts lists the uploaded parts.
247 //
248 // imur    the return value of InitiateMultipartUpload.
249 //
250 // ListUploadedPartsResponse    the return value if it succeeds, only valid when error is nil.
251 // error    it's nil if the operation succeeds, otherwise it's an error object.
252 //
253 func (bucket Bucket) ListUploadedParts(imur InitiateMultipartUploadResult, options ...Option) (ListUploadedPartsResult, error) {
254         var out ListUploadedPartsResult
255         options = append(options, EncodingType("url"))
256
257         params := map[string]interface{}{}
258         params, err := GetRawParams(options)
259         if err != nil {
260                 return out, err
261         }
262
263         params["uploadId"] = imur.UploadID
264         resp, err := bucket.do("GET", imur.Key, params, options, nil, nil)
265         if err != nil {
266                 return out, err
267         }
268         defer resp.Body.Close()
269
270         err = xmlUnmarshal(resp.Body, &out)
271         if err != nil {
272                 return out, err
273         }
274         err = decodeListUploadedPartsResult(&out)
275         return out, err
276 }
277
278 // ListMultipartUploads lists all ongoing multipart upload tasks
279 //
280 // options    listObject's filter. Prefix specifies the returned object's prefix; KeyMarker specifies the returned object's start point in lexicographic order;
281 //            MaxKeys specifies the max entries to return; Delimiter is the character for grouping object keys.
282 //
283 // ListMultipartUploadResponse    the return value if it succeeds, only valid when error is nil.
284 // error    it's nil if the operation succeeds, otherwise it's an error object.
285 //
286 func (bucket Bucket) ListMultipartUploads(options ...Option) (ListMultipartUploadResult, error) {
287         var out ListMultipartUploadResult
288
289         options = append(options, EncodingType("url"))
290         params, err := GetRawParams(options)
291         if err != nil {
292                 return out, err
293         }
294         params["uploads"] = nil
295
296         resp, err := bucket.do("GET", "", params, options, nil, nil)
297         if err != nil {
298                 return out, err
299         }
300         defer resp.Body.Close()
301
302         err = xmlUnmarshal(resp.Body, &out)
303         if err != nil {
304                 return out, err
305         }
306         err = decodeListMultipartUploadResult(&out)
307         return out, err
308 }