package main import ( "encoding/json" "fmt" "net/http" "strconv" "strings" "time" ) const remotePackageJSONURL = "https://gitea.hesukastro.com/hesukastro/vsix-hpl-toolbox/raw/branch/main/package.json" const updateRepositoryURL = "https://gitea.hesukastro.com/hesukastro/vsix-hpl-toolbox" type updateCheckResponse struct { OK bool `json:"ok"` Status string `json:"status"` CurrentVersion string `json:"currentVersion"` RemoteVersion string `json:"remoteVersion,omitempty"` Message string `json:"message"` RepositoryURL string `json:"repositoryUrl,omitempty"` } func UpdateCheckEndpoint(w http.ResponseWriter, r *http.Request) { remoteVersion, err := fetchRemoteVersion() if err != nil { writeJSON(w, updateCheckResponse{ OK: false, Status: "error", CurrentVersion: AppVersion, Message: "HPL Toolbox update check failed: " + err.Error(), }) return } comparison := compareVersions(remoteVersion, AppVersion) if comparison > 0 { writeJSON(w, updateCheckResponse{ OK: true, Status: "update", CurrentVersion: AppVersion, RemoteVersion: remoteVersion, Message: fmt.Sprintf("HPL Toolbox update available: %s (installed: %s).", remoteVersion, AppVersion), RepositoryURL: updateRepositoryURL, }) return } writeJSON(w, updateCheckResponse{ OK: true, Status: "current", CurrentVersion: AppVersion, RemoteVersion: remoteVersion, Message: fmt.Sprintf("HPL Toolbox is up to date (%s).", AppVersion), }) } func fetchRemoteVersion() (string, error) { client := http.Client{Timeout: 10 * time.Second} req, err := http.NewRequest(http.MethodGet, remotePackageJSONURL, nil) if err != nil { return "", err } req.Header.Set("Accept", "application/json") resp, err := client.Do(req) if err != nil { return "", err } defer resp.Body.Close() if resp.StatusCode < 200 || resp.StatusCode >= 300 { return "", fmt.Errorf("remote package.json returned HTTP %d", resp.StatusCode) } var packageJSON struct { Version string `json:"version"` } if err := json.NewDecoder(resp.Body).Decode(&packageJSON); err != nil { return "", err } if strings.TrimSpace(packageJSON.Version) == "" { return "", fmt.Errorf("remote package.json is missing a version") } return strings.TrimSpace(packageJSON.Version), nil } func compareVersions(left, right string) int { leftParts := parseVersionParts(left) rightParts := parseVersionParts(right) length := len(leftParts) if len(rightParts) > length { length = len(rightParts) } for i := 0; i < length; i++ { leftPart := 0 rightPart := 0 if i < len(leftParts) { leftPart = leftParts[i] } if i < len(rightParts) { rightPart = rightParts[i] } if leftPart > rightPart { return 1 } if leftPart < rightPart { return -1 } } return 0 } func parseVersionParts(version string) []int { fields := strings.FieldsFunc(version, func(r rune) bool { return r == '.' || r == '-' }) parts := make([]int, 0, len(fields)) for _, field := range fields { part, err := strconv.Atoi(field) if err == nil { parts = append(parts, part) } } return parts }