Files
2026-02-22 15:21:18 -05:00

59 lines
1.3 KiB
Go

package external
import (
"context"
"encoding/json"
"fmt"
"net/http"
"time"
"github.com/kjannette/trahn-backend/internal/httputil"
)
const coingeckoURL = "https://api.coingecko.com/api/v3/simple/price?ids=ethereum&vs_currencies=usd"
type CoinGeckoClient struct {
httpClient *http.Client
retry httputil.RetryConfig
}
func NewCoinGeckoClient() *CoinGeckoClient {
return &CoinGeckoClient{
httpClient: &http.Client{Timeout: 10 * time.Second},
retry: httputil.RetryConfig{
MaxAttempts: 3,
BaseDelay: 2 * time.Second,
MaxDelay: 10 * time.Second,
},
}
}
func (c *CoinGeckoClient) GetETHPrice(ctx context.Context) (float64, error) {
resp, err := httputil.Do(ctx, c.httpClient, c.retry, func() (*http.Request, error) {
return http.NewRequestWithContext(ctx, http.MethodGet, coingeckoURL, nil)
})
if err != nil {
return 0, fmt.Errorf("coingecko fetch: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return 0, fmt.Errorf("coingecko returned status %d", resp.StatusCode)
}
var data struct {
Ethereum struct {
USD float64 `json:"usd"`
} `json:"ethereum"`
}
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
return 0, fmt.Errorf("decode: %w", err)
}
if data.Ethereum.USD <= 0 {
return 0, fmt.Errorf("invalid price: %f", data.Ethereum.USD)
}
return data.Ethereum.USD, nil
}