|
- package mq
-
- import (
- "database/sql"
- "fmt"
- "sort"
-
- "github.com/jmoiron/sqlx"
- "gitlink.org.cn/cloudream/common/consts/errorcode"
- "gitlink.org.cn/cloudream/common/pkgs/logger"
- "gitlink.org.cn/cloudream/common/pkgs/mq"
- cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
- "gitlink.org.cn/cloudream/storage/common/pkgs/db/model"
- coormq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/coordinator"
- )
-
- // GetPackage 通过PackageID获取包信息
- // 参数:
- // - msg: 包含需要获取的PackageID的请求消息
- // 返回值:
- // - *coormq.GetPackageResp: 获取包信息成功的响应
- // - *mq.CodeMessage: 错误时返回的错误信息
- func (svc *Service) GetPackage(msg *coormq.GetPackage) (*coormq.GetPackageResp, *mq.CodeMessage) {
- // 通过ID从数据库获取包信息
- pkg, err := svc.db.Package().GetByID(svc.db.SQLCtx(), msg.PackageID)
- if err != nil {
- // 记录日志并返回错误信息
- logger.WithField("PackageID", msg.PackageID).
- Warnf("get package: %s", err.Error())
-
- return nil, mq.Failed(errorcode.OperationFailed, "get package failed")
- }
-
- // 返回成功响应
- return mq.ReplyOK(coormq.NewGetPackageResp(pkg))
- }
-
- func (svc *Service) GetPackageByName(msg *coormq.GetPackageByName) (*coormq.GetPackageByNameResp, *mq.CodeMessage) {
- pkg, err := svc.db.Package().GetUserPackageByName(svc.db.SQLCtx(), msg.UserID, msg.BucketName, msg.PackageName)
- if err != nil {
- logger.WithField("UserID", msg.UserID).
- WithField("BucketName", msg.BucketName).
- WithField("PackageName", msg.PackageName).
- Warnf("get package by name: %s", err.Error())
-
- return nil, mq.Failed(errorcode.OperationFailed, "get package by name failed")
- }
-
- return mq.ReplyOK(coormq.NewGetPackageByNameResp(pkg))
- }
-
- func (svc *Service) CreatePackage(msg *coormq.CreatePackage) (*coormq.CreatePackageResp, *mq.CodeMessage) {
- var pkg cdssdk.Package
- err := svc.db.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
- var err error
-
- // 检查桶是否可用
- isAvai, _ := svc.db.Bucket().IsAvailable(tx, msg.BucketID, msg.UserID)
- if !isAvai {
- return fmt.Errorf("bucket is not avaiable to the user")
- }
-
- pkgID, err := svc.db.Package().Create(tx, msg.BucketID, msg.Name)
- if err != nil {
- return fmt.Errorf("creating package: %w", err)
- }
-
- pkg, err = svc.db.Package().GetByID(tx, pkgID)
- if err != nil {
- return fmt.Errorf("getting package by id: %w", err)
- }
-
- return nil
- })
- if err != nil {
- // 记录日志并返回错误信息
- logger.WithField("BucketID", msg.BucketID).
- WithField("Name", msg.Name).
- Warn(err.Error())
- return nil, mq.Failed(errorcode.OperationFailed, "creating package failed")
- }
-
- return mq.ReplyOK(coormq.NewCreatePackageResp(pkg))
- }
-
- // UpdatePackage 更新包的信息
- // 参数:
- // - msg: 包含更新包所需信息的请求消息
- // 返回值:
- // - *coormq.UpdatePackageResp: 更新包成功的响应
- // - *mq.CodeMessage: 错误时返回的错误信息
- func (svc *Service) UpdatePackage(msg *coormq.UpdatePackage) (*coormq.UpdatePackageResp, *mq.CodeMessage) {
-
- var added []cdssdk.Object
- err := svc.db.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
- // 验证包是否存在
- _, err := svc.db.Package().GetByID(tx, msg.PackageID)
- if err != nil {
- return fmt.Errorf("getting package by id: %w", err)
- }
-
- // 删除对象
- if len(msg.Deletes) > 0 {
- if err := svc.db.Object().BatchDelete(tx, msg.Deletes); err != nil {
- return fmt.Errorf("deleting objects: %w", err)
- }
- }
-
- // 添加对象
- if len(msg.Adds) > 0 {
- ad, err := svc.db.Object().BatchAdd(tx, msg.PackageID, msg.Adds)
- if err != nil {
- return fmt.Errorf("adding objects: %w", err)
- }
- added = ad
- }
-
- return nil
- })
- if err != nil {
- // 记录日志并返回错误信息
- logger.WithField("PackageID", msg.PackageID).Warn(err.Error())
- return nil, mq.Failed(errorcode.OperationFailed, "update package failed")
- }
-
- return mq.ReplyOK(coormq.NewUpdatePackageResp(added))
- }
-
- // DeletePackage 删除一个包
- // 参数:
- // - msg: 包含删除包所需信息的请求消息
- // 返回值:
- // - *coormq.DeletePackageResp: 删除包成功的响应
- // - *mq.CodeMessage: 错误时返回的错误信息
- func (svc *Service) DeletePackage(msg *coormq.DeletePackage) (*coormq.DeletePackageResp, *mq.CodeMessage) {
- // 在事务中执行删除包的操作
- err := svc.db.DoTx(sql.LevelSerializable, func(tx *sqlx.Tx) error {
- // 验证包是否可用
- isAvai, _ := svc.db.Package().IsAvailable(tx, msg.UserID, msg.PackageID)
- if !isAvai {
- return fmt.Errorf("package is not available to the user")
- }
-
- // 软删除包
- err := svc.db.Package().SoftDelete(tx, msg.PackageID)
- if err != nil {
- return fmt.Errorf("soft delete package: %w", err)
- }
-
- // 删除未使用的包
- err = svc.db.Package().DeleteUnused(tx, msg.PackageID)
- if err != nil {
- logger.WithField("UserID", msg.UserID).
- WithField("PackageID", msg.PackageID).
- Warnf("deleting unused package: %w", err.Error())
- }
-
- return nil
- })
- if err != nil {
- // 记录日志并返回错误信息
- logger.WithField("UserID", msg.UserID).
- WithField("PackageID", msg.PackageID).
- Warnf(err.Error())
- return nil, mq.Failed(errorcode.OperationFailed, "delete package failed")
- }
-
- // 返回成功响应
- return mq.ReplyOK(coormq.NewDeletePackageResp())
- }
-
- // GetPackageCachedNodes 获取缓存了指定package的节点信息
- // 参数:
- // - msg: 包含packageID和用户ID的信息请求
- // 返回值:
- // - *coormq.GetPackageCachedNodesResp: 包含缓存了package数据的节点信息列表
- // - *mq.CodeMessage: 错误信息,如果操作失败
- func (svc *Service) GetPackageCachedNodes(msg *coormq.GetPackageCachedNodes) (*coormq.GetPackageCachedNodesResp, *mq.CodeMessage) {
- // 检查package是否可用
- isAva, err := svc.db.Package().IsAvailable(svc.db.SQLCtx(), msg.UserID, msg.PackageID)
- if err != nil {
- // 记录检查package可用性失败的日志
- logger.WithField("UserID", msg.UserID).
- WithField("PackageID", msg.PackageID).
- Warnf("check package available failed, err: %s", err.Error())
- return nil, mq.Failed(errorcode.OperationFailed, "check package available failed")
- }
- if !isAva {
- // 记录package不可用的日志
- logger.WithField("UserID", msg.UserID).
- WithField("PackageID", msg.PackageID).
- Warnf("package is not available to the user")
- return nil, mq.Failed(errorcode.OperationFailed, "package is not available to the user")
- }
-
- // 获取package中的对象详情,用于后续统计节点缓存信息
- objDetails, err := svc.db.Object().GetPackageObjectDetails(svc.db.SQLCtx(), msg.PackageID)
- if err != nil {
- // 记录获取package对象详情失败的日志
- logger.WithField("PackageID", msg.PackageID).
- Warnf("get package block details: %s", err.Error())
-
- return nil, mq.Failed(errorcode.OperationFailed, "get package block details failed")
- }
-
- // 统计各节点缓存的文件信息
- var packageSize int64
- nodeInfoMap := make(map[cdssdk.NodeID]*cdssdk.NodePackageCachingInfo)
- for _, obj := range objDetails {
- for _, block := range obj.Blocks {
- // 更新或创建节点缓存信息
- info, ok := nodeInfoMap[block.NodeID]
- if !ok {
- info = &cdssdk.NodePackageCachingInfo{
- NodeID: block.NodeID,
- }
- nodeInfoMap[block.NodeID] = info
- }
-
- // 更新节点的文件大小和对象计数
- info.FileSize += obj.Object.Size
- info.ObjectCount++
- }
- }
-
- // 整理节点缓存信息,并按节点ID排序
- var nodeInfos []cdssdk.NodePackageCachingInfo
- for _, nodeInfo := range nodeInfoMap {
- nodeInfos = append(nodeInfos, *nodeInfo)
- }
-
- sort.Slice(nodeInfos, func(i, j int) bool {
- return nodeInfos[i].NodeID < nodeInfos[j].NodeID
- })
- // 返回成功响应,包含节点缓存信息
- return mq.ReplyOK(coormq.NewGetPackageCachedNodesResp(nodeInfos, packageSize))
- }
-
- // GetPackageLoadedNodes 获取加载了指定package的节点ID列表
- // 参数:
- // - msg: 包含packageID的信息请求
- // 返回值:
- // - *coormq.GetPackageLoadedNodesResp: 包含加载了package的节点ID列表
- // - *mq.CodeMessage: 错误信息,如果操作失败
- func (svc *Service) GetPackageLoadedNodes(msg *coormq.GetPackageLoadedNodes) (*coormq.GetPackageLoadedNodesResp, *mq.CodeMessage) {
- // 根据packageID查找相关的存储信息
- storages, err := svc.db.StoragePackage().FindPackageStorages(svc.db.SQLCtx(), msg.PackageID)
- if err != nil {
- // 记录查找存储信息失败的日志
- logger.WithField("PackageID", msg.PackageID).
- Warnf("get storages by packageID failed, err: %s", err.Error())
- return nil, mq.Failed(errorcode.OperationFailed, "get storages by packageID failed")
- }
-
- // 去重,获取唯一节点ID列表
- uniqueNodeIDs := make(map[cdssdk.NodeID]bool)
- var nodeIDs []cdssdk.NodeID
- for _, stg := range storages {
- if !uniqueNodeIDs[stg.NodeID] {
- uniqueNodeIDs[stg.NodeID] = true
- nodeIDs = append(nodeIDs, stg.NodeID)
- }
- }
-
- // 返回成功响应,包含节点ID列表
- return mq.ReplyOK(coormq.NewGetPackageLoadedNodesResp(nodeIDs))
- }
-
- // GetPackageLoadLogDetails 获取指定package的加载日志详情
- // 参数:
- // - msg: 包含packageID的信息请求
- // 返回值:
- // - *coormq.GetPackageLoadLogDetailsResp: 包含package加载日志的详细信息列表
- // - *mq.CodeMessage: 错误信息,如果操作失败
- func (svc *Service) GetPackageLoadLogDetails(msg *coormq.GetPackageLoadLogDetails) (*coormq.GetPackageLoadLogDetailsResp, *mq.CodeMessage) {
- var logs []coormq.PackageLoadLogDetail
- // 根据packageID获取加载日志
- rawLogs, err := svc.db.StoragePackageLog().GetByPackageID(svc.db.SQLCtx(), msg.PackageID)
- if err != nil {
- // 记录获取加载日志失败的日志
- logger.WithField("PackageID", msg.PackageID).
- Warnf("getting storage package log: %s", err.Error())
- return nil, mq.Failed(errorcode.OperationFailed, "get storage package log failed")
- }
-
- // 通过存储ID获取存储信息,用于填充日志详情
- stgs := make(map[cdssdk.StorageID]model.Storage)
-
- for _, raw := range rawLogs {
- stg, ok := stgs[raw.StorageID]
- if !ok {
- stg, err = svc.db.Storage().GetByID(svc.db.SQLCtx(), raw.StorageID)
- if err != nil {
- // 记录获取存储信息失败的日志
- logger.WithField("PackageID", msg.PackageID).
- Warnf("getting storage: %s", err.Error())
- return nil, mq.Failed(errorcode.OperationFailed, "get storage failed")
- }
-
- stgs[raw.StorageID] = stg
- }
-
- // 填充日志详情
- logs = append(logs, coormq.PackageLoadLogDetail{
- Storage: stg,
- UserID: raw.UserID,
- CreateTime: raw.CreateTime,
- })
- }
-
- // 返回成功响应,包含package加载日志详情
- return mq.ReplyOK(coormq.RespGetPackageLoadLogDetails(logs))
- }
|