Files
Meshray-Manager/internal/handler/update.go
T
2026-06-30 15:14:37 +08:00

174 lines
4.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package handler
import (
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
// UpdateHandler 系统更新处理器
type UpdateHandler struct {
httpClient *http.Client
currentVersion string
}
// NewUpdateHandler 创建系统更新处理器
func NewUpdateHandler(currentVersion string) *UpdateHandler {
return &UpdateHandler{
httpClient: &http.Client{
Timeout: 10 * time.Second,
},
currentVersion: currentVersion,
}
}
// GitHubRelease GitHub 发布响应结构
type GitHubRelease struct {
TagName string `json:"tag_name"`
Name string `json:"name"`
Body string `json:"body"`
PublishedAt string `json:"published_at"`
HtmlURL string `json:"html_url"`
Assets []struct {
Name string `json:"name"`
DownloadURL string `json:"browser_download_url"`
Size int64 `json:"size"`
} `json:"assets"`
}
// CheckUpdateResponse 检查更新响应
type CheckUpdateResponse struct {
HasUpdate bool `json:"has_update"`
LatestVersion string `json:"latest_version"`
CurrentVersion string `json:"current_version"`
ReleaseNotes string `json:"release_notes"`
DownloadURL string `json:"download_url"`
PublishedAt string `json:"published_at"`
Error string `json:"error,omitempty"`
}
// CheckUpdate 检查更新
// @Summary 检查系统更新
// @Tags System
// @Accept json
// @Produce json
// @Success 200 {object} CheckUpdateResponse
// @Router /api/v1/system/update/check [get]
func (h *UpdateHandler) CheckUpdate() (*CheckUpdateResponse, error) {
// Gitea Releases API
repo := "zkcoi/meshray"
url := fmt.Sprintf("https://git.zkcoi.com/api/v1/repos/%s/releases/latest", repo)
resp, err := h.httpClient.Get(url)
if err != nil {
return &CheckUpdateResponse{
HasUpdate: false,
CurrentVersion: h.currentVersion,
Error: "检查更新失败:" + err.Error(),
}, nil
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return &CheckUpdateResponse{
HasUpdate: false,
CurrentVersion: h.currentVersion,
Error: "读取响应失败:" + err.Error(),
}, nil
}
var release GitHubRelease
if err := json.Unmarshal(body, &release); err != nil {
return &CheckUpdateResponse{
HasUpdate: false,
CurrentVersion: h.currentVersion,
Error: "解析响应失败:" + err.Error(),
}, nil
}
// 移除版本号前缀的 'v'
latestVersion := release.TagName
if len(latestVersion) > 0 && latestVersion[0] == 'v' {
latestVersion = latestVersion[1:]
}
currentVersion := h.currentVersion
if len(currentVersion) > 0 && currentVersion[0] == 'v' {
currentVersion = currentVersion[1:]
}
// 比较版本号
hasUpdate := compareVersions(latestVersion, currentVersion) > 0
downloadURL := release.HtmlURL
if len(release.Assets) > 0 {
// 优先选择 Windows 可执行文件
for _, asset := range release.Assets {
if asset.Name == "meshray.exe" {
downloadURL = asset.DownloadURL
break
}
}
}
return &CheckUpdateResponse{
HasUpdate: hasUpdate,
LatestVersion: release.TagName,
CurrentVersion: h.currentVersion,
ReleaseNotes: release.Body,
DownloadURL: downloadURL,
PublishedAt: release.PublishedAt,
}, nil
}
// compareVersions 比较版本号
// 返回:1 (v1 > v2), 0 (v1 == v2), -1 (v1 < v2)
func compareVersions(v1, v2 string) int {
if v1 == v2 {
return 0
}
// 简单版本号比较(格式:major.minor.patch
parts1 := parseVersion(v1)
parts2 := parseVersion(v2)
for i := 0; i < len(parts1) && i < len(parts2); i++ {
if parts1[i] > parts2[i] {
return 1
} else if parts1[i] < parts2[i] {
return -1
}
}
// 如果前面都相同,比较长度
if len(parts1) > len(parts2) {
return 1
}
return -1
}
// parseVersion 解析版本号字符串为整数数组
func parseVersion(version string) []int {
var parts []int
current := 0
for i, ch := range version {
if ch == '.' {
parts = append(parts, current)
current = 0
} else if ch >= '0' && ch <= '9' {
current = current*10 + int(ch-'0')
}
// 处理最后一个字符
if i == len(version)-1 {
parts = append(parts, current)
}
}
return parts
}