Some checks failed
Build Multi-Platform Binaries / build-frontend (push) Successful in 30s
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Successful in 1m4s
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Successful in 45s
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Successful in 1m29s
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Successful in 45s
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Successful in 1m27s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Successful in 50s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, server, true) (push) Successful in 1m42s
Build Multi-Platform Binaries / build-binaries (arm64, darwin, server, false) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Has been cancelled
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Has been cancelled
208 lines
4.6 KiB
Go
208 lines
4.6 KiB
Go
package version
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// 版本信息
|
|
const Version = "1.0.0"
|
|
|
|
// 仓库信息
|
|
const (
|
|
RepoURL = "https://git.92coco.cn:8443/flik/GoTunnel"
|
|
APIBaseURL = "https://git.92coco.cn:8443/api/v1"
|
|
RepoOwner = "flik"
|
|
RepoName = "GoTunnel"
|
|
)
|
|
|
|
// Info 版本详细信息
|
|
type Info struct {
|
|
Version string `json:"version"`
|
|
GitCommit string `json:"git_commit"`
|
|
BuildTime string `json:"build_time"`
|
|
GoVersion string `json:"go_version"`
|
|
OS string `json:"os"`
|
|
Arch string `json:"arch"`
|
|
}
|
|
|
|
// GetInfo 获取版本信息
|
|
func GetInfo() Info {
|
|
return Info{
|
|
Version: Version,
|
|
GitCommit: "",
|
|
BuildTime: "",
|
|
GoVersion: runtime.Version(),
|
|
OS: runtime.GOOS,
|
|
Arch: runtime.GOARCH,
|
|
}
|
|
}
|
|
|
|
// ReleaseInfo Release 信息
|
|
type ReleaseInfo struct {
|
|
TagName string `json:"tag_name"`
|
|
Name string `json:"name"`
|
|
Body string `json:"body"`
|
|
PublishedAt string `json:"published_at"`
|
|
Assets []ReleaseAsset `json:"assets"`
|
|
}
|
|
|
|
// ReleaseAsset Release 资产
|
|
type ReleaseAsset struct {
|
|
Name string `json:"name"`
|
|
Size int64 `json:"size"`
|
|
BrowserDownloadURL string `json:"browser_download_url"`
|
|
}
|
|
|
|
// UpdateInfo 更新信息
|
|
type UpdateInfo struct {
|
|
Latest string `json:"latest"`
|
|
ReleaseNote string `json:"release_note"`
|
|
DownloadURL string `json:"download_url"`
|
|
AssetName string `json:"asset_name"`
|
|
AssetSize int64 `json:"asset_size"`
|
|
}
|
|
|
|
// GetLatestRelease 获取最新 Release
|
|
func GetLatestRelease() (*ReleaseInfo, error) {
|
|
url := fmt.Sprintf("%s/repos/%s/%s/releases/latest", APIBaseURL, RepoOwner, RepoName)
|
|
|
|
client := &http.Client{Timeout: 30 * time.Second}
|
|
resp, err := client.Get(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
body, _ := io.ReadAll(resp.Body)
|
|
return nil, fmt.Errorf("API error: %s - %s", resp.Status, string(body))
|
|
}
|
|
|
|
var release ReleaseInfo
|
|
if err := json.NewDecoder(resp.Body).Decode(&release); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &release, nil
|
|
}
|
|
|
|
// CheckUpdate 检查更新(返回最新版本信息)
|
|
func CheckUpdate(component string) (*UpdateInfo, error) {
|
|
release, err := GetLatestRelease()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("get latest release: %w", err)
|
|
}
|
|
|
|
// 查找对应平台的资产
|
|
assetName := getAssetName(component)
|
|
var downloadURL string
|
|
var assetSize int64
|
|
|
|
for _, asset := range release.Assets {
|
|
if asset.Name == assetName {
|
|
downloadURL = asset.BrowserDownloadURL
|
|
assetSize = asset.Size
|
|
break
|
|
}
|
|
}
|
|
|
|
return &UpdateInfo{
|
|
Latest: release.TagName,
|
|
ReleaseNote: release.Body,
|
|
DownloadURL: downloadURL,
|
|
AssetName: assetName,
|
|
AssetSize: assetSize,
|
|
}, nil
|
|
}
|
|
|
|
// CheckUpdateForPlatform 检查指定平台的更新
|
|
func CheckUpdateForPlatform(component, osName, arch string) (*UpdateInfo, error) {
|
|
release, err := GetLatestRelease()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("get latest release: %w", err)
|
|
}
|
|
|
|
// 查找对应平台的资产
|
|
assetName := getAssetNameForPlatform(component, osName, arch)
|
|
var downloadURL string
|
|
var assetSize int64
|
|
|
|
for _, asset := range release.Assets {
|
|
if asset.Name == assetName {
|
|
downloadURL = asset.BrowserDownloadURL
|
|
assetSize = asset.Size
|
|
break
|
|
}
|
|
}
|
|
|
|
return &UpdateInfo{
|
|
Latest: release.TagName,
|
|
ReleaseNote: release.Body,
|
|
DownloadURL: downloadURL,
|
|
AssetName: assetName,
|
|
AssetSize: assetSize,
|
|
}, nil
|
|
}
|
|
|
|
// getAssetName 获取当前平台的资产文件名
|
|
func getAssetName(component string) string {
|
|
return getAssetNameForPlatform(component, runtime.GOOS, runtime.GOARCH)
|
|
}
|
|
|
|
// getAssetNameForPlatform 获取指定平台的资产文件名
|
|
func getAssetNameForPlatform(component, osName, arch string) string {
|
|
ext := ""
|
|
if osName == "windows" {
|
|
ext = ".exe"
|
|
}
|
|
return fmt.Sprintf("%s_%s_%s%s", component, osName, arch, ext)
|
|
}
|
|
|
|
// CompareVersions 比较版本号
|
|
// 返回: -1 (v1 < v2), 0 (v1 == v2), 1 (v1 > v2)
|
|
func CompareVersions(v1, v2 string) int {
|
|
parts1 := parseVersionParts(v1)
|
|
parts2 := parseVersionParts(v2)
|
|
|
|
maxLen := len(parts1)
|
|
if len(parts2) > maxLen {
|
|
maxLen = len(parts2)
|
|
}
|
|
|
|
for i := 0; i < maxLen; i++ {
|
|
var p1, p2 int
|
|
if i < len(parts1) {
|
|
p1 = parts1[i]
|
|
}
|
|
if i < len(parts2) {
|
|
p2 = parts2[i]
|
|
}
|
|
|
|
if p1 < p2 {
|
|
return -1
|
|
}
|
|
if p1 > p2 {
|
|
return 1
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func parseVersionParts(v string) []int {
|
|
v = strings.TrimPrefix(v, "v")
|
|
parts := strings.Split(v, ".")
|
|
result := make([]int, len(parts))
|
|
for i, p := range parts {
|
|
n, _ := strconv.Atoi(p)
|
|
result[i] = n
|
|
}
|
|
return result
|
|
}
|