Error Handling: - Fix silent Write() error in WebSocket (events.go) - Add error context to transport handshake messages - Check os.MkdirAll error in zip extraction (miner.go) - Explicitly ignore io.Copy errors on drain with comments - Add retry logic (2 attempts) for transient stats collection failures Resource Lifecycle: - Add shutdown mechanism to DigestAuth goroutine - Call Service.Stop() on context cancellation - Add NodeService transport cleanup to Service.Stop() - Fix WriteStdin goroutine leak on timeout with non-blocking send API Design: - Add profile validation (name, miner type required) - Return 404 instead of 500 for missing profile PUT - Make DELETE profile idempotent (return success if not found) - Standardize error responses in node_service.go handlers Observability: - Add logging for P2P GetAllStats failures - Add request ID correlation helper for handler logs - Add logging for miner process exits (xmrig_start.go) - Rate limit debug logs in transport hot path (1 in 100) - Add metrics infrastructure with /metrics endpoint 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
57 lines
1.7 KiB
Go
57 lines
1.7 KiB
Go
package mining
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
)
|
|
|
|
// StatsCollector defines the interface for collecting miner statistics.
|
|
// This allows different miner types to implement their own stats collection logic
|
|
// while sharing common HTTP fetching infrastructure.
|
|
type StatsCollector interface {
|
|
// CollectStats fetches and returns performance metrics from the miner.
|
|
CollectStats(ctx context.Context) (*PerformanceMetrics, error)
|
|
}
|
|
|
|
// HTTPStatsConfig holds configuration for HTTP-based stats collection.
|
|
type HTTPStatsConfig struct {
|
|
Host string
|
|
Port int
|
|
Endpoint string // e.g., "/2/summary" for XMRig, "/summary" for TT-Miner
|
|
}
|
|
|
|
// FetchJSONStats performs an HTTP GET request and decodes the JSON response.
|
|
// This is a common helper for HTTP-based miner stats collection.
|
|
// The caller must provide the target struct to decode into.
|
|
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
|
|
}
|