OSDN Git Service

Create ossClient.go (#574)
[bytom/vapor.git] / vendor / github.com / aliyun / aliyun-oss-go-sdk / oss / utils.go
1 package oss
2
3 import (
4         "bytes"
5         "errors"
6         "fmt"
7         "hash/crc32"
8         "hash/crc64"
9         "io"
10         "net/http"
11         "os"
12         "os/exec"
13         "runtime"
14         "strconv"
15         "strings"
16         "time"
17 )
18
19 var sys_name string
20 var sys_release string
21 var sys_machine string
22
23 func init() {
24         sys_name = runtime.GOOS
25         sys_release = "-"
26         sys_machine = runtime.GOARCH
27
28         if out, err := exec.Command("uname", "-s").CombinedOutput(); err == nil {
29                 sys_name = string(bytes.TrimSpace(out))
30         }
31         if out, err := exec.Command("uname", "-r").CombinedOutput(); err == nil {
32                 sys_release = string(bytes.TrimSpace(out))
33         }
34         if out, err := exec.Command("uname", "-m").CombinedOutput(); err == nil {
35                 sys_machine = string(bytes.TrimSpace(out))
36         }
37 }
38
39 // userAgent gets user agent
40 // It has the SDK version information, OS information and GO version
41 func userAgent() string {
42         sys := getSysInfo()
43         return fmt.Sprintf("aliyun-sdk-go/%s (%s/%s/%s;%s)", Version, sys.name,
44                 sys.release, sys.machine, runtime.Version())
45 }
46
47 type sysInfo struct {
48         name    string // OS name such as windows/Linux
49         release string // OS version 2.6.32-220.23.2.ali1089.el5.x86_64 etc
50         machine string // CPU type amd64/x86_64
51 }
52
53 // getSysInfo gets system info
54 // gets the OS information and CPU type
55 func getSysInfo() sysInfo {
56         return sysInfo{name: sys_name, release: sys_release, machine: sys_machine}
57 }
58
59 // GetRangeConfig gets the download range from the options.
60 func GetRangeConfig(options []Option) (*UnpackedRange, error) {
61         rangeOpt, err := FindOption(options, HTTPHeaderRange, nil)
62         if err != nil || rangeOpt == nil {
63                 return nil, err
64         }
65         return ParseRange(rangeOpt.(string))
66 }
67
68 // UnpackedRange
69 type UnpackedRange struct {
70         HasStart bool  // Flag indicates if the start point is specified
71         HasEnd   bool  // Flag indicates if the end point is specified
72         Start    int64 // Start point
73         End      int64 // End point
74 }
75
76 // InvalidRangeError returns invalid range error
77 func InvalidRangeError(r string) error {
78         return fmt.Errorf("InvalidRange %s", r)
79 }
80
81 func GetRangeString(unpackRange UnpackedRange) string {
82         var strRange string
83         if unpackRange.HasStart && unpackRange.HasEnd {
84                 strRange = fmt.Sprintf("%d-%d", unpackRange.Start, unpackRange.End)
85         } else if unpackRange.HasStart {
86                 strRange = fmt.Sprintf("%d-", unpackRange.Start)
87         } else if unpackRange.HasEnd {
88                 strRange = fmt.Sprintf("-%d", unpackRange.End)
89         }
90         return strRange
91 }
92
93 // ParseRange parse various styles of range such as bytes=M-N
94 func ParseRange(normalizedRange string) (*UnpackedRange, error) {
95         var err error
96         hasStart := false
97         hasEnd := false
98         var start int64
99         var end int64
100
101         // Bytes==M-N or ranges=M-N
102         nrSlice := strings.Split(normalizedRange, "=")
103         if len(nrSlice) != 2 || nrSlice[0] != "bytes" {
104                 return nil, InvalidRangeError(normalizedRange)
105         }
106
107         // Bytes=M-N,X-Y
108         rSlice := strings.Split(nrSlice[1], ",")
109         rStr := rSlice[0]
110
111         if strings.HasSuffix(rStr, "-") { // M-
112                 startStr := rStr[:len(rStr)-1]
113                 start, err = strconv.ParseInt(startStr, 10, 64)
114                 if err != nil {
115                         return nil, InvalidRangeError(normalizedRange)
116                 }
117                 hasStart = true
118         } else if strings.HasPrefix(rStr, "-") { // -N
119                 len := rStr[1:]
120                 end, err = strconv.ParseInt(len, 10, 64)
121                 if err != nil {
122                         return nil, InvalidRangeError(normalizedRange)
123                 }
124                 if end == 0 { // -0
125                         return nil, InvalidRangeError(normalizedRange)
126                 }
127                 hasEnd = true
128         } else { // M-N
129                 valSlice := strings.Split(rStr, "-")
130                 if len(valSlice) != 2 {
131                         return nil, InvalidRangeError(normalizedRange)
132                 }
133                 start, err = strconv.ParseInt(valSlice[0], 10, 64)
134                 if err != nil {
135                         return nil, InvalidRangeError(normalizedRange)
136                 }
137                 hasStart = true
138                 end, err = strconv.ParseInt(valSlice[1], 10, 64)
139                 if err != nil {
140                         return nil, InvalidRangeError(normalizedRange)
141                 }
142                 hasEnd = true
143         }
144
145         return &UnpackedRange{hasStart, hasEnd, start, end}, nil
146 }
147
148 // AdjustRange returns adjusted range, adjust the range according to the length of the file
149 func AdjustRange(ur *UnpackedRange, size int64) (start, end int64) {
150         if ur == nil {
151                 return 0, size
152         }
153
154         if ur.HasStart && ur.HasEnd {
155                 start = ur.Start
156                 end = ur.End + 1
157                 if ur.Start < 0 || ur.Start >= size || ur.End > size || ur.Start > ur.End {
158                         start = 0
159                         end = size
160                 }
161         } else if ur.HasStart {
162                 start = ur.Start
163                 end = size
164                 if ur.Start < 0 || ur.Start >= size {
165                         start = 0
166                 }
167         } else if ur.HasEnd {
168                 start = size - ur.End
169                 end = size
170                 if ur.End < 0 || ur.End > size {
171                         start = 0
172                         end = size
173                 }
174         }
175         return
176 }
177
178 // GetNowSec returns Unix time, the number of seconds elapsed since January 1, 1970 UTC.
179 // gets the current time in Unix time, in seconds.
180 func GetNowSec() int64 {
181         return time.Now().Unix()
182 }
183
184 // GetNowNanoSec returns t as a Unix time, the number of nanoseconds elapsed
185 // since January 1, 1970 UTC. The result is undefined if the Unix time
186 // in nanoseconds cannot be represented by an int64. Note that this
187 // means the result of calling UnixNano on the zero Time is undefined.
188 // gets the current time in Unix time, in nanoseconds.
189 func GetNowNanoSec() int64 {
190         return time.Now().UnixNano()
191 }
192
193 // GetNowGMT gets the current time in GMT format.
194 func GetNowGMT() string {
195         return time.Now().UTC().Format(http.TimeFormat)
196 }
197
198 // FileChunk is the file chunk definition
199 type FileChunk struct {
200         Number int   // Chunk number
201         Offset int64 // Chunk offset
202         Size   int64 // Chunk size.
203 }
204
205 // SplitFileByPartNum splits big file into parts by the num of parts.
206 // Split the file with specified parts count, returns the split result when error is nil.
207 func SplitFileByPartNum(fileName string, chunkNum int) ([]FileChunk, error) {
208         if chunkNum <= 0 || chunkNum > 10000 {
209                 return nil, errors.New("chunkNum invalid")
210         }
211
212         file, err := os.Open(fileName)
213         if err != nil {
214                 return nil, err
215         }
216         defer file.Close()
217
218         stat, err := file.Stat()
219         if err != nil {
220                 return nil, err
221         }
222
223         if int64(chunkNum) > stat.Size() {
224                 return nil, errors.New("oss: chunkNum invalid")
225         }
226
227         var chunks []FileChunk
228         var chunk = FileChunk{}
229         var chunkN = (int64)(chunkNum)
230         for i := int64(0); i < chunkN; i++ {
231                 chunk.Number = int(i + 1)
232                 chunk.Offset = i * (stat.Size() / chunkN)
233                 if i == chunkN-1 {
234                         chunk.Size = stat.Size()/chunkN + stat.Size()%chunkN
235                 } else {
236                         chunk.Size = stat.Size() / chunkN
237                 }
238                 chunks = append(chunks, chunk)
239         }
240
241         return chunks, nil
242 }
243
244 // SplitFileByPartSize splits big file into parts by the size of parts.
245 // Splits the file by the part size. Returns the FileChunk when error is nil.
246 func SplitFileByPartSize(fileName string, chunkSize int64) ([]FileChunk, error) {
247         if chunkSize <= 0 {
248                 return nil, errors.New("chunkSize invalid")
249         }
250
251         file, err := os.Open(fileName)
252         if err != nil {
253                 return nil, err
254         }
255         defer file.Close()
256
257         stat, err := file.Stat()
258         if err != nil {
259                 return nil, err
260         }
261         var chunkN = stat.Size() / chunkSize
262         if chunkN >= 10000 {
263                 return nil, errors.New("Too many parts, please increase part size")
264         }
265
266         var chunks []FileChunk
267         var chunk = FileChunk{}
268         for i := int64(0); i < chunkN; i++ {
269                 chunk.Number = int(i + 1)
270                 chunk.Offset = i * chunkSize
271                 chunk.Size = chunkSize
272                 chunks = append(chunks, chunk)
273         }
274
275         if stat.Size()%chunkSize > 0 {
276                 chunk.Number = len(chunks) + 1
277                 chunk.Offset = int64(len(chunks)) * chunkSize
278                 chunk.Size = stat.Size() % chunkSize
279                 chunks = append(chunks, chunk)
280         }
281
282         return chunks, nil
283 }
284
285 // GetPartEnd calculates the end position
286 func GetPartEnd(begin int64, total int64, per int64) int64 {
287         if begin+per > total {
288                 return total - 1
289         }
290         return begin + per - 1
291 }
292
293 // CrcTable returns the table constructed from the specified polynomial
294 var CrcTable = func() *crc64.Table {
295         return crc64.MakeTable(crc64.ECMA)
296 }
297
298 // CrcTable returns the table constructed from the specified polynomial
299 var crc32Table = func() *crc32.Table {
300         return crc32.MakeTable(crc32.IEEE)
301 }
302
303 // choiceTransferPartOption choices valid option supported by Uploadpart or DownloadPart
304 func ChoiceTransferPartOption(options []Option) []Option {
305         var outOption []Option
306
307         listener, _ := FindOption(options, progressListener, nil)
308         if listener != nil {
309                 outOption = append(outOption, Progress(listener.(ProgressListener)))
310         }
311
312         payer, _ := FindOption(options, HTTPHeaderOssRequester, nil)
313         if payer != nil {
314                 outOption = append(outOption, RequestPayer(PayerType(payer.(string))))
315         }
316
317         versionId, _ := FindOption(options, "versionId", nil)
318         if versionId != nil {
319                 outOption = append(outOption, VersionId(versionId.(string)))
320         }
321
322         trafficLimit, _ := FindOption(options, HTTPHeaderOssTrafficLimit, nil)
323         if trafficLimit != nil {
324                 speed, _ := strconv.ParseInt(trafficLimit.(string), 10, 64)
325                 outOption = append(outOption, TrafficLimitHeader(speed))
326         }
327
328         respHeader, _ := FindOption(options, responseHeader, nil)
329         if respHeader != nil {
330                 outOption = append(outOption, GetResponseHeader(respHeader.(*http.Header)))
331         }
332
333         return outOption
334 }
335
336 // ChoiceCompletePartOption choices valid option supported by CompleteMulitiPart
337 func ChoiceCompletePartOption(options []Option) []Option {
338         var outOption []Option
339
340         listener, _ := FindOption(options, progressListener, nil)
341         if listener != nil {
342                 outOption = append(outOption, Progress(listener.(ProgressListener)))
343         }
344
345         payer, _ := FindOption(options, HTTPHeaderOssRequester, nil)
346         if payer != nil {
347                 outOption = append(outOption, RequestPayer(PayerType(payer.(string))))
348         }
349
350         acl, _ := FindOption(options, HTTPHeaderOssObjectACL, nil)
351         if acl != nil {
352                 outOption = append(outOption, ObjectACL(ACLType(acl.(string))))
353         }
354
355         callback, _ := FindOption(options, HTTPHeaderOssCallback, nil)
356         if callback != nil {
357                 outOption = append(outOption, Callback(callback.(string)))
358         }
359
360         callbackVar, _ := FindOption(options, HTTPHeaderOssCallbackVar, nil)
361         if callbackVar != nil {
362                 outOption = append(outOption, CallbackVar(callbackVar.(string)))
363         }
364
365         respHeader, _ := FindOption(options, responseHeader, nil)
366         if respHeader != nil {
367                 outOption = append(outOption, GetResponseHeader(respHeader.(*http.Header)))
368         }
369
370         forbidOverWrite, _ := FindOption(options, HTTPHeaderOssForbidOverWrite, nil)
371         if forbidOverWrite != nil {
372                 if forbidOverWrite.(string) == "true" {
373                         outOption = append(outOption, ForbidOverWrite(true))
374                 } else {
375                         outOption = append(outOption, ForbidOverWrite(false))
376                 }
377         }
378
379         return outOption
380 }
381
382 // ChoiceAbortPartOption choices valid option supported by AbortMultipartUpload
383 func ChoiceAbortPartOption(options []Option) []Option {
384         var outOption []Option
385         payer, _ := FindOption(options, HTTPHeaderOssRequester, nil)
386         if payer != nil {
387                 outOption = append(outOption, RequestPayer(PayerType(payer.(string))))
388         }
389
390         respHeader, _ := FindOption(options, responseHeader, nil)
391         if respHeader != nil {
392                 outOption = append(outOption, GetResponseHeader(respHeader.(*http.Header)))
393         }
394
395         return outOption
396 }
397
398 // ChoiceHeadObjectOption choices valid option supported by HeadObject
399 func ChoiceHeadObjectOption(options []Option) []Option {
400         var outOption []Option
401
402         // not select HTTPHeaderRange to get whole object length
403         payer, _ := FindOption(options, HTTPHeaderOssRequester, nil)
404         if payer != nil {
405                 outOption = append(outOption, RequestPayer(PayerType(payer.(string))))
406         }
407
408         versionId, _ := FindOption(options, "versionId", nil)
409         if versionId != nil {
410                 outOption = append(outOption, VersionId(versionId.(string)))
411         }
412
413         respHeader, _ := FindOption(options, responseHeader, nil)
414         if respHeader != nil {
415                 outOption = append(outOption, GetResponseHeader(respHeader.(*http.Header)))
416         }
417
418         return outOption
419 }
420
421 func CheckBucketName(bucketName string) error {
422         nameLen := len(bucketName)
423         if nameLen < 3 || nameLen > 63 {
424                 return fmt.Errorf("bucket name %s len is between [3-63],now is %d", bucketName, nameLen)
425         }
426
427         for _, v := range bucketName {
428                 if !(('a' <= v && v <= 'z') || ('0' <= v && v <= '9') || v == '-') {
429                         return fmt.Errorf("bucket name %s can only include lowercase letters, numbers, and -", bucketName)
430                 }
431         }
432         if bucketName[0] == '-' || bucketName[nameLen-1] == '-' {
433                 return fmt.Errorf("bucket name %s must start and end with a lowercase letter or number", bucketName)
434         }
435         return nil
436 }
437
438 func GetReaderLen(reader io.Reader) (int64, error) {
439         var contentLength int64
440         var err error
441         switch v := reader.(type) {
442         case *bytes.Buffer:
443                 contentLength = int64(v.Len())
444         case *bytes.Reader:
445                 contentLength = int64(v.Len())
446         case *strings.Reader:
447                 contentLength = int64(v.Len())
448         case *os.File:
449                 fInfo, fError := v.Stat()
450                 if fError != nil {
451                         err = fmt.Errorf("can't get reader content length,%s", fError.Error())
452                 } else {
453                         contentLength = fInfo.Size()
454                 }
455         case *io.LimitedReader:
456                 contentLength = int64(v.N)
457         case *LimitedReadCloser:
458                 contentLength = int64(v.N)
459         default:
460                 err = fmt.Errorf("can't get reader content length,unkown reader type")
461         }
462         return contentLength, err
463 }
464
465 func LimitReadCloser(r io.Reader, n int64) io.Reader {
466         var lc LimitedReadCloser
467         lc.R = r
468         lc.N = n
469         return &lc
470 }
471
472 // LimitedRC support Close()
473 type LimitedReadCloser struct {
474         io.LimitedReader
475 }
476
477 func (lc *LimitedReadCloser) Close() error {
478         if closer, ok := lc.R.(io.ReadCloser); ok {
479                 return closer.Close()
480         }
481         return nil
482 }
483
484 type DiscardReadCloser struct {
485         RC      io.ReadCloser
486         Discard int
487 }
488
489 func (drc *DiscardReadCloser) Read(b []byte) (int, error) {
490         n, err := drc.RC.Read(b)
491         if drc.Discard == 0 || n <= 0 {
492                 return n, err
493         }
494
495         if n <= drc.Discard {
496                 drc.Discard -= n
497                 return 0, err
498         }
499
500         realLen := n - drc.Discard
501         copy(b[0:realLen], b[drc.Discard:n])
502         drc.Discard = 0
503         return realLen, err
504 }
505
506 func (drc *DiscardReadCloser) Close() error {
507         closer, ok := drc.RC.(io.ReadCloser)
508         if ok {
509                 return closer.Close()
510         }
511         return nil
512 }