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.

update.go 4.0 kB

7 months ago
6 months ago
7 months ago
6 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
6 months ago
7 months ago
7 months ago
7 months ago
7 months ago
7 months ago
6 months ago
7 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. package uploader
  2. import (
  3. "context"
  4. "fmt"
  5. "io"
  6. "path"
  7. "sync"
  8. "time"
  9. "github.com/samber/lo"
  10. "gitlink.org.cn/cloudream/common/pkgs/ioswitch/exec"
  11. "gitlink.org.cn/cloudream/jcs-pub/client/internal/db"
  12. "gitlink.org.cn/cloudream/jcs-pub/client/types"
  13. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/distlock"
  14. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/ioswitch2"
  15. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/ioswitch2/ops2"
  16. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/ioswitch2/parser"
  17. )
  18. type UpdateUploader struct {
  19. uploader *Uploader
  20. pkgID types.PackageID
  21. targetSpace types.UserSpaceDetail
  22. pubLock *distlock.Mutex
  23. loadToSpaces []types.UserSpaceDetail
  24. loadToPath []string
  25. successes []db.AddObjectEntry
  26. lock sync.Mutex
  27. commited bool
  28. }
  29. type UploadSpaceInfo struct {
  30. Space types.UserSpaceDetail
  31. Delay time.Duration
  32. IsSameLocation bool
  33. }
  34. type UpdateResult struct {
  35. // 上传成功的文件列表,Key为Path
  36. Objects map[string]types.Object
  37. }
  38. type UploadOption struct {
  39. CreateTime time.Time // 设置文件的上传时间,如果为0值,则使用开始上传时的时间。
  40. }
  41. func (w *UpdateUploader) Upload(pat string, stream io.Reader, opts ...UploadOption) error {
  42. opt := UploadOption{}
  43. if len(opts) > 0 {
  44. opt = opts[0]
  45. }
  46. if opt.CreateTime.IsZero() {
  47. opt.CreateTime = time.Now()
  48. }
  49. ft := ioswitch2.NewFromTo()
  50. fromExec, hd := ioswitch2.NewFromDriver(ioswitch2.RawStream())
  51. ft.AddFrom(fromExec).
  52. AddTo(ioswitch2.NewToShardStore(*w.targetSpace.MasterHub, w.targetSpace, ioswitch2.RawStream(), "shardInfo"))
  53. for i, space := range w.loadToSpaces {
  54. ft.AddTo(ioswitch2.NewToPublicStore(*space.MasterHub, space, path.Join(w.loadToPath[i], pat)))
  55. }
  56. plans := exec.NewPlanBuilder()
  57. err := parser.Parse(ft, plans)
  58. if err != nil {
  59. return fmt.Errorf("parsing plan: %w", err)
  60. }
  61. exeCtx := exec.NewExecContext()
  62. exec.SetValueByType(exeCtx, w.uploader.stgPool)
  63. exec := plans.Execute(exeCtx)
  64. exec.BeginWrite(io.NopCloser(stream), hd)
  65. ret, err := exec.Wait(context.TODO())
  66. if err != nil {
  67. return fmt.Errorf("executing plan: %w", err)
  68. }
  69. w.lock.Lock()
  70. defer w.lock.Unlock()
  71. // 记录上传结果
  72. shardInfo := ret["shardInfo"].(*ops2.ShardInfoValue)
  73. w.successes = append(w.successes, db.AddObjectEntry{
  74. Path: pat,
  75. Size: shardInfo.Size,
  76. FileHash: shardInfo.Hash,
  77. CreateTime: opt.CreateTime,
  78. UserSpaceIDs: []types.UserSpaceID{w.targetSpace.UserSpace.UserSpaceID},
  79. })
  80. return nil
  81. }
  82. // 取消上传对象。必须在对象调用了Upload之后调用。
  83. func (w *UpdateUploader) CancelObject(path string) {
  84. w.lock.Lock()
  85. defer w.lock.Unlock()
  86. w.successes = lo.Reject(w.successes, func(e db.AddObjectEntry, i int) bool {
  87. return e.Path == path
  88. })
  89. }
  90. // 重命名对象。必须在对象调用了Upload之后调用。不会检查新路径是否已经存在,需由调用方去做保证。
  91. func (w *UpdateUploader) RenameObject(path string, newPath string) {
  92. w.lock.Lock()
  93. defer w.lock.Unlock()
  94. for i := range w.successes {
  95. if w.successes[i].Path == path {
  96. w.successes[i].Path = newPath
  97. break
  98. }
  99. }
  100. }
  101. func (w *UpdateUploader) Commit() (UpdateResult, error) {
  102. w.lock.Lock()
  103. defer w.lock.Unlock()
  104. if w.commited {
  105. return UpdateResult{}, fmt.Errorf("package already commited")
  106. }
  107. w.commited = true
  108. defer w.pubLock.Unlock()
  109. var addedObjs []types.Object
  110. err := w.uploader.db.DoTx(func(tx db.SQLContext) error {
  111. var err error
  112. addedObjs, err = w.uploader.db.Object().BatchAdd(tx, w.pkgID, w.successes)
  113. return err
  114. })
  115. if err != nil {
  116. return UpdateResult{}, fmt.Errorf("adding objects: %w", err)
  117. }
  118. ret := UpdateResult{
  119. Objects: make(map[string]types.Object),
  120. }
  121. for _, entry := range addedObjs {
  122. ret.Objects[entry.Path] = entry
  123. }
  124. return ret, nil
  125. }
  126. func (w *UpdateUploader) Abort() {
  127. w.lock.Lock()
  128. defer w.lock.Unlock()
  129. if w.commited {
  130. return
  131. }
  132. w.commited = true
  133. w.pubLock.Unlock()
  134. }

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