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

11 months ago
11 months ago
2 years ago
11 months ago
11 months ago
11 months ago
1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. package mq
  2. import (
  3. "errors"
  4. "fmt"
  5. "sort"
  6. "gitlink.org.cn/cloudream/storage/common/pkgs/db2"
  7. "gorm.io/gorm"
  8. "gitlink.org.cn/cloudream/common/consts/errorcode"
  9. "gitlink.org.cn/cloudream/common/pkgs/logger"
  10. "gitlink.org.cn/cloudream/common/pkgs/mq"
  11. cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
  12. coormq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/coordinator"
  13. )
  14. func (svc *Service) GetPackage(msg *coormq.GetPackage) (*coormq.GetPackageResp, *mq.CodeMessage) {
  15. pkg, err := svc.db2.Package().GetByID(svc.db2.DefCtx(), msg.PackageID)
  16. if err != nil {
  17. logger.WithField("PackageID", msg.PackageID).
  18. Warnf("get package: %s", err.Error())
  19. if errors.Is(err, gorm.ErrRecordNotFound) {
  20. return nil, mq.Failed(errorcode.DataNotFound, "package not found")
  21. }
  22. return nil, mq.Failed(errorcode.OperationFailed, "get package failed")
  23. }
  24. return mq.ReplyOK(coormq.NewGetPackageResp(pkg))
  25. }
  26. func (svc *Service) GetPackageByName(msg *coormq.GetPackageByName) (*coormq.GetPackageByNameResp, *mq.CodeMessage) {
  27. pkg, err := svc.db2.Package().GetUserPackageByName(svc.db2.DefCtx(), msg.UserID, msg.BucketName, msg.PackageName)
  28. if err != nil {
  29. logger.WithField("UserID", msg.UserID).
  30. WithField("BucketName", msg.BucketName).
  31. WithField("PackageName", msg.PackageName).
  32. Warnf("get package by name: %s", err.Error())
  33. if errors.Is(err, gorm.ErrRecordNotFound) {
  34. return nil, mq.Failed(errorcode.DataNotFound, "package not found")
  35. }
  36. return nil, mq.Failed(errorcode.OperationFailed, "get package by name failed")
  37. }
  38. return mq.ReplyOK(coormq.NewGetPackageByNameResp(pkg))
  39. }
  40. func (svc *Service) CreatePackage(msg *coormq.CreatePackage) (*coormq.CreatePackageResp, *mq.CodeMessage) {
  41. var pkg cdssdk.Package
  42. err := svc.db2.DoTx(func(tx db2.SQLContext) error {
  43. var err error
  44. isAvai, _ := svc.db2.Bucket().IsAvailable(tx, msg.BucketID, msg.UserID)
  45. if !isAvai {
  46. return fmt.Errorf("bucket is not avaiable to the user")
  47. }
  48. pkgID, err := svc.db2.Package().Create(tx, msg.BucketID, msg.Name)
  49. if err != nil {
  50. return fmt.Errorf("creating package: %w", err)
  51. }
  52. pkg, err = svc.db2.Package().GetByID(tx, pkgID)
  53. if err != nil {
  54. return fmt.Errorf("getting package by id: %w", err)
  55. }
  56. return nil
  57. })
  58. if err != nil {
  59. logger.WithField("BucketID", msg.BucketID).
  60. WithField("Name", msg.Name).
  61. Warn(err.Error())
  62. if errors.Is(err, gorm.ErrDuplicatedKey) {
  63. return nil, mq.Failed(errorcode.DataExists, "package already exists")
  64. }
  65. return nil, mq.Failed(errorcode.OperationFailed, err.Error())
  66. }
  67. return mq.ReplyOK(coormq.NewCreatePackageResp(pkg))
  68. }
  69. func (svc *Service) UpdatePackage(msg *coormq.UpdatePackage) (*coormq.UpdatePackageResp, *mq.CodeMessage) {
  70. var added []cdssdk.Object
  71. err := svc.db2.DoTx(func(tx db2.SQLContext) error {
  72. _, err := svc.db2.Package().GetByID(tx, msg.PackageID)
  73. if err != nil {
  74. return fmt.Errorf("getting package by id: %w", err)
  75. }
  76. // 先执行删除操作
  77. if len(msg.Deletes) > 0 {
  78. if err := svc.db2.Object().BatchDelete(tx, msg.Deletes); err != nil {
  79. return fmt.Errorf("deleting objects: %w", err)
  80. }
  81. }
  82. // 再执行添加操作
  83. if len(msg.Adds) > 0 {
  84. ad, err := svc.db2.Object().BatchAdd(tx, msg.PackageID, msg.Adds)
  85. if err != nil {
  86. return fmt.Errorf("adding objects: %w", err)
  87. }
  88. added = ad
  89. }
  90. return nil
  91. })
  92. if err != nil {
  93. logger.WithField("PackageID", msg.PackageID).Warn(err.Error())
  94. return nil, mq.Failed(errorcode.OperationFailed, "update package failed")
  95. }
  96. return mq.ReplyOK(coormq.NewUpdatePackageResp(added))
  97. }
  98. func (svc *Service) DeletePackage(msg *coormq.DeletePackage) (*coormq.DeletePackageResp, *mq.CodeMessage) {
  99. err := svc.db2.DoTx(func(tx db2.SQLContext) error {
  100. isAvai, _ := svc.db2.Package().IsAvailable(tx, msg.UserID, msg.PackageID)
  101. if !isAvai {
  102. return fmt.Errorf("package is not available to the user")
  103. }
  104. err := svc.db2.Package().SoftDelete(tx, msg.PackageID)
  105. if err != nil {
  106. return fmt.Errorf("soft delete package: %w", err)
  107. }
  108. err = svc.db2.Package().DeleteUnused(tx, msg.PackageID)
  109. if err != nil {
  110. logger.WithField("UserID", msg.UserID).
  111. WithField("PackageID", msg.PackageID).
  112. Warnf("deleting unused package: %w", err.Error())
  113. }
  114. err = svc.db2.PackageAccessStat().DeleteByPackageID(tx, msg.PackageID)
  115. if err != nil {
  116. logger.WithField("UserID", msg.UserID).
  117. WithField("PackageID", msg.PackageID).
  118. Warnf("deleting package access stat: %w", err.Error())
  119. }
  120. return nil
  121. })
  122. if err != nil {
  123. logger.WithField("UserID", msg.UserID).
  124. WithField("PackageID", msg.PackageID).
  125. Warnf(err.Error())
  126. return nil, mq.Failed(errorcode.OperationFailed, "delete package failed")
  127. }
  128. return mq.ReplyOK(coormq.NewDeletePackageResp())
  129. }
  130. func (svc *Service) GetPackageCachedStorages(msg *coormq.GetPackageCachedStorages) (*coormq.GetPackageCachedStoragesResp, *mq.CodeMessage) {
  131. isAva, err := svc.db2.Package().IsAvailable(svc.db2.DefCtx(), msg.UserID, msg.PackageID)
  132. if err != nil {
  133. logger.WithField("UserID", msg.UserID).
  134. WithField("PackageID", msg.PackageID).
  135. Warnf("check package available failed, err: %s", err.Error())
  136. return nil, mq.Failed(errorcode.OperationFailed, "check package available failed")
  137. }
  138. if !isAva {
  139. logger.WithField("UserID", msg.UserID).
  140. WithField("PackageID", msg.PackageID).
  141. Warnf("package is not available to the user")
  142. return nil, mq.Failed(errorcode.OperationFailed, "package is not available to the user")
  143. }
  144. // 这个函数只是统计哪些节点缓存了Package中的数据,不需要多么精确,所以可以不用事务
  145. objDetails, err := svc.db2.Object().GetPackageObjectDetails(svc.db2.DefCtx(), msg.PackageID)
  146. if err != nil {
  147. logger.WithField("PackageID", msg.PackageID).
  148. Warnf("get package block details: %s", err.Error())
  149. return nil, mq.Failed(errorcode.OperationFailed, "get package block details failed")
  150. }
  151. var packageSize int64
  152. stgInfoMap := make(map[cdssdk.StorageID]*cdssdk.StoragePackageCachingInfo)
  153. for _, obj := range objDetails {
  154. // 只要存了文件的一个块,就认为此节点存了整个文件
  155. for _, block := range obj.Blocks {
  156. info, ok := stgInfoMap[block.StorageID]
  157. if !ok {
  158. info = &cdssdk.StoragePackageCachingInfo{
  159. StorageID: block.StorageID,
  160. }
  161. stgInfoMap[block.StorageID] = info
  162. }
  163. info.FileSize += obj.Object.Size
  164. info.ObjectCount++
  165. }
  166. }
  167. var stgInfos []cdssdk.StoragePackageCachingInfo
  168. for _, stgInfo := range stgInfoMap {
  169. stgInfos = append(stgInfos, *stgInfo)
  170. }
  171. sort.Slice(stgInfos, func(i, j int) bool {
  172. return stgInfos[i].StorageID < stgInfos[j].StorageID
  173. })
  174. return mq.ReplyOK(coormq.ReqGetPackageCachedStoragesResp(stgInfos, packageSize))
  175. }
  176. func (svc *Service) GetPackageLoadedStorages(msg *coormq.GetPackageLoadedStorages) (*coormq.GetPackageLoadedStoragesResp, *mq.CodeMessage) {
  177. storages, err := svc.db2.StoragePackage().FindPackageStorages(svc.db2.DefCtx(), msg.PackageID)
  178. if err != nil {
  179. logger.WithField("PackageID", msg.PackageID).
  180. Warnf("get storages by packageID failed, err: %s", err.Error())
  181. return nil, mq.Failed(errorcode.OperationFailed, "get storages by packageID failed")
  182. }
  183. uniqueStgIDs := make(map[cdssdk.StorageID]bool)
  184. var stgIDs []cdssdk.StorageID
  185. for _, stg := range storages {
  186. if !uniqueStgIDs[stg.StorageID] {
  187. uniqueStgIDs[stg.StorageID] = true
  188. stgIDs = append(stgIDs, stg.StorageID)
  189. }
  190. }
  191. return mq.ReplyOK(coormq.NewGetPackageLoadedStoragesResp(stgIDs))
  192. }
  193. func (svc *Service) AddAccessStat(msg *coormq.AddAccessStat) {
  194. pkgIDs := make([]cdssdk.PackageID, len(msg.Entries))
  195. objIDs := make([]cdssdk.ObjectID, len(msg.Entries))
  196. for i, e := range msg.Entries {
  197. pkgIDs[i] = e.PackageID
  198. objIDs[i] = e.ObjectID
  199. }
  200. err := svc.db2.DoTx(func(tx db2.SQLContext) error {
  201. avaiPkgIDs, err := svc.db2.Package().BatchTestPackageID(tx, pkgIDs)
  202. if err != nil {
  203. return fmt.Errorf("batch test package id: %w", err)
  204. }
  205. avaiObjIDs, err := svc.db2.Object().BatchTestObjectID(tx, objIDs)
  206. if err != nil {
  207. return fmt.Errorf("batch test object id: %w", err)
  208. }
  209. var willAdds []coormq.AddAccessStatEntry
  210. for _, e := range msg.Entries {
  211. if avaiPkgIDs[e.PackageID] && avaiObjIDs[e.ObjectID] {
  212. willAdds = append(willAdds, e)
  213. }
  214. }
  215. if len(willAdds) > 0 {
  216. err := svc.db2.PackageAccessStat().BatchAddCounter(tx, willAdds)
  217. if err != nil {
  218. return fmt.Errorf("batch add package access stat counter: %w", err)
  219. }
  220. err = svc.db2.ObjectAccessStat().BatchAddCounter(tx, willAdds)
  221. if err != nil {
  222. return fmt.Errorf("batch add object access stat counter: %w", err)
  223. }
  224. }
  225. return nil
  226. })
  227. if err != nil {
  228. logger.Warn(err.Error())
  229. }
  230. }

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