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 6.1KB

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