144 lines
3.6 KiB
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
|
|
}
|