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

11 months ago
11 months ago
2 years ago
11 months ago
11 months ago
11 months ago
1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. package mq
  2. import (
  3. "errors"
  4. "fmt"
  5. "sort"
  6. stgmod "gitlink.org.cn/cloudream/storage/common/models"
  7. "gitlink.org.cn/cloudream/storage/common/pkgs/db2"
  8. "gorm.io/gorm"
  9. "gitlink.org.cn/cloudream/common/consts/errorcode"
  10. "gitlink.org.cn/cloudream/common/pkgs/logger"
  11. "gitlink.org.cn/cloudream/common/pkgs/mq"
  12. cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
  13. coormq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/coordinator"
  14. )
  15. func (svc *Service) GetPackage(msg *coormq.GetPackage) (*coormq.GetPackageResp, *mq.CodeMessage) {
  16. pkg, err := svc.db2.Package().GetByID(svc.db2.DefCtx(), msg.PackageID)
  17. if err != nil {
  18. logger.WithField("PackageID", msg.PackageID).
  19. Warnf("get package: %s", err.Error())
  20. if errors.Is(err, gorm.ErrRecordNotFound) {
  21. return nil, mq.Failed(errorcode.DataNotFound, "package not found")
  22. }
  23. return nil, mq.Failed(errorcode.OperationFailed, "get package failed")
  24. }
  25. return mq.ReplyOK(coormq.NewGetPackageResp(pkg))
  26. }
  27. func (svc *Service) GetPackageByName(msg *coormq.GetPackageByName) (*coormq.GetPackageByNameResp, *mq.CodeMessage) {
  28. pkg, err := svc.db2.Package().GetUserPackageByName(svc.db2.DefCtx(), msg.UserID, msg.BucketName, msg.PackageName)
  29. if err != nil {
  30. logger.WithField("UserID", msg.UserID).
  31. WithField("BucketName", msg.BucketName).
  32. WithField("PackageName", msg.PackageName).
  33. Warnf("get package by name: %s", err.Error())
  34. if errors.Is(err, gorm.ErrRecordNotFound) {
  35. return nil, mq.Failed(errorcode.DataNotFound, "package not found")
  36. }
  37. return nil, mq.Failed(errorcode.OperationFailed, "get package by name failed")
  38. }
  39. return mq.ReplyOK(coormq.NewGetPackageByNameResp(pkg))
  40. }
  41. func (svc *Service) CreatePackage(msg *coormq.CreatePackage) (*coormq.CreatePackageResp, *mq.CodeMessage) {
  42. var pkg cdssdk.Package
  43. err := svc.db2.DoTx(func(tx db2.SQLContext) error {
  44. var err error
  45. isAvai, _ := svc.db2.Bucket().IsAvailable(tx, msg.BucketID, msg.UserID)
  46. if !isAvai {
  47. return fmt.Errorf("bucket is not avaiable to the user")
  48. }
  49. pkg, err = svc.db2.Package().Create(tx, msg.BucketID, msg.Name)
  50. if err != nil {
  51. return fmt.Errorf("creating package: %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. if errors.Is(err, gorm.ErrDuplicatedKey) {
  60. return nil, mq.Failed(errorcode.DataExists, "package already exists")
  61. }
  62. return nil, mq.Failed(errorcode.OperationFailed, err.Error())
  63. }
  64. svc.evtPub.Publish(&stgmod.BodyNewPackage{
  65. Info: pkg,
  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. ad, err := svc.db2.Object().BatchAdd(tx, msg.PackageID, msg.Adds)
  77. if err != nil {
  78. return fmt.Errorf("adding objects: %w", err)
  79. }
  80. added = ad
  81. return nil
  82. })
  83. if err != nil {
  84. logger.WithField("PackageID", msg.PackageID).Warn(err.Error())
  85. return nil, mq.Failed(errorcode.OperationFailed, "update package failed")
  86. }
  87. addedMp := make(map[string]cdssdk.Object)
  88. for _, obj := range added {
  89. addedMp[obj.Path] = obj
  90. }
  91. for _, add := range msg.Adds {
  92. var blks []stgmod.BlockDistributionObjectInfo
  93. for _, stgID := range add.StorageIDs {
  94. blks = append(blks, stgmod.BlockDistributionObjectInfo{
  95. BlockType: stgmod.BlockTypeRaw,
  96. StorageID: stgID,
  97. })
  98. }
  99. svc.evtPub.Publish(&stgmod.BodyNewOrUpdateObject{
  100. Info: addedMp[add.Path],
  101. BlockDistribution: blks,
  102. })
  103. }
  104. return mq.ReplyOK(coormq.NewUpdatePackageResp(added))
  105. }
  106. func (svc *Service) DeletePackage(msg *coormq.DeletePackage) (*coormq.DeletePackageResp, *mq.CodeMessage) {
  107. err := svc.db2.DoTx(func(tx db2.SQLContext) error {
  108. isAvai, _ := svc.db2.Package().IsAvailable(tx, msg.UserID, msg.PackageID)
  109. if !isAvai {
  110. return fmt.Errorf("package is not available to the user")
  111. }
  112. err := svc.db2.Package().DeleteComplete(tx, msg.PackageID)
  113. if err != nil {
  114. return fmt.Errorf("deleting package: %w", err)
  115. }
  116. return nil
  117. })
  118. if err != nil {
  119. logger.WithField("UserID", msg.UserID).
  120. WithField("PackageID", msg.PackageID).
  121. Warnf(err.Error())
  122. return nil, mq.Failed(errorcode.OperationFailed, "delete package failed")
  123. }
  124. svc.evtPub.Publish(&stgmod.BodyPackageDeleted{
  125. PackageID: msg.PackageID,
  126. })
  127. return mq.ReplyOK(coormq.NewDeletePackageResp())
  128. }
  129. func (svc *Service) ClonePackage(msg *coormq.ClonePackage) (*coormq.ClonePackageResp, *mq.CodeMessage) {
  130. var pkg cdssdk.Package
  131. err := svc.db2.DoTx(func(tx db2.SQLContext) error {
  132. var err error
  133. isAvai, _ := svc.db2.Bucket().IsAvailable(tx, msg.BucketID, msg.UserID)
  134. if !isAvai {
  135. return fmt.Errorf("bucket is not avaiable to the user")
  136. }
  137. pkg, err = svc.db2.Package().Create(tx, msg.BucketID, msg.Name)
  138. if err != nil {
  139. return fmt.Errorf("creating package: %w", err)
  140. }
  141. objs, err := svc.db2.Object().GetPackageObjects(tx, msg.PackageID)
  142. if err != nil {
  143. return fmt.Errorf("getting package objects: %w", err)
  144. }
  145. objBlks, err := svc.db2.ObjectBlock().GetInPackageID(tx, msg.PackageID)
  146. if err != nil {
  147. return fmt.Errorf("getting object blocks: %w", err)
  148. }
  149. clonedObjs := make([]cdssdk.Object, len(objs))
  150. for i, obj := range objs {
  151. clonedObjs[i] = obj
  152. clonedObjs[i].ObjectID = 0
  153. clonedObjs[i].PackageID = pkg.PackageID
  154. }
  155. err = svc.db2.Object().BatchCreate(tx, &clonedObjs)
  156. if err != nil {
  157. return fmt.Errorf("batch creating objects: %w", err)
  158. }
  159. oldToNew := make(map[cdssdk.ObjectID]cdssdk.ObjectID)
  160. for i, obj := range clonedObjs {
  161. oldToNew[objs[i].ObjectID] = obj.ObjectID
  162. }
  163. clonedBlks := make([]stgmod.ObjectBlock, len(objBlks))
  164. for i, blk := range objBlks {
  165. clonedBlks[i] = blk
  166. clonedBlks[i].ObjectID = oldToNew[blk.ObjectID]
  167. }
  168. err = svc.db2.ObjectBlock().BatchCreate(tx, clonedBlks)
  169. if err != nil {
  170. return fmt.Errorf("batch creating object blocks: %w", err)
  171. }
  172. return nil
  173. })
  174. if err != nil {
  175. if errors.Is(err, gorm.ErrDuplicatedKey) {
  176. return nil, mq.Failed(errorcode.DataExists, "package already exists")
  177. }
  178. return nil, mq.Failed(errorcode.OperationFailed, err.Error())
  179. }
  180. svc.evtPub.Publish(&stgmod.BodyPackageCloned{
  181. SourcePackageID: msg.PackageID,
  182. NewPackage: pkg,
  183. })
  184. return mq.ReplyOK(coormq.RespClonePackage(pkg))
  185. }
  186. func (svc *Service) GetPackageCachedStorages(msg *coormq.GetPackageCachedStorages) (*coormq.GetPackageCachedStoragesResp, *mq.CodeMessage) {
  187. isAva, err := svc.db2.Package().IsAvailable(svc.db2.DefCtx(), msg.UserID, msg.PackageID)
  188. if err != nil {
  189. logger.WithField("UserID", msg.UserID).
  190. WithField("PackageID", msg.PackageID).
  191. Warnf("check package available failed, err: %s", err.Error())
  192. return nil, mq.Failed(errorcode.OperationFailed, "check package available failed")
  193. }
  194. if !isAva {
  195. logger.WithField("UserID", msg.UserID).
  196. WithField("PackageID", msg.PackageID).
  197. Warnf("package is not available to the user")
  198. return nil, mq.Failed(errorcode.OperationFailed, "package is not available to the user")
  199. }
  200. // 这个函数只是统计哪些节点缓存了Package中的数据,不需要多么精确,所以可以不用事务
  201. objDetails, err := svc.db2.Object().GetPackageObjectDetails(svc.db2.DefCtx(), msg.PackageID)
  202. if err != nil {
  203. logger.WithField("PackageID", msg.PackageID).
  204. Warnf("get package block details: %s", err.Error())
  205. return nil, mq.Failed(errorcode.OperationFailed, "get package block details failed")
  206. }
  207. var packageSize int64
  208. stgInfoMap := make(map[cdssdk.StorageID]*cdssdk.StoragePackageCachingInfo)
  209. for _, obj := range objDetails {
  210. // 只要存了文件的一个块,就认为此节点存了整个文件
  211. for _, block := range obj.Blocks {
  212. info, ok := stgInfoMap[block.StorageID]
  213. if !ok {
  214. info = &cdssdk.StoragePackageCachingInfo{
  215. StorageID: block.StorageID,
  216. }
  217. stgInfoMap[block.StorageID] = info
  218. }
  219. info.FileSize += obj.Object.Size
  220. info.ObjectCount++
  221. }
  222. }
  223. var stgInfos []cdssdk.StoragePackageCachingInfo
  224. for _, stgInfo := range stgInfoMap {
  225. stgInfos = append(stgInfos, *stgInfo)
  226. }
  227. sort.Slice(stgInfos, func(i, j int) bool {
  228. return stgInfos[i].StorageID < stgInfos[j].StorageID
  229. })
  230. return mq.ReplyOK(coormq.ReqGetPackageCachedStoragesResp(stgInfos, packageSize))
  231. }
  232. func (svc *Service) AddAccessStat(msg *coormq.AddAccessStat) {
  233. pkgIDs := make([]cdssdk.PackageID, len(msg.Entries))
  234. objIDs := make([]cdssdk.ObjectID, len(msg.Entries))
  235. for i, e := range msg.Entries {
  236. pkgIDs[i] = e.PackageID
  237. objIDs[i] = e.ObjectID
  238. }
  239. err := svc.db2.DoTx(func(tx db2.SQLContext) error {
  240. avaiPkgIDs, err := svc.db2.Package().BatchTestPackageID(tx, pkgIDs)
  241. if err != nil {
  242. return fmt.Errorf("batch test package id: %w", err)
  243. }
  244. avaiObjIDs, err := svc.db2.Object().BatchTestObjectID(tx, objIDs)
  245. if err != nil {
  246. return fmt.Errorf("batch test object id: %w", err)
  247. }
  248. var willAdds []coormq.AddAccessStatEntry
  249. for _, e := range msg.Entries {
  250. if avaiPkgIDs[e.PackageID] && avaiObjIDs[e.ObjectID] {
  251. willAdds = append(willAdds, e)
  252. }
  253. }
  254. if len(willAdds) > 0 {
  255. err := svc.db2.PackageAccessStat().BatchAddCounter(tx, willAdds)
  256. if err != nil {
  257. return fmt.Errorf("batch add package access stat counter: %w", err)
  258. }
  259. err = svc.db2.ObjectAccessStat().BatchAddCounter(tx, willAdds)
  260. if err != nil {
  261. return fmt.Errorf("batch add object access stat counter: %w", err)
  262. }
  263. }
  264. return nil
  265. })
  266. if err != nil {
  267. logger.Warn(err.Error())
  268. }
  269. }

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