1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-01-19 08:19:15 +08:00

feat: 应用商店离线包改为从 gitee github 获取

This commit is contained in:
zhengkunwang223 2023-02-10 18:07:29 +08:00 committed by zhengkunwang223
parent 9c1fef0309
commit 80a0dfdfc0
14 changed files with 126 additions and 63 deletions

View File

@ -58,7 +58,7 @@ func (b *BaseApi) UpdateSetting(c *gin.Context) {
return return
} }
if err := settingService.Update(c, req.Key, req.Value); err != nil { if err := settingService.Update(req.Key, req.Value); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return return
} }
@ -240,12 +240,12 @@ func (b *BaseApi) MFABind(c *gin.Context) {
return return
} }
if err := settingService.Update(c, "MFAStatus", "enable"); err != nil { if err := settingService.Update("MFAStatus", "enable"); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return return
} }
if err := settingService.Update(c, "MFASecret", req.Secret); err != nil { if err := settingService.Update("MFASecret", req.Secret); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return return
} }

View File

@ -30,6 +30,8 @@ type SettingInfo struct {
EmailVars string `json:"emailVars"` EmailVars string `json:"emailVars"`
WeChatVars string `json:"weChatVars"` WeChatVars string `json:"weChatVars"`
DingVars string `json:"dingVars"` DingVars string `json:"dingVars"`
AppStoreVersion string `json:"appStoreVersion"`
} }
type SettingUpdate struct { type SettingUpdate struct {

View File

@ -333,14 +333,12 @@ func (a AppService) SyncInstalled(installId uint) error {
} }
func (a AppService) SyncAppList() error { func (a AppService) SyncAppList() error {
if err := getAppFromOss(); err != nil { if err := getAppFromRepo(); err != nil {
global.LOG.Errorf("get app from oss error: %s", err.Error()) global.LOG.Errorf("get app from oss error: %s", err.Error())
return err return err
} }
appDir := constant.AppResourceDir appDir := constant.AppResourceDir
listFile := path.Join(appDir, "list.json") listFile := path.Join(appDir, "list.json")
content, err := os.ReadFile(listFile) content, err := os.ReadFile(listFile)
if err != nil { if err != nil {
return err return err
@ -354,22 +352,18 @@ func (a AppService) SyncAppList() error {
tags []*model.Tag tags []*model.Tag
appTags []*model.AppTag appTags []*model.AppTag
) )
for _, t := range list.Tags { for _, t := range list.Tags {
tags = append(tags, &model.Tag{ tags = append(tags, &model.Tag{
Key: t.Key, Key: t.Key,
Name: t.Name, Name: t.Name,
}) })
} }
oldApps, err := appRepo.GetBy() oldApps, err := appRepo.GetBy()
if err != nil { if err != nil {
return err return err
} }
appsMap := getApps(oldApps, list.Items) appsMap := getApps(oldApps, list.Items)
for _, l := range list.Items { for _, l := range list.Items {
app := appsMap[l.Key] app := appsMap[l.Key]
icon, err := os.ReadFile(path.Join(appDir, l.Key, "metadata", "logo.png")) icon, err := os.ReadFile(path.Join(appDir, l.Key, "metadata", "logo.png"))
if err != nil { if err != nil {
@ -433,9 +427,7 @@ func (a AppService) SyncAppList() error {
updateArray = append(updateArray, v) updateArray = append(updateArray, v)
} }
} }
tx, ctx := getTxAndContext() tx, ctx := getTxAndContext()
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() tx.Rollback()
@ -461,7 +453,6 @@ func (a AppService) SyncAppList() error {
return err return err
} }
} }
apps := append(addAppArray, updateArray...) apps := append(addAppArray, updateArray...)
var ( var (
@ -478,7 +469,6 @@ func (a AppService) SyncAppList() error {
}) })
} }
} }
for _, d := range a.Details { for _, d := range a.Details {
d.AppId = a.ID d.AppId = a.ID
if d.ID == 0 { if d.ID == 0 {
@ -488,7 +478,6 @@ func (a AppService) SyncAppList() 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() tx.Rollback()

View File

@ -4,9 +4,8 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "github.com/1Panel-dev/1Panel/backend/utils/git"
"math" "math"
"net/http"
"os" "os"
"path" "path"
"reflect" "reflect"
@ -500,46 +499,32 @@ func handleErr(install model.AppInstall, err error, out string) error {
return reErr return reErr
} }
func getAppFromOss() error { func getAppFromRepo() error {
res, err := http.Get(global.CONF.System.AppOss + "/apps/apps.json") repoInfo, err := git.CheckAndGetInfo(global.CONF.System.AppRepoOwner, global.CONF.System.AppRepoName)
if err != nil { if err != nil {
return err 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 appDir := constant.AppResourceDir
content, _ := os.ReadFile(path.Join(appDir, "list.json")) setting, err := NewISettingService().GetSettingInfo()
if err != nil {
if content != nil {
oldConfig := &dto.AppOssConfig{}
if err := json.Unmarshal(content, oldConfig); err != nil {
return err return err
} }
if oldConfig.Version == ossConfig.Version { if !common.CompareVersion(repoInfo.Version, setting.AppStoreVersion) {
return nil return nil
} }
} downloadUrl := fmt.Sprintf("%sapps-%s.tar.gz", repoInfo.DownloadPath, repoInfo.Version)
fileOp := files.NewFileOp() fileOp := files.NewFileOp()
if _, err := fileOp.CopyAndBackup(appDir); err != nil { if _, err := fileOp.CopyAndBackup(appDir); err != nil {
return err return err
} }
packagePath := path.Join(constant.ResourceDir, path.Base(downloadUrl))
packagePath := path.Join(constant.ResourceDir, path.Base(ossConfig.Package)) if err := fileOp.DownloadFile(downloadUrl, packagePath); err != nil {
if err := fileOp.DownloadFile(ossConfig.Package, packagePath); err != nil {
return err return err
} }
if err := fileOp.Decompress(packagePath, constant.ResourceDir, files.Zip); err != nil { if err := fileOp.Decompress(packagePath, constant.ResourceDir, files.TarGz); err != nil {
return err return err
} }
_ = NewISettingService().Update("AppStoreVersion", repoInfo.Version)
defer func() { defer func() {
_ = fileOp.DeleteFile(packagePath) _ = fileOp.DeleteFile(packagePath)
}() }()

View File

@ -17,7 +17,7 @@ type SettingService struct{}
type ISettingService interface { type ISettingService interface {
GetSettingInfo() (*dto.SettingInfo, error) GetSettingInfo() (*dto.SettingInfo, error)
Update(c *gin.Context, key, value string) error Update(key, value string) error
UpdatePassword(c *gin.Context, old, new string) error UpdatePassword(c *gin.Context, old, new string) error
UpdatePort(port uint) error UpdatePort(port uint) error
HandlePasswordExpired(c *gin.Context, old, new string) error HandlePasswordExpired(c *gin.Context, old, new string) error
@ -48,7 +48,7 @@ func (u *SettingService) GetSettingInfo() (*dto.SettingInfo, error) {
return &info, err return &info, err
} }
func (u *SettingService) Update(c *gin.Context, key, value string) error { func (u *SettingService) Update(key, value string) error {
if key == "ExpirationDays" { if key == "ExpirationDays" {
timeout, _ := strconv.Atoi(value) timeout, _ := strconv.Atoi(value)
if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format("2006-01-02 15:04:05")); err != nil { if err := settingRepo.Update("ExpirationTime", time.Now().AddDate(0, 0, timeout).Format("2006-01-02 15:04:05")); err != nil {

View File

@ -33,7 +33,7 @@ func NewIUpgradeService() IUpgradeService {
} }
func (u *UpgradeService) SearchUpgrade() (*dto.UpgradeInfo, error) { func (u *UpgradeService) SearchUpgrade() (*dto.UpgradeInfo, error) {
currentVerion, err := settingRepo.Get(settingRepo.WithByKey("SystemVersion")) currentVersion, err := settingRepo.Get(settingRepo.WithByKey("SystemVersion"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -57,7 +57,7 @@ func (u *UpgradeService) SearchUpgrade() (*dto.UpgradeInfo, error) {
} }
} }
if len(releaseInfo.NewVersion) != 0 { if len(releaseInfo.NewVersion) != 0 {
isNew, err := compareVersion(currentVerion.Value, releaseInfo.NewVersion) isNew, err := compareVersion(currentVersion.Value, releaseInfo.NewVersion)
if !isNew && err != nil { if !isNew && err != nil {
return nil, err return nil, err
} }
@ -183,8 +183,8 @@ func (u *UpgradeService) handleRollback(fileOp files.FileOp, originalDir string,
func (u *UpgradeService) loadLatestFromGithub() (dto.UpgradeInfo, error) { func (u *UpgradeService) loadLatestFromGithub() (dto.UpgradeInfo, error) {
var info dto.UpgradeInfo var info dto.UpgradeInfo
client := github.NewClient(nil) client := github.NewClient(nil)
ctx, cancle := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancle() defer cancel()
stats, res, err := client.Repositories.GetLatestRelease(ctx, "wanghe-fit2cloud", "1Panel") stats, res, err := client.Repositories.GetLatestRelease(ctx, "wanghe-fit2cloud", "1Panel")
if res.StatusCode != 200 || err != nil { if res.StatusCode != 200 || err != nil {
return info, fmt.Errorf("load upgrade info from github failed, err: %v", err) return info, fmt.Errorf("load upgrade info from github failed, err: %v", err)
@ -198,8 +198,8 @@ func (u *UpgradeService) loadLatestFromGithub() (dto.UpgradeInfo, error) {
func (u *UpgradeService) loadLatestFromGitee() (dto.UpgradeInfo, error) { func (u *UpgradeService) loadLatestFromGitee() (dto.UpgradeInfo, error) {
var info dto.UpgradeInfo var info dto.UpgradeInfo
client := gitee.NewAPIClient(gitee.NewConfiguration()) client := gitee.NewAPIClient(gitee.NewConfiguration())
ctx, cancle := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancle() defer cancel()
stats, res, err := client.RepositoriesApi.GetV5ReposOwnerRepoReleasesLatest(ctx, "wanghe-fit2cloud", "1Panel", &gitee.GetV5ReposOwnerRepoReleasesLatestOpts{}) stats, res, err := client.RepositoriesApi.GetV5ReposOwnerRepoReleasesLatest(ctx, "wanghe-fit2cloud", "1Panel", &gitee.GetV5ReposOwnerRepoReleasesLatestOpts{})
if res.StatusCode != 200 || err != nil { if res.StatusCode != 200 || err != nil {
return info, fmt.Errorf("load upgrade info from gitee failed, err: %v", err) return info, fmt.Errorf("load upgrade info from gitee failed, err: %v", err)

View File

@ -9,4 +9,6 @@ type System struct {
Cache string `mapstructure:"cache"` Cache string `mapstructure:"cache"`
Backup string `mapstructure:"backup"` Backup string `mapstructure:"backup"`
AppOss string `mapstructure:"app_oss"` AppOss string `mapstructure:"app_oss"`
AppRepoOwner string `mapstructure:"app_repo_owner"`
AppRepoName string `mapstructure:"app_repo_name"`
} }

View File

@ -32,6 +32,7 @@ var (
ErrTokenParse = errors.New("ErrTokenParse") ErrTokenParse = errors.New("ErrTokenParse")
ErrPageGenerate = errors.New("generate page info failed") ErrPageGenerate = errors.New("generate page info failed")
ErrRepoNotValid = "ErrRepoNotValid"
) )
// api // api

View File

@ -11,7 +11,7 @@ ErrNotLogin: "User is not Login: {{ .detail }}"
ErrNotSafety: "The login status of the current user is unsafe: {{ .detail }}" ErrNotSafety: "The login status of the current user is unsafe: {{ .detail }}"
ErrPasswordExpired: "The current password has expired: {{ .detail }}" ErrPasswordExpired: "The current password has expired: {{ .detail }}"
ErrNotSupportType: "The system does not support the current type: {{ .detail }}" ErrNotSupportType: "The system does not support the current type: {{ .detail }}"
ErrRepoNotValid: "Remote repository verification failed"
#common #common
ErrNameIsExist: "Name is already exist" ErrNameIsExist: "Name is already exist"

View File

@ -11,7 +11,7 @@ ErrNotLogin: "用户未登录: {{ .detail }}"
ErrNotSafety: "当前用户登录状态不安全: {{ .detail }}" ErrNotSafety: "当前用户登录状态不安全: {{ .detail }}"
ErrPasswordExpired: "当前密码已过期: {{ .detail }}" ErrPasswordExpired: "当前密码已过期: {{ .detail }}"
ErrNotSupportType: "系统暂不支持当前类型: {{ .detail }}" ErrNotSupportType: "系统暂不支持当前类型: {{ .detail }}"
ErrRepoNotValid: "远程仓库校验失败!"
#common #common
ErrNameIsExist: "名称已存在" ErrNameIsExist: "名称已存在"

View File

@ -139,6 +139,9 @@ var AddTableSetting = &gormigrate.Migration{
if err := tx.Create(&model.Setting{Key: "SystemStatus", Value: "Free"}).Error; err != nil { if err := tx.Create(&model.Setting{Key: "SystemStatus", Value: "Free"}).Error; err != nil {
return err return err
} }
if err := tx.Create(&model.Setting{Key: "AppStoreVersion", Value: "0"}).Error; err != nil {
return err
}
return nil return nil
}, },
} }

View File

@ -23,7 +23,7 @@ func Init() {
v.SetConfigType("yaml") v.SetConfigType("yaml")
if fileOp.Stat("/opt/1panel/conf/app.yaml") { if fileOp.Stat("/opt/1panel/conf/app.yaml") {
v.SetConfigName("app") v.SetConfigName("app")
v.AddConfigPath(path.Join("/opt/1pane/conf")) v.AddConfigPath(path.Join("/opt/1panel/conf"))
if err := v.ReadInConfig(); err != nil { if err := v.ReadInConfig(); err != nil {
panic(fmt.Errorf("Fatal error config file: %s \n", err)) panic(fmt.Errorf("Fatal error config file: %s \n", err))
} }

79
backend/utils/git/git.go Normal file
View File

@ -0,0 +1,79 @@
package git
import (
"context"
"crypto/tls"
"errors"
"fmt"
"gitee.com/openeuler/go-gitee/gitee"
"github.com/google/go-github/github"
"net/http"
"time"
)
type RepoInfo struct {
RepoType string
Version string
ReleaseNote string
CreatedAt string
DownloadPath string
}
var gitRepoTypes = []string{"gitee", "github"}
func CheckAndGetInfo(owner, repoName string) (*RepoInfo, error) {
for _, repoType := range gitRepoTypes {
url := fmt.Sprintf("https://%s.com/%s/%s", repoType, owner, repoName)
if checkValid(url) {
res, err := getLatestRepoInfo(repoType, owner, repoName)
if err == nil {
return res, nil
}
}
}
return nil, errors.New("remote repo get failed")
}
func checkValid(addr string) bool {
timeout := 2 * time.Second
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := http.Client{
Transport: tr,
Timeout: timeout,
}
if _, err := client.Get(addr); err != nil {
return false
}
return true
}
func getLatestRepoInfo(repoType, owner, repoName string) (*RepoInfo, error) {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
var repoInfo RepoInfo
repoInfo.RepoType = repoType
if repoType == "gitee" {
client := gitee.NewAPIClient(gitee.NewConfiguration())
stats, res, err := client.RepositoriesApi.GetV5ReposOwnerRepoReleasesLatest(ctx, owner, repoName, &gitee.GetV5ReposOwnerRepoReleasesLatestOpts{})
if res.StatusCode != 200 || err != nil {
return nil, err
}
repoInfo.Version = stats.Name
repoInfo.ReleaseNote = stats.Body
repoInfo.CreatedAt = stats.CreatedAt.Format("2006-01-02 15:04:05")
repoInfo.DownloadPath = fmt.Sprintf("https://gitee.com/%s/%s/releases/download/%s/", owner, repoName, repoInfo.Version)
} else {
client := github.NewClient(nil)
stats, res, err := client.Repositories.GetLatestRelease(ctx, owner, repoName)
if res.StatusCode != 200 || err != nil {
return nil, err
}
repoInfo.Version = *stats.Name
repoInfo.ReleaseNote = *stats.Body
repoInfo.CreatedAt = stats.PublishedAt.Add(8 * time.Hour).Format("2006-01-02 15:04:05")
repoInfo.DownloadPath = fmt.Sprintf("https://github.com/%s/%s/releases/download/%s/", owner, repoName, repoInfo.Version)
}
return &repoInfo, nil
}

View File

@ -1,6 +1,8 @@
system: system:
db_file: 1Panel.db db_file: 1Panel.db
app_oss: "https://1panel.oss-cn-hangzhou.aliyuncs.com" app_oss: "https://1panel.oss-cn-hangzhou.aliyuncs.com"
app_repo_owner: "1Panel-dev"
app_repo_name: 'appstore'
log: log:
level: debug level: debug