AX Principle 2: comments must show concrete usage, not restate the type signature in prose. StatsCollector and HTTPStatsConfig had three lines of descriptive prose that added no information an agent couldn't infer from the names alone. Co-Authored-By: Charon <charon@lethean.io>
54 lines
1.5 KiB
Go
54 lines
1.5 KiB
Go
package mining
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
)
|
|
|
|
// 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 fmt.Errorf("API port is zero")
|
|
}
|
|
|
|
url := fmt.Sprintf("http://%s:%d%s", config.Host, config.Port, config.Endpoint)
|
|
|
|
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create request: %w", err)
|
|
}
|
|
|
|
resp, err := getHTTPClient().Do(req)
|
|
if err != nil {
|
|
return fmt.Errorf("HTTP request failed: %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("unexpected status code %d", resp.StatusCode)
|
|
}
|
|
|
|
if err := json.NewDecoder(resp.Body).Decode(target); err != nil {
|
|
return fmt.Errorf("failed to decode response: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|