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

2 years ago
2 years ago
2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. package mq
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "sort"
  6. "github.com/jmoiron/sqlx"
  7. "gitlink.org.cn/cloudream/common/consts/errorcode"
  8. "gitlink.org.cn/cloudream/common/pkgs/logger"
  9. "gitlink.org.cn/cloudream/common/pkgs/mq"
  10. cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
  11. "gitlink.org.cn/cloudream/storage/common/pkgs/db/model"
  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.db.Package().GetByID(svc.db.SQLCtx(), msg.PackageID)
  16. if err != nil {
  17. logger.WithField("PackageID", msg.PackageID).
  18. Warnf("get package: %s", err.Error())
  19. return nil, mq.Failed(errorcode.OperationFailed, "get package failed")
  20. }
  21. return mq.ReplyOK(coormq.NewGetPackageResp(pkg))
  22. }
  23. func (svc *Service) GetPackageByName(msg *coormq.GetPackageByName) (*coormq.GetPackageByNameResp, *mq.CodeMessage) {
  24. pkg, err := svc.db.Package().GetUserPackageByName(svc.db.SQLCtx(), msg.UserID, msg.BucketName, msg.PackageName)
  25. if err != nil {
  26. logger.WithField("UserID", msg.UserID).
  27. WithField("BucketName", msg.BucketName).
  28. WithField("PackageName", msg.PackageName).
  29. Warnf("get package by name: %s", err.Error())
  30. if err == sql.ErrNoRows {
  31. return nil, mq.Failed(errorcode.DataNotFound, "package not found")
  32. }
  33. return nil, mq.Failed(errorcode.OperationFailed, "get package by name failed")
  34. }
  35. return mq.ReplyOK(coormq.NewGetPackageByNameResp(pkg))
  36. }
  37. func (svc *Service) CreatePackage(msg *coormq.CreatePackage) (*coormq.CreatePackageResp, *mq.CodeMessage) {
  38. var pkg cdssdk.Package
  39. err := svc.db.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
  40. var err error
  41. isAvai, _ := svc.db.Bucket().IsAvailable(tx, msg.BucketID, msg.UserID)
  42. if !isAvai {
  43. return fmt.Errorf("bucket is not avaiable to the user")
  44. }
  45. pkgID, err := svc.db.Package().Create(tx, msg.BucketID, msg.Name)
  46. if err != nil {
  47. return fmt.Errorf("creating package: %w", err)
  48. }
  49. pkg, err = svc.db.Package().GetByID(tx, pkgID)
  50. if err != nil {
  51. return fmt.Errorf("getting package by id: %w", err)
  52. }
  53. return nil
  54. })
  55. if err != nil {
  56. logger.WithField("BucketID", msg.BucketID).
  57. WithField("Name", msg.Name).
  58. Warn(err.Error())
  59. return nil, mq.Failed(errorcode.OperationFailed, "creating package failed")
  60. }
  61. return mq.ReplyOK(coormq.NewCreatePackageResp(pkg))
  62. }
  63. func (svc *Service) UpdatePackage(msg *coormq.UpdatePackage) (*coormq.UpdatePackageResp, *mq.CodeMessage) {
  64. var added []cdssdk.Object
  65. err := svc.db.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
  66. _, err := svc.db.Package().GetByID(tx, msg.PackageID)
  67. if err != nil {
  68. return fmt.Errorf("getting package by id: %w", err)
  69. }
  70. // 先执行删除操作
  71. if len(msg.Deletes) > 0 {
  72. if err := svc.db.Object().BatchDelete(tx, msg.Deletes); err != nil {
  73. return fmt.Errorf("deleting objects: %w", err)
  74. }
  75. }
  76. // 再执行添加操作
  77. if len(msg.Adds) > 0 {
  78. ad, err := svc.db.Object().BatchAdd(tx, msg.PackageID, msg.Adds)
  79. if err != nil {
  80. return fmt.Errorf("adding objects: %w", err)
  81. }
  82. added = ad
  83. }
  84. return nil
  85. })
  86. if err != nil {
  87. logger.WithField("PackageID", msg.PackageID).Warn(err.Error())
  88. return nil, mq.Failed(errorcode.OperationFailed, "update package failed")
  89. }
  90. return mq.ReplyOK(coormq.NewUpdatePackageResp(added))
  91. }
  92. func (svc *Service) DeletePackage(msg *coormq.DeletePackage) (*coormq.DeletePackageResp, *mq.CodeMessage) {
  93. err := svc.db.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
  94. isAvai, _ := svc.db.Package().IsAvailable(tx, msg.UserID, msg.PackageID)
  95. if !isAvai {
  96. return fmt.Errorf("package is not available to the user")
  97. }
  98. err := svc.db.Package().SoftDelete(tx, msg.PackageID)
  99. if err != nil {
  100. return fmt.Errorf("soft delete package: %w", err)
  101. }
  102. err = svc.db.Package().DeleteUnused(tx, msg.PackageID)
  103. if err != nil {
  104. logger.WithField("UserID", msg.UserID).
  105. WithField("PackageID", msg.PackageID).
  106. Warnf("deleting unused package: %w", err.Error())
  107. }
  108. return nil
  109. })
  110. if err != nil {
  111. logger.WithField("UserID", msg.UserID).
  112. WithField("PackageID", msg.PackageID).
  113. Warnf(err.Error())
  114. return nil, mq.Failed(errorcode.OperationFailed, "delete package failed")
  115. }
  116. return mq.ReplyOK(coormq.NewDeletePackageResp())
  117. }
  118. func (svc *Service) GetPackageCachedNodes(msg *coormq.GetPackageCachedNodes) (*coormq.GetPackageCachedNodesResp, *mq.CodeMessage) {
  119. isAva, err := svc.db.Package().IsAvailable(svc.db.SQLCtx(), msg.UserID, msg.PackageID)
  120. if err != nil {
  121. logger.WithField("UserID", msg.UserID).
  122. WithField("PackageID", msg.PackageID).
  123. Warnf("check package available failed, err: %s", err.Error())
  124. return nil, mq.Failed(errorcode.OperationFailed, "check package available failed")
  125. }
  126. if !isAva {
  127. logger.WithField("UserID", msg.UserID).
  128. WithField("PackageID", msg.PackageID).
  129. Warnf("package is not available to the user")
  130. return nil, mq.Failed(errorcode.OperationFailed, "package is not available to the user")
  131. }
  132. // 这个函数只是统计哪些节点缓存了Package中的数据,不需要多么精确,所以可以不用事务
  133. objDetails, err := svc.db.Object().GetPackageObjectDetails(svc.db.SQLCtx(), msg.PackageID)
  134. if err != nil {
  135. logger.WithField("PackageID", msg.PackageID).
  136. Warnf("get package block details: %s", err.Error())
  137. return nil, mq.Failed(errorcode.OperationFailed, "get package block details failed")
  138. }
  139. var packageSize int64
  140. nodeInfoMap := make(map[cdssdk.NodeID]*cdssdk.NodePackageCachingInfo)
  141. for _, obj := range objDetails {
  142. // 只要存了文件的一个块,就认为此节点存了整个文件
  143. for _, block := range obj.Blocks {
  144. info, ok := nodeInfoMap[block.NodeID]
  145. if !ok {
  146. info = &cdssdk.NodePackageCachingInfo{
  147. NodeID: block.NodeID,
  148. }
  149. nodeInfoMap[block.NodeID] = info
  150. }
  151. info.FileSize += obj.Object.Size
  152. info.ObjectCount++
  153. }
  154. }
  155. var nodeInfos []cdssdk.NodePackageCachingInfo
  156. for _, nodeInfo := range nodeInfoMap {
  157. nodeInfos = append(nodeInfos, *nodeInfo)
  158. }
  159. sort.Slice(nodeInfos, func(i, j int) bool {
  160. return nodeInfos[i].NodeID < nodeInfos[j].NodeID
  161. })
  162. return mq.ReplyOK(coormq.NewGetPackageCachedNodesResp(nodeInfos, packageSize))
  163. }
  164. func (svc *Service) GetPackageLoadedNodes(msg *coormq.GetPackageLoadedNodes) (*coormq.GetPackageLoadedNodesResp, *mq.CodeMessage) {
  165. storages, err := svc.db.StoragePackage().FindPackageStorages(svc.db.SQLCtx(), msg.PackageID)
  166. if err != nil {
  167. logger.WithField("PackageID", msg.PackageID).
  168. Warnf("get storages by packageID failed, err: %s", err.Error())
  169. return nil, mq.Failed(errorcode.OperationFailed, "get storages by packageID failed")
  170. }
  171. uniqueNodeIDs := make(map[cdssdk.NodeID]bool)
  172. var nodeIDs []cdssdk.NodeID
  173. for _, stg := range storages {
  174. if !uniqueNodeIDs[stg.NodeID] {
  175. uniqueNodeIDs[stg.NodeID] = true
  176. nodeIDs = append(nodeIDs, stg.NodeID)
  177. }
  178. }
  179. return mq.ReplyOK(coormq.NewGetPackageLoadedNodesResp(nodeIDs))
  180. }
  181. func (svc *Service) GetPackageLoadLogDetails(msg *coormq.GetPackageLoadLogDetails) (*coormq.GetPackageLoadLogDetailsResp, *mq.CodeMessage) {
  182. var logs []coormq.PackageLoadLogDetail
  183. rawLogs, err := svc.db.StoragePackageLog().GetByPackageID(svc.db.SQLCtx(), msg.PackageID)
  184. if err != nil {
  185. logger.WithField("PackageID", msg.PackageID).
  186. Warnf("getting storage package log: %s", err.Error())
  187. return nil, mq.Failed(errorcode.OperationFailed, "get storage package log failed")
  188. }
  189. stgs := make(map[cdssdk.StorageID]model.Storage)
  190. for _, raw := range rawLogs {
  191. stg, ok := stgs[raw.StorageID]
  192. if !ok {
  193. stg, err = svc.db.Storage().GetByID(svc.db.SQLCtx(), raw.StorageID)
  194. if err != nil {
  195. logger.WithField("PackageID", msg.PackageID).
  196. Warnf("getting storage: %s", err.Error())
  197. return nil, mq.Failed(errorcode.OperationFailed, "get storage failed")
  198. }
  199. stgs[raw.StorageID] = stg
  200. }
  201. logs = append(logs, coormq.PackageLoadLogDetail{
  202. Storage: stg,
  203. UserID: raw.UserID,
  204. CreateTime: raw.CreateTime,
  205. })
  206. }
  207. return mq.ReplyOK(coormq.RespGetPackageLoadLogDetails(logs))
  208. }

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