fiatRates: timestamps as int64, errors as -1, update field names and tests

pull/345/head
Vladyslav Burzakovskyy 2019-12-20 15:57:23 +01:00 committed by Martin
parent bc0e95f174
commit c58b1538d6
6 changed files with 72 additions and 82 deletions

View File

@ -1153,17 +1153,15 @@ func (w *Worker) getFiatRatesResult(currency string, ticker *db.CurrencyRatesTic
Rates: ticker.Rates,
}, nil
}
rates := make(map[string]float64, 1)
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 {
rates[currency] = rate
return &db.ResultTickerAsString{
Timestamp: timestamp,
Rate: rate,
}, nil
}
return &db.ResultTickerAsString{
Timestamp: timestamp,
Rates: rates,
}, nil
}
// GetFiatRatesForBlockID returns fiat rates for block height or block hash
@ -1207,7 +1205,7 @@ func (w *Worker) GetCurrentFiatRates(currency string) (*db.ResultTickerAsString,
}
// GetFiatRatesForTimestamps returns fiat rates for each of the provided dates
func (w *Worker) GetFiatRatesForTimestamps(timestamps []string, currency string) (*db.ResultTickersAsString, error) {
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 {
@ -1216,23 +1214,20 @@ func (w *Worker) GetFiatRatesForTimestamps(timestamps []string, currency string)
ret := &db.ResultTickersAsString{}
for _, timestamp := range timestamps {
date, err := db.FiatRatesTimestampToTime(timestamp)
if err != nil {
ret.Tickers = append(ret.Tickers, db.ResultTickerAsString{Error: fmt.Sprintf("%q is not a valid Unix timestamp.", timestamp)})
continue
}
ticker, err := w.db.FiatRatesFindTicker(date)
date := time.Unix(timestamp, 0)
date = date.UTC()
ticker, err := w.db.FiatRatesFindTicker(&date)
if err != nil {
glog.Errorf("Error finding ticker for date %v. Error: %v", date, err)
ret.Tickers = append(ret.Tickers, db.ResultTickerAsString{Timestamp: date.Unix(), Error: "Ticker not found."})
ret.Tickers = append(ret.Tickers, db.ResultTickerAsString{Timestamp: date.Unix(), Rate: -1})
continue
} else if ticker == nil {
ret.Tickers = append(ret.Tickers, db.ResultTickerAsString{Timestamp: date.Unix(), Error: fmt.Sprintf("No tickers available for currency %q", currency)})
ret.Tickers = append(ret.Tickers, db.ResultTickerAsString{Timestamp: date.Unix(), Rate: -1})
continue
}
result, err := w.getFiatRatesResult(currency, ticker)
if err != nil {
ret.Tickers = append(ret.Tickers, db.ResultTickerAsString{Error: fmt.Sprintf("%v", err)})
ret.Tickers = append(ret.Tickers, db.ResultTickerAsString{Timestamp: date.Unix(), Rate: -1})
continue
}
ret.Tickers = append(ret.Tickers, *result)
@ -1241,17 +1236,11 @@ func (w *Worker) GetFiatRatesForTimestamps(timestamps []string, currency string)
}
// GetFiatRatesTickersList returns the list of available fiatRates tickers
func (w *Worker) GetFiatRatesTickersList(timestampString string) (*db.ResultTickerListAsString, error) {
if timestampString == "" {
return nil, NewAPIError("Missing or empty \"timestamp\" parameter", true)
}
func (w *Worker) GetFiatRatesTickersList(timestamp int64) (*db.ResultTickerListAsString, error) {
date := time.Unix(timestamp, 0)
date = date.UTC()
date, err := db.FiatRatesTimestampToTime(timestampString)
if err != nil {
return nil, NewAPIError(fmt.Sprintf("%v is not a valid Unix timestamp.", timestampString), false)
}
ticker, err := w.db.FiatRatesFindTicker(date)
ticker, err := w.db.FiatRatesFindTicker(&date)
if err != nil {
return nil, NewAPIError(fmt.Sprintf("Error finding ticker: %v", err), false)
} else if ticker == nil {
@ -1263,7 +1252,6 @@ func (w *Worker) GetFiatRatesTickersList(timestampString string) (*db.ResultTick
keys = append(keys, k)
}
sort.Strings(keys) // sort to get deterministic results
timestamp := ticker.Timestamp.UTC().Unix()
return &db.ResultTickerListAsString{
Timestamp: timestamp,

View File

@ -42,8 +42,9 @@ type CurrencyRatesTicker struct {
// ResultTickerAsString contains formatted CurrencyRatesTicker data
type ResultTickerAsString struct {
Timestamp int64 `json:"ts,omitempty"`
Timestamp int64 `json:"rate_ts,omitempty"`
Rates map[string]float64 `json:"rates,omitempty"`
Rate float64 `json:"rate,omitempty"`
Error string `json:"error,omitempty"`
}
@ -190,17 +191,6 @@ func FiatRatesConvertDate(date string) (*time.Time, error) {
return nil, errors.New(msg)
}
// FiatRatesTimestampToTime converts the unix timestamp string to a Time object
func FiatRatesTimestampToTime(timestamp string) (*time.Time, error) {
i, err := strconv.ParseInt(timestamp, 10, 64)
if err != nil {
return nil, err
}
ts := time.Unix(i, 0)
ts = ts.UTC()
return &ts, nil
}
// FiatRatesStoreTicker stores ticker data at the specified time
func (d *RocksDB) FiatRatesStoreTicker(ticker *CurrencyRatesTicker) error {
if len(ticker.Rates) == 0 {

View File

@ -1130,7 +1130,11 @@ func (s *PublicServer) apiSendTx(r *http.Request, apiVersion int) (interface{},
// apiTickersList returns a list of available FiatRates currencies
func (s *PublicServer) apiTickersList(r *http.Request, apiVersion int) (interface{}, error) {
s.metrics.ExplorerViews.With(common.Labels{"action": "api-tickers-list"}).Inc()
timestamp := strings.ToLower(r.URL.Query().Get("timestamp"))
timestampString := strings.ToLower(r.URL.Query().Get("timestamp"))
timestamp, err := strconv.ParseInt(timestampString, 10, 64)
if err != nil {
return nil, api.NewAPIError("Parameter \"timestamp\" is not a valid Unix timestamp.", true)
}
result, err := s.api.GetFiatRatesTickersList(timestamp)
return result, err
}
@ -1145,10 +1149,16 @@ func (s *PublicServer) apiTickers(r *http.Request, apiVersion int) (interface{},
// 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)
} else if timestamp := r.URL.Query().Get("timestamp"); timestamp != "" {
} 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()
resultTickers, err := s.api.GetFiatRatesForTimestamps([]string{timestamp}, currency)
timestamp, err := strconv.ParseInt(timestampString, 10, 64)
if err != nil {
return nil, api.NewAPIError("Parameter \"timestamp\" is not a valid Unix timestamp.", true)
}
resultTickers, err := s.api.GetFiatRatesForTimestamps([]int64{timestamp}, currency)
if err != nil {
return nil, err
}

View File

@ -524,7 +524,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
status: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: []string{
`{"ts":1574346615,"rates":{"eur":7134.1,"usd":7914.5}}`,
`{"rate_ts":1574346615,"rates":{"eur":7134.1,"usd":7914.5}}`,
},
},
{
@ -533,7 +533,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
status: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: []string{
`{"ts":1574346615,"rates":{"usd":7914.5}}`,
`{"rate_ts":1574346615,"rate":7914.5}`,
},
},
{
@ -542,16 +542,16 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
status: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: []string{
`{"ts":1574344800,"rates":{"usd":7814.5}}`,
`{"rate_ts":1574344800,"rate":7814.5}`,
},
},
{
name: "apiFiatRates incorrect timestamp",
r: newGetRequest(ts.URL + "/api/v2/tickers?currency=usd&timestamp=yesterday"),
status: http.StatusOK,
status: http.StatusBadRequest,
contentType: "application/json; charset=utf-8",
body: []string{
`{"error":"\"yesterday\" is not a valid Unix timestamp."}`,
`{"error":"Parameter \"timestamp\" is not a valid Unix timestamp."}`,
},
},
{
@ -560,7 +560,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
status: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: []string{
`{"ts":7980386400,"error":"No tickers available for currency \"usd\""}`,
`{"rate_ts":7980386400,"rate":-1}`,
},
},
{
@ -569,7 +569,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
status: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: []string{
`{"ts":1574344800,"rates":{"eur":7100}}`,
`{"rate_ts":1574344800,"rate":7100}`,
},
},
{
@ -578,7 +578,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
status: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: []string{
`{"ts":1521511200,"rates":{"usd":2000}}`,
`{"rate_ts":1521511200,"rate":2000}`,
},
},
{
@ -587,7 +587,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
status: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: []string{
`{"ts":1521611721,"rates":{"usd":2003}}`,
`{"rate_ts":1521611721,"rate":2003}`,
},
},
{
@ -596,7 +596,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
status: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: []string{
`{"ts":1574346615,"rates":{"eur":7134.1}}`,
`{"rate_ts":1574346615,"rate":7134.1}`,
},
},
{
@ -605,7 +605,7 @@ func httpTestsBitcoinType(t *testing.T, ts *httptest.Server) {
status: http.StatusOK,
contentType: "application/json; charset=utf-8",
body: []string{
`{"error":"Currency \"does_not_exist\" is not available for timestamp 1574346615."}`,
`{"rate_ts":1574346615,"rate":-1}`,
},
},
{
@ -1202,7 +1202,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
"": "",
},
},
want: `{"id":"17","data":{"ts":1574346615,"rates":{"eur":7134.1,"usd":7914.5}}}`,
want: `{"id":"17","data":{"rate_ts":1574346615,"rates":{"eur":7134.1,"usd":7914.5}}}`,
},
{
name: "websocket getCurrentFiatRates usd",
@ -1212,7 +1212,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
"currency": "usd",
},
},
want: `{"id":"18","data":{"ts":1574346615,"rates":{"usd":7914.5}}}`,
want: `{"id":"18","data":{"rate_ts":1574346615,"rate":7914.5}}`,
},
{
name: "websocket getCurrentFiatRates eur",
@ -1222,7 +1222,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
"currency": "eur",
},
},
want: `{"id":"19","data":{"ts":1574346615,"rates":{"eur":7134.1}}}`,
want: `{"id":"19","data":{"rate_ts":1574346615,"rate":7134.1}}`,
},
{
name: "websocket getCurrentFiatRates incorrect currency",
@ -1253,7 +1253,7 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
"timestamps": []string{"yesterday"},
},
},
want: `{"id":"22","data":{"tickers":[{"error":"\"yesterday\" is not a valid Unix timestamp."}]}}`,
want: `{"id":"22","data":{"error":{"message":"json: cannot unmarshal string into Go struct field .timestamps of type int64"}}}`,
},
{
name: "websocket getFiatRatesForTimestamps incorrect (future) date",
@ -1261,10 +1261,10 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{
"currency": "usd",
"timestamps": []string{"7885693815"},
"timestamps": []int64{7885693815},
},
},
want: `{"id":"23","data":{"tickers":[{"ts":7885693815,"error":"No tickers available for currency \"usd\""}]}}`,
want: `{"id":"23","data":{"tickers":[{"rate_ts":7885693815,"rate":-1}]}}`,
},
{
name: "websocket getFiatRatesForTimestamps exact date",
@ -1272,10 +1272,10 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{
"currency": "usd",
"timestamps": []string{"1574346615"},
"timestamps": []int64{1574346615},
},
},
want: `{"id":"24","data":{"tickers":[{"ts":1574346615,"rates":{"usd":7914.5}}]}}`,
want: `{"id":"24","data":{"tickers":[{"rate_ts":1574346615,"rate":7914.5}]}}`,
},
{
name: "websocket getFiatRatesForTimestamps closest date, eur",
@ -1283,10 +1283,10 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{
"currency": "eur",
"timestamps": []string{"1521507600"},
"timestamps": []int64{1521507600},
},
},
want: `{"id":"25","data":{"tickers":[{"ts":1521511200,"rates":{"eur":1300}}]}}`,
want: `{"id":"25","data":{"tickers":[{"rate_ts":1521511200,"rate":1300}]}}`,
},
{
name: "websocket getFiatRatesForTimestamps multiple timestamps usd",
@ -1294,10 +1294,10 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{
"currency": "usd",
"timestamps": []string{"1570346615", "1574346615"},
"timestamps": []int64{1570346615, 1574346615},
},
},
want: `{"id":"26","data":{"tickers":[{"ts":1574344800,"rates":{"usd":7814.5}},{"ts":1574346615,"rates":{"usd":7914.5}}]}}`,
want: `{"id":"26","data":{"tickers":[{"rate_ts":1574344800,"rate":7814.5},{"rate_ts":1574346615,"rate":7914.5}]}}`,
},
{
name: "websocket getFiatRatesForTimestamps multiple timestamps eur",
@ -1305,10 +1305,10 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{
"currency": "eur",
"timestamps": []string{"1570346615", "1574346615"},
"timestamps": []int64{1570346615, 1574346615},
},
},
want: `{"id":"27","data":{"tickers":[{"ts":1574344800,"rates":{"eur":7100}},{"ts":1574346615,"rates":{"eur":7134.1}}]}}`,
want: `{"id":"27","data":{"tickers":[{"rate_ts":1574344800,"rate":7100},{"rate_ts":1574346615,"rate":7134.1}]}}`,
},
{
name: "websocket getFiatRatesForTimestamps multiple timestamps with an error",
@ -1316,10 +1316,10 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{
"currency": "usd",
"timestamps": []string{"1570346615", "1574346615", "not-a-real-date"},
"timestamps": []int64{1570346615, 1574346615, 2000000000},
},
},
want: `{"id":"28","data":{"tickers":[{"ts":1574344800,"rates":{"usd":7814.5}},{"ts":1574346615,"rates":{"usd":7914.5}},{"error":"\"not-a-real-date\" is not a valid Unix timestamp."}]}}`,
want: `{"id":"28","data":{"tickers":[{"rate_ts":1574344800,"rate":7814.5},{"rate_ts":1574346615,"rate":7914.5},{"rate_ts":2000000000,"rate":-1}]}}`,
},
{
name: "websocket getFiatRatesForTimestamps multiple errors",
@ -1327,20 +1327,20 @@ func websocketTestsBitcoinType(t *testing.T, ts *httptest.Server) {
Method: "getFiatRatesForTimestamps",
Params: map[string]interface{}{
"currency": "usd",
"timestamps": []string{"7832854800", "not-a-real-date"},
"timestamps": []int64{7832854800, 2000000000},
},
},
want: `{"id":"29","data":{"tickers":[{"ts":7832854800,"error":"No tickers available for currency \"usd\""},{"error":"\"not-a-real-date\" is not a valid Unix timestamp."}]}}`,
want: `{"id":"29","data":{"tickers":[{"rate_ts":7832854800,"rate":-1},{"rate_ts":2000000000,"rate":-1}]}}`,
},
{
name: "websocket getTickersList",
req: websocketReq{
Method: "getFiatRatesTickersList",
Params: map[string]interface{}{
"date": "1570346615",
"timestamp": 1570346615,
},
},
want: `{"id":"30","data":{"data_timestamp":1574344800,"available_currencies":["eur","usd"]}}`,
want: `{"id":"30","data":{"data_timestamp":1570346615,"available_currencies":["eur","usd"]}}`,
},
{
name: "websocket getBalanceHistory Addr2",

View File

@ -364,8 +364,8 @@ var requestHandlers = map[string]func(*WebsocketServer, *websocketChannel, *webs
},
"getFiatRatesForTimestamps": func(s *WebsocketServer, c *websocketChannel, req *websocketReq) (rv interface{}, err error) {
r := struct {
Timestamps []string `json:"timestamps"`
Currency string `json:"currency"`
Timestamps []int64 `json:"timestamps"`
Currency string `json:"currency"`
}{}
err = json.Unmarshal(req.Params, &r)
if err == nil {
@ -375,11 +375,11 @@ var requestHandlers = map[string]func(*WebsocketServer, *websocketChannel, *webs
},
"getFiatRatesTickersList": func(s *WebsocketServer, c *websocketChannel, req *websocketReq) (rv interface{}, err error) {
r := struct {
Date string `json:"date"`
Timestamp int64 `json:"timestamp"`
}{}
err = json.Unmarshal(req.Params, &r)
if err == nil {
rv, err = s.getFiatRatesTickersList(r.Date)
rv, err = s.getFiatRatesTickersList(r.Timestamp)
}
return
},
@ -833,12 +833,13 @@ func (s *WebsocketServer) getCurrentFiatRates(currency string) (interface{}, err
return ret, err
}
func (s *WebsocketServer) getFiatRatesForTimestamps(timestamps []string, currency string) (interface{}, error) {
func (s *WebsocketServer) getFiatRatesForTimestamps(timestamps []int64, currency string) (interface{}, error) {
ret, err := s.api.GetFiatRatesForTimestamps(timestamps, currency)
return ret, err
}
func (s *WebsocketServer) getFiatRatesTickersList(timestamp string) (interface{}, error) {
func (s *WebsocketServer) getFiatRatesTickersList(timestamp int64) (interface{}, error) {
glog.Errorf("ts: %v", timestamp)
ret, err := s.api.GetFiatRatesTickersList(timestamp)
return ret, err
}

View File

@ -301,7 +301,7 @@
const method = 'getFiatRatesForTimestamps';
var timestamps = document.getElementById('getFiatRatesForTimestampsList').value.split(",");
var currency = document.getElementById('getFiatRatesForTimestampsCurrency').value;
timestamps = timestamps.map(s => s.trim());
timestamps = timestamps.map(Number);
const params = {
timestamps,
"currency": currency
@ -324,9 +324,10 @@
function getFiatRatesTickersList() {
const method = 'getFiatRatesTickersList';
var date = document.getElementById('getFiatRatesTickersListDate').value;
var timestamp = document.getElementById('getFiatRatesTickersListDate').value;
timestamp = parseInt(timestamp);
const params = {
date,
timestamp,
};
send(method, params, function (result) {
document.getElementById('getFiatRatesTickersListResult').innerText = JSON.stringify(result).replace(/,/g, ", ");