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

2 years ago
2 years ago
2 years ago
2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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. // GetPackage 通过PackageID获取包信息
  15. // 参数:
  16. // - msg: 包含需要获取的PackageID的请求消息
  17. // 返回值:
  18. // - *coormq.GetPackageResp: 获取包信息成功的响应
  19. // - *mq.CodeMessage: 错误时返回的错误信息
  20. func (svc *Service) GetPackage(msg *coormq.GetPackage) (*coormq.GetPackageResp, *mq.CodeMessage) {
  21. // 通过ID从数据库获取包信息
  22. pkg, err := svc.db.Package().GetByID(svc.db.SQLCtx(), msg.PackageID)
  23. if err != nil {
  24. // 记录日志并返回错误信息
  25. logger.WithField("PackageID", msg.PackageID).
  26. Warnf("get package: %s", err.Error())
  27. return nil, mq.Failed(errorcode.OperationFailed, "get package failed")
  28. }
  29. // 返回成功响应
  30. return mq.ReplyOK(coormq.NewGetPackageResp(pkg))
  31. }
  32. func (svc *Service) GetPackageByName(msg *coormq.GetPackageByName) (*coormq.GetPackageByNameResp, *mq.CodeMessage) {
  33. pkg, err := svc.db.Package().GetUserPackageByName(svc.db.SQLCtx(), msg.UserID, msg.BucketName, msg.PackageName)
  34. if err != nil {
  35. logger.WithField("UserID", msg.UserID).
  36. WithField("BucketName", msg.BucketName).
  37. WithField("PackageName", msg.PackageName).
  38. Warnf("get package by name: %s", err.Error())
  39. return nil, mq.Failed(errorcode.OperationFailed, "get package by name failed")
  40. }
  41. return mq.ReplyOK(coormq.NewGetPackageByNameResp(pkg))
  42. }
  43. func (svc *Service) CreatePackage(msg *coormq.CreatePackage) (*coormq.CreatePackageResp, *mq.CodeMessage) {
  44. var pkg cdssdk.Package
  45. err := svc.db.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
  46. var err error
  47. // 检查桶是否可用
  48. isAvai, _ := svc.db.Bucket().IsAvailable(tx, msg.BucketID, msg.UserID)
  49. if !isAvai {
  50. return fmt.Errorf("bucket is not avaiable to the user")
  51. }
  52. pkgID, err := svc.db.Package().Create(tx, msg.BucketID, msg.Name)
  53. if err != nil {
  54. return fmt.Errorf("creating package: %w", err)
  55. }
  56. pkg, err = svc.db.Package().GetByID(tx, pkgID)
  57. if err != nil {
  58. return fmt.Errorf("getting package by id: %w", err)
  59. }
  60. return nil
  61. })
  62. if err != nil {
  63. // 记录日志并返回错误信息
  64. logger.WithField("BucketID", msg.BucketID).
  65. WithField("Name", msg.Name).
  66. Warn(err.Error())
  67. return nil, mq.Failed(errorcode.OperationFailed, "creating package failed")
  68. }
  69. return mq.ReplyOK(coormq.NewCreatePackageResp(pkg))
  70. }
  71. // UpdatePackage 更新包的信息
  72. // 参数:
  73. // - msg: 包含更新包所需信息的请求消息
  74. // 返回值:
  75. // - *coormq.UpdatePackageResp: 更新包成功的响应
  76. // - *mq.CodeMessage: 错误时返回的错误信息
  77. func (svc *Service) UpdatePackage(msg *coormq.UpdatePackage) (*coormq.UpdatePackageResp, *mq.CodeMessage) {
  78. var added []cdssdk.Object
  79. err := svc.db.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
  80. // 验证包是否存在
  81. _, err := svc.db.Package().GetByID(tx, msg.PackageID)
  82. if err != nil {
  83. return fmt.Errorf("getting package by id: %w", err)
  84. }
  85. // 删除对象
  86. if len(msg.Deletes) > 0 {
  87. if err := svc.db.Object().BatchDelete(tx, msg.Deletes); err != nil {
  88. return fmt.Errorf("deleting objects: %w", err)
  89. }
  90. }
  91. // 添加对象
  92. if len(msg.Adds) > 0 {
  93. ad, err := svc.db.Object().BatchAdd(tx, msg.PackageID, msg.Adds)
  94. if err != nil {
  95. return fmt.Errorf("adding objects: %w", err)
  96. }
  97. added = ad
  98. }
  99. return nil
  100. })
  101. if err != nil {
  102. // 记录日志并返回错误信息
  103. logger.WithField("PackageID", msg.PackageID).Warn(err.Error())
  104. return nil, mq.Failed(errorcode.OperationFailed, "update package failed")
  105. }
  106. return mq.ReplyOK(coormq.NewUpdatePackageResp(added))
  107. }
  108. // DeletePackage 删除一个包
  109. // 参数:
  110. // - msg: 包含删除包所需信息的请求消息
  111. // 返回值:
  112. // - *coormq.DeletePackageResp: 删除包成功的响应
  113. // - *mq.CodeMessage: 错误时返回的错误信息
  114. func (svc *Service) DeletePackage(msg *coormq.DeletePackage) (*coormq.DeletePackageResp, *mq.CodeMessage) {
  115. // 在事务中执行删除包的操作
  116. err := svc.db.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
  117. // 验证包是否可用
  118. isAvai, _ := svc.db.Package().IsAvailable(tx, msg.UserID, msg.PackageID)
  119. if !isAvai {
  120. return fmt.Errorf("package is not available to the user")
  121. }
  122. // 软删除包
  123. err := svc.db.Package().SoftDelete(tx, msg.PackageID)
  124. if err != nil {
  125. return fmt.Errorf("soft delete package: %w", err)
  126. }
  127. // 删除未使用的包
  128. err = svc.db.Package().DeleteUnused(tx, msg.PackageID)
  129. if err != nil {
  130. logger.WithField("UserID", msg.UserID).
  131. WithField("PackageID", msg.PackageID).
  132. Warnf("deleting unused package: %w", err.Error())
  133. }
  134. return nil
  135. })
  136. if err != nil {
  137. // 记录日志并返回错误信息
  138. logger.WithField("UserID", msg.UserID).
  139. WithField("PackageID", msg.PackageID).
  140. Warnf(err.Error())
  141. return nil, mq.Failed(errorcode.OperationFailed, "delete package failed")
  142. }
  143. // 返回成功响应
  144. return mq.ReplyOK(coormq.NewDeletePackageResp())
  145. }
  146. // GetPackageCachedNodes 获取缓存了指定package的节点信息
  147. // 参数:
  148. // - msg: 包含packageID和用户ID的信息请求
  149. // 返回值:
  150. // - *coormq.GetPackageCachedNodesResp: 包含缓存了package数据的节点信息列表
  151. // - *mq.CodeMessage: 错误信息,如果操作失败
  152. func (svc *Service) GetPackageCachedNodes(msg *coormq.GetPackageCachedNodes) (*coormq.GetPackageCachedNodesResp, *mq.CodeMessage) {
  153. // 检查package是否可用
  154. isAva, err := svc.db.Package().IsAvailable(svc.db.SQLCtx(), msg.UserID, msg.PackageID)
  155. if err != nil {
  156. // 记录检查package可用性失败的日志
  157. logger.WithField("UserID", msg.UserID).
  158. WithField("PackageID", msg.PackageID).
  159. Warnf("check package available failed, err: %s", err.Error())
  160. return nil, mq.Failed(errorcode.OperationFailed, "check package available failed")
  161. }
  162. if !isAva {
  163. // 记录package不可用的日志
  164. logger.WithField("UserID", msg.UserID).
  165. WithField("PackageID", msg.PackageID).
  166. Warnf("package is not available to the user")
  167. return nil, mq.Failed(errorcode.OperationFailed, "package is not available to the user")
  168. }
  169. // 获取package中的对象详情,用于后续统计节点缓存信息
  170. objDetails, err := svc.db.Object().GetPackageObjectDetails(svc.db.SQLCtx(), msg.PackageID)
  171. if err != nil {
  172. // 记录获取package对象详情失败的日志
  173. logger.WithField("PackageID", msg.PackageID).
  174. Warnf("get package block details: %s", err.Error())
  175. return nil, mq.Failed(errorcode.OperationFailed, "get package block details failed")
  176. }
  177. // 统计各节点缓存的文件信息
  178. var packageSize int64
  179. nodeInfoMap := make(map[cdssdk.NodeID]*cdssdk.NodePackageCachingInfo)
  180. for _, obj := range objDetails {
  181. for _, block := range obj.Blocks {
  182. // 更新或创建节点缓存信息
  183. info, ok := nodeInfoMap[block.NodeID]
  184. if !ok {
  185. info = &cdssdk.NodePackageCachingInfo{
  186. NodeID: block.NodeID,
  187. }
  188. nodeInfoMap[block.NodeID] = info
  189. }
  190. // 更新节点的文件大小和对象计数
  191. info.FileSize += obj.Object.Size
  192. info.ObjectCount++
  193. }
  194. }
  195. // 整理节点缓存信息,并按节点ID排序
  196. var nodeInfos []cdssdk.NodePackageCachingInfo
  197. for _, nodeInfo := range nodeInfoMap {
  198. nodeInfos = append(nodeInfos, *nodeInfo)
  199. }
  200. sort.Slice(nodeInfos, func(i, j int) bool {
  201. return nodeInfos[i].NodeID < nodeInfos[j].NodeID
  202. })
  203. // 返回成功响应,包含节点缓存信息
  204. return mq.ReplyOK(coormq.NewGetPackageCachedNodesResp(nodeInfos, packageSize))
  205. }
  206. // GetPackageLoadedNodes 获取加载了指定package的节点ID列表
  207. // 参数:
  208. // - msg: 包含packageID的信息请求
  209. // 返回值:
  210. // - *coormq.GetPackageLoadedNodesResp: 包含加载了package的节点ID列表
  211. // - *mq.CodeMessage: 错误信息,如果操作失败
  212. func (svc *Service) GetPackageLoadedNodes(msg *coormq.GetPackageLoadedNodes) (*coormq.GetPackageLoadedNodesResp, *mq.CodeMessage) {
  213. // 根据packageID查找相关的存储信息
  214. storages, err := svc.db.StoragePackage().FindPackageStorages(svc.db.SQLCtx(), msg.PackageID)
  215. if err != nil {
  216. // 记录查找存储信息失败的日志
  217. logger.WithField("PackageID", msg.PackageID).
  218. Warnf("get storages by packageID failed, err: %s", err.Error())
  219. return nil, mq.Failed(errorcode.OperationFailed, "get storages by packageID failed")
  220. }
  221. // 去重,获取唯一节点ID列表
  222. uniqueNodeIDs := make(map[cdssdk.NodeID]bool)
  223. var nodeIDs []cdssdk.NodeID
  224. for _, stg := range storages {
  225. if !uniqueNodeIDs[stg.NodeID] {
  226. uniqueNodeIDs[stg.NodeID] = true
  227. nodeIDs = append(nodeIDs, stg.NodeID)
  228. }
  229. }
  230. // 返回成功响应,包含节点ID列表
  231. return mq.ReplyOK(coormq.NewGetPackageLoadedNodesResp(nodeIDs))
  232. }
  233. // GetPackageLoadLogDetails 获取指定package的加载日志详情
  234. // 参数:
  235. // - msg: 包含packageID的信息请求
  236. // 返回值:
  237. // - *coormq.GetPackageLoadLogDetailsResp: 包含package加载日志的详细信息列表
  238. // - *mq.CodeMessage: 错误信息,如果操作失败
  239. func (svc *Service) GetPackageLoadLogDetails(msg *coormq.GetPackageLoadLogDetails) (*coormq.GetPackageLoadLogDetailsResp, *mq.CodeMessage) {
  240. var logs []coormq.PackageLoadLogDetail
  241. // 根据packageID获取加载日志
  242. rawLogs, err := svc.db.StoragePackageLog().GetByPackageID(svc.db.SQLCtx(), msg.PackageID)
  243. if err != nil {
  244. // 记录获取加载日志失败的日志
  245. logger.WithField("PackageID", msg.PackageID).
  246. Warnf("getting storage package log: %s", err.Error())
  247. return nil, mq.Failed(errorcode.OperationFailed, "get storage package log failed")
  248. }
  249. // 通过存储ID获取存储信息,用于填充日志详情
  250. stgs := make(map[cdssdk.StorageID]model.Storage)
  251. for _, raw := range rawLogs {
  252. stg, ok := stgs[raw.StorageID]
  253. if !ok {
  254. stg, err = svc.db.Storage().GetByID(svc.db.SQLCtx(), raw.StorageID)
  255. if err != nil {
  256. // 记录获取存储信息失败的日志
  257. logger.WithField("PackageID", msg.PackageID).
  258. Warnf("getting storage: %s", err.Error())
  259. return nil, mq.Failed(errorcode.OperationFailed, "get storage failed")
  260. }
  261. stgs[raw.StorageID] = stg
  262. }
  263. // 填充日志详情
  264. logs = append(logs, coormq.PackageLoadLogDetail{
  265. Storage: stg,
  266. UserID: raw.UserID,
  267. CreateTime: raw.CreateTime,
  268. })
  269. }
  270. // 返回成功响应,包含package加载日志详情
  271. return mq.ReplyOK(coormq.RespGetPackageLoadLogDetails(logs))
  272. }

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