2025-11-09 01:02:31 +00:00
|
|
|
package mining
|
|
|
|
|
|
2025-12-31 13:33:42 +00:00
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"net/http"
|
|
|
|
|
)
|
|
|
|
|
|
2025-11-09 01:02:31 +00:00
|
|
|
var (
|
|
|
|
|
version = "dev"
|
|
|
|
|
commit = "none"
|
|
|
|
|
date = "unknown"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// GetVersion returns the version of the application
|
|
|
|
|
func GetVersion() string {
|
|
|
|
|
return version
|
|
|
|
|
}
|
2025-12-31 09:24:12 +00:00
|
|
|
|
|
|
|
|
// GetCommit returns the git commit hash
|
|
|
|
|
func GetCommit() string {
|
|
|
|
|
return commit
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetBuildDate returns the build date
|
|
|
|
|
func GetBuildDate() string {
|
|
|
|
|
return date
|
|
|
|
|
}
|
2025-12-31 13:33:42 +00:00
|
|
|
|
|
|
|
|
// GitHubRelease represents the structure of a GitHub release response.
|
|
|
|
|
type GitHubRelease struct {
|
|
|
|
|
TagName string `json:"tag_name"`
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FetchLatestGitHubVersion fetches the latest release version from a GitHub repository.
|
|
|
|
|
// It takes the repository owner and name (e.g., "xmrig", "xmrig") and returns the tag name.
|
2025-12-31 15:03:46 +00:00
|
|
|
// Uses a circuit breaker to prevent cascading failures when GitHub API is unavailable.
|
2025-12-31 13:33:42 +00:00
|
|
|
func FetchLatestGitHubVersion(owner, repo string) (string, error) {
|
2025-12-31 15:03:46 +00:00
|
|
|
cb := getGitHubCircuitBreaker()
|
|
|
|
|
|
|
|
|
|
result, err := cb.Execute(func() (interface{}, error) {
|
|
|
|
|
return fetchGitHubVersionDirect(owner, repo)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
// If circuit is open, try to return cached value with warning
|
|
|
|
|
if err == ErrCircuitOpen {
|
|
|
|
|
if cached, ok := cb.GetCached(); ok {
|
|
|
|
|
if tagName, ok := cached.(string); ok {
|
|
|
|
|
return tagName, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return "", fmt.Errorf("github API unavailable (circuit breaker open): %w", err)
|
|
|
|
|
}
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tagName, ok := result.(string)
|
|
|
|
|
if !ok {
|
|
|
|
|
return "", fmt.Errorf("unexpected result type from circuit breaker")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tagName, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fetchGitHubVersionDirect is the actual GitHub API call, wrapped by circuit breaker
|
|
|
|
|
func fetchGitHubVersionDirect(owner, repo string) (string, error) {
|
2025-12-31 13:33:42 +00:00
|
|
|
url := fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/latest", owner, repo)
|
|
|
|
|
|
|
|
|
|
resp, err := getHTTPClient().Get(url)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", fmt.Errorf("failed to fetch version: %w", err)
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
|
io.Copy(io.Discard, resp.Body) // Drain body to allow connection reuse
|
|
|
|
|
return "", fmt.Errorf("failed to get latest release: unexpected status code %d", resp.StatusCode)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var release GitHubRelease
|
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(&release); err != nil {
|
|
|
|
|
return "", fmt.Errorf("failed to decode release: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return release.TagName, nil
|
|
|
|
|
}
|