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 3.9 kB

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

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