fiatRates: accept an array of strings everywhere and return all available rates if it's empty

pull/358/head
Vladyslav Burzakovskyy 2020-01-22 13:30:54 +01:00 committed by Martin
parent 87065d13ef
commit 4ca66f3b1d
5 changed files with 85 additions and 49 deletions

View File

@ -1155,27 +1155,59 @@ func (w *Worker) GetBlocks(page int, blocksOnPage int) (*Blocks, error) {
return r, nil
}
// removeEmty removes empty strings from a slice
func removeEmpty(stringSlice []string) []string {
var ret []string
for _, str := range stringSlice {
if str != "" {
ret = append(ret, str)
}
}
return ret
}
// getFiatRatesResult checks if CurrencyRatesTicker contains all necessary data and returns formatted result
func (w *Worker) getFiatRatesResult(currency string, ticker *db.CurrencyRatesTicker) (*db.ResultTickerAsString, error) {
if currency == "" {
func (w *Worker) getFiatRatesResult(currencies []string, ticker *db.CurrencyRatesTicker) (*db.ResultTickerAsString, error) {
currencies = removeEmpty(currencies)
if len(currencies) == 0 {
// Return all available ticker rates
return &db.ResultTickerAsString{
Timestamp: ticker.Timestamp.UTC().Unix(),
Rates: ticker.Rates,
}, nil
}
timestamp := ticker.Timestamp.UTC().Unix()
if rate, found := ticker.Rates[currency]; !found {
return nil, NewAPIError(fmt.Sprintf("Currency %q is not available for timestamp %d.", currency, timestamp), true)
if len(currencies) == 1 {
// Return one specific rate
var currency = strings.ToLower(currencies[0])
timestamp := ticker.Timestamp.UTC().Unix()
if rate, found := ticker.Rates[currency]; !found {
return nil, NewAPIError(fmt.Sprintf("Currency %q is not available for timestamp %d.", currency, timestamp), true)
} else {
return &db.ResultTickerAsString{
Timestamp: timestamp,
Rate: rate,
}, nil
}
} else {
// Check if currencies from the list are available in the ticker rates
rates := make(map[string]float64)
for _, currency := range currencies {
currency = strings.ToLower(currency)
if rate, found := ticker.Rates[currency]; found {
rates[currency] = rate
} else {
rates[currency] = -1
}
}
return &db.ResultTickerAsString{
Timestamp: timestamp,
Rate: rate,
Timestamp: ticker.Timestamp.UTC().Unix(),
Rates: rates,
}, nil
}
}
// GetFiatRatesForBlockID returns fiat rates for block height or block hash
func (w *Worker) GetFiatRatesForBlockID(bid string, currency string) (*db.ResultTickerAsString, error) {
func (w *Worker) GetFiatRatesForBlockID(bid string, currencies []string) (*db.ResultTickerAsString, error) {
var ticker *db.CurrencyRatesTicker
bi, err := w.getBlockInfoFromBlockID(bid)
if err != nil {
@ -1190,9 +1222,9 @@ func (w *Worker) GetFiatRatesForBlockID(bid string, currency string) (*db.Result
if err != nil {
return nil, NewAPIError(fmt.Sprintf("Error finding ticker: %v", err), false)
} else if ticker == nil {
return nil, NewAPIError(fmt.Sprintf("No tickers available for %s (%s)", tm, currency), true)
return nil, NewAPIError(fmt.Sprintf("No tickers available for %s", tm), true)
}
result, err := w.getFiatRatesResult(currency, ticker)
result, err := w.getFiatRatesResult(currencies, ticker)
if err != nil {
return nil, err
}
@ -1200,14 +1232,14 @@ func (w *Worker) GetFiatRatesForBlockID(bid string, currency string) (*db.Result
}
// GetCurrentFiatRates returns last available fiat rates
func (w *Worker) GetCurrentFiatRates(currency string) (*db.ResultTickerAsString, error) {
func (w *Worker) GetCurrentFiatRates(currencies []string) (*db.ResultTickerAsString, error) {
ticker, err := w.db.FiatRatesFindLastTicker()
if err != nil {
return nil, NewAPIError(fmt.Sprintf("Error finding ticker: %v", err), false)
} else if ticker == nil {
return nil, NewAPIError(fmt.Sprintf("No tickers found!"), true)
}
result, err := w.getFiatRatesResult(currency, ticker)
result, err := w.getFiatRatesResult(currencies, ticker)
if err != nil {
return nil, err
}
@ -1215,10 +1247,8 @@ func (w *Worker) GetCurrentFiatRates(currency string) (*db.ResultTickerAsString,
}
// GetFiatRatesForTimestamps returns fiat rates for each of the provided dates
func (w *Worker) GetFiatRatesForTimestamps(timestamps []int64, currency string) (*db.ResultTickersAsString, error) {
if currency == "" {
return nil, NewAPIError("Missing or empty \"currency\" parameter.", true)
} else if len(timestamps) == 0 {
func (w *Worker) GetFiatRatesForTimestamps(timestamps []int64, currencies []string) (*db.ResultTickersAsString, error) {
if len(timestamps) == 0 {
return nil, NewAPIError("No timestamps provided", true)
}
@ -1235,7 +1265,7 @@ func (w *Worker) GetFiatRatesForTimestamps(timestamps []int64, currency string)
ret.Tickers = append(ret.Tickers, db.ResultTickerAsString{Timestamp: date.Unix(), Rate: -1})
continue
}
result, err := w.getFiatRatesResult(currency, ticker)
result, err := w.getFiatRatesResult(currencies, ticker)
if err != nil {
ret.Tickers = append(ret.Tickers, db.ResultTickerAsString{Timestamp: date.Unix(), Rate: -1})
continue

View File

@ -1157,12 +1157,17 @@ func (s *PublicServer) apiTickersList(r *http.Request, apiVersion int) (interfac
func (s *PublicServer) apiTickers(r *http.Request, apiVersion int) (interface{}, error) {
var result *db.ResultTickerAsString
var err error
currency := strings.ToLower(r.URL.Query().Get("currency"))
var currencies []string
if currency != "" {
currencies = []string{currency}
}
if block := r.URL.Query().Get("block"); block != "" {
// Get tickers for specified block height or block hash
s.metrics.ExplorerViews.With(common.Labels{"action": "api-tickers-block"}).Inc()
result, err = s.api.GetFiatRatesForBlockID(block, currency)
result, err = s.api.GetFiatRatesForBlockID(block, currencies)
} else if timestampString := r.URL.Query().Get("timestamp"); timestampString != "" {
// Get tickers for specified timestamp
s.metrics.ExplorerViews.With(common.Labels{"action": "api-tickers-date"}).Inc()
@ -1172,7 +1177,7 @@ func (s *PublicServer) apiTickers(r *http.Request, apiVersion int) (interface{},
return nil, api.NewAPIError("Parameter \"timestamp\" is not a valid Unix timestamp.", true)
}
resultTickers, err := s.api.GetFiatRatesForTimestamps([]int64{timestamp}, currency)
resultTickers, err := s.api.GetFiatRatesForTimestamps([]int64{timestamp}, currencies)
if err != nil {
return nil, err
}
@ -1180,7 +1185,7 @@ func (s *PublicServer) apiTickers(r *http.Request, apiVersion int) (interface{},
} else {
// No parameters - get the latest available ticker
s.metrics.ExplorerViews.With(common.Labels{"action": "api-tickers-last"}).Inc()
result, err = s.api.GetCurrentFiatRates(currency)
result, err = s.api.GetCurrentFiatRates(currencies)
}
if err != nil {
return nil, err

View File

@ -1,4 +1,4 @@
// build unittest
// +build unittest
package server
@ -1195,11 +1195,11 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
want: `{"id":"16","data":{}}`,
},
{
name: "websocket getCurrentFiatRates no currency",
name: "websocket getCurrentFiatRates all currencies",
req: websocketReq{
Method: "getCurrentFiatRates",
Params: map[string]interface{}{
"": "",
"currencies": []string{},
},
},
want: `{"id":"17","data":{"ts":1574346615,"rates":{"eur":7134.1,"usd":7914.5}}}`,
@ -1209,7 +1209,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{
Method: "getCurrentFiatRates",
Params: map[string]interface{}{
"currency": "usd",
"currencies": []string{"usd"},
},
},
want: `{"id":"18","data":{"ts":1574346615,"rate":7914.5}}`,
@ -1219,7 +1219,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{
Method: "getCurrentFiatRates",
Params: map[string]interface{}{
"currency": "eur",
"currencies": []string{"eur"},
},
},
want: `{"id":"19","data":{"ts":1574346615,"rate":7134.1}}`,
@ -1229,7 +1229,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{
Method: "getCurrentFiatRates",
Params: map[string]interface{}{
"currency": "does-not-exist",
"currencies": []string{"does-not-exist"},
},
},
want: `{"id":"20","data":{"error":{"message":"Currency \"does-not-exist\" is not available for timestamp 1574346615."}}}`,
@ -1239,7 +1239,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{
Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{
"currency": "usd",
"currencies": []string{"usd"},
},
},
want: `{"id":"21","data":{"error":{"message":"No timestamps provided"}}}`,
@ -1249,7 +1249,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{
Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{
"currency": "usd",
"currencies": []string{"usd"},
"timestamps": []string{"yesterday"},
},
},
@ -1260,7 +1260,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{
Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{
"currency": "usd",
"currencies": []string{"usd"},
"timestamps": []int64{7885693815},
},
},
@ -1271,7 +1271,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{
Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{
"currency": "usd",
"currencies": []string{"usd"},
"timestamps": []int64{1574346615},
},
},
@ -1282,7 +1282,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{
Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{
"currency": "eur",
"currencies": []string{"eur"},
"timestamps": []int64{1521507600},
},
},
@ -1293,7 +1293,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{
Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{
"currency": "usd",
"currencies": []string{"usd"},
"timestamps": []int64{1570346615, 1574346615},
},
},
@ -1304,7 +1304,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{
Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{
"currency": "eur",
"currencies": []string{"eur"},
"timestamps": []int64{1570346615, 1574346615},
},
},
@ -1315,7 +1315,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{
Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{
"currency": "usd",
"currencies": []string{"usd"},
"timestamps": []int64{1570346615, 1574346615, 2000000000},
},
},
@ -1326,7 +1326,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{
Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{
"currency": "usd",
"currencies": []string{"usd"},
"timestamps": []int64{7832854800, 2000000000},
},
},

View File

@ -352,22 +352,22 @@ var requestHandlers = map[string]func(*WebsocketServer, *websocketChannel, *webs
},
"getCurrentFiatRates": func(s *WebsocketServer, c *websocketChannel, req *websocketReq) (rv interface{}, err error) {
r := struct {
Currency string `json:"currency"`
Currencies []string `json:"currencies"`
}{}
err = json.Unmarshal(req.Params, &r)
if err == nil {
rv, err = s.getCurrentFiatRates(strings.ToLower(r.Currency))
rv, err = s.getCurrentFiatRates(r.Currencies)
}
return
},
"getFiatRatesForTimestamps": func(s *WebsocketServer, c *websocketChannel, req *websocketReq) (rv interface{}, err error) {
r := struct {
Timestamps []int64 `json:"timestamps"`
Currency string `json:"currency"`
Timestamps []int64 `json:"timestamps"`
Currencies []string `json:"currencies"`
}{}
err = json.Unmarshal(req.Params, &r)
if err == nil {
rv, err = s.getFiatRatesForTimestamps(r.Timestamps, strings.ToLower(r.Currency))
rv, err = s.getFiatRatesForTimestamps(r.Timestamps, r.Currencies)
}
return
},
@ -826,13 +826,13 @@ func (s *WebsocketServer) OnNewFiatRatesTicker(ticker *db.CurrencyRatesTicker) {
s.broadcastTicker(allFiatRates, ticker.Rates)
}
func (s *WebsocketServer) getCurrentFiatRates(currency string) (interface{}, error) {
ret, err := s.api.GetCurrentFiatRates(currency)
func (s *WebsocketServer) getCurrentFiatRates(currencies []string) (interface{}, error) {
ret, err := s.api.GetCurrentFiatRates(currencies)
return ret, err
}
func (s *WebsocketServer) getFiatRatesForTimestamps(timestamps []int64, currency string) (interface{}, error) {
ret, err := s.api.GetFiatRatesForTimestamps(timestamps, currency)
func (s *WebsocketServer) getFiatRatesForTimestamps(timestamps []int64, currencies []string) (interface{}, error) {
ret, err := s.api.GetFiatRatesForTimestamps(timestamps, currencies)
return ret, err
}

View File

@ -302,11 +302,12 @@
function getFiatRatesForTimestamps() {
const method = 'getFiatRatesForTimestamps';
var timestamps = document.getElementById('getFiatRatesForTimestampsList').value.split(",");
var currency = document.getElementById('getFiatRatesForTimestampsCurrency').value;
var currencies = document.getElementById('getFiatRatesForTimestampsCurrency').value.split(",");
console.log(currencies);
timestamps = timestamps.map(Number);
const params = {
timestamps,
"currency": currency
'currencies': currencies
};
send(method, params, function (result) {
document.getElementById('getFiatRatesForTimestampsResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
@ -315,9 +316,9 @@
function getCurrentFiatRates() {
const method = 'getCurrentFiatRates';
var currency = document.getElementById('getCurrentFiatRatesCurrency').value;
var currencies = document.getElementById('getCurrentFiatRatesCurrency').value.split(",");
const params = {
"currency": currency
"currencies": currencies
};
send(method, params, function (result) {
document.getElementById('getCurrentFiatRatesResult').innerText = JSON.stringify(result).replace(/,/g, ", ");
@ -540,7 +541,7 @@
<input class="btn btn-secondary" type="button" value="get fiat rates for dates" onclick="getFiatRatesForTimestamps()">
</div>
<div class="col-1">
<input type="text" class="form-control" id="getFiatRatesForTimestampsCurrency" value="usd">
<input type="text" class="form-control" id="getFiatRatesForTimestampsCurrency" placeholder="usd,eur">
</div>
<div class="col-7">
<input type="text" class="form-control" id="getFiatRatesForTimestampsList" value="1575288000,1575550800">