Store current ticker in the internal state
This commit is contained in:
parent
3e816b931f
commit
715567d7f3
@ -1633,7 +1633,7 @@ func removeEmpty(stringSlice []string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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(currencies []string, ticker *db.CurrencyRatesTicker, token string) (*FiatTicker, error) {
|
func (w *Worker) getFiatRatesResult(currencies []string, ticker *common.CurrencyRatesTicker, token string) (*FiatTicker, error) {
|
||||||
if token != "" {
|
if token != "" {
|
||||||
if len(currencies) != 1 {
|
if len(currencies) != 1 {
|
||||||
return nil, NewAPIError("Rates for token only for a single currency", true)
|
return nil, NewAPIError("Rates for token only for a single currency", true)
|
||||||
@ -1672,7 +1672,7 @@ func (w *Worker) getFiatRatesResult(currencies []string, ticker *db.CurrencyRate
|
|||||||
|
|
||||||
// GetFiatRatesForBlockID returns fiat rates for block height or block hash
|
// GetFiatRatesForBlockID returns fiat rates for block height or block hash
|
||||||
func (w *Worker) GetFiatRatesForBlockID(blockID string, currencies []string, token string) (*FiatTicker, error) {
|
func (w *Worker) GetFiatRatesForBlockID(blockID string, currencies []string, token string) (*FiatTicker, error) {
|
||||||
var ticker *db.CurrencyRatesTicker
|
var ticker *common.CurrencyRatesTicker
|
||||||
bi, err := w.getBlockInfoFromBlockID(blockID)
|
bi, err := w.getBlockInfoFromBlockID(blockID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == bchain.ErrBlockNotFound {
|
if err == bchain.ErrBlockNotFound {
|
||||||
@ -1707,13 +1707,14 @@ func (w *Worker) GetCurrentFiatRates(currencies []string, token string) (*FiatTi
|
|||||||
if len(currencies) == 1 {
|
if len(currencies) == 1 {
|
||||||
vsCurrency = currencies[0]
|
vsCurrency = currencies[0]
|
||||||
}
|
}
|
||||||
ticker, err := w.db.FiatRatesGetCurrentTicker(vsCurrency, token)
|
ticker := w.is.GetCurrentTicker(vsCurrency, token)
|
||||||
if ticker == nil || err != nil {
|
var err error
|
||||||
|
if ticker == nil {
|
||||||
ticker, err = w.db.FiatRatesFindLastTicker(vsCurrency, token)
|
ticker, err = w.db.FiatRatesFindLastTicker(vsCurrency, token)
|
||||||
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("No tickers found!", true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result, err := w.getFiatRatesResult(currencies, ticker, token)
|
result, err := w.getFiatRatesResult(currencies, ticker, token)
|
||||||
@ -2101,6 +2102,10 @@ func (w *Worker) GetSystemInfo(internal bool) (*SystemInfo, error) {
|
|||||||
columnStats = w.is.GetAllDBColumnStats()
|
columnStats = w.is.GetAllDBColumnStats()
|
||||||
internalDBSize = w.is.DBSizeTotal()
|
internalDBSize = w.is.DBSizeTotal()
|
||||||
}
|
}
|
||||||
|
var currentFiatRatesTime time.Time
|
||||||
|
if w.is.CurrentTicker != nil {
|
||||||
|
currentFiatRatesTime = w.is.CurrentTicker.Timestamp
|
||||||
|
}
|
||||||
blockbookInfo := &BlockbookInfo{
|
blockbookInfo := &BlockbookInfo{
|
||||||
Coin: w.is.Coin,
|
Coin: w.is.Coin,
|
||||||
Host: w.is.Host,
|
Host: w.is.Host,
|
||||||
@ -2118,7 +2123,7 @@ func (w *Worker) GetSystemInfo(internal bool) (*SystemInfo, error) {
|
|||||||
Decimals: w.chainParser.AmountDecimals(),
|
Decimals: w.chainParser.AmountDecimals(),
|
||||||
HasFiatRates: w.is.HasFiatRates,
|
HasFiatRates: w.is.HasFiatRates,
|
||||||
HasTokenFiatRates: w.is.HasTokenFiatRates,
|
HasTokenFiatRates: w.is.HasTokenFiatRates,
|
||||||
CurrentFiatRatesTime: nonZeroTime(w.is.CurrentFiatRatesTime),
|
CurrentFiatRatesTime: nonZeroTime(currentFiatRatesTime),
|
||||||
HistoricalFiatRatesTime: nonZeroTime(w.is.HistoricalFiatRatesTime),
|
HistoricalFiatRatesTime: nonZeroTime(w.is.HistoricalFiatRatesTime),
|
||||||
HistoricalTokenFiatRatesTime: nonZeroTime(w.is.HistoricalTokenFiatRatesTime),
|
HistoricalTokenFiatRatesTime: nonZeroTime(w.is.HistoricalTokenFiatRatesTime),
|
||||||
DbSize: w.db.DatabaseSizeOnDisk(),
|
DbSize: w.db.DatabaseSizeOnDisk(),
|
||||||
|
|||||||
@ -527,7 +527,7 @@ func onNewBlockHash(hash string, height uint32) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func onNewFiatRatesTicker(ticker *db.CurrencyRatesTicker) {
|
func onNewFiatRatesTicker(ticker *common.CurrencyRatesTicker) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
glog.Error("onNewFiatRatesTicker recovered from panic: ", r)
|
glog.Error("onNewFiatRatesTicker recovered from panic: ", r)
|
||||||
|
|||||||
74
common/currencyrateticker.go
Normal file
74
common/currencyrateticker.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// CurrencyRatesTicker contains coin ticker data fetched from API
|
||||||
|
type CurrencyRatesTicker struct {
|
||||||
|
Timestamp time.Time `json:"timestamp"` // return as unix timestamp in API
|
||||||
|
Rates map[string]float32 `json:"rates"` // rates of the base currency against a list of vs currencies
|
||||||
|
TokenRates map[string]float32 `json:"tokenRates"` // rates of the tokens (identified by the address of the contract) against the base currency
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert converts value in base currency to toCurrency
|
||||||
|
func (t *CurrencyRatesTicker) Convert(baseValue float64, toCurrency string) float64 {
|
||||||
|
rate, found := t.Rates[toCurrency]
|
||||||
|
if !found {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return baseValue * float64(rate)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConvertTokenToBase converts token value to base currency
|
||||||
|
func (t *CurrencyRatesTicker) ConvertTokenToBase(value float64, token string) float64 {
|
||||||
|
if t.TokenRates != nil {
|
||||||
|
rate, found := t.TokenRates[token]
|
||||||
|
if found {
|
||||||
|
return value * float64(rate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConvertTokenToBase converts token value to toCurrency currency
|
||||||
|
func (t *CurrencyRatesTicker) ConvertToken(value float64, token string, toCurrency string) float64 {
|
||||||
|
baseValue := t.ConvertTokenToBase(value, token)
|
||||||
|
if baseValue > 0 {
|
||||||
|
return t.Convert(baseValue, toCurrency)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenRateInCurrency return token rate in toCurrency currency
|
||||||
|
func (t *CurrencyRatesTicker) TokenRateInCurrency(token string, toCurrency string) float32 {
|
||||||
|
if t.TokenRates != nil {
|
||||||
|
rate, found := t.TokenRates[token]
|
||||||
|
if found {
|
||||||
|
baseRate, found := t.Rates[toCurrency]
|
||||||
|
if found {
|
||||||
|
return baseRate * rate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSuitableTicker checks if the ticker can provide data for given vsCurrency or token
|
||||||
|
func IsSuitableTicker(ticker *CurrencyRatesTicker, vsCurrency string, token string) bool {
|
||||||
|
if vsCurrency != "" {
|
||||||
|
if ticker.Rates == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if _, found := ticker.Rates[vsCurrency]; !found {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if token != "" {
|
||||||
|
if ticker.TokenRates == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if _, found := ticker.TokenRates[token]; !found {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
62
common/currencyrateticker_test.go
Normal file
62
common/currencyrateticker_test.go
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCurrencyRatesTicker_ConvertToken(t *testing.T) {
|
||||||
|
ticker := &CurrencyRatesTicker{
|
||||||
|
Rates: map[string]float32{
|
||||||
|
"usd": 2129.987654321,
|
||||||
|
"eur": 1332.12345678,
|
||||||
|
},
|
||||||
|
TokenRates: map[string]float32{
|
||||||
|
"0x82df128257a7d7556262e1ab7f1f639d9775b85e": 0.4092341123,
|
||||||
|
"0x6b175474e89094c44da98b954eedeac495271d0f": 12.32323232323232,
|
||||||
|
"0xdac17f958d2ee523a2206206994597c13d831ec7": 1332421341235.51234,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
value float64
|
||||||
|
token string
|
||||||
|
toCurrency string
|
||||||
|
want float64
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "usd 0x82df128257a7d7556262e1ab7f1f639d9775b85e",
|
||||||
|
value: 10,
|
||||||
|
token: "0x82df128257a7d7556262e1ab7f1f639d9775b85e",
|
||||||
|
toCurrency: "usd",
|
||||||
|
want: 8716.635514874506,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "eur 0xdac17f958d2ee523a2206206994597c13d831ec7",
|
||||||
|
value: 23.123,
|
||||||
|
token: "0xdac17f958d2ee523a2206206994597c13d831ec7",
|
||||||
|
toCurrency: "eur",
|
||||||
|
want: 4.104216071804417e+16,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "eur 0xdac17f958d2ee523a2206206994597c13d831ec8",
|
||||||
|
value: 23.123,
|
||||||
|
token: "0xdac17f958d2ee523a2206206994597c13d831ec8",
|
||||||
|
toCurrency: "eur",
|
||||||
|
want: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "eur 0xdac17f958d2ee523a2206206994597c13d831ec7",
|
||||||
|
value: 23.123,
|
||||||
|
token: "0xdac17f958d2ee523a2206206994597c13d831ec7",
|
||||||
|
toCurrency: "czk",
|
||||||
|
want: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
if got := ticker.ConvertToken(tt.value, tt.token, tt.toCurrency); got != tt.want {
|
||||||
|
t.Errorf("CurrencyRatesTicker.ConvertToken() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -78,11 +78,11 @@ type InternalState struct {
|
|||||||
UtxoChecked bool `json:"utxoChecked"`
|
UtxoChecked bool `json:"utxoChecked"`
|
||||||
|
|
||||||
// store only the historical state, not the current state of the fiat rates in DB
|
// store only the historical state, not the current state of the fiat rates in DB
|
||||||
HasFiatRates bool `json:"-"`
|
HasFiatRates bool `json:"-"`
|
||||||
HasTokenFiatRates bool `json:"-"`
|
HasTokenFiatRates bool `json:"-"`
|
||||||
CurrentFiatRatesTime time.Time `json:"-"`
|
HistoricalFiatRatesTime time.Time `json:"historicalFiatRatesTime"`
|
||||||
HistoricalFiatRatesTime time.Time `json:"historicalFiatRatesTime"`
|
HistoricalTokenFiatRatesTime time.Time `json:"historicalTokenFiatRatesTime"`
|
||||||
HistoricalTokenFiatRatesTime time.Time `json:"historicalTokenFiatRatesTime"`
|
CurrentTicker *CurrencyRatesTicker `json:"currentTicker"`
|
||||||
|
|
||||||
BackendInfo BackendInfo `json:"-"`
|
BackendInfo BackendInfo `json:"-"`
|
||||||
}
|
}
|
||||||
@ -268,6 +268,24 @@ func (is *InternalState) Pack() ([]byte, error) {
|
|||||||
return json.Marshal(is)
|
return json.Marshal(is)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCurrentTicker returns current ticker
|
||||||
|
func (is *InternalState) GetCurrentTicker(vsCurrency string, token string) *CurrencyRatesTicker {
|
||||||
|
is.mux.Lock()
|
||||||
|
currentTicker := is.CurrentTicker
|
||||||
|
is.mux.Unlock()
|
||||||
|
if currentTicker != nil && IsSuitableTicker(currentTicker, vsCurrency, token) {
|
||||||
|
return currentTicker
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCurrentTicker sets current ticker
|
||||||
|
func (is *InternalState) SetCurrentTicker(t *CurrencyRatesTicker) {
|
||||||
|
is.mux.Lock()
|
||||||
|
defer is.mux.Unlock()
|
||||||
|
is.CurrentTicker = t
|
||||||
|
}
|
||||||
|
|
||||||
// UnpackInternalState unmarshals internal state from json
|
// UnpackInternalState unmarshals internal state from json
|
||||||
func UnpackInternalState(buf []byte) (*InternalState, error) {
|
func UnpackInternalState(buf []byte) (*InternalState, error) {
|
||||||
var is InternalState
|
var is InternalState
|
||||||
|
|||||||
124
db/fiat.go
124
db/fiat.go
@ -10,64 +10,14 @@ import (
|
|||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/juju/errors"
|
"github.com/juju/errors"
|
||||||
"github.com/linxGnu/grocksdb"
|
"github.com/linxGnu/grocksdb"
|
||||||
|
"github.com/trezor/blockbook/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FiatRatesTimeFormat is a format string for storing FiatRates timestamps in rocksdb
|
// FiatRatesTimeFormat is a format string for storing FiatRates timestamps in rocksdb
|
||||||
const FiatRatesTimeFormat = "20060102150405" // YYYYMMDDhhmmss
|
const FiatRatesTimeFormat = "20060102150405" // YYYYMMDDhhmmss
|
||||||
|
|
||||||
var tickersMux sync.Mutex
|
var lastTickerInDB *common.CurrencyRatesTicker
|
||||||
var lastTickerInDB *CurrencyRatesTicker
|
var lastTickerInDBMux sync.Mutex
|
||||||
var currentTicker *CurrencyRatesTicker
|
|
||||||
|
|
||||||
// CurrencyRatesTicker contains coin ticker data fetched from API
|
|
||||||
type CurrencyRatesTicker struct {
|
|
||||||
Timestamp time.Time // return as unix timestamp in API
|
|
||||||
Rates map[string]float32 // rates of the base currency against a list of vs currencies
|
|
||||||
TokenRates map[string]float32 // rates of the tokens (identified by the address of the contract) against the base currency
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert converts value in base currency to toCurrency
|
|
||||||
func (t *CurrencyRatesTicker) Convert(baseValue float64, toCurrency string) float64 {
|
|
||||||
rate, found := t.Rates[toCurrency]
|
|
||||||
if !found {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return baseValue * float64(rate)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvertTokenToBase converts token value to base currency
|
|
||||||
func (t *CurrencyRatesTicker) ConvertTokenToBase(value float64, token string) float64 {
|
|
||||||
if t.TokenRates != nil {
|
|
||||||
rate, found := t.TokenRates[token]
|
|
||||||
if found {
|
|
||||||
return value * float64(rate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvertTokenToBase converts token value to toCurrency currency
|
|
||||||
func (t *CurrencyRatesTicker) ConvertToken(value float64, token string, toCurrency string) float64 {
|
|
||||||
baseValue := t.ConvertTokenToBase(value, token)
|
|
||||||
if baseValue > 0 {
|
|
||||||
return t.Convert(baseValue, toCurrency)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// TokenRateInCurrency return token rate in toCurrency currency
|
|
||||||
func (t *CurrencyRatesTicker) TokenRateInCurrency(token string, toCurrency string) float32 {
|
|
||||||
if t.TokenRates != nil {
|
|
||||||
rate, found := t.TokenRates[token]
|
|
||||||
if found {
|
|
||||||
baseRate, found := t.Rates[toCurrency]
|
|
||||||
if found {
|
|
||||||
return baseRate * rate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func packTimestamp(t *time.Time) []byte {
|
func packTimestamp(t *time.Time) []byte {
|
||||||
return []byte(t.UTC().Format(FiatRatesTimeFormat))
|
return []byte(t.UTC().Format(FiatRatesTimeFormat))
|
||||||
@ -82,7 +32,7 @@ func unpackFloat32(buf []byte) (float32, int) {
|
|||||||
return math.Float32frombits(binary.BigEndian.Uint32(buf)), 4
|
return math.Float32frombits(binary.BigEndian.Uint32(buf)), 4
|
||||||
}
|
}
|
||||||
|
|
||||||
func packCurrencyRatesTicker(ticker *CurrencyRatesTicker) []byte {
|
func packCurrencyRatesTicker(ticker *common.CurrencyRatesTicker) []byte {
|
||||||
buf := make([]byte, 0, 32)
|
buf := make([]byte, 0, 32)
|
||||||
varBuf := make([]byte, vlq.MaxLen64)
|
varBuf := make([]byte, vlq.MaxLen64)
|
||||||
l := packVaruint(uint(len(ticker.Rates)), varBuf)
|
l := packVaruint(uint(len(ticker.Rates)), varBuf)
|
||||||
@ -102,9 +52,9 @@ func packCurrencyRatesTicker(ticker *CurrencyRatesTicker) []byte {
|
|||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func unpackCurrencyRatesTicker(buf []byte) (*CurrencyRatesTicker, error) {
|
func unpackCurrencyRatesTicker(buf []byte) (*common.CurrencyRatesTicker, error) {
|
||||||
var (
|
var (
|
||||||
ticker CurrencyRatesTicker
|
ticker common.CurrencyRatesTicker
|
||||||
s string
|
s string
|
||||||
l int
|
l int
|
||||||
len uint
|
len uint
|
||||||
@ -152,7 +102,7 @@ func FiatRatesConvertDate(date string) (*time.Time, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FiatRatesStoreTicker stores ticker data at the specified time
|
// FiatRatesStoreTicker stores ticker data at the specified time
|
||||||
func (d *RocksDB) FiatRatesStoreTicker(wb *grocksdb.WriteBatch, ticker *CurrencyRatesTicker) error {
|
func (d *RocksDB) FiatRatesStoreTicker(wb *grocksdb.WriteBatch, ticker *common.CurrencyRatesTicker) error {
|
||||||
if len(ticker.Rates) == 0 {
|
if len(ticker.Rates) == 0 {
|
||||||
return errors.New("Error storing ticker: empty rates")
|
return errors.New("Error storing ticker: empty rates")
|
||||||
}
|
}
|
||||||
@ -160,27 +110,7 @@ func (d *RocksDB) FiatRatesStoreTicker(wb *grocksdb.WriteBatch, ticker *Currency
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isSuitableTicker(ticker *CurrencyRatesTicker, vsCurrency string, token string) bool {
|
func getTickerFromIterator(it *grocksdb.Iterator, vsCurrency string, token string) (*common.CurrencyRatesTicker, error) {
|
||||||
if vsCurrency != "" {
|
|
||||||
if ticker.Rates == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if _, found := ticker.Rates[vsCurrency]; !found {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if token != "" {
|
|
||||||
if ticker.TokenRates == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if _, found := ticker.TokenRates[token]; !found {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTickerFromIterator(it *grocksdb.Iterator, vsCurrency string, token string) (*CurrencyRatesTicker, error) {
|
|
||||||
timeObj, err := time.Parse(FiatRatesTimeFormat, string(it.Key().Data()))
|
timeObj, err := time.Parse(FiatRatesTimeFormat, string(it.Key().Data()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -189,7 +119,7 @@ func getTickerFromIterator(it *grocksdb.Iterator, vsCurrency string, token strin
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !isSuitableTicker(ticker, vsCurrency, token) {
|
if !common.IsSuitableTicker(ticker, vsCurrency, token) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
ticker.Timestamp = timeObj.UTC()
|
ticker.Timestamp = timeObj.UTC()
|
||||||
@ -197,7 +127,7 @@ func getTickerFromIterator(it *grocksdb.Iterator, vsCurrency string, token strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FiatRatesGetTicker gets FiatRates ticker at the specified timestamp if it exist
|
// FiatRatesGetTicker gets FiatRates ticker at the specified timestamp if it exist
|
||||||
func (d *RocksDB) FiatRatesGetTicker(tickerTime *time.Time) (*CurrencyRatesTicker, error) {
|
func (d *RocksDB) FiatRatesGetTicker(tickerTime *time.Time) (*common.CurrencyRatesTicker, error) {
|
||||||
tickerTimeFormatted := tickerTime.UTC().Format(FiatRatesTimeFormat)
|
tickerTimeFormatted := tickerTime.UTC().Format(FiatRatesTimeFormat)
|
||||||
val, err := d.db.GetCF(d.ro, d.cfh[cfFiatRates], []byte(tickerTimeFormatted))
|
val, err := d.db.GetCF(d.ro, d.cfh[cfFiatRates], []byte(tickerTimeFormatted))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -217,21 +147,22 @@ func (d *RocksDB) FiatRatesGetTicker(tickerTime *time.Time) (*CurrencyRatesTicke
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FiatRatesFindTicker gets FiatRates data closest to the specified timestamp, of the base currency, vsCurrency or the token if specified
|
// FiatRatesFindTicker gets FiatRates data closest to the specified timestamp, of the base currency, vsCurrency or the token if specified
|
||||||
func (d *RocksDB) FiatRatesFindTicker(tickerTime *time.Time, vsCurrency string, token string) (*CurrencyRatesTicker, error) {
|
func (d *RocksDB) FiatRatesFindTicker(tickerTime *time.Time, vsCurrency string, token string) (*common.CurrencyRatesTicker, error) {
|
||||||
tickersMux.Lock()
|
currentTicker := d.is.GetCurrentTicker("", "")
|
||||||
|
lastTickerInDBMux.Lock()
|
||||||
|
dbTicker := lastTickerInDB
|
||||||
|
lastTickerInDBMux.Unlock()
|
||||||
if currentTicker != nil {
|
if currentTicker != nil {
|
||||||
if !tickerTime.Before(currentTicker.Timestamp) || (lastTickerInDB != nil && tickerTime.After(lastTickerInDB.Timestamp)) {
|
if !tickerTime.Before(currentTicker.Timestamp) || (dbTicker != nil && tickerTime.After(dbTicker.Timestamp)) {
|
||||||
f := true
|
f := true
|
||||||
if token != "" && currentTicker.TokenRates != nil {
|
if token != "" && currentTicker.TokenRates != nil {
|
||||||
_, f = currentTicker.TokenRates[token]
|
_, f = currentTicker.TokenRates[token]
|
||||||
}
|
}
|
||||||
if f {
|
if f {
|
||||||
tickersMux.Unlock()
|
|
||||||
return currentTicker, nil
|
return currentTicker, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tickersMux.Unlock()
|
|
||||||
|
|
||||||
tickerTimeFormatted := tickerTime.UTC().Format(FiatRatesTimeFormat)
|
tickerTimeFormatted := tickerTime.UTC().Format(FiatRatesTimeFormat)
|
||||||
it := d.db.NewIteratorCF(d.ro, d.cfh[cfFiatRates])
|
it := d.db.NewIteratorCF(d.ro, d.cfh[cfFiatRates])
|
||||||
@ -251,7 +182,7 @@ func (d *RocksDB) FiatRatesFindTicker(tickerTime *time.Time, vsCurrency string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FiatRatesFindLastTicker gets the last FiatRates record, of the base currency, vsCurrency or the token if specified
|
// FiatRatesFindLastTicker gets the last FiatRates record, of the base currency, vsCurrency or the token if specified
|
||||||
func (d *RocksDB) FiatRatesFindLastTicker(vsCurrency string, token string) (*CurrencyRatesTicker, error) {
|
func (d *RocksDB) FiatRatesFindLastTicker(vsCurrency string, token string) (*common.CurrencyRatesTicker, error) {
|
||||||
it := d.db.NewIteratorCF(d.ro, d.cfh[cfFiatRates])
|
it := d.db.NewIteratorCF(d.ro, d.cfh[cfFiatRates])
|
||||||
defer it.Close()
|
defer it.Close()
|
||||||
|
|
||||||
@ -264,29 +195,12 @@ func (d *RocksDB) FiatRatesFindLastTicker(vsCurrency string, token string) (*Cur
|
|||||||
if ticker != nil {
|
if ticker != nil {
|
||||||
// if without filter, store the ticker for later use
|
// if without filter, store the ticker for later use
|
||||||
if vsCurrency == "" && token == "" {
|
if vsCurrency == "" && token == "" {
|
||||||
tickersMux.Lock()
|
lastTickerInDBMux.Lock()
|
||||||
lastTickerInDB = ticker
|
lastTickerInDB = ticker
|
||||||
tickersMux.Unlock()
|
lastTickerInDBMux.Unlock()
|
||||||
}
|
}
|
||||||
return ticker, nil
|
return ticker, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FiatRatesGetCurrentTicker returns current ticker
|
|
||||||
func (d *RocksDB) FiatRatesGetCurrentTicker(vsCurrency string, token string) (*CurrencyRatesTicker, error) {
|
|
||||||
tickersMux.Lock()
|
|
||||||
defer tickersMux.Unlock()
|
|
||||||
if currentTicker != nil && isSuitableTicker(currentTicker, vsCurrency, token) {
|
|
||||||
return currentTicker, nil
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FiatRatesCurrentTicker sets current ticker
|
|
||||||
func (d *RocksDB) FiatRatesSetCurrentTicker(t *CurrencyRatesTicker) {
|
|
||||||
tickersMux.Lock()
|
|
||||||
defer tickersMux.Unlock()
|
|
||||||
currentTicker = t
|
|
||||||
}
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/linxGnu/grocksdb"
|
"github.com/linxGnu/grocksdb"
|
||||||
|
"github.com/trezor/blockbook/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRocksTickers(t *testing.T) {
|
func TestRocksTickers(t *testing.T) {
|
||||||
@ -37,7 +38,7 @@ func TestRocksTickers(t *testing.T) {
|
|||||||
futureKey, _ := time.Parse(FiatRatesTimeFormat, "20190630000000")
|
futureKey, _ := time.Parse(FiatRatesTimeFormat, "20190630000000")
|
||||||
|
|
||||||
ts1, _ := time.Parse(FiatRatesTimeFormat, "20190628000000")
|
ts1, _ := time.Parse(FiatRatesTimeFormat, "20190628000000")
|
||||||
ticker1 := &CurrencyRatesTicker{
|
ticker1 := &common.CurrencyRatesTicker{
|
||||||
Timestamp: ts1,
|
Timestamp: ts1,
|
||||||
Rates: map[string]float32{
|
Rates: map[string]float32{
|
||||||
"usd": 20000,
|
"usd": 20000,
|
||||||
@ -49,7 +50,7 @@ func TestRocksTickers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ts2, _ := time.Parse(FiatRatesTimeFormat, "20190629000000")
|
ts2, _ := time.Parse(FiatRatesTimeFormat, "20190629000000")
|
||||||
ticker2 := &CurrencyRatesTicker{
|
ticker2 := &common.CurrencyRatesTicker{
|
||||||
Timestamp: ts2,
|
Timestamp: ts2,
|
||||||
Rates: map[string]float32{
|
Rates: map[string]float32{
|
||||||
"usd": 30000,
|
"usd": 30000,
|
||||||
@ -157,15 +158,13 @@ func TestRocksTickers(t *testing.T) {
|
|||||||
t.Errorf("Ticker %v found unexpectedly for aud vsCurrency", ticker)
|
t.Errorf("Ticker %v found unexpectedly for aud vsCurrency", ticker)
|
||||||
}
|
}
|
||||||
|
|
||||||
ticker, err = d.FiatRatesGetCurrentTicker("", "")
|
ticker = d.is.GetCurrentTicker("", "")
|
||||||
if err != nil {
|
if ticker != nil {
|
||||||
t.Errorf("TestRocksTickers err: %+v", err)
|
|
||||||
} else if ticker != nil {
|
|
||||||
t.Errorf("FiatRatesGetCurrentTicker %v found unexpectedly", ticker)
|
t.Errorf("FiatRatesGetCurrentTicker %v found unexpectedly", ticker)
|
||||||
}
|
}
|
||||||
|
|
||||||
d.FiatRatesSetCurrentTicker(ticker1)
|
d.is.SetCurrentTicker(ticker1)
|
||||||
ticker, err = d.FiatRatesGetCurrentTicker("", "")
|
ticker = d.is.GetCurrentTicker("", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("TestRocksTickers err: %+v", err)
|
t.Errorf("TestRocksTickers err: %+v", err)
|
||||||
} else if ticker == nil {
|
} else if ticker == nil {
|
||||||
@ -174,7 +173,7 @@ func TestRocksTickers(t *testing.T) {
|
|||||||
t.Errorf("Incorrect ticker found. Expected: %v, found: %+v", ticker1.Timestamp, ticker.Timestamp)
|
t.Errorf("Incorrect ticker found. Expected: %v, found: %+v", ticker1.Timestamp, ticker.Timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
d.FiatRatesSetCurrentTicker(nil)
|
d.is.SetCurrentTicker(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_packUnpackCurrencyRatesTicker(t *testing.T) {
|
func Test_packUnpackCurrencyRatesTicker(t *testing.T) {
|
||||||
@ -182,15 +181,15 @@ func Test_packUnpackCurrencyRatesTicker(t *testing.T) {
|
|||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
data CurrencyRatesTicker
|
data common.CurrencyRatesTicker
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "empty",
|
name: "empty",
|
||||||
data: CurrencyRatesTicker{},
|
data: common.CurrencyRatesTicker{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "rates",
|
name: "rates",
|
||||||
data: CurrencyRatesTicker{
|
data: common.CurrencyRatesTicker{
|
||||||
Rates: map[string]float32{
|
Rates: map[string]float32{
|
||||||
"usd": 2129.2341123,
|
"usd": 2129.2341123,
|
||||||
"eur": 1332.51234,
|
"eur": 1332.51234,
|
||||||
@ -199,7 +198,7 @@ func Test_packUnpackCurrencyRatesTicker(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "rates&tokenrates",
|
name: "rates&tokenrates",
|
||||||
data: CurrencyRatesTicker{
|
data: common.CurrencyRatesTicker{
|
||||||
Rates: map[string]float32{
|
Rates: map[string]float32{
|
||||||
"usd": 322129.987654321,
|
"usd": 322129.987654321,
|
||||||
"eur": 291332.12345678,
|
"eur": 291332.12345678,
|
||||||
@ -226,64 +225,3 @@ func Test_packUnpackCurrencyRatesTicker(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCurrencyRatesTicker_ConvertToken(t *testing.T) {
|
|
||||||
ticker := &CurrencyRatesTicker{
|
|
||||||
Rates: map[string]float32{
|
|
||||||
"usd": 2129.987654321,
|
|
||||||
"eur": 1332.12345678,
|
|
||||||
},
|
|
||||||
TokenRates: map[string]float32{
|
|
||||||
"0x82df128257a7d7556262e1ab7f1f639d9775b85e": 0.4092341123,
|
|
||||||
"0x6b175474e89094c44da98b954eedeac495271d0f": 12.32323232323232,
|
|
||||||
"0xdac17f958d2ee523a2206206994597c13d831ec7": 1332421341235.51234,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
type args struct {
|
|
||||||
baseValue float64
|
|
||||||
toCurrency string
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
value float64
|
|
||||||
token string
|
|
||||||
toCurrency string
|
|
||||||
want float64
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "usd 0x82df128257a7d7556262e1ab7f1f639d9775b85e",
|
|
||||||
value: 10,
|
|
||||||
token: "0x82df128257a7d7556262e1ab7f1f639d9775b85e",
|
|
||||||
toCurrency: "usd",
|
|
||||||
want: 8716.635514874506,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "eur 0xdac17f958d2ee523a2206206994597c13d831ec7",
|
|
||||||
value: 23.123,
|
|
||||||
token: "0xdac17f958d2ee523a2206206994597c13d831ec7",
|
|
||||||
toCurrency: "eur",
|
|
||||||
want: 4.104216071804417e+16,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "eur 0xdac17f958d2ee523a2206206994597c13d831ec8",
|
|
||||||
value: 23.123,
|
|
||||||
token: "0xdac17f958d2ee523a2206206994597c13d831ec8",
|
|
||||||
toCurrency: "eur",
|
|
||||||
want: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "eur 0xdac17f958d2ee523a2206206994597c13d831ec7",
|
|
||||||
value: 23.123,
|
|
||||||
token: "0xdac17f958d2ee523a2206206994597c13d831ec7",
|
|
||||||
toCurrency: "czk",
|
|
||||||
want: 0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
if got := ticker.ConvertToken(tt.value, tt.token, tt.toCurrency); got != tt.want {
|
|
||||||
t.Errorf("CurrencyRatesTicker.ConvertToken() = %v, want %v", got, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/linxGnu/grocksdb"
|
"github.com/linxGnu/grocksdb"
|
||||||
|
"github.com/trezor/blockbook/common"
|
||||||
"github.com/trezor/blockbook/db"
|
"github.com/trezor/blockbook/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -223,11 +224,11 @@ func (cg *Coingecko) platformIds() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cg *Coingecko) CurrentTickers() (*db.CurrencyRatesTicker, error) {
|
func (cg *Coingecko) CurrentTickers() (*common.CurrencyRatesTicker, error) {
|
||||||
cg.updatingCurrent = true
|
cg.updatingCurrent = true
|
||||||
defer func() { cg.updatingCurrent = false }()
|
defer func() { cg.updatingCurrent = false }()
|
||||||
|
|
||||||
var newTickers = db.CurrencyRatesTicker{}
|
var newTickers = common.CurrencyRatesTicker{}
|
||||||
|
|
||||||
if vsCurrencies == nil {
|
if vsCurrencies == nil {
|
||||||
vs, err := cg.simpleSupportedVSCurrencies()
|
vs, err := cg.simpleSupportedVSCurrencies()
|
||||||
@ -275,7 +276,7 @@ func (cg *Coingecko) CurrentTickers() (*db.CurrencyRatesTicker, error) {
|
|||||||
return &newTickers, nil
|
return &newTickers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cg *Coingecko) getHistoricalTicker(tickersToUpdate map[uint]*db.CurrencyRatesTicker, coinId string, vsCurrency string, token string) (bool, error) {
|
func (cg *Coingecko) getHistoricalTicker(tickersToUpdate map[uint]*common.CurrencyRatesTicker, coinId string, vsCurrency string, token string) (bool, error) {
|
||||||
lastTicker, err := cg.db.FiatRatesFindLastTicker(vsCurrency, token)
|
lastTicker, err := cg.db.FiatRatesFindLastTicker(vsCurrency, token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@ -306,7 +307,7 @@ func (cg *Coingecko) getHistoricalTicker(tickersToUpdate map[uint]*db.CurrencyRa
|
|||||||
rate := float32(p[1])
|
rate := float32(p[1])
|
||||||
if timestamp%(24*3600) == 0 && timestamp != 0 && rate != 0 { // process only tickers for the whole day with non 0 value
|
if timestamp%(24*3600) == 0 && timestamp != 0 && rate != 0 { // process only tickers for the whole day with non 0 value
|
||||||
var found bool
|
var found bool
|
||||||
var ticker *db.CurrencyRatesTicker
|
var ticker *common.CurrencyRatesTicker
|
||||||
if ticker, found = tickersToUpdate[timestamp]; !found {
|
if ticker, found = tickersToUpdate[timestamp]; !found {
|
||||||
u := time.Unix(int64(timestamp), 0).UTC()
|
u := time.Unix(int64(timestamp), 0).UTC()
|
||||||
ticker, err = cg.db.FiatRatesGetTicker(&u)
|
ticker, err = cg.db.FiatRatesGetTicker(&u)
|
||||||
@ -321,7 +322,7 @@ func (cg *Coingecko) getHistoricalTicker(tickersToUpdate map[uint]*db.CurrencyRa
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ticker = &db.CurrencyRatesTicker{
|
ticker = &common.CurrencyRatesTicker{
|
||||||
Timestamp: u,
|
Timestamp: u,
|
||||||
Rates: make(map[string]float32),
|
Rates: make(map[string]float32),
|
||||||
}
|
}
|
||||||
@ -341,7 +342,7 @@ func (cg *Coingecko) getHistoricalTicker(tickersToUpdate map[uint]*db.CurrencyRa
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cg *Coingecko) storeTickers(tickersToUpdate map[uint]*db.CurrencyRatesTicker) error {
|
func (cg *Coingecko) storeTickers(tickersToUpdate map[uint]*common.CurrencyRatesTicker) error {
|
||||||
if len(tickersToUpdate) > 0 {
|
if len(tickersToUpdate) > 0 {
|
||||||
wb := grocksdb.NewWriteBatch()
|
wb := grocksdb.NewWriteBatch()
|
||||||
defer wb.Destroy()
|
defer wb.Destroy()
|
||||||
@ -368,7 +369,7 @@ func (cg *Coingecko) throttleHistoricalDownload() {
|
|||||||
|
|
||||||
// UpdateHistoricalTickers gets historical tickers for the main crypto currency
|
// UpdateHistoricalTickers gets historical tickers for the main crypto currency
|
||||||
func (cg *Coingecko) UpdateHistoricalTickers() error {
|
func (cg *Coingecko) UpdateHistoricalTickers() error {
|
||||||
tickersToUpdate := make(map[uint]*db.CurrencyRatesTicker)
|
tickersToUpdate := make(map[uint]*common.CurrencyRatesTicker)
|
||||||
|
|
||||||
// reload vs_currencies
|
// reload vs_currencies
|
||||||
vs, err := cg.simpleSupportedVSCurrencies()
|
vs, err := cg.simpleSupportedVSCurrencies()
|
||||||
@ -401,7 +402,7 @@ func (cg *Coingecko) UpdateHistoricalTokenTickers() error {
|
|||||||
}
|
}
|
||||||
cg.updatingTokens = true
|
cg.updatingTokens = true
|
||||||
defer func() { cg.updatingTokens = false }()
|
defer func() { cg.updatingTokens = false }()
|
||||||
tickersToUpdate := make(map[uint]*db.CurrencyRatesTicker)
|
tickersToUpdate := make(map[uint]*common.CurrencyRatesTicker)
|
||||||
|
|
||||||
if cg.platformIdentifier != "" && cg.platformVsCurrency != "" {
|
if cg.platformIdentifier != "" && cg.platformVsCurrency != "" {
|
||||||
// reload platform ids
|
// reload platform ids
|
||||||
@ -425,7 +426,7 @@ func (cg *Coingecko) UpdateHistoricalTokenTickers() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
tickersToUpdate = make(map[uint]*db.CurrencyRatesTicker)
|
tickersToUpdate = make(map[uint]*common.CurrencyRatesTicker)
|
||||||
glog.Infof("Coingecko updated %d of %d token tickers", count, len(platformIds))
|
glog.Infof("Coingecko updated %d of %d token tickers", count, len(platformIds))
|
||||||
}
|
}
|
||||||
if req {
|
if req {
|
||||||
|
|||||||
@ -8,15 +8,16 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
"github.com/trezor/blockbook/common"
|
||||||
"github.com/trezor/blockbook/db"
|
"github.com/trezor/blockbook/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OnNewFiatRatesTicker is used to send notification about a new FiatRates ticker
|
// OnNewFiatRatesTicker is used to send notification about a new FiatRates ticker
|
||||||
type OnNewFiatRatesTicker func(ticker *db.CurrencyRatesTicker)
|
type OnNewFiatRatesTicker func(ticker *common.CurrencyRatesTicker)
|
||||||
|
|
||||||
// RatesDownloaderInterface provides method signatures for specific fiat rates downloaders
|
// RatesDownloaderInterface provides method signatures for specific fiat rates downloaders
|
||||||
type RatesDownloaderInterface interface {
|
type RatesDownloaderInterface interface {
|
||||||
CurrentTickers() (*db.CurrencyRatesTicker, error)
|
CurrentTickers() (*common.CurrencyRatesTicker, error)
|
||||||
UpdateHistoricalTickers() error
|
UpdateHistoricalTickers() error
|
||||||
UpdateHistoricalTokenTickers() error
|
UpdateHistoricalTokenTickers() error
|
||||||
}
|
}
|
||||||
@ -80,17 +81,25 @@ func NewFiatRatesDownloader(db *db.RocksDB, apiType string, params string, callb
|
|||||||
func (rd *RatesDownloader) Run() error {
|
func (rd *RatesDownloader) Run() error {
|
||||||
var lastHistoricalTickers time.Time
|
var lastHistoricalTickers time.Time
|
||||||
is := rd.db.GetInternalState()
|
is := rd.db.GetInternalState()
|
||||||
|
tickerFromIs := is.GetCurrentTicker("", "")
|
||||||
|
firstRun := true
|
||||||
for {
|
for {
|
||||||
|
unix := time.Now().Unix()
|
||||||
|
next := unix + rd.periodSeconds
|
||||||
|
next -= next % rd.periodSeconds
|
||||||
|
// skip waiting for the period for the first run if there are no tickerFromIs or they are too old
|
||||||
|
if !firstRun || (tickerFromIs != nil && next-tickerFromIs.Timestamp.Unix() < rd.periodSeconds) {
|
||||||
|
// wait for the next run with a slight random value to avoid too many request at the same time
|
||||||
|
next += int64(rand.Intn(12))
|
||||||
|
time.Sleep(time.Duration(next-unix) * time.Second)
|
||||||
|
}
|
||||||
|
firstRun = false
|
||||||
tickers, err := rd.downloader.CurrentTickers()
|
tickers, err := rd.downloader.CurrentTickers()
|
||||||
if err != nil || tickers == nil {
|
if err != nil || tickers == nil {
|
||||||
glog.Error("FiatRatesDownloader: CurrentTickers error ", err)
|
glog.Error("FiatRatesDownloader: CurrentTickers error ", err)
|
||||||
} else {
|
} else {
|
||||||
rd.db.FiatRatesSetCurrentTicker(tickers)
|
is.SetCurrentTicker(tickers)
|
||||||
glog.Info("FiatRatesDownloader: CurrentTickers updated")
|
glog.Info("FiatRatesDownloader: CurrentTickers updated")
|
||||||
if is != nil {
|
|
||||||
is.CurrentFiatRatesTime = time.Now()
|
|
||||||
}
|
|
||||||
if rd.callbackOnNewTicker != nil {
|
if rd.callbackOnNewTicker != nil {
|
||||||
rd.callbackOnNewTicker(tickers)
|
rd.callbackOnNewTicker(tickers)
|
||||||
}
|
}
|
||||||
@ -128,11 +137,5 @@ func (rd *RatesDownloader) Run() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// wait for the next run with a slight random value to avoid too many request at the same time
|
|
||||||
unix := time.Now().Unix()
|
|
||||||
next := unix + rd.periodSeconds
|
|
||||||
next -= next % rd.periodSeconds
|
|
||||||
next += int64(rand.Intn(12))
|
|
||||||
time.Sleep(time.Duration(next-unix) * time.Second)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -165,7 +165,7 @@ func TestFiatRates(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
wantCurrentTickers := db.CurrencyRatesTicker{
|
wantCurrentTickers := common.CurrencyRatesTicker{
|
||||||
Rates: map[string]float32{
|
Rates: map[string]float32{
|
||||||
"aed": 8447.1,
|
"aed": 8447.1,
|
||||||
"ars": 268901,
|
"ars": 268901,
|
||||||
@ -208,7 +208,7 @@ func TestFiatRates(t *testing.T) {
|
|||||||
if err != nil || ticker == nil {
|
if err != nil || ticker == nil {
|
||||||
t.Fatalf("FiatRatesFindLastTicker failed with error: %v", err)
|
t.Fatalf("FiatRatesFindLastTicker failed with error: %v", err)
|
||||||
}
|
}
|
||||||
wantTicker := db.CurrencyRatesTicker{
|
wantTicker := common.CurrencyRatesTicker{
|
||||||
Rates: map[string]float32{
|
Rates: map[string]float32{
|
||||||
"aed": 241272.48,
|
"aed": 241272.48,
|
||||||
"ars": 241272.48,
|
"ars": 241272.48,
|
||||||
@ -233,7 +233,7 @@ func TestFiatRates(t *testing.T) {
|
|||||||
if err != nil || ticker == nil {
|
if err != nil || ticker == nil {
|
||||||
t.Fatalf("FiatRatesFindLastTicker failed with error: %v", err)
|
t.Fatalf("FiatRatesFindLastTicker failed with error: %v", err)
|
||||||
}
|
}
|
||||||
wantTicker = db.CurrencyRatesTicker{
|
wantTicker = common.CurrencyRatesTicker{
|
||||||
Rates: map[string]float32{
|
Rates: map[string]float32{
|
||||||
"aed": 240402.97,
|
"aed": 240402.97,
|
||||||
"ars": 240402.97,
|
"ars": 240402.97,
|
||||||
@ -266,7 +266,7 @@ func TestFiatRates(t *testing.T) {
|
|||||||
if err != nil || ticker == nil {
|
if err != nil || ticker == nil {
|
||||||
t.Fatalf("FiatRatesFindLastTicker failed with error: %v", err)
|
t.Fatalf("FiatRatesFindLastTicker failed with error: %v", err)
|
||||||
}
|
}
|
||||||
wantTicker = db.CurrencyRatesTicker{
|
wantTicker = common.CurrencyRatesTicker{
|
||||||
Rates: map[string]float32{
|
Rates: map[string]float32{
|
||||||
"aed": 240402.97,
|
"aed": 240402.97,
|
||||||
"ars": 240402.97,
|
"ars": 240402.97,
|
||||||
|
|||||||
@ -222,7 +222,7 @@ func (s *PublicServer) OnNewBlock(hash string, height uint32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OnNewFiatRatesTicker notifies users subscribed to bitcoind/fiatrates about new ticker
|
// OnNewFiatRatesTicker notifies users subscribed to bitcoind/fiatrates about new ticker
|
||||||
func (s *PublicServer) OnNewFiatRatesTicker(ticker *db.CurrencyRatesTicker) {
|
func (s *PublicServer) OnNewFiatRatesTicker(ticker *common.CurrencyRatesTicker) {
|
||||||
s.websocket.OnNewFiatRatesTicker(ticker)
|
s.websocket.OnNewFiatRatesTicker(ticker)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -173,7 +173,7 @@ func insertFiatRate(date string, rates map[string]float32, tokenRates map[string
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
ticker := &db.CurrencyRatesTicker{
|
ticker := &common.CurrencyRatesTicker{
|
||||||
Timestamp: *convertedDate,
|
Timestamp: *convertedDate,
|
||||||
Rates: rates,
|
Rates: rates,
|
||||||
TokenRates: tokenRates,
|
TokenRates: tokenRates,
|
||||||
|
|||||||
@ -979,7 +979,7 @@ func (s *WebsocketServer) OnNewTx(tx *bchain.MempoolTx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *WebsocketServer) broadcastTicker(currency string, rates map[string]float32, ticker *db.CurrencyRatesTicker) {
|
func (s *WebsocketServer) broadcastTicker(currency string, rates map[string]float32, ticker *common.CurrencyRatesTicker) {
|
||||||
as, ok := s.fiatRatesSubscriptions[currency]
|
as, ok := s.fiatRatesSubscriptions[currency]
|
||||||
if ok && len(as) > 0 {
|
if ok && len(as) > 0 {
|
||||||
data := struct {
|
data := struct {
|
||||||
@ -1022,7 +1022,7 @@ func (s *WebsocketServer) broadcastTicker(currency string, rates map[string]floa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OnNewFiatRatesTicker is a callback that broadcasts info about fiat rates affecting subscribed currency
|
// OnNewFiatRatesTicker is a callback that broadcasts info about fiat rates affecting subscribed currency
|
||||||
func (s *WebsocketServer) OnNewFiatRatesTicker(ticker *db.CurrencyRatesTicker) {
|
func (s *WebsocketServer) OnNewFiatRatesTicker(ticker *common.CurrencyRatesTicker) {
|
||||||
s.fiatRatesSubscriptionsLock.Lock()
|
s.fiatRatesSubscriptionsLock.Lock()
|
||||||
defer s.fiatRatesSubscriptionsLock.Unlock()
|
defer s.fiatRatesSubscriptionsLock.Unlock()
|
||||||
for currency, rate := range ticker.Rates {
|
for currency, rate := range ticker.Rates {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user