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

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