mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 11:26:44 +01:00
Priceupdater-v0 (#23)
* First price-updater implementation * Lint corrections * Structs revision * Read Write Mutex * Review price updater and apply small changes Co-authored-by: Toni Ramírez <toni@iden3.com> Co-authored-by: Eduard S <eduard@iden3.io>
This commit is contained in:
136
priceupdater/priceupdater.go
Normal file
136
priceupdater/priceupdater.go
Normal file
@@ -0,0 +1,136 @@
|
||||
package priceupdater
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/dghubble/sling"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrSymbolDoesNotExistInDatabase is used when trying to get a token that is not in the DB
|
||||
ErrSymbolDoesNotExistInDatabase = errors.New("symbol does not exist in database")
|
||||
)
|
||||
|
||||
// ConfigPriceUpdater contains the configuration set by the coordinator
|
||||
type ConfigPriceUpdater struct {
|
||||
RecommendedFee uint64 // in dollars
|
||||
RecommendedCreateAccountFee uint64 // in dollars
|
||||
TokensList []string
|
||||
APIURL string
|
||||
}
|
||||
|
||||
// TokenInfo contains the updated value for the token
|
||||
type TokenInfo struct {
|
||||
Symbol string
|
||||
Value float64
|
||||
LastUpdated time.Time
|
||||
}
|
||||
|
||||
// PriceUpdater definition
|
||||
type PriceUpdater struct {
|
||||
db map[string]TokenInfo
|
||||
config ConfigPriceUpdater
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
// NewPriceUpdater is the constructor for the updater
|
||||
func NewPriceUpdater(config ConfigPriceUpdater) PriceUpdater {
|
||||
|
||||
return PriceUpdater{
|
||||
db: make(map[string]TokenInfo),
|
||||
config: config,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// UpdatePrices is triggered by the Coordinator, and internally will update the token prices in the db
|
||||
func (p *PriceUpdater) UpdatePrices() error {
|
||||
|
||||
tr := &http.Transport{
|
||||
MaxIdleConns: 10,
|
||||
IdleConnTimeout: 10 * time.Second,
|
||||
DisableCompression: true,
|
||||
}
|
||||
httpClient := &http.Client{Transport: tr}
|
||||
client := sling.New().Base(p.config.APIURL).Client(httpClient)
|
||||
|
||||
state := [10]float64{}
|
||||
|
||||
for _, tokenSymbol := range p.config.TokensList {
|
||||
|
||||
resp, err := client.New().Get("ticker/t" + tokenSymbol + "USD").ReceiveSuccess(&state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
return fmt.Errorf("Unexpected response status code: %v", resp.StatusCode)
|
||||
}
|
||||
|
||||
tinfo := TokenInfo{
|
||||
Symbol: tokenSymbol,
|
||||
Value: state[6],
|
||||
LastUpdated: time.Now(),
|
||||
}
|
||||
|
||||
p.UpdateTokenInfo(tinfo)
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateConfig allows to update the price-updater configuration
|
||||
func (p *PriceUpdater) UpdateConfig(config ConfigPriceUpdater) {
|
||||
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
p.config = config
|
||||
|
||||
}
|
||||
|
||||
// Get one token information
|
||||
func (p *PriceUpdater) Get(tokenSymbol string) (TokenInfo, error) {
|
||||
|
||||
var info TokenInfo
|
||||
|
||||
// Check if symbol exists in database
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
|
||||
if info, ok := p.db[tokenSymbol]; ok {
|
||||
return info, nil
|
||||
}
|
||||
|
||||
return info, ErrSymbolDoesNotExistInDatabase
|
||||
|
||||
}
|
||||
|
||||
// GetPrices gets all the prices contained in the db
|
||||
func (p *PriceUpdater) GetPrices() map[string]TokenInfo {
|
||||
|
||||
var info = make(map[string]TokenInfo)
|
||||
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
|
||||
for key, value := range p.db {
|
||||
info[key] = value
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
// UpdateTokenInfo updates one token info
|
||||
func (p *PriceUpdater) UpdateTokenInfo(tokenInfo TokenInfo) {
|
||||
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
p.db[tokenInfo.Symbol] = tokenInfo
|
||||
|
||||
}
|
||||
40
priceupdater/priceupdater_test.go
Normal file
40
priceupdater/priceupdater_test.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package priceupdater
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCon(t *testing.T) {
|
||||
|
||||
config := ConfigPriceUpdater{
|
||||
|
||||
RecommendedFee: 1,
|
||||
RecommendedCreateAccountFee: 1,
|
||||
TokensList: []string{"ETH", "NEC"},
|
||||
APIURL: "https://api-pub.bitfinex.com/v2/",
|
||||
}
|
||||
|
||||
pud := NewPriceUpdater(config)
|
||||
|
||||
err := pud.UpdatePrices()
|
||||
assert.Equal(t, err, nil)
|
||||
|
||||
info, _ := pud.Get("ETH")
|
||||
assert.NotZero(t, info.Value)
|
||||
|
||||
info2, _ := pud.Get("NEC")
|
||||
assert.NotZero(t, info2.Value)
|
||||
|
||||
info3, err := pud.Get("INVENTED")
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, ErrSymbolDoesNotExistInDatabase, err)
|
||||
}
|
||||
assert.Equal(t, info3.Value, float64(0))
|
||||
|
||||
prices := pud.GetPrices()
|
||||
assert.Equal(t, prices["ETH"], info)
|
||||
assert.Equal(t, prices["NEC"], info2)
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user