521 lines
16 KiB
Go
521 lines
16 KiB
Go
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, "取消成功")
|
||
}
|