resp→response, db→database pattern across mining, logging packages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
91 lines
2.4 KiB
Go
91 lines
2.4 KiB
Go
package mining
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"strconv"
|
|
)
|
|
|
|
var (
|
|
version = "dev"
|
|
commit = "none"
|
|
date = "unknown"
|
|
)
|
|
|
|
// versionString := mining.GetVersion() // "1.2.3" or "dev" when unset
|
|
func GetVersion() string {
|
|
return version
|
|
}
|
|
|
|
// commitHash := mining.GetCommit() // "a1b2c3d" or "none" when unset
|
|
func GetCommit() string {
|
|
return commit
|
|
}
|
|
|
|
// buildDate := mining.GetBuildDate() // "2026-04-02T00:00:00Z" or "unknown" when unset
|
|
func GetBuildDate() string {
|
|
return date
|
|
}
|
|
|
|
// release := &GitHubRelease{TagName: "v6.21.0", Name: "XMRig v6.21.0"}
|
|
type GitHubRelease struct {
|
|
TagName string `json:"tag_name"`
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
// tag, err := FetchLatestGitHubVersion("xmrig", "xmrig") // "v6.21.0"
|
|
func FetchLatestGitHubVersion(owner, repo string) (string, error) {
|
|
circuitBreaker := getGitHubCircuitBreaker()
|
|
|
|
result, err := circuitBreaker.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 := circuitBreaker.GetCached(); ok {
|
|
if tagName, ok := cached.(string); ok {
|
|
return tagName, nil
|
|
}
|
|
}
|
|
return "", ErrInternal("github API unavailable (circuit breaker open)").WithCause(err)
|
|
}
|
|
return "", err
|
|
}
|
|
|
|
tagName, ok := result.(string)
|
|
if !ok {
|
|
return "", ErrInternal("unexpected result type from circuit breaker")
|
|
}
|
|
|
|
return tagName, nil
|
|
}
|
|
|
|
// tag, err := fetchGitHubVersionDirect("xmrig", "xmrig") // "v6.21.0"; called via circuit breaker
|
|
func fetchGitHubVersionDirect(owner, repo string) (string, error) {
|
|
url := "https://api.github.com/repos/" + owner + "/" + repo + "/releases/latest"
|
|
|
|
response, err := getHTTPClient().Get(url)
|
|
if err != nil {
|
|
return "", ErrInternal("failed to fetch version").WithCause(err)
|
|
}
|
|
defer response.Body.Close()
|
|
|
|
if response.StatusCode != http.StatusOK {
|
|
io.Copy(io.Discard, response.Body) // Drain body to allow connection reuse
|
|
return "", ErrInternal("failed to get latest release: unexpected status code " + strconv.Itoa(response.StatusCode))
|
|
}
|
|
|
|
body, err := io.ReadAll(response.Body)
|
|
if err != nil {
|
|
return "", ErrInternal("failed to read release response").WithCause(err)
|
|
}
|
|
|
|
var release GitHubRelease
|
|
if err := UnmarshalJSON(body, &release); err != nil {
|
|
return "", ErrInternal("failed to decode release").WithCause(err)
|
|
}
|
|
|
|
return release.TagName, nil
|
|
}
|