Sale Djenic 534c756bf5 fix_: re-trying http requests up to the predefined max retries
This commit should fix the issue with Cryptocompare and CoinGecko providers down.
Often happens that the first request fails and because of that:
- the Router cannot complete calculation successfully
- some tests are failing
- some users very often see a red banner line saying the providers are down
2024-05-23 16:28:50 +02:00

191 lines
5.3 KiB
Go

package cryptocompare
import (
"context"
"encoding/json"
"fmt"
"net/url"
"strings"
"github.com/status-im/status-go/services/wallet/thirdparty"
"github.com/status-im/status-go/services/wallet/thirdparty/utils"
)
const baseURL = "https://min-api.cryptocompare.com"
const extraParamStatus = "Status.im"
type HistoricalPricesContainer struct {
Aggregated bool `json:"Aggregated"`
TimeFrom int64 `json:"TimeFrom"`
TimeTo int64 `json:"TimeTo"`
HistoricalData []thirdparty.HistoricalPrice `json:"Data"`
}
type HistoricalPricesData struct {
Data HistoricalPricesContainer `json:"Data"`
}
type TokenDetailsContainer struct {
Data map[string]thirdparty.TokenDetails `json:"Data"`
}
type MarketValuesContainer struct {
Raw map[string]map[string]thirdparty.TokenMarketValues `json:"Raw"`
}
type Client struct {
httpClient *thirdparty.HTTPClient
}
func NewClient() *Client {
return &Client{
httpClient: thirdparty.NewHTTPClient(),
}
}
func (c *Client) FetchPrices(symbols []string, currencies []string) (map[string]map[string]float64, error) {
chunks := utils.ChunkSymbols(symbols, 60)
result := make(map[string]map[string]float64)
realCurrencies := utils.RenameSymbols(currencies)
for _, smbls := range chunks {
realSymbols := utils.RenameSymbols(smbls)
params := url.Values{}
params.Add("fsyms", strings.Join(realSymbols, ","))
params.Add("tsyms", strings.Join(realCurrencies, ","))
params.Add("extraParams", extraParamStatus)
url := fmt.Sprintf("%s/data/pricemulti", baseURL)
response, err := c.httpClient.DoGetRequest(context.Background(), url, params)
if err != nil {
return nil, err
}
prices := make(map[string]map[string]float64)
err = json.Unmarshal(response, &prices)
if err != nil {
return nil, fmt.Errorf("%s - %s", err, string(response))
}
for _, symbol := range smbls {
result[symbol] = map[string]float64{}
for _, currency := range currencies {
result[symbol][currency] = prices[utils.GetRealSymbol(symbol)][utils.GetRealSymbol(currency)]
}
}
}
return result, nil
}
func (c *Client) FetchTokenDetails(symbols []string) (map[string]thirdparty.TokenDetails, error) {
url := fmt.Sprintf("%s/data/all/coinlist", baseURL)
response, err := c.httpClient.DoGetRequest(context.Background(), url, nil)
if err != nil {
return nil, err
}
container := TokenDetailsContainer{}
err = json.Unmarshal(response, &container)
if err != nil {
return nil, err
}
tokenDetails := make(map[string]thirdparty.TokenDetails)
for _, symbol := range symbols {
tokenDetails[symbol] = container.Data[utils.GetRealSymbol(symbol)]
}
return tokenDetails, nil
}
func (c *Client) FetchTokenMarketValues(symbols []string, currency string) (map[string]thirdparty.TokenMarketValues, error) {
chunks := utils.ChunkSymbols(symbols)
realCurrency := utils.GetRealSymbol(currency)
item := map[string]thirdparty.TokenMarketValues{}
for _, smbls := range chunks {
realSymbols := utils.RenameSymbols(smbls)
params := url.Values{}
params.Add("fsyms", strings.Join(realSymbols, ","))
params.Add("tsyms", realCurrency)
params.Add("extraParams", extraParamStatus)
url := fmt.Sprintf("%s/data/pricemultifull", baseURL)
response, err := c.httpClient.DoGetRequest(context.Background(), url, params)
if err != nil {
return nil, err
}
container := MarketValuesContainer{}
err = json.Unmarshal(response, &container)
if len(container.Raw) == 0 {
return nil, fmt.Errorf("no data found - %s", string(response))
}
if err != nil {
return nil, fmt.Errorf("%s - %s", err, string(response))
}
for _, symbol := range smbls {
item[symbol] = container.Raw[utils.GetRealSymbol(symbol)][utils.GetRealSymbol(currency)]
}
}
return item, nil
}
func (c *Client) FetchHistoricalHourlyPrices(symbol string, currency string, limit int, aggregate int) ([]thirdparty.HistoricalPrice, error) {
item := []thirdparty.HistoricalPrice{}
params := url.Values{}
params.Add("fsym", utils.GetRealSymbol(symbol))
params.Add("tsym", currency)
params.Add("aggregate", fmt.Sprintf("%d", aggregate))
params.Add("limit", fmt.Sprintf("%d", limit))
params.Add("extraParams", extraParamStatus)
url := fmt.Sprintf("%s/data/v2/histohour", baseURL)
response, err := c.httpClient.DoGetRequest(context.Background(), url, params)
if err != nil {
return item, err
}
container := HistoricalPricesData{}
err = json.Unmarshal(response, &container)
if err != nil {
return item, err
}
item = container.Data.HistoricalData
return item, nil
}
func (c *Client) FetchHistoricalDailyPrices(symbol string, currency string, limit int, allData bool, aggregate int) ([]thirdparty.HistoricalPrice, error) {
item := []thirdparty.HistoricalPrice{}
params := url.Values{}
params.Add("fsym", utils.GetRealSymbol(symbol))
params.Add("tsym", currency)
params.Add("aggregate", fmt.Sprintf("%d", aggregate))
params.Add("limit", fmt.Sprintf("%d", limit))
params.Add("allData", fmt.Sprintf("%v", allData))
params.Add("extraParams", extraParamStatus)
url := fmt.Sprintf("%s/data/v2/histoday", baseURL)
response, err := c.httpClient.DoGetRequest(context.Background(), url, params)
if err != nil {
return item, err
}
container := HistoricalPricesData{}
err = json.Unmarshal(response, &container)
if err != nil {
return item, err
}
item = container.Data.HistoricalData
return item, nil
}