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.

base_store.go 3.4 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. package rclone
  2. import (
  3. "context"
  4. "crypto/sha256"
  5. "io"
  6. "time"
  7. "github.com/inhies/go-bytesize"
  8. "github.com/rclone/rclone/fs"
  9. "gitlink.org.cn/cloudream/common/pkgs/logger"
  10. "gitlink.org.cn/cloudream/common/utils/io2"
  11. stgtypes "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/types"
  12. jcstypes "gitlink.org.cn/cloudream/jcs-pub/common/types"
  13. )
  14. type BaseStore struct {
  15. Fs fs.Fs
  16. Detail *jcstypes.UserSpaceDetail
  17. }
  18. func NewBaseStore(fs fs.Fs, detail *jcstypes.UserSpaceDetail) *BaseStore {
  19. return &BaseStore{
  20. Fs: fs,
  21. Detail: detail,
  22. }
  23. }
  24. func (s *BaseStore) Write(pat jcstypes.JPath, stream io.Reader, opt stgtypes.WriteOption) (stgtypes.FileInfo, error) {
  25. modTime := opt.ModTime
  26. if modTime.IsZero() {
  27. modTime = time.Now()
  28. }
  29. dir := pat.CopyParent()
  30. if dir.Len() > 0 {
  31. err := s.Fs.Mkdir(context.Background(), dir.String())
  32. if err != nil {
  33. return stgtypes.FileInfo{}, err
  34. }
  35. }
  36. counter := io2.Counter(stream)
  37. hasher := io2.NewReadHasher(sha256.New(), counter)
  38. _, err := s.Fs.Put(context.Background(), hasher, &ObjectInfo{
  39. RemoteValue: pat.String(),
  40. ModTimeValue: modTime,
  41. SizeValue: -1,
  42. })
  43. if err != nil {
  44. return stgtypes.FileInfo{}, err
  45. }
  46. return stgtypes.FileInfo{
  47. Path: pat,
  48. Size: counter.Count(),
  49. Hash: jcstypes.NewFullHash(hasher.Sum()),
  50. }, nil
  51. }
  52. func (s *BaseStore) Read(objPath jcstypes.JPath, opt stgtypes.OpenOption) (io.ReadCloser, error) {
  53. if opt.Length == 0 {
  54. return io2.ErrorReader(io.EOF), nil
  55. }
  56. var opts []fs.OpenOption
  57. if opt.Length > 0 {
  58. opts = append(opts, &fs.RangeOption{
  59. Start: opt.Offset,
  60. End: opt.Offset + opt.Length - 1,
  61. })
  62. } else if opt.Offset > 0 {
  63. opts = append(opts, &fs.SeekOption{
  64. Offset: opt.Offset,
  65. })
  66. }
  67. obj, err := s.Fs.NewObject(context.Background(), objPath.String())
  68. if err != nil {
  69. return nil, err
  70. }
  71. return obj.Open(context.Background(), opts...)
  72. }
  73. func (s *BaseStore) Mkdir(path jcstypes.JPath) error {
  74. return s.Fs.Mkdir(context.Background(), path.String())
  75. }
  76. func (s *BaseStore) ReadDir(pat jcstypes.JPath) stgtypes.DirReader {
  77. return NewDirReader(s.Fs, pat.String(), pat.Clone())
  78. }
  79. func (s *BaseStore) CleanTemps() {
  80. log := s.getLogger()
  81. startTime := time.Now()
  82. tempDir := Join(s.Detail.UserSpace.WorkingDir.String(), stgtypes.TempWorkingDir)
  83. cnt, size := s.cleanTemps(tempDir, false)
  84. log.Infof("clean %d temp files, size: %v, time: %v", cnt, bytesize.ByteSize(size), time.Since(startTime))
  85. }
  86. func (s *BaseStore) cleanTemps(root string, removeRoot bool) (int, int64) {
  87. log := s.getLogger()
  88. es, err := s.Fs.List(context.Background(), root)
  89. if err != nil {
  90. log.Warnf("list dir %v: %v", root, err)
  91. return 0, 0
  92. }
  93. cnt := 0
  94. size := int64(0)
  95. for _, e := range es {
  96. switch e := e.(type) {
  97. case fs.Object:
  98. err := e.Remove(context.Background())
  99. if err != nil {
  100. log.Warnf("remove file %v: %v", e.Remote(), err)
  101. } else {
  102. cnt++
  103. size += e.Size()
  104. }
  105. case fs.Directory:
  106. c, s := s.cleanTemps(e.Remote(), true)
  107. cnt += c
  108. size += s
  109. }
  110. }
  111. if removeRoot {
  112. err := s.Fs.Rmdir(context.Background(), root)
  113. if err != nil {
  114. log.Warnf("remove dir %v: %v", root, err)
  115. }
  116. }
  117. return cnt, size
  118. }
  119. func (s *BaseStore) Test() error {
  120. _, err := s.Fs.List(context.Background(), "")
  121. return err
  122. }
  123. func (s *BaseStore) getLogger() logger.Logger {
  124. return logger.WithField("BaseStore", "RClone").WithField("UserSpace", s.Detail.UserSpace)
  125. }

本项目旨在将云际存储公共基础设施化,使个人及企业可低门槛使用高效的云际存储服务(安装开箱即用云际存储客户端即可,无需关注其他组件的部署),同时支持用户灵活便捷定制云际存储的功能细节。