mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-09-10 16:46:26 +08:00
216 lines
6.2 KiB
Go
216 lines
6.2 KiB
Go
package version
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
|
"github.com/1Panel-dev/1Panel/agent/app/model"
|
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
|
"github.com/1Panel-dev/1Panel/agent/global"
|
|
"github.com/1Panel-dev/1Panel/agent/utils/common"
|
|
)
|
|
|
|
func GetUpgradeVersionInfo() (*dto.UpgradeInfo, error) {
|
|
var upgrade dto.UpgradeInfo
|
|
var currentVersion model.Setting
|
|
if err := global.CoreDB.Model(&model.Setting{}).Where("key = ?", "SystemVersion").First(¤tVersion).Error; err != nil {
|
|
global.LOG.Errorf("load %s from db setting failed, err: %v", "SystemVersion", err)
|
|
return nil, err
|
|
}
|
|
var developerMode model.Setting
|
|
if err := global.CoreDB.Model(&model.Setting{}).Where("key = ?", "DeveloperMode").First(&developerMode).Error; err != nil {
|
|
global.LOG.Errorf("load %s from db setting failed, err: %v", "DeveloperMode", err)
|
|
return nil, err
|
|
}
|
|
|
|
upgrade.TestVersion, upgrade.NewVersion, upgrade.LatestVersion = loadVersionByMode(developerMode.Value, currentVersion.Value)
|
|
var itemVersion string
|
|
if len(upgrade.NewVersion) != 0 {
|
|
itemVersion = upgrade.NewVersion
|
|
}
|
|
if (global.CONF.Base.Mode == "dev" || developerMode.Value == constant.StatusEnable) && len(upgrade.TestVersion) != 0 {
|
|
itemVersion = upgrade.TestVersion
|
|
}
|
|
if len(upgrade.LatestVersion) != 0 {
|
|
itemVersion = upgrade.LatestVersion
|
|
}
|
|
if len(itemVersion) == 0 {
|
|
return &upgrade, nil
|
|
}
|
|
mode := global.CONF.Base.Mode
|
|
if strings.Contains(itemVersion, "beta") {
|
|
mode = "beta"
|
|
}
|
|
notes, err := loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.RemoteURL.RepoUrl, mode, itemVersion, itemVersion))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("load releases-notes of version %s failed, err: %v", itemVersion, err)
|
|
}
|
|
upgrade.ReleaseNote = notes
|
|
return &upgrade, nil
|
|
}
|
|
|
|
func loadVersionByMode(developer, currentVersion string) (string, string, string) {
|
|
var current, latest string
|
|
if global.CONF.Base.Mode == "dev" {
|
|
betaVersionLatest := loadVersion(true, currentVersion, "beta")
|
|
devVersionLatest := loadVersion(true, currentVersion, "dev")
|
|
if common.ComparePanelVersion(betaVersionLatest, devVersionLatest) {
|
|
return betaVersionLatest, "", ""
|
|
}
|
|
return devVersionLatest, "", ""
|
|
}
|
|
|
|
betaVersionLatest := ""
|
|
latest = loadVersion(true, currentVersion, "stable")
|
|
current = loadVersion(false, currentVersion, "stable")
|
|
if developer == constant.StatusEnable {
|
|
betaVersionLatest = loadVersion(true, currentVersion, "beta")
|
|
}
|
|
if current != latest {
|
|
return betaVersionLatest, current, latest
|
|
}
|
|
|
|
versionPart := strings.Split(current, ".")
|
|
if len(versionPart) < 3 {
|
|
return betaVersionLatest, current, latest
|
|
}
|
|
num, _ := strconv.Atoi(versionPart[1])
|
|
if num == 0 {
|
|
return betaVersionLatest, current, latest
|
|
}
|
|
if num >= 10 {
|
|
if current[:6] == currentVersion[:6] {
|
|
return betaVersionLatest, current, ""
|
|
}
|
|
return betaVersionLatest, "", latest
|
|
}
|
|
if current[:5] == currentVersion[:5] {
|
|
return betaVersionLatest, current, ""
|
|
}
|
|
return betaVersionLatest, "", latest
|
|
}
|
|
|
|
func loadVersion(isLatest bool, currentVersion, mode string) string {
|
|
path := fmt.Sprintf("%s/%s/latest", global.CONF.RemoteURL.RepoUrl, mode)
|
|
if !isLatest {
|
|
path = fmt.Sprintf("%s/%s/latest.current", global.CONF.RemoteURL.RepoUrl, mode)
|
|
}
|
|
_, latestVersionRes, err := HandleRequest(path, http.MethodGet, constant.TimeOut20s)
|
|
if err != nil {
|
|
global.LOG.Errorf("load latest version from oss failed, err: %v", err)
|
|
return ""
|
|
}
|
|
version := string(latestVersionRes)
|
|
if strings.Contains(version, "<") {
|
|
global.LOG.Errorf("load latest version from oss failed, err: %v", version)
|
|
return ""
|
|
}
|
|
if isLatest {
|
|
return checkVersion(version, currentVersion)
|
|
}
|
|
|
|
versionMap := make(map[string]string)
|
|
if err := json.Unmarshal(latestVersionRes, &versionMap); err != nil {
|
|
global.LOG.Errorf("load latest version from oss failed (error unmarshal), err: %v", err)
|
|
return ""
|
|
}
|
|
|
|
versionPart := strings.Split(currentVersion, ".")
|
|
if len(versionPart) < 3 {
|
|
global.LOG.Errorf("current version is error format: %s", currentVersion)
|
|
return ""
|
|
}
|
|
num, _ := strconv.Atoi(versionPart[1])
|
|
if num >= 10 {
|
|
if version, ok := versionMap[currentVersion[0:5]]; ok {
|
|
return checkVersion(version, currentVersion)
|
|
}
|
|
return ""
|
|
}
|
|
if version, ok := versionMap[currentVersion[0:4]]; ok {
|
|
return checkVersion(version, currentVersion)
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func checkVersion(v2, v1 string) string {
|
|
addSuffix := false
|
|
if !strings.Contains(v1, "-") {
|
|
v1 = v1 + "-lts"
|
|
}
|
|
if !strings.Contains(v2, "-") {
|
|
addSuffix = true
|
|
v2 = v2 + "-lts"
|
|
}
|
|
if common.ComparePanelVersion(v2, v1) {
|
|
if addSuffix {
|
|
return strings.TrimSuffix(v2, "-lts")
|
|
}
|
|
return v2
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func loadReleaseNotes(path string) (string, error) {
|
|
_, releaseNotes, err := HandleRequest(path, http.MethodGet, constant.TimeOut20s)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(releaseNotes), nil
|
|
}
|
|
|
|
func HandleRequest(url, method string, timeout int) (int, []byte, error) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
global.LOG.Errorf("handle request failed, error message: %v", r)
|
|
return
|
|
}
|
|
}()
|
|
|
|
transport := loadRequestTransport()
|
|
client := http.Client{Timeout: time.Duration(timeout) * time.Second, Transport: transport}
|
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
|
|
defer cancel()
|
|
request, err := http.NewRequestWithContext(ctx, method, url, nil)
|
|
if err != nil {
|
|
return 0, nil, err
|
|
}
|
|
request.Header.Set("Content-Type", "application/json")
|
|
resp, err := client.Do(request)
|
|
if err != nil {
|
|
return 0, nil, err
|
|
}
|
|
if resp.StatusCode != http.StatusOK {
|
|
return 0, nil, errors.New(resp.Status)
|
|
}
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
return 0, nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
return resp.StatusCode, body, nil
|
|
}
|
|
|
|
func loadRequestTransport() *http.Transport {
|
|
return &http.Transport{
|
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
|
DialContext: (&net.Dialer{
|
|
Timeout: 60 * time.Second,
|
|
KeepAlive: 60 * time.Second,
|
|
}).DialContext,
|
|
TLSHandshakeTimeout: 5 * time.Second,
|
|
ResponseHeaderTimeout: 10 * time.Second,
|
|
IdleConnTimeout: 15 * time.Second,
|
|
}
|
|
}
|