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

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

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