From 5f5a48041b231f796e2dc4d47fb5e4bcc83ba59c Mon Sep 17 00:00:00 2001 From: zhengkunwang223 Date: Fri, 14 Oct 2022 14:48:55 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E4=BB=8EOSS=E6=9B=B4=E6=96=B0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/apps.json | 4 ++ backend/app.yaml | 3 +- backend/app/dto/app.go | 91 +++++++++++++++++--------------- backend/app/repo/app_install.go | 2 +- backend/app/service/app.go | 5 +- backend/app/service/app_utils.go | 62 +++++++++++++++++++--- backend/app/service/file.go | 2 +- backend/utils/files/file_op.go | 38 ++++++++++++- 8 files changed, 150 insertions(+), 57 deletions(-) create mode 100644 apps/apps.json diff --git a/apps/apps.json b/apps/apps.json new file mode 100644 index 000000000..6d72ca95c --- /dev/null +++ b/apps/apps.json @@ -0,0 +1,4 @@ +{ + "version": "0.0.1", + "package": "" +} diff --git a/backend/app.yaml b/backend/app.yaml index d0850568b..9e51cf59e 100644 --- a/backend/app.yaml +++ b/backend/app.yaml @@ -3,8 +3,7 @@ system: db_type: sqlite level: debug data_dir: /opt/1Panel/data - resource_dir: /opt/1Panel/data/resource - app_dir: /opt/1Panel/data/apps + app_oss: "https://1panel.oss-cn-hangzhou.aliyuncs.com/apps.json" mysql: path: localhost diff --git a/backend/app/dto/app.go b/backend/app/dto/app.go index d4e24fb32..2c1c1d314 100644 --- a/backend/app/dto/app.go +++ b/backend/app/dto/app.go @@ -24,49 +24,6 @@ type AppDetailDTO struct { Params interface{} `json:"params"` } -type AppList struct { - Version string `json:"version"` - Tags []Tag `json:"tags"` - Items []AppDefine `json:"items"` -} - -type AppDefine struct { - Key string `json:"key"` - Name string `json:"name"` - Tags []string `json:"tags"` - Versions []string `json:"versions"` - Icon string `json:"icon"` - Author string `json:"author"` - Source string `json:"source"` - ShortDesc string `json:"short_desc"` - Type string `json:"type"` - Required []string `json:"Required"` - CrossVersionUpdate bool `json:"crossVersionUpdate"` -} - -func (define AppDefine) GetRequired() string { - by, _ := json.Marshal(define.Required) - return string(by) -} - -type Tag struct { - Key string `json:"key"` - Name string `json:"name"` -} - -type AppForm struct { - FormFields []AppFormFields `json:"form_fields"` -} - -type AppFormFields struct { - Type string `json:"type"` - LabelZh string `json:"label_zh"` - LabelEn string `json:"label_en"` - Required string `json:"required"` - Default string `json:"default"` - EnvKey string `json:"env_variable"` -} - type AppRequest struct { PageInfo Name string `json:"name"` @@ -143,7 +100,55 @@ type ContainerExec struct { Auth AuthParam `json:"auth"` } +type AppOssConfig struct { + Version string `json:"version"` + Package string `json:"package"` +} + type AppVersion struct { Version string `json:"version"` DetailId uint `json:"detailId"` } + +type AppList struct { + Version string `json:"version"` + Tags []Tag `json:"tags"` + Items []AppDefine `json:"items"` +} + +type AppDefine struct { + Key string `json:"key"` + Name string `json:"name"` + Tags []string `json:"tags"` + Versions []string `json:"versions"` + Icon string `json:"icon"` + Author string `json:"author"` + Source string `json:"source"` + ShortDesc string `json:"short_desc"` + Type string `json:"type"` + Required []string `json:"Required"` + CrossVersionUpdate bool `json:"crossVersionUpdate"` +} + +func (define AppDefine) GetRequired() string { + by, _ := json.Marshal(define.Required) + return string(by) +} + +type Tag struct { + Key string `json:"key"` + Name string `json:"name"` +} + +type AppForm struct { + FormFields []AppFormFields `json:"form_fields"` +} + +type AppFormFields struct { + Type string `json:"type"` + LabelZh string `json:"label_zh"` + LabelEn string `json:"label_en"` + Required string `json:"required"` + Default string `json:"default"` + EnvKey string `json:"env_variable"` +} diff --git a/backend/app/repo/app_install.go b/backend/app/repo/app_install.go index 3eb97d02c..ad8d13568 100644 --- a/backend/app/repo/app_install.go +++ b/backend/app/repo/app_install.go @@ -84,5 +84,5 @@ func (a AppInstallRepo) BatchUpdateBy(maps map[string]interface{}, opts ...DBOpt if len(opts) == 0 { db = db.Where("1=1") } - return db.Updates(&maps).Error + return db.Debug().Updates(&maps).Error } diff --git a/backend/app/service/app.go b/backend/app/service/app.go index 96e64be82..b074decc6 100644 --- a/backend/app/service/app.go +++ b/backend/app/service/app.go @@ -444,7 +444,10 @@ func (a AppService) SyncInstalled(installId uint) error { } func (a AppService) SyncAppList() error { - //TODO 从 oss 拉取最新列表 + if err := getAppFromOss(); err != nil { + global.LOG.Errorf("get app from oss error: %s", err.Error()) + return err + } appDir := constant.AppResourceDir iconDir := path.Join(appDir, "icons") diff --git a/backend/app/service/app_utils.go b/backend/app/service/app_utils.go index 5de087afa..a9812bade 100644 --- a/backend/app/service/app_utils.go +++ b/backend/app/service/app_utils.go @@ -7,6 +7,7 @@ import ( "github.com/1Panel-dev/1Panel/app/dto" "github.com/1Panel-dev/1Panel/app/model" "github.com/1Panel-dev/1Panel/constant" + "github.com/1Panel-dev/1Panel/global" "github.com/1Panel-dev/1Panel/utils/cmd" "github.com/1Panel-dev/1Panel/utils/common" "github.com/1Panel-dev/1Panel/utils/compose" @@ -14,7 +15,9 @@ import ( "github.com/joho/godotenv" "github.com/pkg/errors" "gopkg.in/yaml.v3" + "io/ioutil" "math" + "net/http" "os" "path" "reflect" @@ -229,13 +232,9 @@ func restoreInstall(install model.AppInstall, backup model.AppInstallBackup) err if !fileOp.Stat(backupFile) { return errors.New(fmt.Sprintf("%s file is not exist", backup.Name)) } - backDir := installDir + "_back" - if fileOp.Stat(backDir) { - if err := fileOp.DeleteDir(backDir); err != nil { - return err - } - } - if err := fileOp.Rename(installDir, backDir); err != nil { + + backupDir, err := fileOp.Backup(installDir) + if err != nil { return err } if err := fileOp.Decompress(backupFile, installKeyDir, files.TarGz); err != nil { @@ -280,7 +279,7 @@ func restoreInstall(install model.AppInstall, backup model.AppInstallBackup) err } install.Param = backup.Param - _ = fileOp.DeleteDir(backDir) + _ = fileOp.DeleteDir(backupDir) if out, err := compose.Up(install.GetComposePath()); err != nil { return handleErr(install, err, out) } @@ -456,3 +455,50 @@ func handleErr(install model.AppInstall, err error, out string) error { _ = appInstallRepo.Save(&install) return reErr } + +func getAppFromOss() error { + res, err := http.Get(global.CONF.System.AppOss) + if err != nil { + return err + } + appByte, err := ioutil.ReadAll(res.Body) + if err != nil { + return err + } + var ossConfig dto.AppOssConfig + if err := json.Unmarshal(appByte, &ossConfig); err != nil { + return err + } + appDir := constant.AppResourceDir + oldListFile := path.Join(appDir, "list.json") + content, err := os.ReadFile(oldListFile) + if err != nil { + return err + } + list := &dto.AppList{} + if err := json.Unmarshal(content, list); err != nil { + return err + } + if list.Version == ossConfig.Version { + return nil + } + + fileOp := files.NewFileOp() + if _, err := fileOp.Backup(appDir); err != nil { + return err + } + + packageName := path.Base(ossConfig.Package) + packagePath := path.Join(constant.ResourceDir, packageName) + if err := fileOp.DownloadFile(ossConfig.Package, packagePath); err != nil { + return err + } + if err := fileOp.Decompress(packagePath, constant.ResourceDir, files.Zip); err != nil { + return err + } + + defer func() { + _ = fileOp.DeleteFile(packagePath) + }() + return nil +} diff --git a/backend/app/service/file.go b/backend/app/service/file.go index a40205b2f..3da89be9d 100644 --- a/backend/app/service/file.go +++ b/backend/app/service/file.go @@ -126,7 +126,7 @@ func (f FileService) ChangeName(re dto.FileRename) error { func (f FileService) Wget(w dto.FileWget) (string, error) { fo := files.NewFileOp() key := "file-wget-" + uuid.NewV4().String() - return key, fo.DownloadFile(w.Url, filepath.Join(w.Path, w.Name), key) + return key, fo.DownloadFileWithProcess(w.Url, filepath.Join(w.Path, w.Name), key) } func (f FileService) MvFile(m dto.FileMove) error { diff --git a/backend/utils/files/file_op.go b/backend/utils/files/file_op.go index bfaddc382..6a36be426 100644 --- a/backend/utils/files/file_op.go +++ b/backend/utils/files/file_op.go @@ -137,7 +137,7 @@ func (w *WriteCounter) SaveProcess() { } -func (f FileOp) DownloadFile(url, dst, key string) error { +func (f FileOp) DownloadFileWithProcess(url, dst, key string) error { resp, err := http.Get(url) if err != nil { global.LOG.Errorf("get download file [%s] error, err %s", dst, err.Error()) @@ -167,6 +167,26 @@ func (f FileOp) DownloadFile(url, dst, key string) error { return nil } +func (f FileOp) DownloadFile(url, dst string) error { + resp, err := http.Get(url) + if err != nil { + global.LOG.Errorf("get download file [%s] error, err %s", dst, err.Error()) + } + + out, err := os.Create(dst) + if err != nil { + global.LOG.Errorf("create download file [%s] error, err %s", dst, err.Error()) + } + + if _, err = io.Copy(out, resp.Body); err != nil { + global.LOG.Errorf("save download file [%s] error, err %s", dst, err.Error()) + } + out.Close() + resp.Body.Close() + + return nil +} + func (f FileOp) Cut(oldPaths []string, dst string) error { for _, p := range oldPaths { base := filepath.Base(p) @@ -396,3 +416,19 @@ func (f FileOp) Decompress(srcFile string, dst string, cType CompressType) error } return format.Extract(context.Background(), input, nil, handler) } + +func (f FileOp) Backup(srcFile string) (string, error) { + backupPath := srcFile + "_bak" + info, _ := f.Fs.Stat(backupPath) + if info != nil { + if info.IsDir() { + f.DeleteDir(backupPath) + } else { + f.DeleteFile(backupPath) + } + } + if err := f.Rename(srcFile, backupPath); err != nil { + return backupPath, err + } + return backupPath, nil +}