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.

downloader.go 4.9 kB

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
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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. package downloader
  2. import (
  3. "fmt"
  4. "io"
  5. lru "github.com/hashicorp/golang-lru/v2"
  6. "gitlink.org.cn/cloudream/common/pkgs/iterator"
  7. "gitlink.org.cn/cloudream/jcs-pub/client/internal/db"
  8. "gitlink.org.cn/cloudream/jcs-pub/client/internal/downloader/strategy"
  9. "gitlink.org.cn/cloudream/jcs-pub/client/internal/speedstats"
  10. clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types"
  11. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/connectivity"
  12. "gitlink.org.cn/cloudream/jcs-pub/common/pkgs/storage/pool"
  13. )
  14. const (
  15. DefaultMaxStripCacheCount = 128
  16. )
  17. type DownloadIterator = iterator.Iterator[*Downloading]
  18. type DownloadReqeust struct {
  19. ObjectID clitypes.ObjectID
  20. Offset int64
  21. Length int64
  22. }
  23. type downloadReqeust2 struct {
  24. Detail *clitypes.ObjectDetail
  25. Raw DownloadReqeust
  26. }
  27. type Downloading struct {
  28. Object *clitypes.Object
  29. File io.ReadCloser // 文件流,如果文件不存在,那么为nil
  30. Request DownloadReqeust
  31. }
  32. type Downloader struct {
  33. strips *StripCache
  34. cfg Config
  35. conn *connectivity.Collector
  36. stgPool *pool.Pool
  37. selector *strategy.Selector
  38. db *db.DB
  39. speedStats *speedstats.SpeedStats
  40. }
  41. func NewDownloader(cfg Config, conn *connectivity.Collector, stgPool *pool.Pool, sel *strategy.Selector, db *db.DB, speedStats *speedstats.SpeedStats) *Downloader {
  42. if cfg.MaxStripCacheCount == 0 {
  43. cfg.MaxStripCacheCount = DefaultMaxStripCacheCount
  44. }
  45. ch, _ := lru.New[ECStripKey, ObjectECStrip](cfg.MaxStripCacheCount)
  46. return &Downloader{
  47. strips: ch,
  48. cfg: cfg,
  49. conn: conn,
  50. stgPool: stgPool,
  51. selector: sel,
  52. db: db,
  53. speedStats: speedStats,
  54. }
  55. }
  56. func (d *Downloader) DownloadObjects(reqs []DownloadReqeust) DownloadIterator {
  57. objIDs := make([]clitypes.ObjectID, len(reqs))
  58. for i, req := range reqs {
  59. objIDs[i] = req.ObjectID
  60. }
  61. if len(objIDs) == 0 {
  62. return iterator.Empty[*Downloading]()
  63. }
  64. objDetails, err := db.DoTx11(d.db, d.db.Object().BatchGetDetails, objIDs)
  65. if err != nil {
  66. return iterator.FuseError[*Downloading](fmt.Errorf("request to db: %w", err))
  67. }
  68. detailsMap := make(map[clitypes.ObjectID]*clitypes.ObjectDetail)
  69. for _, detail := range objDetails {
  70. d := detail
  71. detailsMap[detail.Object.ObjectID] = &d
  72. }
  73. req2s := make([]downloadReqeust2, len(reqs))
  74. for i, req := range reqs {
  75. req2s[i] = downloadReqeust2{
  76. Detail: detailsMap[req.ObjectID],
  77. Raw: req,
  78. }
  79. }
  80. return NewDownloadObjectIterator(d, req2s)
  81. }
  82. func (d *Downloader) DownloadObjectByDetail(detail clitypes.ObjectDetail, off int64, length int64) (*Downloading, error) {
  83. req2s := []downloadReqeust2{{
  84. Detail: &detail,
  85. Raw: DownloadReqeust{
  86. ObjectID: detail.Object.ObjectID,
  87. Offset: off,
  88. Length: length,
  89. },
  90. }}
  91. iter := NewDownloadObjectIterator(d, req2s)
  92. return iter.MoveNext()
  93. }
  94. func (d *Downloader) DownloadPackage(pkgID clitypes.PackageID, prefix string) (clitypes.Package, DownloadIterator, error) {
  95. pkg, details, err := db.DoTx02(d.db, func(tx db.SQLContext) (clitypes.Package, []clitypes.ObjectDetail, error) {
  96. pkg, err := d.db.Package().GetByID(tx, pkgID)
  97. if err != nil {
  98. return clitypes.Package{}, nil, err
  99. }
  100. var details []clitypes.ObjectDetail
  101. if prefix != "" {
  102. objs, err := d.db.Object().GetWithPathPrefix(tx, pkgID, prefix)
  103. if err != nil {
  104. return clitypes.Package{}, nil, err
  105. }
  106. objIDs := make([]clitypes.ObjectID, len(objs))
  107. for i, obj := range objs {
  108. objIDs[i] = obj.ObjectID
  109. }
  110. allBlocks, err := d.db.ObjectBlock().BatchGetByObjectID(tx, objIDs)
  111. if err != nil {
  112. return clitypes.Package{}, nil, err
  113. }
  114. allPinnedObjs, err := d.db.PinnedObject().BatchGetByObjectID(tx, objIDs)
  115. if err != nil {
  116. return clitypes.Package{}, nil, err
  117. }
  118. details = make([]clitypes.ObjectDetail, 0, len(objs))
  119. for _, obj := range objs {
  120. detail := clitypes.ObjectDetail{
  121. Object: obj,
  122. }
  123. details = append(details, detail)
  124. }
  125. clitypes.DetailsFillObjectBlocks(details, allBlocks)
  126. clitypes.DetailsFillPinnedAt(details, allPinnedObjs)
  127. } else {
  128. details, err = d.db.Object().GetPackageObjectDetails(tx, pkgID)
  129. if err != nil {
  130. return clitypes.Package{}, nil, err
  131. }
  132. }
  133. return pkg, details, nil
  134. })
  135. if err != nil {
  136. return clitypes.Package{}, nil, err
  137. }
  138. req2s := make([]downloadReqeust2, len(details))
  139. for i, objDetail := range details {
  140. dt := objDetail
  141. req2s[i] = downloadReqeust2{
  142. Detail: &dt,
  143. Raw: DownloadReqeust{
  144. ObjectID: objDetail.Object.ObjectID,
  145. Offset: 0,
  146. Length: objDetail.Object.Size,
  147. },
  148. }
  149. }
  150. return pkg, NewDownloadObjectIterator(d, req2s), nil
  151. }
  152. type ObjectECStrip struct {
  153. Data []byte
  154. ObjectFileHash clitypes.FileHash // 添加这条缓存时,Object的FileHash
  155. }
  156. type ECStripKey struct {
  157. ObjectID clitypes.ObjectID
  158. StripIndex int64
  159. }
  160. type StripCache = lru.Cache[ECStripKey, ObjectECStrip]

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