136 lines
4.3 KiB
Go
136 lines
4.3 KiB
Go
package db
|
|
|
|
import (
|
|
"encoding/json"
|
|
"time"
|
|
|
|
"github.com/golang/glog"
|
|
"github.com/juju/errors"
|
|
)
|
|
|
|
// FiatRatesTimeFormat is a format string for storing FiatRates timestamps in rocksdb
|
|
const FiatRatesTimeFormat = "20060102150405" // YYYYMMDDhhmmss
|
|
|
|
// CurrencyRatesTicker contains coin ticker data fetched from API
|
|
type CurrencyRatesTicker struct {
|
|
Timestamp *time.Time // return as unix timestamp in API
|
|
Rates map[string]float64
|
|
}
|
|
|
|
// ResultTickerAsString contains formatted CurrencyRatesTicker data
|
|
type ResultTickerAsString struct {
|
|
Timestamp int64 `json:"ts,omitempty"`
|
|
Rates map[string]float64 `json:"rates"`
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
// ResultTickersAsString contains a formatted CurrencyRatesTicker list
|
|
type ResultTickersAsString struct {
|
|
Tickers []ResultTickerAsString `json:"tickers"`
|
|
}
|
|
|
|
// ResultTickerListAsString contains formatted data about available currency tickers
|
|
type ResultTickerListAsString struct {
|
|
Timestamp int64 `json:"ts,omitempty"`
|
|
Tickers []string `json:"available_currencies"`
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
// FiatRatesConvertDate checks if the date is in correct format and returns the Time object.
|
|
// Possible formats are: YYYYMMDDhhmmss, YYYYMMDDhhmm, YYYYMMDDhh, YYYYMMDD
|
|
func FiatRatesConvertDate(date string) (*time.Time, error) {
|
|
for format := FiatRatesTimeFormat; len(format) >= 8; format = format[:len(format)-2] {
|
|
convertedDate, err := time.Parse(format, date)
|
|
if err == nil {
|
|
return &convertedDate, nil
|
|
}
|
|
}
|
|
msg := "Date \"" + date + "\" does not match any of available formats. "
|
|
msg += "Possible formats are: YYYYMMDDhhmmss, YYYYMMDDhhmm, YYYYMMDDhh, YYYYMMDD"
|
|
return nil, errors.New(msg)
|
|
}
|
|
|
|
// FiatRatesStoreTicker stores ticker data at the specified time
|
|
func (d *RocksDB) FiatRatesStoreTicker(ticker *CurrencyRatesTicker) error {
|
|
if len(ticker.Rates) == 0 {
|
|
return errors.New("Error storing ticker: empty rates")
|
|
} else if ticker.Timestamp == nil {
|
|
return errors.New("Error storing ticker: empty timestamp")
|
|
}
|
|
ratesMarshalled, err := json.Marshal(ticker.Rates)
|
|
if err != nil {
|
|
glog.Error("Error marshalling ticker rates: ", err)
|
|
return err
|
|
}
|
|
timeFormatted := ticker.Timestamp.UTC().Format(FiatRatesTimeFormat)
|
|
err = d.db.PutCF(d.wo, d.cfh[cfFiatRates], []byte(timeFormatted), ratesMarshalled)
|
|
if err != nil {
|
|
glog.Error("Error storing ticker: ", err)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// FiatRatesFindTicker gets FiatRates data closest to the specified timestamp
|
|
func (d *RocksDB) FiatRatesFindTicker(tickerTime *time.Time) (*CurrencyRatesTicker, error) {
|
|
ticker := &CurrencyRatesTicker{}
|
|
tickerTimeFormatted := tickerTime.UTC().Format(FiatRatesTimeFormat)
|
|
it := d.db.NewIteratorCF(d.ro, d.cfh[cfFiatRates])
|
|
defer it.Close()
|
|
|
|
for it.Seek([]byte(tickerTimeFormatted)); it.Valid(); it.Next() {
|
|
timeObj, err := time.Parse(FiatRatesTimeFormat, string(it.Key().Data()))
|
|
if err != nil {
|
|
glog.Error("FiatRatesFindTicker time parse error: ", err)
|
|
return nil, err
|
|
}
|
|
timeObj = timeObj.UTC()
|
|
ticker.Timestamp = &timeObj
|
|
err = json.Unmarshal(it.Value().Data(), &ticker.Rates)
|
|
if err != nil {
|
|
glog.Error("FiatRatesFindTicker error unpacking rates: ", err)
|
|
return nil, err
|
|
}
|
|
break
|
|
}
|
|
if err := it.Err(); err != nil {
|
|
glog.Error("FiatRatesFindTicker Iterator error: ", err)
|
|
return nil, err
|
|
}
|
|
if !it.Valid() {
|
|
return nil, nil // ticker not found
|
|
}
|
|
return ticker, nil
|
|
}
|
|
|
|
// FiatRatesFindLastTicker gets the last FiatRates record
|
|
func (d *RocksDB) FiatRatesFindLastTicker() (*CurrencyRatesTicker, error) {
|
|
ticker := &CurrencyRatesTicker{}
|
|
it := d.db.NewIteratorCF(d.ro, d.cfh[cfFiatRates])
|
|
defer it.Close()
|
|
|
|
for it.SeekToLast(); it.Valid(); it.Next() {
|
|
timeObj, err := time.Parse(FiatRatesTimeFormat, string(it.Key().Data()))
|
|
if err != nil {
|
|
glog.Error("FiatRatesFindTicker time parse error: ", err)
|
|
return nil, err
|
|
}
|
|
timeObj = timeObj.UTC()
|
|
ticker.Timestamp = &timeObj
|
|
err = json.Unmarshal(it.Value().Data(), &ticker.Rates)
|
|
if err != nil {
|
|
glog.Error("FiatRatesFindTicker error unpacking rates: ", err)
|
|
return nil, err
|
|
}
|
|
break
|
|
}
|
|
if err := it.Err(); err != nil {
|
|
glog.Error("FiatRatesFindLastTicker Iterator error: ", err)
|
|
return ticker, err
|
|
}
|
|
if !it.Valid() {
|
|
return nil, nil // ticker not found
|
|
}
|
|
return ticker, nil
|
|
}
|