diff --git a/api/worker.go b/api/worker.go index 7d34822c..3c1fa0c2 100644 --- a/api/worker.go +++ b/api/worker.go @@ -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 diff --git a/server/public.go b/server/public.go index d0cea301..5f4c1b6a 100644 --- a/server/public.go +++ b/server/public.go @@ -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 diff --git a/server/public_test.go b/server/public_test.go index 802df350..c1f3c949 100644 --- a/server/public_test.go +++ b/server/public_test.go @@ -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}, }, }, diff --git a/server/websocket.go b/server/websocket.go index e051b9eb..f193abb4 100644 --- a/server/websocket.go +++ b/server/websocket.go @@ -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 } diff --git a/static/test-websocket.html b/static/test-websocket.html index 8f40faf4..f519cfda 100644 --- a/static/test-websocket.html +++ b/static/test-websocket.html @@ -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 @@
- +