mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-31 22:18:07 +08:00
feat: 修改本地应用同步逻辑
This commit is contained in:
parent
aeabed70db
commit
872581fa4b
@ -1,7 +1,7 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AppDatabase struct {
|
type AppDatabase struct {
|
||||||
@ -31,12 +31,6 @@ type AppVersion struct {
|
|||||||
DetailId uint `json:"detailId"`
|
DetailId uint `json:"detailId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//type AppList struct {
|
|
||||||
// Version string `json:"version"`
|
|
||||||
// Tags []Tag `json:"tags"`
|
|
||||||
// Items []AppDefine `json:"items"`
|
|
||||||
//}
|
|
||||||
|
|
||||||
type AppList struct {
|
type AppList struct {
|
||||||
Valid bool `json:"valid"`
|
Valid bool `json:"valid"`
|
||||||
Violations []string `json:"violations"`
|
Violations []string `json:"violations"`
|
||||||
@ -56,6 +50,18 @@ type AppDefine struct {
|
|||||||
Versions []AppConfigVersion `json:"versions"`
|
Versions []AppConfigVersion `json:"versions"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LocalAppAppDefine struct {
|
||||||
|
AppProperty model.App `json:"additionalProperties" yaml:"additionalProperties"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LocalAppParam struct {
|
||||||
|
AppParams LocalAppInstallDefine `json:"additionalProperties" yaml:"additionalProperties"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LocalAppInstallDefine struct {
|
||||||
|
FormFields interface{} `json:"formFields" yaml:"formFields"`
|
||||||
|
}
|
||||||
|
|
||||||
type ExtraProperties struct {
|
type ExtraProperties struct {
|
||||||
Tags []Tag `json:"tags"`
|
Tags []Tag `json:"tags"`
|
||||||
}
|
}
|
||||||
@ -84,11 +90,6 @@ type AppConfigVersion struct {
|
|||||||
AppForm interface{} `json:"additionalProperties"`
|
AppForm interface{} `json:"additionalProperties"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (config AppProperty) GetRequired() string {
|
|
||||||
by, _ := json.Marshal(config.Required)
|
|
||||||
return string(by)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
@ -3,13 +3,13 @@ package model
|
|||||||
type App struct {
|
type App struct {
|
||||||
BaseModel
|
BaseModel
|
||||||
Name string `json:"name" gorm:"type:varchar(64);not null"`
|
Name string `json:"name" gorm:"type:varchar(64);not null"`
|
||||||
Key string `json:"key" gorm:"type:varchar(64);not null;uniqueIndex"`
|
Key string `json:"key" gorm:"type:varchar(64);not null;"`
|
||||||
ShortDescZh string `json:"shortDescZh" gorm:"type:longtext;"`
|
ShortDescZh string `json:"shortDescZh" yaml:"shortDescZh" gorm:"type:longtext;"`
|
||||||
ShortDescEn string `json:"shortDescEn" gorm:"type:longtext;"`
|
ShortDescEn string `json:"shortDescEn" yaml:"shortDescEn" gorm:"type:longtext;"`
|
||||||
Icon string `json:"icon" gorm:"type:longtext;"`
|
Icon string `json:"icon" gorm:"type:longtext;"`
|
||||||
Type string `json:"type" gorm:"type:varchar(64);not null"`
|
Type string `json:"type" gorm:"type:varchar(64);not null"`
|
||||||
Status string `json:"status" gorm:"type:varchar(64);not null"`
|
Status string `json:"status" gorm:"type:varchar(64);not null"`
|
||||||
Required string `json:"required" gorm:"type:varchar(64);not null"`
|
Required string `json:"required" gorm:"type:varchar(64);"`
|
||||||
CrossVersionUpdate bool `json:"crossVersionUpdate"`
|
CrossVersionUpdate bool `json:"crossVersionUpdate"`
|
||||||
Limit int `json:"limit" gorm:"type:Integer;not null"`
|
Limit int `json:"limit" gorm:"type:Integer;not null"`
|
||||||
Website string `json:"website" gorm:"type:varchar(64);not null"`
|
Website string `json:"website" gorm:"type:varchar(64);not null"`
|
||||||
@ -21,6 +21,6 @@ type App struct {
|
|||||||
LastModified int `json:"lastModified" gorm:"type:Integer;"`
|
LastModified int `json:"lastModified" gorm:"type:Integer;"`
|
||||||
|
|
||||||
Details []AppDetail `json:"-" gorm:"-:migration"`
|
Details []AppDetail `json:"-" gorm:"-:migration"`
|
||||||
TagsKey []string `json:"-" gorm:"-"`
|
TagsKey []string `json:"tags" yaml:"tags" gorm:"-"`
|
||||||
AppTags []AppTag `json:"-" gorm:"-:migration"`
|
AppTags []AppTag `json:"-" gorm:"-:migration"`
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/clause"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AppDetailRepo struct {
|
type AppDetailRepo struct {
|
||||||
@ -18,6 +19,7 @@ type IAppDetailRepo interface {
|
|||||||
DeleteByAppIds(ctx context.Context, appIds []uint) error
|
DeleteByAppIds(ctx context.Context, appIds []uint) error
|
||||||
GetBy(opts ...DBOption) ([]model.AppDetail, error)
|
GetBy(opts ...DBOption) ([]model.AppDetail, error)
|
||||||
BatchUpdateBy(maps map[string]interface{}, opts ...DBOption) error
|
BatchUpdateBy(maps map[string]interface{}, opts ...DBOption) error
|
||||||
|
BatchDelete(ctx context.Context, appDetails []model.AppDetail) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIAppDetailRepo() IAppDetailRepo {
|
func NewIAppDetailRepo() IAppDetailRepo {
|
||||||
@ -66,3 +68,7 @@ func (a AppDetailRepo) BatchUpdateBy(maps map[string]interface{}, opts ...DBOpti
|
|||||||
}
|
}
|
||||||
return db.Updates(&maps).Error
|
return db.Updates(&maps).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a AppDetailRepo) BatchDelete(ctx context.Context, appDetails []model.AppDetail) error {
|
||||||
|
return getTx(ctx).Omit(clause.Associations).Delete(&appDetails).Error
|
||||||
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@ -332,6 +333,10 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
|||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
if err = downloadApp(app, appDetail, appInstall, req); err != nil {
|
if err = downloadApp(app, appDetail, appInstall, req); err != nil {
|
||||||
|
if appInstall.Status == constant.Installing {
|
||||||
|
appInstall.Status = constant.Error
|
||||||
|
appInstall.Message = err.Error()
|
||||||
|
}
|
||||||
_ = appInstallRepo.Save(ctx, appInstall)
|
_ = appInstallRepo.Save(ctx, appInstall)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -376,152 +381,274 @@ func (a AppService) GetAppUpdate() (*response.AppUpdateRes, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a AppService) SyncAppListFromLocal() {
|
func (a AppService) SyncAppListFromLocal() {
|
||||||
//fileOp := files.NewFileOp()
|
fileOp := files.NewFileOp()
|
||||||
//appDir := constant.LocalAppResourceDir
|
localAppDir := constant.LocalAppResourceDir
|
||||||
//listFile := path.Join(appDir, "list.json")
|
if !fileOp.Stat(localAppDir) {
|
||||||
//if !fileOp.Stat(listFile) {
|
return
|
||||||
// return
|
}
|
||||||
//}
|
var (
|
||||||
//global.LOG.Infof("start sync local apps...")
|
err error
|
||||||
//content, err := fileOp.GetContent(listFile)
|
dirEntries []os.DirEntry
|
||||||
//if err != nil {
|
localApps []model.App
|
||||||
// global.LOG.Errorf("get list.json content failed %s", err.Error())
|
)
|
||||||
// return
|
|
||||||
//}
|
defer func() {
|
||||||
//list := &dto.AppList{}
|
if err != nil {
|
||||||
//if err := json.Unmarshal(content, list); err != nil {
|
global.LOG.Errorf("sync app failed %v", err)
|
||||||
// global.LOG.Errorf("unmarshal list.json failed %s", err.Error())
|
}
|
||||||
// return
|
}()
|
||||||
//}
|
|
||||||
//oldApps, _ := appRepo.GetBy(appRepo.WithResource(constant.AppResourceLocal))
|
global.LOG.Infof("start sync local apps...")
|
||||||
//appsMap := getApps(oldApps, list.Apps, true)
|
dirEntries, err = os.ReadDir(localAppDir)
|
||||||
//for _, l := range list.Apps {
|
if err != nil {
|
||||||
// localKey := "local" + l.Config.Key
|
return
|
||||||
// app := appsMap[localKey]
|
}
|
||||||
// icon, err := os.ReadFile(path.Join(appDir, l.Config.Key, "metadata", "logo.png"))
|
for _, dirEntry := range dirEntries {
|
||||||
// if err != nil {
|
if dirEntry.IsDir() {
|
||||||
// global.LOG.Errorf("get [%s] icon error: %s", l.Name, err.Error())
|
appDir := path.Join(localAppDir, dirEntry.Name())
|
||||||
// continue
|
appDirEntries, err := os.ReadDir(appDir)
|
||||||
// }
|
if err != nil || len(appDirEntries) == 0 {
|
||||||
// iconStr := base64.StdEncoding.EncodeToString(icon)
|
continue
|
||||||
// app.Icon = iconStr
|
}
|
||||||
// app.TagsKey = append(l.Tags, "Local")
|
configYamlPath := path.Join(appDir, "data.yml")
|
||||||
// app.Recommend = 9999
|
if !fileOp.Stat(configYamlPath) {
|
||||||
// versions := l.Versions
|
continue
|
||||||
// detailsMap := getAppDetails(app.Details, versions)
|
}
|
||||||
//
|
iconPath := path.Join(appDir, "logo.png")
|
||||||
// for _, v := range versions {
|
if !fileOp.Stat(iconPath) {
|
||||||
// detail := detailsMap[v]
|
continue
|
||||||
// detailPath := path.Join(appDir, l.Key, "versions", v)
|
}
|
||||||
// if _, err := os.Stat(detailPath); err != nil {
|
configYamlByte, err := fileOp.GetContent(configYamlPath)
|
||||||
// global.LOG.Errorf("get [%s] folder error: %s", detailPath, err.Error())
|
if err != nil {
|
||||||
// continue
|
continue
|
||||||
// }
|
}
|
||||||
// readmeStr, err := os.ReadFile(path.Join(detailPath, "README.md"))
|
localAppDefine := dto.LocalAppAppDefine{}
|
||||||
// if err != nil {
|
if err := yaml.Unmarshal(configYamlByte, &localAppDefine); err != nil {
|
||||||
// global.LOG.Errorf("get [%s] README error: %s", detailPath, err.Error())
|
continue
|
||||||
// }
|
}
|
||||||
// detail.Readme = string(readmeStr)
|
app := localAppDefine.AppProperty
|
||||||
// dockerComposeStr, err := os.ReadFile(path.Join(detailPath, "docker-compose.yml"))
|
app.Resource = constant.AppResourceLocal
|
||||||
// if err != nil {
|
app.Status = constant.AppNormal
|
||||||
// global.LOG.Errorf("get [%s] docker-compose.yml error: %s", detailPath, err.Error())
|
app.Recommend = 9999
|
||||||
// continue
|
app.TagsKey = append(app.TagsKey, "Local")
|
||||||
// }
|
app.Key = "local" + app.Key
|
||||||
// detail.DockerCompose = string(dockerComposeStr)
|
readMePath := path.Join(appDir, "README.md")
|
||||||
// paramStr, err := os.ReadFile(path.Join(detailPath, "config.json"))
|
if fileOp.Stat(configYamlPath) {
|
||||||
// if err != nil {
|
readMeByte, err := fileOp.GetContent(readMePath)
|
||||||
// global.LOG.Errorf("get [%s] form.json error: %s", detailPath, err.Error())
|
if err == nil {
|
||||||
// }
|
app.ReadMe = string(readMeByte)
|
||||||
// detail.Params = string(paramStr)
|
}
|
||||||
// detailsMap[v] = detail
|
}
|
||||||
// }
|
|
||||||
// var newDetails []model.AppDetail
|
iconByte, _ := fileOp.GetContent(iconPath)
|
||||||
// for _, v := range detailsMap {
|
if iconByte != nil {
|
||||||
// newDetails = append(newDetails, v)
|
iconStr := base64.StdEncoding.EncodeToString(iconByte)
|
||||||
// }
|
app.Icon = iconStr
|
||||||
// app.Details = newDetails
|
}
|
||||||
// appsMap[localKey] = app
|
var appDetails []model.AppDetail
|
||||||
//}
|
for _, appDirEntry := range appDirEntries {
|
||||||
//var (
|
if appDirEntry.IsDir() {
|
||||||
// addAppArray []model.App
|
appDetail := model.AppDetail{
|
||||||
// updateArray []model.App
|
Version: appDirEntry.Name(),
|
||||||
// appIds []uint
|
Status: constant.AppNormal,
|
||||||
//)
|
}
|
||||||
//for _, v := range appsMap {
|
versionDir := path.Join(appDir, appDirEntry.Name())
|
||||||
// if v.ID == 0 {
|
dockerComposePath := path.Join(versionDir, "docker-compose.yml")
|
||||||
// addAppArray = append(addAppArray, v)
|
if !fileOp.Stat(dockerComposePath) {
|
||||||
// } else {
|
continue
|
||||||
// updateArray = append(updateArray, v)
|
}
|
||||||
// appIds = append(appIds, v.ID)
|
dockerComposeByte, _ := fileOp.GetContent(dockerComposePath)
|
||||||
// }
|
if dockerComposeByte == nil {
|
||||||
//}
|
continue
|
||||||
//tx, ctx := getTxAndContext()
|
}
|
||||||
//if len(addAppArray) > 0 {
|
appDetail.DockerCompose = string(dockerComposeByte)
|
||||||
// if err := appRepo.BatchCreate(ctx, addAppArray); err != nil {
|
paramPath := path.Join(versionDir, "data.yml")
|
||||||
// tx.Rollback()
|
if !fileOp.Stat(paramPath) {
|
||||||
// return
|
continue
|
||||||
// }
|
}
|
||||||
//}
|
paramByte, _ := fileOp.GetContent(paramPath)
|
||||||
//for _, update := range updateArray {
|
if paramByte == nil {
|
||||||
// if err := appRepo.Save(ctx, &update); err != nil {
|
continue
|
||||||
// tx.Rollback()
|
}
|
||||||
// return
|
appParamConfig := dto.LocalAppParam{}
|
||||||
// }
|
if err := yaml.Unmarshal(paramByte, &appParamConfig); err != nil {
|
||||||
//}
|
continue
|
||||||
//if err := appTagRepo.DeleteByAppIds(ctx, appIds); err != nil {
|
}
|
||||||
// tx.Rollback()
|
dataJson, err := json.Marshal(appParamConfig.AppParams)
|
||||||
// return
|
if err != nil {
|
||||||
//}
|
continue
|
||||||
//apps := append(addAppArray, updateArray...)
|
}
|
||||||
//var (
|
appDetail.Params = string(dataJson)
|
||||||
// addDetails []model.AppDetail
|
appDetails = append(appDetails, appDetail)
|
||||||
// updateDetails []model.AppDetail
|
}
|
||||||
// appTags []*model.AppTag
|
}
|
||||||
//)
|
app.Details = appDetails
|
||||||
//tags, _ := tagRepo.All()
|
localApps = append(localApps, app)
|
||||||
//tagMap := make(map[string]uint, len(tags))
|
}
|
||||||
//for _, app := range tags {
|
}
|
||||||
// tagMap[app.Key] = app.ID
|
|
||||||
//}
|
var (
|
||||||
//for _, a := range apps {
|
newApps []model.App
|
||||||
// for _, t := range a.TagsKey {
|
deleteApps []model.App
|
||||||
// tagId, ok := tagMap[t]
|
updateApps []model.App
|
||||||
// if ok {
|
oldAppIds []uint
|
||||||
// appTags = append(appTags, &model.AppTag{
|
|
||||||
// AppId: a.ID,
|
deleteAppIds []uint
|
||||||
// TagId: tagId,
|
deleteAppDetails []model.AppDetail
|
||||||
// })
|
newAppDetails []model.AppDetail
|
||||||
// }
|
updateDetails []model.AppDetail
|
||||||
// }
|
|
||||||
// for _, d := range a.Details {
|
appTags []*model.AppTag
|
||||||
// d.AppId = a.ID
|
)
|
||||||
// if d.ID == 0 {
|
|
||||||
// addDetails = append(addDetails, d)
|
oldApps, _ := appRepo.GetBy(appRepo.WithResource(constant.AppResourceLocal))
|
||||||
// } else {
|
apps := make(map[string]model.App, len(oldApps))
|
||||||
// updateDetails = append(updateDetails, d)
|
for _, old := range oldApps {
|
||||||
// }
|
old.Status = constant.AppTakeDown
|
||||||
// }
|
apps[old.Key] = old
|
||||||
//}
|
}
|
||||||
//if len(addDetails) > 0 {
|
for _, app := range localApps {
|
||||||
// if err := appDetailRepo.BatchCreate(ctx, addDetails); err != nil {
|
if oldApp, ok := apps[app.Key]; ok {
|
||||||
// tx.Rollback()
|
app.ID = oldApp.ID
|
||||||
// return
|
appDetails := make(map[string]model.AppDetail, len(oldApp.Details))
|
||||||
// }
|
for _, old := range oldApp.Details {
|
||||||
//}
|
old.Status = constant.AppTakeDown
|
||||||
//for _, u := range updateDetails {
|
appDetails[old.Version] = old
|
||||||
// if err := appDetailRepo.Update(ctx, u); err != nil {
|
}
|
||||||
// tx.Rollback()
|
for i, newDetail := range app.Details {
|
||||||
// return
|
version := newDetail.Version
|
||||||
// }
|
newDetail.Status = constant.AppNormal
|
||||||
//}
|
newDetail.AppId = app.ID
|
||||||
//if len(appTags) > 0 {
|
oldDetail, exist := appDetails[version]
|
||||||
// if err := appTagRepo.BatchCreate(ctx, appTags); err != nil {
|
if exist {
|
||||||
// tx.Rollback()
|
newDetail.ID = oldDetail.ID
|
||||||
// return
|
}
|
||||||
// }
|
app.Details[i] = newDetail
|
||||||
//}
|
}
|
||||||
//tx.Commit()
|
}
|
||||||
//global.LOG.Infof("sync local apps success")
|
app.TagsKey = append(app.TagsKey, constant.AppResourceLocal)
|
||||||
|
apps[app.Key] = app
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, app := range apps {
|
||||||
|
if app.ID == 0 {
|
||||||
|
newApps = append(newApps, app)
|
||||||
|
} else {
|
||||||
|
oldAppIds = append(oldAppIds, app.ID)
|
||||||
|
if app.Status == constant.AppTakeDown {
|
||||||
|
installs, _ := appInstallRepo.ListBy(appInstallRepo.WithAppId(app.ID))
|
||||||
|
if len(installs) > 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
deleteAppIds = append(deleteAppIds, app.ID)
|
||||||
|
deleteApps = append(deleteApps, app)
|
||||||
|
deleteAppDetails = append(deleteAppDetails, app.Details...)
|
||||||
|
} else {
|
||||||
|
updateApps = append(updateApps, app)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
tags, _ := tagRepo.All()
|
||||||
|
tagMap := make(map[string]uint, len(tags))
|
||||||
|
for _, tag := range tags {
|
||||||
|
tagMap[tag.Key] = tag.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, ctx := getTxAndContext()
|
||||||
|
defer tx.Rollback()
|
||||||
|
if len(newApps) > 0 {
|
||||||
|
if err := appRepo.BatchCreate(ctx, newApps); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, update := range updateApps {
|
||||||
|
if err := appRepo.Save(ctx, &update); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(deleteApps) > 0 {
|
||||||
|
if err := appRepo.BatchDelete(ctx, deleteApps); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := appDetailRepo.DeleteByAppIds(ctx, deleteAppIds); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := appTagRepo.DeleteByAppIds(ctx, oldAppIds); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var ()
|
||||||
|
|
||||||
|
for _, newApp := range newApps {
|
||||||
|
if newApp.ID > 0 {
|
||||||
|
for _, detail := range newApp.Details {
|
||||||
|
detail.AppId = newApp.ID
|
||||||
|
newAppDetails = append(newAppDetails, detail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, update := range updateApps {
|
||||||
|
for _, detail := range update.Details {
|
||||||
|
if detail.ID == 0 {
|
||||||
|
detail.AppId = update.ID
|
||||||
|
newAppDetails = append(newAppDetails, detail)
|
||||||
|
} else {
|
||||||
|
if detail.Status == constant.AppNormal {
|
||||||
|
updateDetails = append(updateDetails, detail)
|
||||||
|
} else {
|
||||||
|
deleteAppDetails = append(deleteAppDetails, detail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allApps := append(newApps, updateApps...)
|
||||||
|
for _, app := range allApps {
|
||||||
|
for _, t := range app.TagsKey {
|
||||||
|
tagId, ok := tagMap[t]
|
||||||
|
if ok {
|
||||||
|
appTags = append(appTags, &model.AppTag{
|
||||||
|
AppId: app.ID,
|
||||||
|
TagId: tagId,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(newAppDetails) > 0 {
|
||||||
|
if err := appDetailRepo.BatchCreate(ctx, newAppDetails); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, updateAppDetail := range updateDetails {
|
||||||
|
if err := appDetailRepo.Update(ctx, updateAppDetail); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(deleteAppDetails) > 0 {
|
||||||
|
if err := appDetailRepo.BatchDelete(ctx, deleteAppDetails); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(oldAppIds) > 0 {
|
||||||
|
if err := appTagRepo.DeleteByAppIds(ctx, oldAppIds); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(appTags) > 0 {
|
||||||
|
if err := appTagRepo.BatchCreate(ctx, appTags); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tx.Commit()
|
||||||
|
global.LOG.Infof("sync local apps success")
|
||||||
}
|
}
|
||||||
func (a AppService) SyncAppListFromRemote() error {
|
func (a AppService) SyncAppListFromRemote() error {
|
||||||
updateRes, err := a.GetAppUpdate()
|
updateRes, err := a.GetAppUpdate()
|
||||||
@ -533,9 +660,10 @@ func (a AppService) SyncAppListFromRemote() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
tags []*model.Tag
|
tags []*model.Tag
|
||||||
appTags []*model.AppTag
|
appTags []*model.AppTag
|
||||||
list = updateRes.List
|
list = updateRes.List
|
||||||
|
oldAppIds []uint
|
||||||
)
|
)
|
||||||
for _, t := range list.Extra.Tags {
|
for _, t := range list.Extra.Tags {
|
||||||
tags = append(tags, &model.Tag{
|
tags = append(tags, &model.Tag{
|
||||||
@ -547,8 +675,12 @@ func (a AppService) SyncAppListFromRemote() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
for _, old := range oldApps {
|
||||||
|
oldAppIds = append(oldAppIds, old.ID)
|
||||||
|
}
|
||||||
|
|
||||||
baseRemoteUrl := fmt.Sprintf("%s/%s/1panel", global.CONF.System.AppRepo, global.CONF.System.Mode)
|
baseRemoteUrl := fmt.Sprintf("%s/%s/1panel", global.CONF.System.AppRepo, global.CONF.System.Mode)
|
||||||
appsMap := getApps(oldApps, list.Apps, false)
|
appsMap := getApps(oldApps, list.Apps)
|
||||||
for _, l := range list.Apps {
|
for _, l := range list.Apps {
|
||||||
app := appsMap[l.AppProperty.Key]
|
app := appsMap[l.AppProperty.Key]
|
||||||
iconRes, err := http.Get(l.Icon)
|
iconRes, err := http.Get(l.Icon)
|
||||||
@ -630,29 +762,25 @@ func (a AppService) SyncAppListFromRemote() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
tx, ctx := getTxAndContext()
|
tx, ctx := getTxAndContext()
|
||||||
|
defer tx.Rollback()
|
||||||
if len(addAppArray) > 0 {
|
if len(addAppArray) > 0 {
|
||||||
if err := appRepo.BatchCreate(ctx, addAppArray); err != nil {
|
if err := appRepo.BatchCreate(ctx, addAppArray); err != nil {
|
||||||
tx.Rollback()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(deleteAppArray) > 0 {
|
if len(deleteAppArray) > 0 {
|
||||||
if err := appRepo.BatchDelete(ctx, deleteAppArray); err != nil {
|
if err := appRepo.BatchDelete(ctx, deleteAppArray); err != nil {
|
||||||
tx.Rollback()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := appDetailRepo.DeleteByAppIds(ctx, deleteIds); err != nil {
|
if err := appDetailRepo.DeleteByAppIds(ctx, deleteIds); err != nil {
|
||||||
tx.Rollback()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := tagRepo.DeleteAll(ctx); err != nil {
|
if err := tagRepo.DeleteAll(ctx); err != nil {
|
||||||
tx.Rollback()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(tags) > 0 {
|
if len(tags) > 0 {
|
||||||
if err := tagRepo.BatchCreate(ctx, tags); err != nil {
|
if err := tagRepo.BatchCreate(ctx, tags); err != nil {
|
||||||
tx.Rollback()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, t := range tags {
|
for _, t := range tags {
|
||||||
@ -661,7 +789,6 @@ func (a AppService) SyncAppListFromRemote() error {
|
|||||||
}
|
}
|
||||||
for _, update := range updateAppArray {
|
for _, update := range updateAppArray {
|
||||||
if err := appRepo.Save(ctx, &update); err != nil {
|
if err := appRepo.Save(ctx, &update); err != nil {
|
||||||
tx.Rollback()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -697,24 +824,23 @@ func (a AppService) SyncAppListFromRemote() error {
|
|||||||
}
|
}
|
||||||
if len(addDetails) > 0 {
|
if len(addDetails) > 0 {
|
||||||
if err := appDetailRepo.BatchCreate(ctx, addDetails); err != nil {
|
if err := appDetailRepo.BatchCreate(ctx, addDetails); err != nil {
|
||||||
tx.Rollback()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, u := range updateDetails {
|
for _, u := range updateDetails {
|
||||||
if err := appDetailRepo.Update(ctx, u); err != nil {
|
if err := appDetailRepo.Update(ctx, u); err != nil {
|
||||||
tx.Rollback()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := appTagRepo.DeleteAll(ctx); err != nil {
|
if len(oldAppIds) > 0 {
|
||||||
tx.Rollback()
|
if err := appTagRepo.DeleteByAppIds(ctx, oldAppIds); err != nil {
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(appTags) > 0 {
|
if len(appTags) > 0 {
|
||||||
if err := appTagRepo.BatchCreate(ctx, appTags); err != nil {
|
if err := appTagRepo.BatchCreate(ctx, appTags); err != nil {
|
||||||
tx.Rollback()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,34 +316,6 @@ func checkRequiredAndLimit(app model.App) error {
|
|||||||
if err := checkLimit(app); err != nil {
|
if err := checkLimit(app); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if app.Required != "" {
|
|
||||||
var requiredArray []string
|
|
||||||
if err := json.Unmarshal([]byte(app.Required), &requiredArray); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, key := range requiredArray {
|
|
||||||
if key == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
requireApp, err := appRepo.GetFirst(appRepo.WithKey(key))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
details, err := appDetailRepo.GetBy(appDetailRepo.WithAppId(requireApp.ID))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var detailIds []uint
|
|
||||||
for _, d := range details {
|
|
||||||
detailIds = append(detailIds, d.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = appInstallRepo.GetFirst(appInstallRepo.WithDetailIdsIn(detailIds))
|
|
||||||
if err != nil {
|
|
||||||
return buserr.WithDetail(constant.ErrAppRequired, requireApp.Name, nil)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,7 +363,7 @@ func downloadApp(app model.App, appDetail model.AppDetail, appInstall *model.App
|
|||||||
installAppDir := path.Join(constant.AppInstallDir, app.Key)
|
installAppDir := path.Join(constant.AppInstallDir, app.Key)
|
||||||
if app.Resource == constant.AppResourceLocal {
|
if app.Resource == constant.AppResourceLocal {
|
||||||
appResourceDir = constant.LocalAppResourceDir
|
appResourceDir = constant.LocalAppResourceDir
|
||||||
appKey = strings.TrimPrefix(app.Resource, "local")
|
appKey = strings.TrimPrefix(app.Key, "local")
|
||||||
installAppDir = path.Join(constant.LocalAppInstallDir, appKey)
|
installAppDir = path.Join(constant.LocalAppInstallDir, appKey)
|
||||||
}
|
}
|
||||||
resourceDir := path.Join(appResourceDir, appKey, appDetail.Version)
|
resourceDir := path.Join(appResourceDir, appKey, appDetail.Version)
|
||||||
@ -520,7 +492,7 @@ func getAppDetails(details []model.AppDetail, versions []dto.AppConfigVersion) m
|
|||||||
return appDetails
|
return appDetails
|
||||||
}
|
}
|
||||||
|
|
||||||
func getApps(oldApps []model.App, items []dto.AppDefine, isLocal bool) map[string]model.App {
|
func getApps(oldApps []model.App, items []dto.AppDefine) map[string]model.App {
|
||||||
apps := make(map[string]model.App, len(oldApps))
|
apps := make(map[string]model.App, len(oldApps))
|
||||||
for _, old := range oldApps {
|
for _, old := range oldApps {
|
||||||
old.Status = constant.AppTakeDown
|
old.Status = constant.AppTakeDown
|
||||||
@ -529,18 +501,11 @@ func getApps(oldApps []model.App, items []dto.AppDefine, isLocal bool) map[strin
|
|||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
config := item.AppProperty
|
config := item.AppProperty
|
||||||
key := config.Key
|
key := config.Key
|
||||||
if isLocal {
|
|
||||||
key = "local" + key
|
|
||||||
}
|
|
||||||
app, ok := apps[key]
|
app, ok := apps[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
app = model.App{}
|
app = model.App{}
|
||||||
}
|
}
|
||||||
if isLocal {
|
app.Resource = constant.AppResourceRemote
|
||||||
app.Resource = constant.AppResourceLocal
|
|
||||||
} else {
|
|
||||||
app.Resource = constant.AppResourceRemote
|
|
||||||
}
|
|
||||||
app.Name = item.Name
|
app.Name = item.Name
|
||||||
app.Limit = config.Limit
|
app.Limit = config.Limit
|
||||||
app.Key = key
|
app.Key = key
|
||||||
@ -551,7 +516,6 @@ func getApps(oldApps []model.App, items []dto.AppDefine, isLocal bool) map[strin
|
|||||||
app.Github = config.Github
|
app.Github = config.Github
|
||||||
app.Type = config.Type
|
app.Type = config.Type
|
||||||
app.CrossVersionUpdate = config.CrossVersionUpdate
|
app.CrossVersionUpdate = config.CrossVersionUpdate
|
||||||
app.Required = config.GetRequired()
|
|
||||||
app.Status = constant.AppNormal
|
app.Status = constant.AppNormal
|
||||||
app.LastModified = item.LastModified
|
app.LastModified = item.LastModified
|
||||||
app.ReadMe = item.ReadMe
|
app.ReadMe = item.ReadMe
|
||||||
@ -572,29 +536,6 @@ func handleErr(install model.AppInstall, err error, out string) error {
|
|||||||
return reErr
|
return reErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAppFromRepo(downloadPath, version string) error {
|
|
||||||
downloadUrl := downloadPath
|
|
||||||
appDir := constant.AppResourceDir
|
|
||||||
|
|
||||||
global.LOG.Infof("download file from %s", downloadUrl)
|
|
||||||
fileOp := files.NewFileOp()
|
|
||||||
if _, err := fileOp.CopyAndBackup(appDir); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
packagePath := path.Join(constant.ResourceDir, path.Base(downloadUrl))
|
|
||||||
if err := fileOp.DownloadFile(downloadUrl, packagePath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := fileOp.Decompress(packagePath, constant.ResourceDir, files.TarGz); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_ = NewISettingService().Update("AppStoreVersion", version)
|
|
||||||
defer func() {
|
|
||||||
_ = fileOp.DeleteFile(packagePath)
|
|
||||||
}()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleInstalled(appInstallList []model.AppInstall, updated bool) ([]response.AppInstalledDTO, error) {
|
func handleInstalled(appInstallList []model.AppInstall, updated bool) ([]response.AppInstalledDTO, error) {
|
||||||
var res []response.AppInstalledDTO
|
var res []response.AppInstalledDTO
|
||||||
for _, installed := range appInstallList {
|
for _, installed := range appInstallList {
|
||||||
|
@ -7,11 +7,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DataDir = global.CONF.System.DataDir
|
DataDir = global.CONF.System.DataDir
|
||||||
ResourceDir = path.Join(DataDir, "resource")
|
ResourceDir = path.Join(DataDir, "resource")
|
||||||
AppResourceDir = path.Join(ResourceDir, "apps")
|
AppResourceDir = path.Join(ResourceDir, "apps")
|
||||||
AppInstallDir = path.Join(DataDir, "apps")
|
AppInstallDir = path.Join(DataDir, "apps")
|
||||||
LocalAppResourceDir = path.Join(ResourceDir, "localApps")
|
LocalAppResourceDir = path.Join(AppResourceDir, "local")
|
||||||
LocalAppInstallDir = path.Join(DataDir, "localApps")
|
LocalAppInstallDir = path.Join(AppInstallDir, "local")
|
||||||
RuntimeDir = path.Join(DataDir, "runtime")
|
RemoteAppResourceDir = path.Join(AppResourceDir, "remote")
|
||||||
|
RuntimeDir = path.Join(DataDir, "runtime")
|
||||||
)
|
)
|
||||||
|
@ -15,10 +15,13 @@ func Init() {
|
|||||||
constant.AppResourceDir = path.Join(constant.ResourceDir, "apps")
|
constant.AppResourceDir = path.Join(constant.ResourceDir, "apps")
|
||||||
constant.AppInstallDir = path.Join(constant.DataDir, "apps")
|
constant.AppInstallDir = path.Join(constant.DataDir, "apps")
|
||||||
constant.RuntimeDir = path.Join(constant.DataDir, "runtime")
|
constant.RuntimeDir = path.Join(constant.DataDir, "runtime")
|
||||||
constant.LocalAppResourceDir = path.Join(constant.ResourceDir, "localApps")
|
|
||||||
constant.LocalAppInstallDir = path.Join(constant.DataDir, "localApps")
|
|
||||||
|
|
||||||
dirs := []string{constant.DataDir, constant.ResourceDir, constant.AppResourceDir, constant.AppInstallDir, global.CONF.System.Backup, constant.RuntimeDir, constant.LocalAppResourceDir}
|
constant.LocalAppResourceDir = path.Join(constant.AppResourceDir, "local")
|
||||||
|
constant.LocalAppInstallDir = path.Join(constant.AppInstallDir, "local")
|
||||||
|
constant.RemoteAppResourceDir = path.Join(constant.AppResourceDir, "remote")
|
||||||
|
|
||||||
|
dirs := []string{constant.DataDir, constant.ResourceDir, constant.AppResourceDir, constant.AppInstallDir,
|
||||||
|
global.CONF.System.Backup, constant.RuntimeDir, constant.LocalAppResourceDir, constant.RemoteAppResourceDir}
|
||||||
|
|
||||||
fileOp := files.NewFileOp()
|
fileOp := files.NewFileOp()
|
||||||
for _, dir := range dirs {
|
for _, dir := range dirs {
|
||||||
|
@ -314,12 +314,9 @@ var AddEntranceAndSSL = &gormigrate.Migration{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var UpdateTableSetting = &gormigrate.Migration{
|
var UpdateTableSetting = &gormigrate.Migration{
|
||||||
ID: "20200511-update-table-setting",
|
ID: "20200516-update-table-setting",
|
||||||
Migrate: func(tx *gorm.DB) error {
|
Migrate: func(tx *gorm.DB) error {
|
||||||
if err := tx.AutoMigrate(&model.App{}); err != nil {
|
if err := tx.Create(&model.Setting{Key: "AppStoreLastModified", Value: "0"}).Error; err != nil {
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := tx.Create(&model.Setting{Key: "AppStoreLastModified", Value: ""}).Error; err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -327,8 +324,11 @@ var UpdateTableSetting = &gormigrate.Migration{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var UpdateTableAppDetail = &gormigrate.Migration{
|
var UpdateTableAppDetail = &gormigrate.Migration{
|
||||||
ID: "20200513-update-table-app-detail",
|
ID: "20200517-update-table-app-detail",
|
||||||
Migrate: func(tx *gorm.DB) error {
|
Migrate: func(tx *gorm.DB) error {
|
||||||
|
if err := tx.AutoMigrate(&model.App{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := tx.AutoMigrate(&model.AppDetail{}); err != nil {
|
if err := tx.AutoMigrate(&model.AppDetail{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user