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.1 kB

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

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