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

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

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