Mining/pkg/mining/stats_collector.go
Claude d7df78af1f
ax(mining): remove banned fmt import from stats_collector
Replace fmt.Errorf/Sprintf with package-native ErrInternal constructors
and strconv.Itoa for URL assembly in FetchJSONStats.

Co-Authored-By: Charon <charon@lethean.io>
2026-04-02 12:47:06 +01:00

54 lines
1.5 KiB
Go

package mining
import (
"context"
"encoding/json"
"io"
"net/http"
"strconv"
)
// var collector StatsCollector = &XMRigStatsCollector{...}
// metrics, err := collector.CollectStats(ctx)
type StatsCollector interface {
CollectStats(ctx context.Context) (*PerformanceMetrics, error)
}
// HTTPStatsConfig{Host: "127.0.0.1", Port: 8080, Endpoint: "/2/summary"}
type HTTPStatsConfig struct {
Host string
Port int
Endpoint string // e.g., "/2/summary" for XMRig, "/summary" for TT-Miner
}
// var summary XMRigSummary
// if err := FetchJSONStats(ctx, HTTPStatsConfig{Host: "127.0.0.1", Port: 8080, Endpoint: "/2/summary"}, &summary); err != nil { return err }
func FetchJSONStats[T any](ctx context.Context, config HTTPStatsConfig, target *T) error {
if config.Port == 0 {
return ErrInternal("API port is zero")
}
requestURL := "http://" + config.Host + ":" + strconv.Itoa(config.Port) + config.Endpoint
req, err := http.NewRequestWithContext(ctx, "GET", requestURL, nil)
if err != nil {
return ErrInternal("failed to create request").WithCause(err)
}
resp, err := getHTTPClient().Do(req)
if err != nil {
return ErrInternal("HTTP request failed").WithCause(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
io.Copy(io.Discard, resp.Body) // Drain body to allow connection reuse
return ErrInternal("unexpected status code: " + strconv.Itoa(resp.StatusCode))
}
if err := json.NewDecoder(resp.Body).Decode(target); err != nil {
return ErrInternal("failed to decode response").WithCause(err)
}
return nil
}