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

minio_ext.go 5.0 kB

5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. package storage
  2. import (
  3. "encoding/xml"
  4. "errors"
  5. "path"
  6. "sort"
  7. "strconv"
  8. "strings"
  9. "sync"
  10. "time"
  11. "code.gitea.io/gitea/modules/log"
  12. "code.gitea.io/gitea/modules/minio_ext"
  13. "code.gitea.io/gitea/modules/setting"
  14. miniov6 "github.com/minio/minio-go/v6"
  15. )
  16. const (
  17. PresignedUploadPartUrlExpireTime = time.Hour * 24 * 7
  18. )
  19. type ComplPart struct {
  20. PartNumber int `json:"partNumber"`
  21. ETag string `json:"eTag"`
  22. }
  23. type CompleteParts struct {
  24. Data []ComplPart `json:"completedParts"`
  25. }
  26. // completedParts is a collection of parts sortable by their part numbers.
  27. // used for sorting the uploaded parts before completing the multipart request.
  28. type completedParts []miniov6.CompletePart
  29. func (a completedParts) Len() int { return len(a) }
  30. func (a completedParts) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
  31. func (a completedParts) Less(i, j int) bool { return a[i].PartNumber < a[j].PartNumber }
  32. // completeMultipartUpload container for completing multipart upload.
  33. type completeMultipartUpload struct {
  34. XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CompleteMultipartUpload" json:"-"`
  35. Parts []miniov6.CompletePart `xml:"Part"`
  36. }
  37. var (
  38. adminClient *minio_ext.Client = nil
  39. coreClient *miniov6.Core = nil
  40. )
  41. var mutex *sync.Mutex
  42. func init() {
  43. mutex = new(sync.Mutex)
  44. }
  45. func getClients() (*minio_ext.Client, *miniov6.Core, error) {
  46. var client *minio_ext.Client
  47. var core *miniov6.Core
  48. mutex.Lock()
  49. defer mutex.Unlock()
  50. if nil != adminClient && nil != coreClient {
  51. client = adminClient
  52. core = coreClient
  53. return client, core, nil
  54. }
  55. var err error
  56. minio := setting.Attachment.Minio
  57. if nil == adminClient {
  58. adminClient, err = minio_ext.New(
  59. minio.Endpoint,
  60. minio.AccessKeyID,
  61. minio.SecretAccessKey,
  62. minio.UseSSL,
  63. )
  64. if nil != err {
  65. return nil, nil, err
  66. }
  67. }
  68. client = adminClient
  69. if nil == coreClient {
  70. coreClient, err = miniov6.NewCore(
  71. minio.Endpoint,
  72. minio.AccessKeyID,
  73. minio.SecretAccessKey,
  74. minio.UseSSL,
  75. )
  76. if nil != err {
  77. return nil, nil, err
  78. }
  79. }
  80. core = coreClient
  81. return client, core, nil
  82. }
  83. func GenMultiPartSignedUrl(uuid string, uploadId string, partNumber int, partSize int64) (string, error) {
  84. minioClient, _, err := getClients()
  85. if err != nil {
  86. log.Error("getClients failed:", err.Error())
  87. return "", err
  88. }
  89. minio := setting.Attachment.Minio
  90. bucketName := minio.Bucket
  91. objectName := strings.TrimPrefix(path.Join(minio.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/")
  92. return minioClient.GenUploadPartSignedUrl(uploadId, bucketName, objectName, partNumber, partSize, PresignedUploadPartUrlExpireTime, setting.Attachment.Minio.Location)
  93. }
  94. func NewMultiPartUpload(uuid string) (string, error) {
  95. _, core, err := getClients()
  96. if err != nil {
  97. log.Error("getClients failed:", err.Error())
  98. return "", err
  99. }
  100. minio := setting.Attachment.Minio
  101. bucketName := minio.Bucket
  102. objectName := strings.TrimPrefix(path.Join(minio.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/")
  103. return core.NewMultipartUpload(bucketName, objectName, miniov6.PutObjectOptions{})
  104. }
  105. func CompleteMultiPartUpload(uuid string, uploadID string, totalChunks int) (string, error) {
  106. client, core, err := getClients()
  107. if err != nil {
  108. log.Error("getClients failed:", err.Error())
  109. return "", err
  110. }
  111. minio := setting.Attachment.Minio
  112. bucketName := minio.Bucket
  113. objectName := strings.TrimPrefix(path.Join(minio.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/")
  114. partInfos, err := client.ListObjectParts(bucketName, objectName, uploadID)
  115. if err != nil {
  116. log.Error("ListObjectParts failed:", err.Error())
  117. return "", err
  118. }
  119. if len(partInfos) != totalChunks {
  120. log.Error("ListObjectParts number(%d) is not equal the set total chunk number(%d)", len(partInfos), totalChunks)
  121. return "", errors.New("the parts is not complete")
  122. }
  123. var complMultipartUpload completeMultipartUpload
  124. for _, partInfo := range partInfos {
  125. complMultipartUpload.Parts = append(complMultipartUpload.Parts, miniov6.CompletePart{
  126. PartNumber: partInfo.PartNumber,
  127. ETag: partInfo.ETag,
  128. })
  129. }
  130. // Sort all completed parts.
  131. sort.Sort(completedParts(complMultipartUpload.Parts))
  132. return core.CompleteMultipartUpload(bucketName, objectName, uploadID, complMultipartUpload.Parts)
  133. }
  134. func GetPartInfos(uuid string, uploadID string) (string, error) {
  135. minioClient, _, err := getClients()
  136. if err != nil {
  137. log.Error("getClients failed:", err.Error())
  138. return "", err
  139. }
  140. minio := setting.Attachment.Minio
  141. bucketName := minio.Bucket
  142. objectName := strings.TrimPrefix(path.Join(minio.BasePath, path.Join(uuid[0:1], uuid[1:2], uuid)), "/")
  143. partInfos, err := minioClient.ListObjectParts(bucketName, objectName, uploadID)
  144. if err != nil {
  145. log.Error("ListObjectParts failed:", err.Error())
  146. return "", err
  147. }
  148. var chunks string
  149. for _, partInfo := range partInfos {
  150. chunks += strconv.Itoa(partInfo.PartNumber) + "-" + partInfo.ETag + ","
  151. }
  152. return chunks, nil
  153. }