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.

package.go 9.2 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. package db
  2. import (
  3. "fmt"
  4. "time"
  5. "github.com/samber/lo"
  6. jcstypes "gitlink.org.cn/cloudream/jcs-pub/common/types"
  7. "gorm.io/gorm"
  8. )
  9. type PackageDB struct {
  10. *DB
  11. }
  12. func (db *DB) Package() *PackageDB {
  13. return &PackageDB{DB: db}
  14. }
  15. func (db *PackageDB) GetByID(ctx SQLContext, packageID jcstypes.PackageID) (jcstypes.Package, error) {
  16. var ret jcstypes.Package
  17. err := ctx.Table("Package").Where("PackageID = ?", packageID).First(&ret).Error
  18. return ret, err
  19. }
  20. func (db *PackageDB) GetByName(ctx SQLContext, bucketID jcstypes.BucketID, name string) (jcstypes.Package, error) {
  21. var ret jcstypes.Package
  22. err := ctx.Table("Package").Where("BucketID = ? AND Name = ?", bucketID, name).First(&ret).Error
  23. return ret, err
  24. }
  25. func (db *PackageDB) GetDetail(ctx SQLContext, packageID jcstypes.PackageID) (jcstypes.PackageDetail, error) {
  26. var pkg jcstypes.Package
  27. err := ctx.Table("Package").Where("PackageID = ?", packageID).First(&pkg).Error
  28. if err != nil {
  29. return jcstypes.PackageDetail{}, err
  30. }
  31. var ret struct {
  32. ObjectCount int64
  33. TotalSize int64
  34. }
  35. err = ctx.Table("Object").
  36. Select("COUNT(*) as ObjectCount, SUM(Size) as TotalSize").
  37. Where("PackageID = ?", packageID).
  38. First(&ret).
  39. Error
  40. if err != nil {
  41. return jcstypes.PackageDetail{}, err
  42. }
  43. return jcstypes.PackageDetail{
  44. Package: pkg,
  45. ObjectCount: ret.ObjectCount,
  46. TotalSize: ret.TotalSize,
  47. }, nil
  48. }
  49. func (db *PackageDB) BatchGetDetailPaged(ctx SQLContext, lastPkgID jcstypes.PackageID, count int) ([]jcstypes.PackageDetail, error) {
  50. var pkgs []jcstypes.Package
  51. err := ctx.Table("Package").
  52. Where("PackageID > ?", lastPkgID).
  53. Order("PackageID ASC").
  54. Limit(count).
  55. Find(&pkgs).Error
  56. if err != nil {
  57. return nil, err
  58. }
  59. if len(pkgs) == 0 {
  60. return nil, nil
  61. }
  62. minPkgID := pkgs[0].PackageID
  63. maxPkgID := pkgs[len(pkgs)-1].PackageID
  64. type detail struct {
  65. ObjectCount int64
  66. TotalSize int64
  67. }
  68. var details []detail
  69. err = ctx.
  70. Table("Package").
  71. Select("COUNT(ObjectID) as ObjectCount, SUM(Size) as TotalSize").
  72. Joins("left join Object o on Package.PackageID = o.PackageID").
  73. Where("Package.PackageID >= ? AND Package.PackageID <= ?", minPkgID, maxPkgID).
  74. Group("Package.PackageID").
  75. Order("Package.PackageID ASC").
  76. Find(&details).Error
  77. if err != nil {
  78. return nil, err
  79. }
  80. ret := make([]jcstypes.PackageDetail, len(pkgs))
  81. for i := range pkgs {
  82. ret[i] = jcstypes.PackageDetail{
  83. Package: pkgs[i],
  84. ObjectCount: details[i].ObjectCount,
  85. TotalSize: details[i].TotalSize,
  86. }
  87. }
  88. return ret, nil
  89. }
  90. func (db *PackageDB) BatchTestPackageID(ctx SQLContext, pkgIDs []jcstypes.PackageID) (map[jcstypes.PackageID]bool, error) {
  91. if len(pkgIDs) == 0 {
  92. return make(map[jcstypes.PackageID]bool), nil
  93. }
  94. var avaiIDs []jcstypes.PackageID
  95. err := ctx.Table("Package").
  96. Select("PackageID").
  97. Where("PackageID IN ?", pkgIDs).
  98. Find(&avaiIDs).Error
  99. if err != nil {
  100. return nil, err
  101. }
  102. avaiIDMap := make(map[jcstypes.PackageID]bool)
  103. for _, pkgID := range avaiIDs {
  104. avaiIDMap[pkgID] = true
  105. }
  106. return avaiIDMap, nil
  107. }
  108. func (*PackageDB) BatchGetAllPackageIDs(ctx SQLContext, start int, count int) ([]jcstypes.PackageID, error) {
  109. var ret []jcstypes.PackageID
  110. err := ctx.Table("Package").Select("PackageID").Limit(count).Offset(start).Find(&ret).Error
  111. return ret, err
  112. }
  113. func (db *PackageDB) GetBucketPackages(ctx SQLContext, bucketID jcstypes.BucketID) ([]jcstypes.Package, error) {
  114. var ret []jcstypes.Package
  115. err := ctx.Table("Package").
  116. Select("Package.*").
  117. Where("BucketID = ?", bucketID).
  118. Find(&ret).Error
  119. return ret, err
  120. }
  121. func (db *PackageDB) GetBucketPackagesByName(ctx SQLContext, bucketName string) ([]jcstypes.Package, error) {
  122. var ret []jcstypes.Package
  123. err := ctx.Table("Package").
  124. Select("Package.*").
  125. Joins("JOIN Bucket ON Package.BucketID = Bucket.BucketID").
  126. Where("Bucket.Name = ?", bucketName).
  127. Find(&ret).Error
  128. return ret, err
  129. }
  130. // 在指定名称的Bucket中查找指定名称的Package
  131. func (*PackageDB) GetByFullName(ctx SQLContext, bucketName string, packageName string) (jcstypes.Package, error) {
  132. var ret jcstypes.Package
  133. err := ctx.Table("Package").
  134. Select("Package.*").
  135. Joins("JOIN Bucket ON Package.BucketID = Bucket.BucketID").
  136. Where("Package.Name = ? AND Bucket.Name = ?", packageName, bucketName).
  137. First(&ret).Error
  138. return ret, err
  139. }
  140. func (db *PackageDB) Create(ctx SQLContext, bucketID jcstypes.BucketID, name string, createTime time.Time) (jcstypes.Package, error) {
  141. var packageID int64
  142. err := ctx.Table("Package").
  143. Select("PackageID").
  144. Where("Name = ? AND BucketID = ?", name, bucketID).
  145. Scan(&packageID).Error
  146. if err != nil {
  147. return jcstypes.Package{}, err
  148. }
  149. if packageID != 0 {
  150. return jcstypes.Package{}, gorm.ErrDuplicatedKey
  151. }
  152. newPackage := jcstypes.Package{Name: name, BucketID: bucketID, CreateTime: createTime}
  153. if err := ctx.Create(&newPackage).Error; err != nil {
  154. return jcstypes.Package{}, fmt.Errorf("insert package failed, err: %w", err)
  155. }
  156. return newPackage, nil
  157. }
  158. func (*PackageDB) Delete(ctx SQLContext, packageID jcstypes.PackageID) error {
  159. err := ctx.Delete(&jcstypes.Package{}, "PackageID = ?", packageID).Error
  160. return err
  161. }
  162. // 删除与Package相关的所有数据
  163. func (db *PackageDB) DeleteComplete(ctx SQLContext, packageID jcstypes.PackageID) error {
  164. if err := db.Package().Delete(ctx, packageID); err != nil {
  165. return fmt.Errorf("delete package state: %w", err)
  166. }
  167. if err := db.ObjectAccessStat().DeleteInPackage(ctx, packageID); err != nil {
  168. return fmt.Errorf("delete from object access stat: %w", err)
  169. }
  170. if err := db.ObjectBlock().DeleteInPackage(ctx, packageID); err != nil {
  171. return fmt.Errorf("delete from object block failed, err: %w", err)
  172. }
  173. if err := db.PinnedObject().DeleteInPackage(ctx, packageID); err != nil {
  174. return fmt.Errorf("deleting pinned objects in package: %w", err)
  175. }
  176. if err := db.Object().DeleteInPackage(ctx, packageID); err != nil {
  177. return fmt.Errorf("deleting objects in package: %w", err)
  178. }
  179. if err := db.PackageAccessStat().DeleteByPackageID(ctx, packageID); err != nil {
  180. return fmt.Errorf("deleting package access stat: %w", err)
  181. }
  182. return nil
  183. }
  184. func (*PackageDB) ChangeState(ctx SQLContext, packageID jcstypes.PackageID, state string) error {
  185. err := ctx.Exec("UPDATE Package SET State = ? WHERE PackageID = ?", state, packageID).Error
  186. return err
  187. }
  188. // 返回ErrRecordNotFound表示没有找到指定名称的Bucket,nil表示找到了
  189. func (*PackageDB) HasPackageIn(ctx SQLContext, bucketID jcstypes.BucketID) error {
  190. var pkg jcstypes.Package
  191. return ctx.Table("Package").Where("BucketID = ?", bucketID).First(&pkg).Error
  192. }
  193. func (*PackageDB) Move(ctx SQLContext, packageID jcstypes.PackageID, newBktID jcstypes.BucketID, newName string) error {
  194. err := ctx.Table("Package").Where("PackageID = ?", packageID).Update("BucketID", newBktID).Update("Name", newName).Error
  195. return err
  196. }
  197. type AddAccessStatEntry struct {
  198. ObjectID jcstypes.ObjectID `json:"objectID"`
  199. PackageID jcstypes.PackageID `json:"packageID"`
  200. UserSpaceID jcstypes.UserSpaceID `json:"userSpaceID"`
  201. Counter float64 `json:"counter"`
  202. }
  203. func (db *PackageDB) BatchAddPackageAccessStat(ctx SQLContext, entries []AddAccessStatEntry) error {
  204. pkgIDs := make(map[jcstypes.PackageID]bool)
  205. objIDs := make(map[jcstypes.ObjectID]bool)
  206. for _, e := range entries {
  207. pkgIDs[e.PackageID] = true
  208. objIDs[e.ObjectID] = true
  209. }
  210. avaiPkgIDs, err := db.Package().BatchTestPackageID(ctx, lo.Keys(pkgIDs))
  211. if err != nil {
  212. return fmt.Errorf("batch test package id: %w", err)
  213. }
  214. avaiObjIDs, err := db.Object().BatchTestObjectID(ctx, lo.Keys(objIDs))
  215. if err != nil {
  216. return fmt.Errorf("batch test object id: %w", err)
  217. }
  218. var willAdds []AddAccessStatEntry
  219. for _, e := range entries {
  220. if avaiPkgIDs[e.PackageID] && avaiObjIDs[e.ObjectID] {
  221. willAdds = append(willAdds, e)
  222. }
  223. }
  224. if len(willAdds) > 0 {
  225. err := db.PackageAccessStat().BatchAddCounter(ctx, willAdds)
  226. if err != nil {
  227. return fmt.Errorf("batch add package access stat counter: %w", err)
  228. }
  229. err = db.ObjectAccessStat().BatchAddCounter(ctx, willAdds)
  230. if err != nil {
  231. return fmt.Errorf("batch add object access stat counter: %w", err)
  232. }
  233. }
  234. return nil
  235. }
  236. // 尝试创建指定名称的Bucket和Package,如果Bucket不存在,则创建Bucket,如果Package已存在,则直接返回已有的Package
  237. func (db *PackageDB) TryCreateAll(ctx SQLContext, bktName string, pkgName string) (jcstypes.Package, error) {
  238. bkt, err := db.Bucket().GetByName(ctx, bktName)
  239. if err == gorm.ErrRecordNotFound {
  240. bkt, err = db.Bucket().Create(ctx, bktName, time.Now())
  241. if err != nil {
  242. return jcstypes.Package{}, fmt.Errorf("create bucket: %w", err)
  243. }
  244. } else if err != nil {
  245. return jcstypes.Package{}, fmt.Errorf("get bucket by name: %w", err)
  246. }
  247. pkg, err := db.GetByName(ctx, bkt.BucketID, pkgName)
  248. if err == nil {
  249. return pkg, nil
  250. }
  251. if err != gorm.ErrRecordNotFound {
  252. return jcstypes.Package{}, fmt.Errorf("get package by name: %w", err)
  253. }
  254. pkg, err = db.Create(ctx, bkt.BucketID, pkgName, time.Now())
  255. if err != nil {
  256. return jcstypes.Package{}, fmt.Errorf("create package: %w", err)
  257. }
  258. return pkg, nil
  259. }

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