mirror of
				https://github.com/1Panel-dev/1Panel.git
				synced 2025-10-26 00:36:12 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			282 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			282 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package service
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"github.com/1Panel-dev/1Panel/backend/app/dto"
 | |
| 	"github.com/1Panel-dev/1Panel/backend/app/dto/request"
 | |
| 	"github.com/1Panel-dev/1Panel/backend/app/dto/response"
 | |
| 	"github.com/1Panel-dev/1Panel/backend/app/model"
 | |
| 	"github.com/1Panel-dev/1Panel/backend/app/repo"
 | |
| 	"github.com/1Panel-dev/1Panel/backend/buserr"
 | |
| 	"github.com/1Panel-dev/1Panel/backend/constant"
 | |
| 	"github.com/1Panel-dev/1Panel/backend/global"
 | |
| 	"github.com/1Panel-dev/1Panel/backend/utils/docker"
 | |
| 	"github.com/1Panel-dev/1Panel/backend/utils/files"
 | |
| 	"github.com/subosito/gotenv"
 | |
| 	"path"
 | |
| 	"path/filepath"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| type RuntimeService struct {
 | |
| }
 | |
| 
 | |
| type IRuntimeService interface {
 | |
| 	Page(req request.RuntimeSearch) (int64, []response.RuntimeRes, error)
 | |
| 	Create(create request.RuntimeCreate) error
 | |
| 	Delete(id uint) error
 | |
| 	Update(req request.RuntimeUpdate) error
 | |
| 	Get(id uint) (res *response.RuntimeRes, err error)
 | |
| }
 | |
| 
 | |
| func NewRuntimeService() IRuntimeService {
 | |
| 	return &RuntimeService{}
 | |
| }
 | |
| 
 | |
| func (r *RuntimeService) Create(create request.RuntimeCreate) (err error) {
 | |
| 	exist, _ := runtimeRepo.GetFirst(runtimeRepo.WithName(create.Name))
 | |
| 	if exist != nil {
 | |
| 		return buserr.New(constant.ErrNameIsExist)
 | |
| 	}
 | |
| 	if create.Resource == constant.ResourceLocal {
 | |
| 		runtime := &model.Runtime{
 | |
| 			Name:     create.Name,
 | |
| 			Resource: create.Resource,
 | |
| 			Type:     create.Type,
 | |
| 			Version:  create.Version,
 | |
| 			Status:   constant.RuntimeNormal,
 | |
| 		}
 | |
| 		return runtimeRepo.Create(context.Background(), runtime)
 | |
| 	}
 | |
| 	exist, _ = runtimeRepo.GetFirst(runtimeRepo.WithImage(create.Image))
 | |
| 	if exist != nil {
 | |
| 		return buserr.New(constant.ErrImageExist)
 | |
| 	}
 | |
| 	appDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(create.AppDetailID))
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	app, err := appRepo.GetFirst(commonRepo.WithByID(appDetail.AppId))
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	fileOp := files.NewFileOp()
 | |
| 	appVersionDir := path.Join(constant.AppResourceDir, app.Resource, app.Key, appDetail.Version)
 | |
| 	if !fileOp.Stat(appVersionDir) || appDetail.Update {
 | |
| 		if err := downloadApp(app, appDetail, nil); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 	buildDir := path.Join(appVersionDir, "build")
 | |
| 	if !fileOp.Stat(buildDir) {
 | |
| 		return buserr.New(constant.ErrDirNotFound)
 | |
| 	}
 | |
| 	runtimeDir := path.Join(constant.RuntimeDir, create.Type)
 | |
| 	tempDir := filepath.Join(runtimeDir, fmt.Sprintf("%d", time.Now().UnixNano()))
 | |
| 	if err = fileOp.CopyDir(buildDir, tempDir); err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 	oldDir := path.Join(tempDir, "build")
 | |
| 	newNameDir := path.Join(runtimeDir, create.Name)
 | |
| 	defer func() {
 | |
| 		if err != nil {
 | |
| 			_ = fileOp.DeleteDir(newNameDir)
 | |
| 		}
 | |
| 	}()
 | |
| 	if oldDir != newNameDir {
 | |
| 		if err = fileOp.Rename(oldDir, newNameDir); err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 		if err = fileOp.DeleteDir(tempDir); err != nil {
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 	composeContent, envContent, forms, err := handleParams(create.Image, create.Type, newNameDir, create.Params)
 | |
| 	if err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 	composeService, err := getComposeService(create.Name, newNameDir, composeContent, envContent, false)
 | |
| 	if err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 	runtime := &model.Runtime{
 | |
| 		Name:          create.Name,
 | |
| 		DockerCompose: string(composeContent),
 | |
| 		Env:           string(envContent),
 | |
| 		AppDetailID:   create.AppDetailID,
 | |
| 		Type:          create.Type,
 | |
| 		Image:         create.Image,
 | |
| 		Resource:      create.Resource,
 | |
| 		Status:        constant.RuntimeBuildIng,
 | |
| 		Version:       create.Version,
 | |
| 		Params:        string(forms),
 | |
| 	}
 | |
| 	if err = runtimeRepo.Create(context.Background(), runtime); err != nil {
 | |
| 		return
 | |
| 	}
 | |
| 	go buildRuntime(runtime, composeService, "")
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func (r *RuntimeService) Page(req request.RuntimeSearch) (int64, []response.RuntimeRes, error) {
 | |
| 	var (
 | |
| 		opts []repo.DBOption
 | |
| 		res  []response.RuntimeRes
 | |
| 	)
 | |
| 	if req.Name != "" {
 | |
| 		opts = append(opts, commonRepo.WithLikeName(req.Name))
 | |
| 	}
 | |
| 	if req.Status != "" {
 | |
| 		opts = append(opts, runtimeRepo.WithStatus(req.Status))
 | |
| 	}
 | |
| 	total, runtimes, err := runtimeRepo.Page(req.Page, req.PageSize, opts...)
 | |
| 	if err != nil {
 | |
| 		return 0, nil, err
 | |
| 	}
 | |
| 	for _, runtime := range runtimes {
 | |
| 		res = append(res, response.RuntimeRes{
 | |
| 			Runtime: runtime,
 | |
| 		})
 | |
| 	}
 | |
| 	return total, res, nil
 | |
| }
 | |
| 
 | |
| func (r *RuntimeService) Delete(id uint) error {
 | |
| 	runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(id))
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	website, _ := websiteRepo.GetFirst(websiteRepo.WithRuntimeID(id))
 | |
| 	if website.ID > 0 {
 | |
| 		return buserr.New(constant.ErrDelWithWebsite)
 | |
| 	}
 | |
| 	if runtime.Resource == constant.ResourceAppstore {
 | |
| 		client, err := docker.NewClient()
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		imageID, err := client.GetImageIDByName(runtime.Image)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		if imageID != "" {
 | |
| 			if err := client.DeleteImage(imageID); err != nil {
 | |
| 				global.LOG.Errorf("delete image id [%s] error %v", imageID, err)
 | |
| 			}
 | |
| 		}
 | |
| 		runtimeDir := path.Join(constant.RuntimeDir, runtime.Type, runtime.Name)
 | |
| 		if err := files.NewFileOp().DeleteDir(runtimeDir); err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 	return runtimeRepo.DeleteBy(commonRepo.WithByID(id))
 | |
| }
 | |
| 
 | |
| func (r *RuntimeService) Get(id uint) (*response.RuntimeRes, error) {
 | |
| 	runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(id))
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	res := &response.RuntimeRes{}
 | |
| 	res.Runtime = *runtime
 | |
| 	if runtime.Resource == constant.ResourceLocal {
 | |
| 		return res, nil
 | |
| 	}
 | |
| 	appDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(runtime.AppDetailID))
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	res.AppID = appDetail.AppId
 | |
| 	var (
 | |
| 		appForm   dto.AppForm
 | |
| 		appParams []response.AppParam
 | |
| 	)
 | |
| 	if err := json.Unmarshal([]byte(runtime.Params), &appForm); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	envs, err := gotenv.Unmarshal(runtime.Env)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	for _, form := range appForm.FormFields {
 | |
| 		if v, ok := envs[form.EnvKey]; ok {
 | |
| 			appParam := response.AppParam{
 | |
| 				Edit:     false,
 | |
| 				Key:      form.EnvKey,
 | |
| 				Rule:     form.Rule,
 | |
| 				Type:     form.Type,
 | |
| 				Required: form.Required,
 | |
| 			}
 | |
| 			if form.Edit {
 | |
| 				appParam.Edit = true
 | |
| 			}
 | |
| 			appParam.LabelZh = form.LabelZh
 | |
| 			appParam.LabelEn = form.LabelEn
 | |
| 			appParam.Multiple = form.Multiple
 | |
| 			appParam.Value = v
 | |
| 			if form.Type == "select" {
 | |
| 				if form.Multiple {
 | |
| 					if v == "" {
 | |
| 						appParam.Value = []string{}
 | |
| 					} else {
 | |
| 						appParam.Value = strings.Split(v, ",")
 | |
| 					}
 | |
| 				} else {
 | |
| 					for _, fv := range form.Values {
 | |
| 						if fv.Value == v {
 | |
| 							appParam.ShowValue = fv.Label
 | |
| 							break
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 				appParam.Values = form.Values
 | |
| 			}
 | |
| 			appParams = append(appParams, appParam)
 | |
| 		}
 | |
| 	}
 | |
| 	res.AppParams = appParams
 | |
| 	return res, nil
 | |
| }
 | |
| 
 | |
| func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
 | |
| 	runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(req.ID))
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	oldImage := runtime.Image
 | |
| 	if runtime.Resource == constant.ResourceLocal {
 | |
| 		runtime.Version = req.Version
 | |
| 		return runtimeRepo.Save(runtime)
 | |
| 	}
 | |
| 	exist, _ := runtimeRepo.GetFirst(runtimeRepo.WithImage(req.Name), runtimeRepo.WithNotId(req.ID))
 | |
| 	if exist != nil {
 | |
| 		return buserr.New(constant.ErrImageExist)
 | |
| 	}
 | |
| 	runtimeDir := path.Join(constant.RuntimeDir, runtime.Type, runtime.Name)
 | |
| 	composeContent, envContent, _, err := handleParams(req.Image, runtime.Type, runtimeDir, req.Params)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	composeService, err := getComposeService(runtime.Name, runtimeDir, composeContent, envContent, false)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	runtime.Image = req.Image
 | |
| 	runtime.Env = string(envContent)
 | |
| 	runtime.DockerCompose = string(composeContent)
 | |
| 	runtime.Status = constant.RuntimeBuildIng
 | |
| 	_ = runtimeRepo.Save(runtime)
 | |
| 	client, err := docker.NewClient()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	imageID, err := client.GetImageIDByName(oldImage)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	go buildRuntime(runtime, composeService, imageID)
 | |
| 	return nil
 | |
| }
 |