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

This commit is contained in:
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 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 // getFiatRatesResult checks if CurrencyRatesTicker contains all necessary data and returns formatted result
func (w *Worker) getFiatRatesResult(currency string, ticker *db.CurrencyRatesTicker) (*db.ResultTickerAsString, error) { func (w *Worker) getFiatRatesResult(currencies []string, ticker *db.CurrencyRatesTicker) (*db.ResultTickerAsString, error) {
if currency == "" { currencies = removeEmpty(currencies)
if len(currencies) == 0 {
// Return all available ticker rates
return &db.ResultTickerAsString{ return &db.ResultTickerAsString{
Timestamp: ticker.Timestamp.UTC().Unix(), Timestamp: ticker.Timestamp.UTC().Unix(),
Rates: ticker.Rates, Rates: ticker.Rates,
}, nil }, nil
} }
timestamp := ticker.Timestamp.UTC().Unix() if len(currencies) == 1 {
if rate, found := ticker.Rates[currency]; !found { // Return one specific rate
return nil, NewAPIError(fmt.Sprintf("Currency %q is not available for timestamp %d.", currency, timestamp), true) 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 { } 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{ return &db.ResultTickerAsString{
Timestamp: timestamp, Timestamp: ticker.Timestamp.UTC().Unix(),
Rate: rate, Rates: rates,
}, nil }, nil
} }
} }
// GetFiatRatesForBlockID returns fiat rates for block height or block hash // 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 var ticker *db.CurrencyRatesTicker
bi, err := w.getBlockInfoFromBlockID(bid) bi, err := w.getBlockInfoFromBlockID(bid)
if err != nil { if err != nil {
@ -1190,9 +1222,9 @@ func (w *Worker) GetFiatRatesForBlockID(bid string, currency string) (*db.Result
if err != nil { if err != nil {
return nil, NewAPIError(fmt.Sprintf("Error finding ticker: %v", err), false) return nil, NewAPIError(fmt.Sprintf("Error finding ticker: %v", err), false)
} else if ticker == nil { } 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 { if err != nil {
return nil, err return nil, err
} }
@ -1200,14 +1232,14 @@ func (w *Worker) GetFiatRatesForBlockID(bid string, currency string) (*db.Result
} }
// GetCurrentFiatRates returns last available fiat rates // 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() ticker, err := w.db.FiatRatesFindLastTicker()
if err != nil { if err != nil {
return nil, NewAPIError(fmt.Sprintf("Error finding ticker: %v", err), false) return nil, NewAPIError(fmt.Sprintf("Error finding ticker: %v", err), false)
} else if ticker == nil { } else if ticker == nil {
return nil, NewAPIError(fmt.Sprintf("No tickers found!"), true) return nil, NewAPIError(fmt.Sprintf("No tickers found!"), true)
} }
result, err := w.getFiatRatesResult(currency, ticker) result, err := w.getFiatRatesResult(currencies, ticker)
if err != nil { if err != nil {
return nil, err 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 // GetFiatRatesForTimestamps returns fiat rates for each of the provided dates
func (w *Worker) GetFiatRatesForTimestamps(timestamps []int64, currency string) (*db.ResultTickersAsString, error) { func (w *Worker) GetFiatRatesForTimestamps(timestamps []int64, currencies []string) (*db.ResultTickersAsString, error) {
if currency == "" { if len(timestamps) == 0 {
return nil, NewAPIError("Missing or empty \"currency\" parameter.", true)
} else if len(timestamps) == 0 {
return nil, NewAPIError("No timestamps provided", true) 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}) ret.Tickers = append(ret.Tickers, db.ResultTickerAsString{Timestamp: date.Unix(), Rate: -1})
continue continue
} }
result, err := w.getFiatRatesResult(currency, ticker) result, err := w.getFiatRatesResult(currencies, ticker)
if err != nil { if err != nil {
ret.Tickers = append(ret.Tickers, db.ResultTickerAsString{Timestamp: date.Unix(), Rate: -1}) ret.Tickers = append(ret.Tickers, db.ResultTickerAsString{Timestamp: date.Unix(), Rate: -1})
continue 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) { func (s *PublicServer) apiTickers(r *http.Request, apiVersion int) (interface{}, error) {
var result *db.ResultTickerAsString var result *db.ResultTickerAsString
var err error var err error
currency := strings.ToLower(r.URL.Query().Get("currency")) currency := strings.ToLower(r.URL.Query().Get("currency"))
var currencies []string
if currency != "" {
currencies = []string{currency}
}
if block := r.URL.Query().Get("block"); block != "" { if block := r.URL.Query().Get("block"); block != "" {
// Get tickers for specified block height or block hash // Get tickers for specified block height or block hash
s.metrics.ExplorerViews.With(common.Labels{"action": "api-tickers-block"}).Inc() 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 != "" { } else if timestampString := r.URL.Query().Get("timestamp"); timestampString != "" {
// Get tickers for specified timestamp // Get tickers for specified timestamp
s.metrics.ExplorerViews.With(common.Labels{"action": "api-tickers-date"}).Inc() 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) 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 { if err != nil {
return nil, err return nil, err
} }
@ -1180,7 +1185,7 @@ func (s *PublicServer) apiTickers(r *http.Request, apiVersion int) (interface{},
} else { } else {
// No parameters - get the latest available ticker // No parameters - get the latest available ticker
s.metrics.ExplorerViews.With(common.Labels{"action": "api-tickers-last"}).Inc() 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 { if err != nil {
return nil, err return nil, err

View File

@ -1,4 +1,4 @@
// build unittest // +build unittest
package server package server
@ -1195,11 +1195,11 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
want: `{"id":"16","data":{}}`, want: `{"id":"16","data":{}}`,
}, },
{ {
name: "websocket getCurrentFiatRates no currency", name: "websocket getCurrentFiatRates all currencies",
req: websocketReq{ req: websocketReq{
Method: "getCurrentFiatRates", Method: "getCurrentFiatRates",
Params: map[string]interface{}{ Params: map[string]interface{}{
"": "", "currencies": []string{},
}, },
}, },
want: `{"id":"17","data":{"ts":1574346615,"rates":{"eur":7134.1,"usd":7914.5}}}`, 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{ req: websocketReq{
Method: "getCurrentFiatRates", Method: "getCurrentFiatRates",
Params: map[string]interface{}{ Params: map[string]interface{}{
"currency": "usd", "currencies": []string{"usd"},
}, },
}, },
want: `{"id":"18","data":{"ts":1574346615,"rate":7914.5}}`, want: `{"id":"18","data":{"ts":1574346615,"rate":7914.5}}`,
@ -1219,7 +1219,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{ req: websocketReq{
Method: "getCurrentFiatRates", Method: "getCurrentFiatRates",
Params: map[string]interface{}{ Params: map[string]interface{}{
"currency": "eur", "currencies": []string{"eur"},
}, },
}, },
want: `{"id":"19","data":{"ts":1574346615,"rate":7134.1}}`, want: `{"id":"19","data":{"ts":1574346615,"rate":7134.1}}`,
@ -1229,7 +1229,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{ req: websocketReq{
Method: "getCurrentFiatRates", Method: "getCurrentFiatRates",
Params: map[string]interface{}{ 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."}}}`, 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{ req: websocketReq{
Method: "getFiatRatesForTimestamps", Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{ Params: map[string]interface{}{
"currency": "usd", "currencies": []string{"usd"},
}, },
}, },
want: `{"id":"21","data":{"error":{"message":"No timestamps provided"}}}`, want: `{"id":"21","data":{"error":{"message":"No timestamps provided"}}}`,
@ -1249,7 +1249,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{ req: websocketReq{
Method: "getFiatRatesForTimestamps", Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{ Params: map[string]interface{}{
"currency": "usd", "currencies": []string{"usd"},
"timestamps": []string{"yesterday"}, "timestamps": []string{"yesterday"},
}, },
}, },
@ -1260,7 +1260,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{ req: websocketReq{
Method: "getFiatRatesForTimestamps", Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{ Params: map[string]interface{}{
"currency": "usd", "currencies": []string{"usd"},
"timestamps": []int64{7885693815}, "timestamps": []int64{7885693815},
}, },
}, },
@ -1271,7 +1271,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{ req: websocketReq{
Method: "getFiatRatesForTimestamps", Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{ Params: map[string]interface{}{
"currency": "usd", "currencies": []string{"usd"},
"timestamps": []int64{1574346615}, "timestamps": []int64{1574346615},
}, },
}, },
@ -1282,7 +1282,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{ req: websocketReq{
Method: "getFiatRatesForTimestamps", Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{ Params: map[string]interface{}{
"currency": "eur", "currencies": []string{"eur"},
"timestamps": []int64{1521507600}, "timestamps": []int64{1521507600},
}, },
}, },
@ -1293,7 +1293,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{ req: websocketReq{
Method: "getFiatRatesForTimestamps", Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{ Params: map[string]interface{}{
"currency": "usd", "currencies": []string{"usd"},
"timestamps": []int64{1570346615, 1574346615}, "timestamps": []int64{1570346615, 1574346615},
}, },
}, },
@ -1304,7 +1304,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{ req: websocketReq{
Method: "getFiatRatesForTimestamps", Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{ Params: map[string]interface{}{
"currency": "eur", "currencies": []string{"eur"},
"timestamps": []int64{1570346615, 1574346615}, "timestamps": []int64{1570346615, 1574346615},
}, },
}, },
@ -1315,7 +1315,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{ req: websocketReq{
Method: "getFiatRatesForTimestamps", Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{ Params: map[string]interface{}{
"currency": "usd", "currencies": []string{"usd"},
"timestamps": []int64{1570346615, 1574346615, 2000000000}, "timestamps": []int64{1570346615, 1574346615, 2000000000},
}, },
}, },
@ -1326,7 +1326,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
req: websocketReq{ req: websocketReq{
Method: "getFiatRatesForTimestamps", Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{ Params: map[string]interface{}{
"currency": "usd", "currencies": []string{"usd"},
"timestamps": []int64{7832854800, 2000000000}, "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) { "getCurrentFiatRates": func(s *WebsocketServer, c *websocketChannel, req *websocketReq) (rv interface{}, err error) {
r := struct { r := struct {
Currency string `json:"currency"` Currencies []string `json:"currencies"`
}{} }{}
err = json.Unmarshal(req.Params, &r) err = json.Unmarshal(req.Params, &r)
if err == nil { if err == nil {
rv, err = s.getCurrentFiatRates(strings.ToLower(r.Currency)) rv, err = s.getCurrentFiatRates(r.Currencies)
} }
return return
}, },
"getFiatRatesForTimestamps": func(s *WebsocketServer, c *websocketChannel, req *websocketReq) (rv interface{}, err error) { "getFiatRatesForTimestamps": func(s *WebsocketServer, c *websocketChannel, req *websocketReq) (rv interface{}, err error) {
r := struct { r := struct {
Timestamps []int64 `json:"timestamps"` Timestamps []int64 `json:"timestamps"`
Currency string `json:"currency"` Currencies []string `json:"currencies"`
}{} }{}
err = json.Unmarshal(req.Params, &r) err = json.Unmarshal(req.Params, &r)
if err == nil { if err == nil {
rv, err = s.getFiatRatesForTimestamps(r.Timestamps, strings.ToLower(r.Currency)) rv, err = s.getFiatRatesForTimestamps(r.Timestamps, r.Currencies)
} }
return return
}, },
@ -826,13 +826,13 @@ func (s *WebsocketServer) OnNewFiatRatesTicker(ticker *db.CurrencyRatesTicker) {
s.broadcastTicker(allFiatRates, ticker.Rates) s.broadcastTicker(allFiatRates, ticker.Rates)
} }
func (s *WebsocketServer) getCurrentFiatRates(currency string) (interface{}, error) { func (s *WebsocketServer) getCurrentFiatRates(currencies []string) (interface{}, error) {
ret, err := s.api.GetCurrentFiatRates(currency) ret, err := s.api.GetCurrentFiatRates(currencies)
return ret, err return ret, err
} }
func (s *WebsocketServer) getFiatRatesForTimestamps(timestamps []int64, currency string) (interface{}, error) { func (s *WebsocketServer) getFiatRatesForTimestamps(timestamps []int64, currencies []string) (interface{}, error) {
ret, err := s.api.GetFiatRatesForTimestamps(timestamps, currency) ret, err := s.api.GetFiatRatesForTimestamps(timestamps, currencies)
return ret, err return ret, err
} }

View File

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