btc-pay-checker/internal/services/price/conversor.go

144 lines
3.6 KiB
Go

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
}