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.

storage.go 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package storage
  5. import (
  6. "context"
  7. "errors"
  8. "fmt"
  9. "io"
  10. "net/url"
  11. "os"
  12. "code.gitea.io/gitea/modules/log"
  13. "code.gitea.io/gitea/modules/setting"
  14. )
  15. var (
  16. // ErrURLNotSupported represents url is not supported
  17. ErrURLNotSupported = errors.New("url method not supported")
  18. )
  19. // ErrInvalidConfiguration is called when there is invalid configuration for a storage
  20. type ErrInvalidConfiguration struct {
  21. cfg interface{}
  22. err error
  23. }
  24. func (err ErrInvalidConfiguration) Error() string {
  25. if err.err != nil {
  26. return fmt.Sprintf("Invalid Configuration Argument: %v: Error: %v", err.cfg, err.err)
  27. }
  28. return fmt.Sprintf("Invalid Configuration Argument: %v", err.cfg)
  29. }
  30. // IsErrInvalidConfiguration checks if an error is an ErrInvalidConfiguration
  31. func IsErrInvalidConfiguration(err error) bool {
  32. _, ok := err.(ErrInvalidConfiguration)
  33. return ok
  34. }
  35. // Type is a type of Storage
  36. type Type string
  37. // NewStorageFunc is a function that creates a storage
  38. type NewStorageFunc func(ctx context.Context, cfg interface{}) (ObjectStorage, error)
  39. var storageMap = map[Type]NewStorageFunc{}
  40. // RegisterStorageType registers a provided storage type with a function to create it
  41. func RegisterStorageType(typ Type, fn func(ctx context.Context, cfg interface{}) (ObjectStorage, error)) {
  42. storageMap[typ] = fn
  43. }
  44. // Object represents the object on the storage
  45. type Object interface {
  46. io.ReadCloser
  47. io.Seeker
  48. Stat() (os.FileInfo, error)
  49. }
  50. // ObjectStorage represents an object storage to handle a bucket and files
  51. type ObjectStorage interface {
  52. Open(path string) (Object, error)
  53. // Save store a object, if size is unknown set -1
  54. Save(path string, r io.Reader, size int64) (int64, error)
  55. Stat(path string) (os.FileInfo, error)
  56. Delete(path string) error
  57. URL(path, name string) (*url.URL, error)
  58. IterateObjects(func(path string, obj Object) error) error
  59. }
  60. // Copy copies a file from source ObjectStorage to dest ObjectStorage
  61. func Copy(dstStorage ObjectStorage, dstPath string, srcStorage ObjectStorage, srcPath string) (int64, error) {
  62. f, err := srcStorage.Open(srcPath)
  63. if err != nil {
  64. return 0, err
  65. }
  66. defer f.Close()
  67. size := int64(-1)
  68. fsinfo, err := f.Stat()
  69. if err == nil {
  70. size = fsinfo.Size()
  71. }
  72. return dstStorage.Save(dstPath, f, size)
  73. }
  74. // Clean delete all the objects in this storage
  75. func Clean(storage ObjectStorage) error {
  76. return storage.IterateObjects(func(path string, obj Object) error {
  77. _ = obj.Close()
  78. return storage.Delete(path)
  79. })
  80. }
  81. // SaveFrom saves data to the ObjectStorage with path p from the callback
  82. func SaveFrom(objStorage ObjectStorage, p string, callback func(w io.Writer) error) error {
  83. pr, pw := io.Pipe()
  84. defer pr.Close()
  85. go func() {
  86. defer pw.Close()
  87. if err := callback(pw); err != nil {
  88. _ = pw.CloseWithError(err)
  89. }
  90. }()
  91. _, err := objStorage.Save(p, pr, -1)
  92. return err
  93. }
  94. var (
  95. // Attachments represents attachments storage
  96. Attachments ObjectStorage
  97. // LFS represents lfs storage
  98. LFS ObjectStorage
  99. // Avatars represents user avatars storage
  100. Avatars ObjectStorage
  101. // RepoAvatars represents repository avatars storage
  102. RepoAvatars ObjectStorage
  103. // RepoArchives represents repository archives storage
  104. RepoArchives ObjectStorage
  105. )
  106. // Init init the stoarge
  107. func Init() error {
  108. if err := initAttachments(); err != nil {
  109. return err
  110. }
  111. if err := initAvatars(); err != nil {
  112. return err
  113. }
  114. if err := initRepoAvatars(); err != nil {
  115. return err
  116. }
  117. if err := initLFS(); err != nil {
  118. return err
  119. }
  120. return initRepoArchives()
  121. }
  122. // NewStorage takes a storage type and some config and returns an ObjectStorage or an error
  123. func NewStorage(typStr string, cfg interface{}) (ObjectStorage, error) {
  124. if len(typStr) == 0 {
  125. typStr = string(LocalStorageType)
  126. }
  127. fn, ok := storageMap[Type(typStr)]
  128. if !ok {
  129. return nil, fmt.Errorf("Unsupported storage type: %s", typStr)
  130. }
  131. return fn(context.Background(), cfg)
  132. }
  133. func initAvatars() (err error) {
  134. log.Info("Initialising Avatar storage with type: %s", setting.Avatar.Storage.Type)
  135. Avatars, err = NewStorage(setting.Avatar.Storage.Type, &setting.Avatar.Storage)
  136. return
  137. }
  138. func initAttachments() (err error) {
  139. log.Info("Initialising Attachment storage with type: %s", setting.Attachment.Storage.Type)
  140. Attachments, err = NewStorage(setting.Attachment.Storage.Type, &setting.Attachment.Storage)
  141. return
  142. }
  143. func initLFS() (err error) {
  144. log.Info("Initialising LFS storage with type: %s", setting.LFS.Storage.Type)
  145. LFS, err = NewStorage(setting.LFS.Storage.Type, &setting.LFS.Storage)
  146. return
  147. }
  148. func initRepoAvatars() (err error) {
  149. log.Info("Initialising Repository Avatar storage with type: %s", setting.RepoAvatar.Storage.Type)
  150. RepoAvatars, err = NewStorage(setting.RepoAvatar.Storage.Type, &setting.RepoAvatar.Storage)
  151. return
  152. }
  153. func initRepoArchives() (err error) {
  154. log.Info("Initialising Repository Archive storage with type: %s", setting.RepoArchive.Storage.Type)
  155. RepoArchives, err = NewStorage(setting.RepoArchive.Storage.Type, &setting.RepoArchive.Storage)
  156. return
  157. }