package price import ( "encoding/json" "fmt" "io" "net/http" "gitea.urkob.com/urko/btc-pay-checker/internal/domain" "gitea.urkob.com/urko/btc-pay-checker/kit" ) type CoinPriceResponse struct { Coins map[string]map[string]interface{} `json:"coins"` } type PriceConversor struct { apiUrl string dollarRateApi string client *http.Client } func NewPriceConversor(apiUrl, dollarRateApi string) *PriceConversor { return &PriceConversor{ apiUrl: apiUrl, client: &http.Client{}, dollarRateApi: dollarRateApi, } } type usdConversorResponse struct { Result string `json:"result"` Provider string `json:"provider"` Documentation string `json:"documentation"` TermsOfUse string `json:"terms_of_use"` TimeLastUpdateUnix int `json:"time_last_update_unix"` TimeLastUpdateUtc string `json:"time_last_update_utc"` TimeNextUpdateUnix int `json:"time_next_update_unix"` TimeNextUpdateUtc string `json:"time_next_update_utc"` TimeEolUnix int `json:"time_eol_unix"` BaseCode string `json:"base_code"` Rates map[string]float64 `json:"rates"` } func (p *PriceConversor) USDTo(c domain.Coin) (float64, error) { usd := 0.0 reqURL := fmt.Sprintf(p.dollarRateApi) req, err := http.NewRequest("GET", reqURL, nil) if err != nil { return usd, fmt.Errorf("http.NewRequest: %s", err) } kit.WithJSONHeaders(req) resp, err := p.client.Do(req) if err != nil { return usd, fmt.Errorf("client.Do: %s", err) } bts, err := io.ReadAll(resp.Body) if err != nil { return usd, fmt.Errorf("iokit.ReadAll: %s", err) } if resp.StatusCode != http.StatusOK { return usd, fmt.Errorf("error %d: %s", resp.StatusCode, string(bts)) } var respBody usdConversorResponse if err = json.Unmarshal(bts, &respBody); err != nil { return usd, fmt.Errorf("json.Unmarshal: %s", err) } v, ok := respBody.Rates[string(c)] if !ok { return usd, fmt.Errorf("coin isn't found") } return v, nil } func (p *PriceConversor) USD(c domain.Coin) (float64, error) { usd := 0.0 reqURL := fmt.Sprintf(p.apiUrl+"/prices/current/%s", c) req, err := http.NewRequest("GET", reqURL, nil) if err != nil { return usd, fmt.Errorf("http.NewRequest: %s", err) } kit.WithJSONHeaders(req) resp, err := p.client.Do(req) if err != nil { return usd, fmt.Errorf("client.Do: %s", err) } bts, err := io.ReadAll(resp.Body) if err != nil { return usd, fmt.Errorf("iokit.ReadAll: %s", err) } if resp.StatusCode != http.StatusOK { return usd, fmt.Errorf("error %d: %s", resp.StatusCode, string(bts)) } var respBody CoinPriceResponse if err = json.Unmarshal(bts, &respBody); err != nil { return usd, fmt.Errorf("json.Unmarshal: %s", err) } if _, hasKey := respBody.Coins[string(c)]; !hasKey { return usd, fmt.Errorf("coin isn't found") } if _, hasKey := respBody.Coins[string(c)]["price"]; !hasKey { return usd, fmt.Errorf("coin price isn't found") } usd, ok := respBody.Coins[string(c)]["price"].(float64) if !ok { return usd, fmt.Errorf("cannot cast price to float64") } return usd, nil } func (p *PriceConversor) UsdToBtc(usdAmount float64) (float64, error) { usd, err := p.USD(domain.CoinBTC) if err != nil { return usdAmount, fmt.Errorf("USDToBtc: %s", err) } return usdAmount / usd, nil } func (p *PriceConversor) BtcToUsd(btcAmount float64) (float64, error) { usd, err := p.USD(domain.CoinBTC) if err != nil { return btcAmount, fmt.Errorf("USDToBtc: %s", err) } return btcAmount * usd, nil }