liuhaijun e94826ce29 add server
Change-Id: I0760f17f6a01c0121b59fcbfafc666032dbc30af
2024-09-19 09:44:15 +00:00

521 lines
16 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package outgiving
import (
"bytes"
"fmt"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/controller/v1/app_manage"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/middleware"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/node"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/out_giving"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/out_giving/status"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/app_manage/project_info"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/model/user"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/file_download_client"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/request"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/response"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/secure"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/utils"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/pkg/utils/file_utils"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/internal/service/app_manage/outgiving"
"git.inspur.com/sbg-jszt/cfn/cfn-schedule/pkg/log"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"io/ioutil"
"net/http"
"path/filepath"
"strings"
"time"
)
// 分发文件管理
func GetItemData(c *gin.Context) {
workspaceId := app_manage.GetWorkspaceId(c)
bodyToMap := request.GetBodyToMap(c)
id, ok := bodyToMap["id"].(string)
if !ok {
controller.Fail(c, http.StatusBadRequest, "参数错误id")
return
}
outGivingModel := out_giving.GetOutGivingModelById(id)
if outGivingModel.Id == "" {
controller.Fail(c, http.StatusBadRequest, "没有数据")
return
}
outGivingNodeProjectList := outGivingModel.GetOutGivingNodeProjectList()
nodeMap := mapNodeModels(outGivingNodeProjectList)
projectMap := mapProjectInfoCacheModels(outGivingNodeProjectList, workspaceId)
collect := transformOutGivingNodeProjects(outGivingNodeProjectList, workspaceId, nodeMap, projectMap, id)
data := map[string]interface{}{
"data": outGivingModel,
"projectList": collect,
}
controller.Success(c, data)
}
func mapNodeModels(outGivingNodeProjectList []out_giving.OutGivingNodeProject) map[string]node.Node {
var nodeIds []string
for _, project := range outGivingNodeProjectList {
nodeIds = append(nodeIds, project.NodeId)
}
nodeModels := node.GetNodeByIds(nodeIds)
nodeMap := make(map[string]node.Node)
for _, model := range nodeModels {
nodeMap[model.Id] = model
}
return nodeMap
}
func mapProjectInfoCacheModels(outGivingNodeProjectList []out_giving.OutGivingNodeProject, workspaceId string) map[string]project_info.ProjectInfo {
var ids []string
for _, project := range outGivingNodeProjectList {
projectId := secure.Sha1Encrypt(workspaceId + project.NodeId + project.ProjectId)
// todo 检查projectId是否能对得上
ids = append(ids, projectId)
}
var projectInfoCacheModels = project_info.GetProjectByIds(ids)
projectMap := make(map[string]project_info.ProjectInfo)
for _, model := range projectInfoCacheModels {
projectMap[model.Id] = model
}
return projectMap
}
func transformOutGivingNodeProjects(outGivingNodeProjectList []out_giving.OutGivingNodeProject, workspaceId string, nodeMap map[string]node.Node, projectMap map[string]project_info.ProjectInfo, id string) []map[string]interface{} {
var collect []map[string]interface{}
for _, outGivingNodeProject := range outGivingNodeProjectList {
nodeModel, exists := nodeMap[outGivingNodeProject.NodeId]
if !exists {
continue
}
// 填充数据ID项目数据是先保存至逻辑节点后又同步的思路所以NodeScriptCacheModel在逻辑节点的Id就是ProjectId在服务端保存时将Id保存至ProjectId字段
// 然后根据secure.Sha1Encrypt(item.WorkspaceId + item.NodeId + item.ProjectId)生成Id
fullId := secure.Sha1Encrypt(workspaceId + outGivingNodeProject.NodeId + outGivingNodeProject.ProjectId)
projectInfoCacheModel, exists := projectMap[fullId]
var cacheProjectName interface{}
if exists {
cacheProjectName = projectInfoCacheModel.Name
}
outGivingLog, _ := outgiving.GetByProject(id, outGivingNodeProject)
var outGivingStatus, outGivingResult, lastTime, fileSize, progressSize interface{}
if outGivingLog != nil {
outGivingStatus = outGivingLog.Status
outGivingResult = outGivingLog.Result
lastTime = outGivingLog.CreateTimeMillis
fileSize = outGivingLog.FileSize
progressSize = outGivingLog.ProgressSize
}
jsonObject := map[string]interface{}{
"sortValue": outGivingNodeProject.SortValue,
"disabled": outGivingNodeProject.Disabled,
"nodeId": outGivingNodeProject.NodeId,
"projectId": outGivingNodeProject.ProjectId,
"nodeName": nodeModel.Name,
"id": fullId,
"cacheProjectName": cacheProjectName,
"outGivingStatus": outGivingStatus,
"outGivingResult": outGivingResult,
"lastTime": lastTime,
"fileSize": fileSize,
"progressSize": progressSize,
}
collect = append(collect, jsonObject)
}
return collect
}
func UploadSharding(c *gin.Context) {
// 获取FormData
form, err := c.MultipartForm()
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, "解析请求参数失败")
return
}
id := form.Value["id"][0]
// 状态判断
_, err = check(id, func(statusCode int, o *out_giving.OutGivingModel) error {
if statusCode == status.ING {
return fmt.Errorf("当前还在分发中,请等待分发结束")
}
return nil
})
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, "当前还在分发中,请等待分发结束")
return
}
// 提取表单字段
nowSlice := form.Value["nowSlice"][0]
totalSlice := form.Value["totalSlice"][0]
sliceID := form.Value["sliceId"][0]
fileSumMD5 := form.Value["fileSumMd5"][0]
// 获取上传的文件
file, header, err := c.Request.FormFile("file")
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, "Failed to get file")
return
}
defer file.Close()
userObject, _ := c.Get(middleware.LoginUserKey)
userModel := userObject.(*user.UserObj)
tempPathName, err := utils.GetUserTempPath(userModel.UserID)
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, "上传失败:创建临时目录失败")
return
}
err = app_manage.UploadShardingImpl(file, header.Filename, tempPathName, sliceID, totalSlice, nowSlice, fileSumMD5, nil)
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, err.Error())
return
}
controller.Success(c, "上传成功")
}
func check(id string, consumer func(int, *out_giving.OutGivingModel) error) (*out_giving.OutGivingModel, error) {
outGivingModel := out_giving.GetOutGivingModelById(id)
if outGivingModel.Id == "" {
return nil, fmt.Errorf("上传失败,没有找到对应的分发项目: %s", id)
}
// 检查状态
statusCode := outGivingModel.Status
return outGivingModel, consumer(statusCode, outGivingModel)
}
func ShardingMerge(c *gin.Context) {
var (
autoUnzip bool
secondaryDirectory string
stripComponents float64
sliceID string
totalSlice float64
fileSumMD5 string
afterOpt float64
clearOld bool
id string
selectProject string
)
bodyToMap := request.GetBodyToMap(c)
autoUnzip, ok := bodyToMap["autoUnzip"].(bool) // type
secondaryDirectory, ok = bodyToMap["secondaryDirectory"].(string)
if !ok {
controller.Fail(c, http.StatusBadRequest, "参数错误levelName")
return
}
stripComponents, ok = bodyToMap["stripComponents"].(float64)
sliceID, ok = bodyToMap["sliceId"].(string)
if !ok {
controller.Fail(c, http.StatusBadRequest, "参数错误sliceID")
return
}
totalSlice, ok = bodyToMap["totalSlice"].(float64)
if !ok {
controller.Fail(c, http.StatusBadRequest, "参数错误totalSlice")
return
}
fileSumMD5, ok = bodyToMap["fileSumMd5"].(string)
if !ok {
controller.Fail(c, http.StatusBadRequest, "参数错误fileSumMD5")
return
}
afterOpt, ok = bodyToMap["afterOpt"].(float64)
id, ok = bodyToMap["id"].(string)
if !ok {
controller.Fail(c, http.StatusBadRequest, "参数错误id")
return
}
clearOld, ok = bodyToMap["clearOld"].(bool)
selectProject, ok = bodyToMap["selectProject"].(string)
// 状态判断
_, err := check(id, func(statusCode int, o *out_giving.OutGivingModel) error {
if statusCode == status.ING {
return fmt.Errorf("当前还在分发中,请等待分发结束")
}
return nil
})
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, "当前还在分发中,请等待分发结束")
return
}
userObject, _ := c.Get(middleware.LoginUserKey)
userModel := userObject.(*user.UserObj)
tempPathName, err := utils.GetUserTempPath(userModel.UserID)
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, "上传失败:创建临时目录失败[tempPathName]")
return
}
path, err := utils.GetDataPath()
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, "上传失败:创建临时目录失败[data]")
return
}
destDir := filepath.Join(path, "outGiving", id)
err = file_utils.MkdirAll(destDir)
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, "上传失败:创建临时目录失败[outGiving Dir]")
return
}
successFile, err := app_manage.ShardingTryMergeImpl(tempPathName, sliceID, int(totalSlice), fileSumMD5)
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, err.Error())
return
}
// 从绝对路径successFile.Name中获取文件名
successFileName := filepath.Base(successFile.Name())
destFile := filepath.Join(destDir, successFileName)
destFile, err = checkZip(destFile, autoUnzip)
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, err.Error())
return
}
err = file_utils.MoveFileOrDir(successFile.Name(), destDir, true)
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, "上传失败:创建临时目录失败[outGiving dest]")
return
}
outGivingModel := out_giving.NewOutGivingModel()
outGivingModel.Id = id
outGivingModel.ClearOld = clearOld
after := int(afterOpt)
outGivingModel.AfterOpt = after
outGivingModel.SecondaryDirectory = &secondaryDirectory
outGivingModel.ModifyUser = userModel.UserID
outGivingModel.ModifyTimeMillis = time.Now().UnixMilli()
out_giving.UpdateOutGivingModel(outGivingModel, []string{"after_opt", "secondary_directory", "clear_old", "secondary_directory", "modify_user", "modify_time_millis"})
stripComponentsInt := int(stripComponents)
outGivingExecId := uuid.New().String()
outGivingRun := outgiving.NewOutGivingRun(id, destFile, userModel, autoUnzip, stripComponentsInt, true)
go outGivingRun.StartRun(selectProject, outGivingExecId)
//outGivingRun.StartRun(selectProject)
dataResp := response.Resp()
dataResp.SetCode(http.StatusOK)
dataResp.Result.Data = map[string]string{
"result": "上传成功,开始分发!",
"outGivingExecId": outGivingExecId,
}
dataResp.Success(c)
//controller.Success(c, "上传成功,开始分发!")
}
func RemoteDownload(c *gin.Context) {
var (
id string
afterOpt float64
clearOld bool
url string
autoUnzip bool
secondaryDirectory string
stripComponents float64
selectProject string
filename string
)
bodyToMap := request.GetBodyToMap(c)
id, ok := bodyToMap["id"].(string)
if !ok {
controller.Fail(c, http.StatusBadRequest, "参数错误id")
return
}
afterOpt, ok = bodyToMap["afterOpt"].(float64)
clearOld, ok = bodyToMap["clearOld"].(bool)
url, ok = bodyToMap["url"].(string)
if !ok {
controller.Fail(c, http.StatusBadRequest, "参数错误url")
return
}
autoUnzip, ok = bodyToMap["autoUnzip"].(bool) // type
secondaryDirectory, ok = bodyToMap["secondaryDirectory"].(string)
if !ok {
controller.Fail(c, http.StatusBadRequest, "参数错误secondaryDirectory")
return
}
stripComponents, ok = bodyToMap["stripComponents"].(float64)
selectProject, ok = bodyToMap["selectProject"].(string)
filename, ok = bodyToMap["filename"].(string)
// 状态判断
outGivingModel, err := check(id, func(statusCode int, o *out_giving.OutGivingModel) error {
if statusCode == status.ING {
return fmt.Errorf("当前还在分发中,请等待分发结束")
}
return nil
})
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, "当前还在分发中,请等待分发结束")
return
}
userObject, _ := c.Get(middleware.LoginUserKey)
userModel := userObject.(*user.UserObj)
outGivingModel.ClearOld = clearOld
after := afterOpt
outGivingModel.AfterOpt = int(after)
outGivingModel.SecondaryDirectory = &secondaryDirectory
outGivingModel.ModifyUser = userModel.UserID
outGivingModel.ModifyTimeMillis = time.Now().UnixMilli()
out_giving.UpdateOutGivingModel(outGivingModel, []string{"after_opt", "secondary_directory", "clear_old", "secondary_directory", "modify_user", "modify_time_millis"})
// 下载
path, err := utils.GetDataPath()
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, "上传失败:创建临时目录失败[data]")
return
}
destDir := filepath.Join(path, "outGiving", id)
err = file_utils.MkdirAll(destDir)
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, "上传失败:创建临时目录失败[outGiving Dir]")
return
}
var destFile string
if len(filename) == 0 {
destFile = filepath.Join(destDir, uuid.New().String())
} else {
destFile = filepath.Join(destDir, filename)
}
err = file_download_client.DownloadFileToLocal(url, destFile, 2)
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, "下载文件失败")
return
}
destFile, err = CheckType(destFile, autoUnzip)
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, err.Error())
return
}
// 开启
stripComponentsInt := int(stripComponents)
outGivingExecId := uuid.New().String()
outGivingRun := outgiving.NewOutGivingRun(id, destFile, userModel, autoUnzip, stripComponentsInt, true)
go outGivingRun.StartRun(selectProject, outGivingExecId)
dataResp := response.Resp()
dataResp.SetCode(http.StatusOK)
dataResp.Result.Data = map[string]string{
"result": "上传成功,开始分发!",
"outGivingExecId": outGivingExecId,
}
dataResp.Success(c)
//controller.Success(c, "上传成功,开始分发!")
}
func CheckType(filePath string, unzip bool) (string, error) {
if !unzip {
return filePath, nil
}
data, err := ioutil.ReadFile(filePath)
if err != nil {
log.Errorf("Error reading file: %v", err)
return "", fmt.Errorf("读取文件失败: %s", filePath)
}
switch {
case bytes.HasPrefix(data, []byte{0x50, 0x4b, 0x03, 0x04}): // ZIP format
return filePath, nil
case bytes.HasPrefix(data, []byte{0x1f, 0x8b}):
return filePath, nil
default:
log.Errorf("UnSupported file type.")
return "", fmt.Errorf("不支持的文件类型: %s", filePath)
}
}
var PACKAGE_EXT = []string{"tar.gz", "zip"}
// 检查并处理ZIP文件
func checkZip(path string, unzip bool) (string, error) {
if unzip {
zip := false
for _, ext := range PACKAGE_EXT {
if strings.HasSuffix(strings.ToLower(path), strings.ToLower(ext)) {
zip = true
break
}
}
if !zip {
return "", fmt.Errorf("不支持的文件类型: %s", filepath.Base(path))
}
}
// 这里仅返回文件对象,未执行解压逻辑,如需解压还需额外实现
return path, nil
}
func Cancel(c *gin.Context) {
bodyToMap := request.GetBodyToMap(c)
id, ok := bodyToMap["id"].(string)
if !ok {
controller.Fail(c, http.StatusBadRequest, "参数错误id")
return
}
// 状态判断
outGigving, err := check(id, func(statusCode int, o *out_giving.OutGivingModel) error {
if statusCode != status.ING {
return fmt.Errorf("当前状态不是分发中")
}
return nil
})
if err != nil {
controller.FailCode(c, http.StatusInternalServerError, err, "当前状态不是分发中")
return
}
userObject, _ := c.Get(middleware.LoginUserKey)
userModel := userObject.(*user.UserObj)
outgiving.Cancel(outGigving.Id, userModel)
controller.Success(c, "取消成功")
}